From 318a88b61fee007c25e22cfd4d277abe0bbcd7f3 Mon Sep 17 00:00:00 2001 From: Daniel Willmann Date: Fri, 14 Dec 2012 23:38:01 +0000 Subject: [PATCH] efl: Introducing ecore_audio - the audio API for efl This is still very much a work in progress, so expect some issues. The signalling is using ecore events for now - that will change to callbacks you can register callbacks for events on specific Ecore_Audio_Objects. EO wasn't there when Ecore_Audio started, but it will probably move to that in the future. Otherwise have fun, don't break it (too much) and please send bug reports and feedback to me. Signed-off-by: Daniel Willmann SVN revision: 80994 --- src/lib/ecore_audio/Ecore_Audio.h | 442 +++++++++++++++++ src/lib/ecore_audio/ecore_audio.c | 557 ++++++++++++++++++++++ src/lib/ecore_audio/ecore_audio_private.h | 295 ++++++++++++ 3 files changed, 1294 insertions(+) create mode 100644 src/lib/ecore_audio/Ecore_Audio.h create mode 100644 src/lib/ecore_audio/ecore_audio.c create mode 100644 src/lib/ecore_audio/ecore_audio_private.h diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h new file mode 100644 index 0000000000..355db7101f --- /dev/null +++ b/src/lib/ecore_audio/Ecore_Audio.h @@ -0,0 +1,442 @@ +#ifndef ECORE_AUDIO_H +#define ECORE_AUDIO_H + +#include + +#ifdef EAPI +#undef EAPI +#endif + +#ifdef __GNUC__ +#if __GNUC__ >= 4 +#define EAPI __attribute__ ((visibility("default"))) +#else +#define EAPI +#endif +#else +#define EAPI +#endif + +/** + * @file Ecore_Audio.h + * @brief Audio utility functions + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @defgroup Ecore_Audio_Group Ecore_Audio - Convenience audio API + * + * @ref Ecore_Audio_Module_API_Group + * + * @{ + */ + +enum _Ecore_Audio_Type { + ECORE_AUDIO_TYPE_PULSE, + ECORE_AUDIO_TYPE_ALSA, + ECORE_AUDIO_TYPE_SNDFILE, + ECORE_AUDIO_TYPE_TONE, + ECORE_AUDIO_TYPE_CUSTOM, + ECORE_AUDIO_MODULE_LAST, +}; + +typedef enum _Ecore_Audio_Type Ecore_Audio_Type; + +typedef struct _Ecore_Audio_Module Ecore_Audio_Module; +/**< The audio module */ +typedef struct _Ecore_Audio_Object Ecore_Audio_Object; /**< The audio object */ +typedef struct _Ecore_Audio_Format Ecore_Audio_Format; +/**< The format of the audio data */ + +typedef int (*Ecore_Audio_Read_Callback)(void *user_data, void *data, int len); + +struct _Ecore_Audio_Vio { + int (*get_length)(Ecore_Audio_Object *in); + int (*seek)(Ecore_Audio_Object *in, int offset, int whence); + int (*tell)(Ecore_Audio_Object *in); + int (*read)(Ecore_Audio_Object *in, void *buffer, int length); + int (*write)(Ecore_Audio_Object *out, const void *buffer, int length); +}; + +typedef struct _Ecore_Audio_Vio Ecore_Audio_Vio; /** < Functions to implement IO virtually */ + +EAPI extern int ECORE_AUDIO_INPUT_STARTED; /**< Sound was started */ +EAPI extern int ECORE_AUDIO_INPUT_STOPPED; /**< Sound was stopped */ +EAPI extern int ECORE_AUDIO_INPUT_LOOPED; /**< Sound looped */ +EAPI extern int ECORE_AUDIO_INPUT_ENDED; /**< Sound playback ended */ +EAPI extern int ECORE_AUDIO_INPUT_PAUSED; /**< Sound paused */ +EAPI extern int ECORE_AUDIO_OUTPUT_INPUT_ADDED; /**< Input added to output */ +EAPI extern int ECORE_AUDIO_OUTPUT_INPUT_REMOVED; /**< Input removed from output */ + +/* Audio operations */ + +/** + * @brief Initialize the Ecore_Audio library. + * + * @return 1 or greater on success, 0 on error. + * + * This function sets up Ecore_Audio and initializes the modules that + * provide the in- and outputs to use. It returns 0 on failure, otherwise + * it returns the number of times it has already been called. + * + * When Ecore_Audio is not used anymore, call ecore_audio_shutdown() + * to shut down the Ecore_Audio library. + */ +EAPI int ecore_audio_init(void); + +/** + * @brief Shut down the Ecore_Audio library. + * + * @return 0 when the library is completely shut down, 1 or + * greater otherwise. + * + * This function shuts down the Ecore_Audio library. It returns 0 when it has + * been called the same number of times than ecore_audio_init(). In that case + * it shuts down all the services it uses. + */ +EAPI int ecore_audio_shutdown(void); + + +/* Output operations*/ + +/** + * @brief Create a new Ecore_Audio_Output instance + * + * @param name the name of the output to create + * @return a new instance or NULL on error + */ +EAPI Ecore_Audio_Object *ecore_audio_output_add(Ecore_Audio_Type type); + +/** + * @brief Set the name of an output + * + * @param output The output + * @param name The name + */ +EAPI void ecore_audio_output_name_set(Ecore_Audio_Object *output, const char *name); + +/** + * @brief Get the name of an output + * + * @param output the output + * + * @return the name of the output + */ +EAPI const char *ecore_audio_output_name_get(Ecore_Audio_Object *output); + +/** + * @brief Free an @ref Ecore_Audio_Output instance + * + * @param out the output + */ +EAPI void ecore_audio_output_del(Ecore_Audio_Object *output); + +/** + * @brief Set the user data pointer + * + * @param output The output + * @param data The pointer to set + */ +EAPI void ecore_audio_output_userdata_set(Ecore_Audio_Object *output, void *data); + +/** + * @brief Get the user data pointer + * + * @param output The output + * + * @return The pointer to the user data + */ +EAPI void *ecore_audio_output_userdata_get(Ecore_Audio_Object *output); + +/** + * @brief Set the volume of the output + * + * @param out the output + * @param volume the volume + */ +EAPI void ecore_audio_output_volume_set(Ecore_Audio_Object *output, double volume); + +/** + * @brief Get the volume of the output + * + * @param out the output + * + * @return the volume + */ +EAPI double ecore_audio_output_volume_get(Ecore_Audio_Object *output); + +/** + * @brief Set the paused state of an output + * + * @param out the output + * @param paused the paused state + */ +EAPI void ecore_audio_output_paused_set(Ecore_Audio_Object *output, Eina_Bool paused); + +/** + * @brief Get the paused state of an output + * + * @param out the output + * + * @return the paused state + */ +EAPI Eina_Bool ecore_audio_output_paused_get(Ecore_Audio_Object *output); + +/** + * @brief Add an input to an output. + * + * @param out the output + * @param in the input + * + * @return True if connecting was successful, False otherwise + */ +EAPI Eina_Bool ecore_audio_output_input_add(Ecore_Audio_Object *output, Ecore_Audio_Object *input); + +/** + * @brief Disconnect an input from an output. This will stop playback of the + * input. + * + * @param out the output + * @param in the input + * + * @return True if disconnecting was successful, False otherwise + */ +EAPI Eina_Bool ecore_audio_output_input_del(Ecore_Audio_Object *output, Ecore_Audio_Object *input); + +/** + * @brief Get the inputs connected to an output. + * + * @param out the output + * + * @return A list of Ecore_Audio_Input that are connected to the output + */ +EAPI Eina_List *ecore_audio_output_inputs_get(Ecore_Audio_Object *output); + +/** + * @brief Set up an input to play after another input. + * + * @param out the output + * @param after the input relative to which the other input will be chained + * @param in the input to chain + * + * @return True if chaining was successful, False otherwise + */ +EAPI Eina_Bool ecore_audio_output_input_chain_after(Ecore_Audio_Object *output, Ecore_Audio_Object *input, Ecore_Audio_Object *after); + + +/* Input operations*/ + +/** + * @brief Create a new Ecore_Audio_Input instance + * + * @param name the name of the input to create + * @return a new instance or NULL on error + */ +EAPI Ecore_Audio_Object *ecore_audio_input_add(Ecore_Audio_Type type); + +/** + * @brief Get the name of an input + * + * @param input the input + * + * @return the name of the input + */ +EAPI const char *ecore_audio_input_name_get(Ecore_Audio_Object *input); + +/** + * @brief Set the name of an input + * + * @param input the input + * @param name The name to set + */ +EAPI void ecore_audio_input_name_set(Ecore_Audio_Object *input, const char *name); + +/** + * @brief Free an @ref Ecore_Audio_Input instance + * + * @param in the input + */ +EAPI void ecore_audio_input_del(Ecore_Audio_Object *input); + +/** + * @brief Set the user data pointer + * + * @param input The input + * @param data The pointer to set + */ +EAPI void ecore_audio_input_userdata_set(Ecore_Audio_Object *input, void *data); + +/** + * @brief Get the user data pointer + * + * @param input The input + * + * @return The pointer to the user data + */ +EAPI void *ecore_audio_input_userdata_get(Ecore_Audio_Object *input); + +/** + * @brief Get the sample rate of the input + * + * @param input The input + * + * @return The samplerate in Hz + */ +EAPI int ecore_audio_input_samplerate_get(Ecore_Audio_Object *input); + +/** + * @brief Set the sample rate of the input + * + * @param input The input + * @param samplerate The sample rate in Hz + */ +EAPI void ecore_audio_input_samplerate_set(Ecore_Audio_Object *input, int samplerate); + +/** + * @brief Get the channels of the input + * + * @param input The input + * + * @return The number of channels + */ +EAPI int ecore_audio_input_channels_get(Ecore_Audio_Object *input); + +/** + * @brief Set the amount of channels in the input + * + * @param input The input + * @param channels The number of channels to set + */ +EAPI void ecore_audio_input_channels_set(Ecore_Audio_Object *input, int channels); + +/** + * @brief Seek within an input stream + * + * @param in the input + * @offset the offset in seconds + * @mode seek mode (SEEK_SET, SEEK_END, or SEEK_CUR) + * @return the current offset + */ +EAPI double ecore_audio_input_seek(Ecore_Audio_Object *input, double offset, int mode); + +/** + * @brief Read data from an input stream + * + * @param in the input + * @param data the buffer to write the audio data into + * @param len the size of the buffer + * + * @return the number of bytes that were read + */ +EAPI int ecore_audio_input_read(Ecore_Audio_Object *input, void *data, int len); + +/** + * @brief Get the paused state of an input + * + * @param in the input + * @return EINA_TRUE if the input is paused, EINA_FALSE otherwise + */ +EAPI Eina_Bool ecore_audio_input_paused_get(Ecore_Audio_Object *input); + +/** + * @brief Set the paused state of an input + * + * @param in the input + * @param paused the paused state to set + * + * If paused is EINA_TRUE if the input is paused, if it is EINA_FALSE the + * input plays normally. + */ +EAPI void ecore_audio_input_paused_set(Ecore_Audio_Object *input, Eina_Bool paused); + +/** + * @brief Set the volume of the input + * + * @param in the input + * @param volume the volume + */ +EAPI void ecore_audio_input_volume_set(Ecore_Audio_Object *input, double volume); + +/** + * @brief Get the volume of the input + * + * @param in the input + * + * @return the volume + */ +EAPI double ecore_audio_input_volume_get(Ecore_Audio_Object *input); + +/** + * @brief Set whether the input loops + * + * @param in the input + * @param looped if the input should loop + */ +EAPI void ecore_audio_input_looped_set(Ecore_Audio_Object *input, Eina_Bool looped); + +/** + * @brief Get whether the input loops + * + * @param in the input + * + * @return if the input loops + */ +EAPI Eina_Bool ecore_audio_input_looped_get(Ecore_Audio_Object *input); + +/** + * @brief Get the length of the input in seconds + * + * @param in the input + * + * @return the length in seconds + */ +EAPI double ecore_audio_input_length_get(Ecore_Audio_Object *input); + +/** + * @brief Set whether the input is preloaded + * + * @param in the input + * @param preloaded if the input is preloaded + */ +EAPI void ecore_audio_input_preloaded_set(Ecore_Audio_Object *input, Eina_Bool preloaded); + +/** + * @brief Get whether the input is preloaded + * + * @param in the input + * + * @return EINA_TRUE if the input is preloaded, otherwise EINA_FALSE + */ +EAPI Eina_Bool ecore_audio_input_preloaded_get(Ecore_Audio_Object *input); + +/** + * @brief Get the outputs this input is connected to + * + * @param in the input + * + * @return A list of outputs + */ +EAPI Ecore_Audio_Object *ecore_audio_input_output_get(Ecore_Audio_Object *input); + +/** + * @brief Get the remaining time of the input + * + * @param in the input + * + * @return The remaining time in seconds + */ +EAPI double ecore_audio_input_remaining_get(Ecore_Audio_Object *input); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/ecore_audio/ecore_audio.c b/src/lib/ecore_audio/ecore_audio.c new file mode 100644 index 0000000000..ccd8e5b3d1 --- /dev/null +++ b/src/lib/ecore_audio/ecore_audio.c @@ -0,0 +1,557 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_FEATURES_H +#include +#endif +#include +#include + +#include "ecore_audio_private.h" + +int _ecore_audio_log_dom = -1; +static int _ecore_audio_init_count = 0; +Eina_List *ecore_audio_modules; + +EAPI int ECORE_AUDIO_INPUT_STARTED; +EAPI int ECORE_AUDIO_INPUT_STOPPED; +EAPI int ECORE_AUDIO_INPUT_LOOPED; +EAPI int ECORE_AUDIO_INPUT_ENDED; +EAPI int ECORE_AUDIO_INPUT_PAUSED; +EAPI int ECORE_AUDIO_OUTPUT_INPUT_ADDED; +EAPI int ECORE_AUDIO_OUTPUT_INPUT_REMOVED; + +static void _dummy_free(void *foo EINA_UNUSED, void *bar EINA_UNUSED) +{ +} + +static int +module_cmp(const void *a, const void *b) +{ + Ecore_Audio_Module *mod = (Ecore_Audio_Module *)a; + Ecore_Audio_Type type = *(Ecore_Audio_Type *)b; + + return !(mod->type == type); +} + +static Ecore_Audio_Module * +get_module_by_type(Ecore_Audio_Type type) +{ + return eina_list_search_unsorted(ecore_audio_modules, module_cmp, &type); +} + +/* externally accessible functions */ + +EAPI int +ecore_audio_init(void) +{ + Ecore_Audio_Module *mod; + + if (++_ecore_audio_init_count != 1) + return _ecore_audio_init_count; + + if (!ecore_init()) + return --_ecore_audio_init_count; + + _ecore_audio_log_dom = eina_log_domain_register("ecore_audio", ECORE_AUDIO_DEFAULT_LOG_COLOR); + if (_ecore_audio_log_dom < 0) + { + EINA_LOG_ERR("Impossible to create a log domain for the ecore audio module."); + return --_ecore_audio_init_count; + } + + DBG("Ecore_Audio init"); + ecore_audio_modules = NULL; + + ECORE_AUDIO_INPUT_STARTED = ecore_event_type_new(); + ECORE_AUDIO_INPUT_STOPPED = ecore_event_type_new(); + ECORE_AUDIO_INPUT_LOOPED = ecore_event_type_new(); + ECORE_AUDIO_INPUT_ENDED = ecore_event_type_new(); + ECORE_AUDIO_INPUT_PAUSED = ecore_event_type_new(); + ECORE_AUDIO_OUTPUT_INPUT_ADDED = ecore_event_type_new(); + ECORE_AUDIO_OUTPUT_INPUT_REMOVED = ecore_event_type_new(); + + return _ecore_audio_init_count; +} + +EAPI int +ecore_audio_shutdown(void) +{ + DBG("Ecore_Audio shutdown"); + if (--_ecore_audio_init_count != 0) + return _ecore_audio_init_count; + + /* FIXME: Shutdown all the inputs and outputs first */ + + eina_list_free(ecore_audio_modules); + + eina_log_domain_unregister(_ecore_audio_log_dom); + _ecore_audio_log_dom = -1; + + ecore_shutdown(); + + return _ecore_audio_init_count; +} + +/* Output operations */ + +EAPI Ecore_Audio_Object * +ecore_audio_output_add(Ecore_Audio_Type type) +{ + Ecore_Audio_Output *out; + Ecore_Audio_Module *module; + + module = get_module_by_type(type); + + if (!module) + return NULL; + + out = calloc(1, sizeof(Ecore_Audio_Output)); + if (!out) + { + ERR("Could not allocate memory for output."); + return NULL; + } + + ECORE_MAGIC_SET(out, ECORE_MAGIC_AUDIO_OUTPUT); + out->module = module; + out->inputs = NULL; + + return module->out_ops->output_new((Ecore_Audio_Object *)out); +} + +EAPI void +ecore_audio_output_del(Ecore_Audio_Object *output) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + Eina_Bool del; + Ecore_Audio_Object *in; + + EINA_SAFETY_ON_NULL_RETURN(out); + + /* Cleanup */ + EINA_LIST_FREE (out->inputs, in) + { + del = ecore_audio_output_input_del(output, in); + if (!del) + WRN("Disconnecting in %p and out %p failed.", in, output); + } + + out->module->out_ops->output_del(output); + eina_stringshare_del(output->name); + free(output); +} + +EAPI void ecore_audio_output_userdata_set(Ecore_Audio_Object *output, void *data) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + out->user_data = data; +} + +EAPI void *ecore_audio_output_userdata_get(Ecore_Audio_Object *output) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + return out->user_data; +} + +EAPI const char *ecore_audio_output_name_get(Ecore_Audio_Object *output) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + EINA_SAFETY_ON_NULL_RETURN_VAL(out, NULL); + + return out->name; +} +EAPI void ecore_audio_output_name_set(Ecore_Audio_Object *output, const char *name) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + EINA_SAFETY_ON_NULL_RETURN(out); + + if (out->name) + eina_stringshare_del(out->name); + + out->name = eina_stringshare_add(name); +} + +EAPI void +ecore_audio_output_volume_set(Ecore_Audio_Object *output, double volume) +{ + EINA_SAFETY_ON_NULL_RETURN(output); + + Ecore_Audio_Module *outmod = output->module; + + outmod->out_ops->output_volume_set(output, volume); +} + +EAPI double +ecore_audio_output_volume_get(Ecore_Audio_Object *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, 0); + Ecore_Audio_Module *outmod = output->module; + + return outmod->out_ops->output_volume_get(output); +} + +EAPI void +ecore_audio_output_paused_set(Ecore_Audio_Object *output, Eina_Bool paused) +{ + EINA_SAFETY_ON_NULL_RETURN(output); + Ecore_Audio_Module *outmod = output->module; + + outmod->out_ops->output_paused_set(output, paused); +} + +EAPI Eina_Bool +ecore_audio_output_paused_get(Ecore_Audio_Object *output) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_TRUE); + + return output->paused; +} + +EAPI Eina_Bool +ecore_audio_output_input_add(Ecore_Audio_Object *output, Ecore_Audio_Object *input) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE); + Ecore_Audio_Module *outmod = output->module; + Eina_Bool ret; + + if (in->output != NULL) + ecore_audio_output_input_del((Ecore_Audio_Object *)in->output, input); + + ret = outmod->out_ops->output_add_input(output, input); + if (ret) + { + in->output = out; + out->inputs = eina_list_append(out->inputs, in); + ecore_event_add(ECORE_AUDIO_OUTPUT_INPUT_ADDED, in, _dummy_free, NULL); + } + + return ret; +} + +EAPI Eina_Bool +ecore_audio_output_input_del(Ecore_Audio_Object *output, Ecore_Audio_Object *input) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(output, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE); + Ecore_Audio_Module *outmod = output->module; + Eina_Bool ret; + + ret = outmod->out_ops->output_del_input(output, input); + if (ret) + { + in->output = NULL; + out->inputs = eina_list_remove(out->inputs, in); + ecore_event_add(ECORE_AUDIO_OUTPUT_INPUT_REMOVED, in, _dummy_free, NULL); + } + + return ret; +} + +EAPI Eina_List *ecore_audio_output_inputs_get(Ecore_Audio_Object *output) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE); + return out->inputs; +} + +EAPI Eina_Bool ecore_audio_output_input_chain_after(Ecore_Audio_Object *output, Ecore_Audio_Object *after, Ecore_Audio_Object *input) +{ + Ecore_Audio_Output *out = (Ecore_Audio_Output *)output; + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(out, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(in, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(after, EINA_FALSE); + + if (!eina_list_data_find(out->inputs, after)) + return EINA_FALSE; + + /* XXX: implement */ + return EINA_FALSE; +} + + +/* Input operations */ + +EAPI Ecore_Audio_Object * +ecore_audio_input_add(Ecore_Audio_Type type) +{ + Ecore_Audio_Input *in; + Ecore_Audio_Module *module; + + module = get_module_by_type(type); + + if (!module) + return NULL; + + in = calloc(1, sizeof(Ecore_Audio_Input)); + if (!in) + { + ERR("Could not allocate memory for input."); + return NULL; + } + + ECORE_MAGIC_SET(in, ECORE_MAGIC_AUDIO_INPUT); + in->module = module; + in->output = NULL; + in->paused = EINA_FALSE; + + return module->in_ops->input_new((Ecore_Audio_Object *)in); +} + +EAPI void +ecore_audio_input_del(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + Eina_Bool del; + Ecore_Audio_Module *module = input->module; + + if (in->output) { + del = ecore_audio_output_input_del((Ecore_Audio_Object *)in->output, input); + if (!del) + WRN("Disconnecting in %p and out %p failed.", input, in->output); + in->output = NULL; + } + + module->in_ops->input_del(input); + eina_stringshare_del(in->name); + free(in); +} + +EAPI void ecore_audio_input_userdata_set(Ecore_Audio_Object *input, void *data) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + in->user_data = data; +} + +EAPI void *ecore_audio_input_userdata_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + return in->user_data; +} + +EAPI const char *ecore_audio_input_name_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(in, NULL); + return in->name; +} + +EAPI void ecore_audio_input_name_set(Ecore_Audio_Object *input, const char *name) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN(in); + + if (in->name) + eina_stringshare_del(in->name); + + in->name = eina_stringshare_add(name); +} + +EAPI int ecore_audio_input_samplerate_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(in, -1); + + return in->samplerate; +} + +EAPI void ecore_audio_input_samplerate_set(Ecore_Audio_Object *input, int samplerate) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN(input); + Ecore_Audio_Module *outmod; + + if (in->samplerate == samplerate) + return; + + in->samplerate = samplerate; + + if (in->output) + { + outmod = in->output->module; + outmod->out_ops->output_update_input_format((Ecore_Audio_Object *)in->output, input); + } +} + +EAPI int ecore_audio_input_channels_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(in, -1); + + return in->channels; +} + +EAPI void ecore_audio_input_channels_set(Ecore_Audio_Object *input, int channels) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN(in); + + if (in->channels == channels) + return; + + in->channels = channels; + +/* XXX: Change channel number for connected streams? + if (in->output) + { + outmod = in->output->module; + outmod->out_ops->output_update_input_format(in->output, in); + } */ +} + +EAPI int ecore_audio_input_read(Ecore_Audio_Object *input, void *data, int len) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + int ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(in, 0); + Ecore_Audio_Module *inmod = input->module; + + if (in->paused) + { + memset(data, 0, len); + return len; + } + + ret = inmod->in_ops->input_read(input, data, len); + if (ret == 0) + { + if (!in->looped) + { + ecore_event_add(ECORE_AUDIO_INPUT_ENDED, in, _dummy_free, NULL); + } + else + { + inmod->in_ops->input_seek(input, 0, SEEK_SET); + ret = inmod->in_ops->input_read(input, data, len); + ecore_event_add(ECORE_AUDIO_INPUT_LOOPED, input, _dummy_free, NULL); + } + } + + return ret; +} + +EAPI double +ecore_audio_input_seek(Ecore_Audio_Object *input, double offs, int mode) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(input, -1); + Ecore_Audio_Module *inmod = input->module; + + return inmod->in_ops->input_seek(input, offs, mode); +} + +EAPI Eina_Bool +ecore_audio_input_paused_get(Ecore_Audio_Object *input) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE); + + return input->paused; +} + +EAPI void +ecore_audio_input_paused_set(Ecore_Audio_Object *input, Eina_Bool paused) +{ + EINA_SAFETY_ON_NULL_RETURN(input); + + if (paused == input->paused) + return; + + input->paused = paused; + ecore_event_add(ECORE_AUDIO_INPUT_PAUSED, input, _dummy_free, NULL); + +} + +EAPI void +ecore_audio_input_volume_set(Ecore_Audio_Object *input, double volume) +{ + EINA_SAFETY_ON_NULL_RETURN(input); + Ecore_Audio_Module *inmod = input->module; + + inmod->in_ops->input_volume_set(input, volume); +} + +EAPI double +ecore_audio_input_volume_get(Ecore_Audio_Object *input) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(input, -1); + Ecore_Audio_Module *inmod = input->module; + + return inmod->in_ops->input_volume_get(input); +} + +EAPI void +ecore_audio_input_looped_set(Ecore_Audio_Object *input, Eina_Bool looped) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN(input); + + in->looped = looped; +} + +EAPI Eina_Bool +ecore_audio_input_looped_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE); + + return in->looped; +} + +EAPI double +ecore_audio_input_length_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(input, -1); + + return in->length; +} + +EAPI void +ecore_audio_input_preloaded_set(Ecore_Audio_Object *input, Eina_Bool preloaded) +{ + EINA_SAFETY_ON_NULL_RETURN(input); + Ecore_Audio_Module *inmod = input->module; + + inmod->in_ops->input_preloaded_set(input, preloaded); +} + +EAPI Eina_Bool +ecore_audio_input_preloaded_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(input, EINA_FALSE); + return in->preloaded; +} + +EAPI Ecore_Audio_Object * +ecore_audio_input_output_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(input, NULL); + return (Ecore_Audio_Object *)in->output; +} + +EAPI double +ecore_audio_input_remaining_get(Ecore_Audio_Object *input) +{ + Ecore_Audio_Input *in = (Ecore_Audio_Input *)input; + EINA_SAFETY_ON_NULL_RETURN_VAL(input, -1); + Ecore_Audio_Module *inmod = input->module; + + return in->length - inmod->in_ops->input_seek(input, 0, SEEK_CUR); +} + +/** + * @} + */ diff --git a/src/lib/ecore_audio/ecore_audio_private.h b/src/lib/ecore_audio/ecore_audio_private.h new file mode 100644 index 0000000000..a893aac50a --- /dev/null +++ b/src/lib/ecore_audio/ecore_audio_private.h @@ -0,0 +1,295 @@ +#ifndef ECORE_AUDIO_PRIVATE_H_ +#define ECORE_AUDIO_PRIVATE_H_ + +#ifdef __linux__ +#include +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "Ecore.h" +#include "ecore_private.h" + +#include "Ecore_Audio.h" + +extern int _ecore_audio_log_dom; + +#ifdef ECORE_AUDIO_DEFAULT_LOG_COLOR +#undef ECORE_AUDIO_DEFAULT_LOG_COLOR +#endif +#define ECORE_AUDIO_DEFAULT_LOG_COLOR EINA_COLOR_BLUE + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_ecore_audio_log_dom, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_ecore_audio_log_dom, __VA_ARGS__) + +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_ecore_audio_log_dom, __VA_ARGS__) + +#ifdef WRN +#undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_ecore_audio_log_dom, __VA_ARGS__) + +#ifdef CRIT +#undef CRIT +#endif +#define CRIT(...) EINA_LOG_DOM_CRIT(_ecore_audio_log_dom, __VA_ARGS__) + +#define ECORE_MAGIC_AUDIO_MODULE 0xabba0001 +#define ECORE_MAGIC_AUDIO_OUTPUT 0xabba0002 +#define ECORE_MAGIC_AUDIO_INPUT 0xabba0003 + +/** + * @addtogroup Ecore_Audio_Module_API_Group Ecore_Audio_Module_API - API for modules + * + * @{ + */ + +typedef struct _Ecore_Audio_Input Ecore_Audio_Input; +typedef struct _Ecore_Audio_Output Ecore_Audio_Output; + +/** + * @brief Functions for inputs + */ +struct input_api +{ + /** + * @brief Create a new input + * + * @param in The input already initialized from @ref ecore_audio_input_new() + * + * @return The input, NULL on error + */ + Ecore_Audio_Object *(*input_new)(Ecore_Audio_Object *in); + + /** + * @brief Free an input + * + * @param in The input + */ + void (*input_del)(Ecore_Audio_Object *in); + + /** + * @brief Read data from an input + * + * @param in The input to read from + * @param data A pointer to a buffer where the data is put + * @param len The amount of data to read in bytes + */ + int (*input_read)(Ecore_Audio_Object *in, void *data, int len); + + /** + * @brief Seek within an input + * + * @param in The input + * @param count The amount to seek in seconds + * @param mode The mode + * + * @return The current position in seconds + * + */ + double (*input_seek)(Ecore_Audio_Object *in, double count, int mode); + + /** + * @brief Set the volume + * + * @param in the input + * @param volume the volume + */ + void (*input_volume_set)(Ecore_Audio_Object *in, double volume); + + /** + * @brief Get the volume + * + * @param in the input + * + * @return the volume + */ + double (*input_volume_get)(Ecore_Audio_Object *in); + + void (*input_looped_set)(Ecore_Audio_Object *in, Eina_Bool looped); + Eina_Bool (*input_looped_get)(Ecore_Audio_Object *in); + + void (*input_preloaded_set)(Ecore_Audio_Object *in, Eina_Bool preloaded); +}; + +/** + * @brief Functions for outputs + */ +struct output_api +{ + /** + * @brief Create a new output + * + * @param out The output already initialized from @ref ecore_audio_output_new() + * + * @return The output, NULL on error + */ + Ecore_Audio_Object *(*output_new)(Ecore_Audio_Object * out); + + /** + * @brief Free an output + * + * @param out the output + */ + void (*output_del)(Ecore_Audio_Object *out); + + /** + * @brief Set the volume of the output + * + * @param out The output + * @param vol The volume in the range of 0-255 + */ + void (*output_volume_set)(Ecore_Audio_Object *out, double vol); + + /** + * @brief Get the volume of the output + * + * @param out The output + * + * @return vol The volume + */ + double (*output_volume_get)(Ecore_Audio_Object *out); + + /** + * @brief Set the paused state of the output + * + * @param out The output + * @param paused The paused state + */ + void (*output_paused_set)(Ecore_Audio_Object *out, Eina_Bool paused); + + /** + * @brief Add an input to an output + * + * @param out The output + * @param in The input + * + * @return EINA_TRUE if the operation was successful, EINA_FALSE otherwise + */ + Eina_Bool (*output_add_input)(Ecore_Audio_Object *out, Ecore_Audio_Object *in); + + /** + * @brief Delete an input from an output + * + * @param out The output + * @param in The input + * + * @return EINA_TRUE if the operation was successful, EINA_FALSE otherwise + */ + Eina_Bool (*output_del_input)(Ecore_Audio_Object *out, Ecore_Audio_Object *in); + + void (*output_update_input_format)(Ecore_Audio_Object *out, Ecore_Audio_Object *in); +}; + +/** + * @brief The structure representing an Ecore_Audio module + */ +struct _Ecore_Audio_Module +{ + ECORE_MAGIC; + Ecore_Audio_Type type; + char *name; + Eina_List *inputs; + Eina_List *outputs; + + void *priv; + + struct input_api *in_ops; + struct output_api *out_ops; +}; + +/** + * @brief A common structure, could be input or output + */ +struct _Ecore_Audio_Object +{ + ECORE_MAGIC; + const char *name; + Ecore_Audio_Module *module; + + Eina_Bool paused; + + void *module_data; + void *obj_data; + void *user_data; + +}; + +/** + * @brief The structure representing an Ecore_Audio output + */ +struct _Ecore_Audio_Output +{ + ECORE_MAGIC; + const char *name; + Ecore_Audio_Module *module; + + Eina_Bool paused; + + void *module_data; + void *obj_data; + void *user_data; + + Eina_List *inputs; /**< The inputs that are connected to this output */ +}; + +/** + * @brief The structure representing an Ecore_Audio input + */ +struct _Ecore_Audio_Input +{ + ECORE_MAGIC; + const char *name; + Ecore_Audio_Module *module; + + Eina_Bool paused; /**< Is the input paused? */ + + void *module_data; + void *obj_data; + void *user_data; + + Ecore_Audio_Output *output; /**< The output this input is connected to */ + + int samplerate; + int channels; + Eina_Bool looped; /**< Loop the sound */ + double length; /**< Length of the sound */ + Eina_Bool preloaded; + Eina_Bool ended; +}; + +/** + * @brief The structure representing an Ecore_Audio format + */ +struct _Ecore_Audio_Format +{ + unsigned int rate; + unsigned short channels; +}; + +struct _Ecore_Audio_Callback { + Ecore_Audio_Read_Callback read_cb; + void *data; +}; + +extern Eina_List *ecore_audio_modules; + +/** + * @} + */ +#endif