efl: Introducing ecore_audio - the audio API for efl
authorDaniel Willmann <d.willmann@samsung.com>
Fri, 14 Dec 2012 23:38:01 +0000 (23:38 +0000)
committerDaniel Willmann <daniel@totalueberwachung.de>
Fri, 14 Dec 2012 23:38:01 +0000 (23:38 +0000)
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 <d.willmann@samsung.com>
SVN revision: 80994

src/lib/ecore_audio/Ecore_Audio.h [new file with mode: 0644]
src/lib/ecore_audio/ecore_audio.c [new file with mode: 0644]
src/lib/ecore_audio/ecore_audio_private.h [new file with mode: 0644]

diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h
new file mode 100644 (file)
index 0000000..355db71
--- /dev/null
@@ -0,0 +1,442 @@
+#ifndef ECORE_AUDIO_H
+#define ECORE_AUDIO_H
+
+#include <Eina.h>
+
+#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 (file)
index 0000000..ccd8e5b
--- /dev/null
@@ -0,0 +1,557 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..a893aac
--- /dev/null
@@ -0,0 +1,295 @@
+#ifndef ECORE_AUDIO_PRIVATE_H_
+#define ECORE_AUDIO_PRIVATE_H_
+
+#ifdef __linux__
+#include <features.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#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