SoundPool implementation has been added. 81/74581/15
authoro.danchenko <o.danchenko@samsung.com>
Tue, 14 Jun 2016 20:02:40 +0000 (23:02 +0300)
committero.danchenko <o.danchenko@samsung.com>
Wed, 29 Jun 2016 17:35:03 +0000 (20:35 +0300)
Change-Id: I232a8cc5af30a4b14135d5b75c8b1debd7b71f3e
Signed-off-by: o.danchenko <o.danchenko@samsung.com>
15 files changed:
CMakeLists.txt
include/internal/priority.h [new file with mode: 0644]
include/internal/soundpool.h [new file with mode: 0644]
include/internal/source.h [new file with mode: 0644]
include/internal/stream.h [new file with mode: 0644]
include/internal/stream_cb_manager.h [new file with mode: 0644]
include/sound_pool.h
include/sound_pool_private.h [new file with mode: 0644]
packaging/sound-pool.spec
src/priority.c [new file with mode: 0644]
src/sound_pool.c
src/soundpool.c [new file with mode: 0644]
src/source.c [new file with mode: 0644]
src/stream.c [new file with mode: 0644]
src/stream_cb_manager.c [new file with mode: 0644]

index 12706f9..d34c3c1 100755 (executable)
@@ -51,7 +51,7 @@ INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
 INSTALL(
         DIRECTORY ${INC_DIR}/ DESTINATION ${INC_DIR}/media
         FILES_MATCHING
-        PATTERN "mm_soundpool_private.h" EXCLUDE
+        PATTERN "sound_pool_private.h" EXCLUDE
         PATTERN "${INC_DIR}/*.h"
         )
 
diff --git a/include/internal/priority.h b/include/internal/priority.h
new file mode 100644 (file)
index 0000000..caf767b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_INTERNAL_PRIORITY_H_
+#define __TIZEN_SOUNDPOOL_INTERNAL_PRIORITY_H_
+
+#include "sound_pool_private.h"
+#include "internal/stream.h"
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Pool Priority Manager type.
+ *
+ * @since_tizen 3.0
+ */
+struct stream_priority_manager_s {
+       sound_pool_t *pool;
+       GList *priority_queue;
+};
+
+sound_pool_error_e _sound_stream_priority_create(sound_pool_t *pool,
+               stream_priority_manager_t **mgr);
+
+sound_pool_error_e _sound_stream_priority_destroy(
+               stream_priority_manager_t *mgr);
+
+sound_pool_error_e _sound_stream_priority_add_stream(
+               stream_priority_manager_t *mgr, sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_priority_remove_stream(
+               stream_priority_manager_t *mgr, sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_priority_check(stream_priority_manager_t *mgr,
+               sound_stream_t *stream, gboolean *out);
+
+void _sound_stream_priority_update_playback(stream_priority_manager_t *mgr);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_INTERNAL_PRIORITY_H_ */
diff --git a/include/internal/soundpool.h b/include/internal/soundpool.h
new file mode 100644 (file)
index 0000000..9b015d3
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_INTERNAL_SOUNDPOOL_H__
+#define __TIZEN_SOUNDPOOL_INTERNAL_SOUNDPOOL_H__
+
+#include "sound_pool_type.h"
+#include "sound_pool_private.h"
+
+#include <glib.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct stream_cb_manager_s stream_cb_manager_t;
+typedef struct stream_priority_manager_s stream_priority_manager_t;
+
+/**
+ * @brief Sound Pool pool type.
+ *
+ * @since_tizen 3.0
+ */
+typedef struct sound_pool_s {
+       ALCcontext *al_context;
+       float volume;
+
+       GHashTable *sources;
+       GHashTable *streams;
+
+       guint max_streams;
+       guint max_stream_index;
+       sound_pool_state_e state;
+
+       struct {
+               sound_pool_state_change_cb callback;
+               void *user_data;
+       } state_cb_info;
+
+       stream_cb_manager_t *cbmgr;
+       stream_priority_manager_t *mgr_priority;
+} sound_pool_t;
+
+/* Max amount of sound pools which could be created. */
+#define SOUND_POOL_MAX_POOLS_AMOUNT 32U
+
+sound_pool_error_e _sound_pool_create(size_t max_streams, sound_pool_t **pool);
+
+sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool);
+
+sound_pool_error_e _sound_pool_activate(sound_pool_t *pool);
+
+sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool);
+
+sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool, sound_pool_state_e *state);
+
+sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume);
+
+sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume);
+
+sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
+               sound_pool_state_change_cb callback, void *data);
+
+sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_INTERNAL_SOUNDPOOL_H__ */
diff --git a/include/internal/source.h b/include/internal/source.h
new file mode 100644 (file)
index 0000000..58117f9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_INTERNAL_SOURCE_H__
+#define __TIZEN_SOUNDPOOL_INTERNAL_SOURCE_H__
+
+#include "sound_pool_private.h"
+#include "internal/soundpool.h"
+
+#include <glib.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Sound Pool source type.
+ *
+ * @since_tizen 3.0
+ */
+typedef struct sound_source_s {
+       sound_pool_t *parent_pool;
+       gchar *tag_name;
+       ALuint al_buffer;
+} sound_source_t;
+
+/* Max length of the tag can be used for source identification. */
+#define MAX_TAG_LEN 255U
+
+sound_pool_error_e _sound_source_create(sound_pool_t *pool, const char *tag,
+               sound_source_t **src);
+
+sound_pool_error_e _sound_source_destroy(sound_source_t *src);
+
+sound_pool_error_e _sound_source_load_from_file(sound_source_t *src, const char *fname);
+
+sound_pool_error_e _sound_pool_get_source_by_tag(sound_pool_t *pool, const char *tag,
+               sound_source_t **src);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_INTERNAL_SOURCE_H__ */
diff --git a/include/internal/stream.h b/include/internal/stream.h
new file mode 100644 (file)
index 0000000..9d67b34
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_INTERNAL_STREAM_H__
+#define __TIZEN_SOUNDPOOL_INTERNAL_STREAM_H__
+
+
+#include "sound_pool_private.h"
+#include "internal/source.h"
+
+#include <glib.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Sound Pool stream type.
+ *
+ * @since_tizen 3.0
+ */
+typedef struct sound_stream_s {
+       unsigned id;
+       sound_source_t *parent_source;
+
+       unsigned priority;
+       unsigned loop;
+       float volume;
+
+       sound_pool_stream_state_e state;
+       sound_pool_stream_state_e state_previous;
+       gboolean stopped;
+
+       struct {
+               sound_pool_stream_state_change_cb callback;
+               void *user_data;
+       } state_cb_info;
+
+       ALuint al_source;
+} sound_stream_t;
+
+sound_pool_error_e _sound_stream_create(sound_source_t *src, sound_stream_t **stream);
+
+sound_pool_error_e _sound_stream_destroy(sound_stream_t *src);
+
+sound_pool_error_e _sound_stream_play(sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_pause(sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_resume(sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_stop(sound_stream_t *stream);
+
+sound_pool_error_e _sound_stream_set_loop(sound_stream_t *stream, unsigned loop);
+sound_pool_error_e _sound_stream_get_loop(sound_stream_t *stream, unsigned *loop);
+
+sound_pool_error_e _sound_stream_set_volume(sound_stream_t *stream, float volume);
+sound_pool_error_e _sound_stream_get_volume(sound_stream_t *stream, float *volume);
+
+sound_pool_error_e _sound_stream_set_priority(sound_stream_t *stream, unsigned rank);
+sound_pool_error_e _sound_stream_get_priority(sound_stream_t *stream, unsigned *rank);
+
+sound_pool_error_e _sound_stream_get_state(sound_stream_t *stream,
+               sound_pool_stream_state_e *state);
+
+sound_pool_error_e _sound_stream_set_callback(sound_stream_t *stream,
+               sound_pool_stream_state_change_cb callback, void *data);
+
+sound_pool_error_e _sound_stream_unset_callback(sound_stream_t *stream);
+
+sound_pool_error_e _sound_pool_get_stream_by_id(sound_pool_t *pool, unsigned id,
+               sound_stream_t **stream);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_INTERNAL_STREAM_H__ */
diff --git a/include/internal/stream_cb_manager.h b/include/internal/stream_cb_manager.h
new file mode 100644 (file)
index 0000000..60ef83a
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_INTERNAL_STREAMCBMANAGER_H__
+#define __TIZEN_SOUNDPOOL_INTERNAL_STREAMCBMANAGER_H__
+
+#include "internal/stream.h"
+
+#include <pthread.h>
+#include <glib.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Stream Callback Manager type.
+ *
+ * @since_tizen 3.0
+ */
+struct stream_cb_manager_s {
+       sound_pool_t *pool;
+       GAsyncQueue *isolator_callback_queue;
+
+       pthread_t isolator_thread;
+       pthread_mutex_t isolator_data_mutex;
+       pthread_cond_t isolator_data_cond;
+       gboolean isolator_state_changed;
+       gboolean isolator_loop_run;
+};
+
+typedef struct stream_cb_manager_event_data_s {
+       sound_stream_t *stream;
+       sound_pool_stream_state_e state;
+       sound_pool_stream_state_e state_previous;
+} stream_cb_manager_event_data_t;
+
+sound_pool_error_e _stream_cb_manager_create(sound_pool_t *pool, stream_cb_manager_t **cbmgr);
+
+sound_pool_error_e _stream_cb_manager_destroy(stream_cb_manager_t *cbmgr);
+
+sound_pool_error_e _stream_cb_manager_register_event(stream_cb_manager_t *cbmgr,
+               sound_stream_t *stream);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_INTERNAL_STREAMCBMANAGER_H__ */
index 67e9d41..b862f0d 100644 (file)
@@ -99,7 +99,7 @@ typedef void (*sound_pool_stream_state_change_cb) (sound_pool_h pool,
  * @param [out]  pool           The handle to the pool that will be created
  * @return @c 0 on success, otherwise a negative error value
  * @retval #SOUND_POOL_ERROR_INVALID_PARAMETER
- *         Invalid parameter (@a pool is NULL or @ max_streams is 0)
+ *         Invalid parameter (@a pool is NULL or @a max_streams is 0)
  * @retval #SOUND_POOL_ERROR_OUT_OF_MEMORY
  *         Not enough memory to create sound pool
  * @retval #SOUND_POOL_ERROR_INVALID_OPERATION
@@ -107,7 +107,7 @@ typedef void (*sound_pool_stream_state_change_cb) (sound_pool_h pool,
  *
  * @see sound_pool_destroy()
  */
-int sound_pool_create(unsigned max_streams, sound_pool_h *pool);
+sound_pool_error_e sound_pool_create(unsigned max_streams, sound_pool_h *pool);
 
 /**
  * @brief Destroys sound pool and cleans allocated memory.
@@ -123,7 +123,7 @@ int sound_pool_create(unsigned max_streams, sound_pool_h *pool);
  *
  * @see sound_pool_create()
  */
-int sound_pool_destroy(sound_pool_h pool);
+sound_pool_error_e sound_pool_destroy(sound_pool_h pool);
 
 /**
  * @brief Loads sound source data from file to pool.
@@ -151,7 +151,7 @@ int sound_pool_destroy(sound_pool_h pool);
  * @see sound_pool_destroy()
  * @see sound_pool_unload_source()
  */
-int sound_pool_load_source_from_file(sound_pool_h pool, const char *file_name,
+sound_pool_error_e sound_pool_load_source_from_file(sound_pool_h pool, const char *file_name,
                const char *tag);
 
 /**
@@ -175,7 +175,7 @@ int sound_pool_load_source_from_file(sound_pool_h pool, const char *file_name,
  * @see sound_pool_create()
  * @see sound_pool_load_source_from_file()
  */
-int sound_pool_unload_source(sound_pool_h pool, const char *tag);
+sound_pool_error_e sound_pool_unload_source(sound_pool_h pool, const char *tag);
 
 /**
  * @brief Gets current @a state of @a pool.
@@ -194,7 +194,7 @@ int sound_pool_unload_source(sound_pool_h pool, const char *tag);
  * @see sound_pool_create()
  * @see sound_pool_state_e
  */
-int sound_pool_get_state(sound_pool_h pool,
+sound_pool_error_e sound_pool_get_state(sound_pool_h pool,
                sound_pool_state_e *state);
 
 /**
@@ -215,7 +215,7 @@ int sound_pool_get_state(sound_pool_h pool,
  * @see sound_pool_deactivate()
  * @see sound_pool_state_e
  */
-int sound_pool_activate(sound_pool_h pool);
+sound_pool_error_e sound_pool_activate(sound_pool_h pool);
 
 /**
  * @brief Changes current @a state of @a pool to SOUND_POOL_STATE_INACTIVE.
@@ -236,7 +236,7 @@ int sound_pool_activate(sound_pool_h pool);
  * @see sound_pool_activate()
  * @see sound_pool_state_e
  */
-int sound_pool_deactivate(sound_pool_h pool);
+sound_pool_error_e sound_pool_deactivate(sound_pool_h pool);
 
 /**
  * @brief Sets callback for handling sound @a pool state change.
@@ -258,7 +258,7 @@ int sound_pool_deactivate(sound_pool_h pool);
  * @see sound_pool_create()
  * @see sound_pool_pool_state_change_cb
  */
-int sound_pool_set_state_change_callback(sound_pool_h pool,
+sound_pool_error_e sound_pool_set_state_change_callback(sound_pool_h pool,
                sound_pool_state_change_cb callback, void *user_data);
 
 /**
@@ -276,7 +276,7 @@ int sound_pool_set_state_change_callback(sound_pool_h pool,
  * @see sound_pool_create()
  * @see sound_pool_set_state_change_callback()
  */
-int sound_pool_unset_state_change_callback(sound_pool_h pool);
+sound_pool_error_e sound_pool_unset_state_change_callback(sound_pool_h pool);
 
 /**
  * @brief Plays source by @a tag.
@@ -324,7 +324,7 @@ int sound_pool_unset_state_change_callback(sound_pool_h pool);
  * @see sound_pool_set_volume
  * @see sound_pool_get_volume
  */
-int sound_pool_stream_play(sound_pool_h pool, const char *tag, unsigned loop,
+sound_pool_error_e sound_pool_stream_play(sound_pool_h pool, const char *tag, unsigned loop,
                float volume, unsigned priority,
                sound_pool_stream_state_change_cb callback, void *user_data,
                unsigned *id);
@@ -353,7 +353,7 @@ int sound_pool_stream_play(sound_pool_h pool, const char *tag, unsigned loop,
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_pause(sound_pool_h pool, unsigned id);
+sound_pool_error_e sound_pool_stream_pause(sound_pool_h pool, unsigned id);
 
 /**
  * @brief Resumes stream by @a id.
@@ -381,7 +381,7 @@ int sound_pool_stream_pause(sound_pool_h pool, unsigned id);
  * @see sound_pool_stream_play()
  * @see sound_pool_stream_pause()
  */
-int sound_pool_stream_resume(sound_pool_h pool, unsigned id);
+sound_pool_error_e sound_pool_stream_resume(sound_pool_h pool, unsigned id);
 
 /**
  * @brief Stops stream by @a id.
@@ -410,7 +410,7 @@ int sound_pool_stream_resume(sound_pool_h pool, unsigned id);
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_stop(sound_pool_h pool, unsigned id);
+sound_pool_error_e sound_pool_stream_stop(sound_pool_h pool, unsigned id);
 
 /**
  * @brief Sets pool global volume parameter.
@@ -431,7 +431,7 @@ int sound_pool_stream_stop(sound_pool_h pool, unsigned id);
  *
  * @see sound_pool_create()
  */
-int sound_pool_set_volume(sound_pool_h pool, float volume);
+sound_pool_error_e sound_pool_set_volume(sound_pool_h pool, float volume);
 
 /**
  * @brief Gets pool global volume parameter.
@@ -448,7 +448,7 @@ int sound_pool_set_volume(sound_pool_h pool, float volume);
  *
  * @see sound_pool_create()
  */
-int sound_pool_get_volume(sound_pool_h pool, float *volume);
+sound_pool_error_e sound_pool_get_volume(sound_pool_h pool, float *volume);
 
 /**
  * @brief Gets current @a state of stream by @a id.
@@ -473,7 +473,7 @@ int sound_pool_get_volume(sound_pool_h pool, float *volume);
  * @see sound_pool_stream_play()
  * @see sound_pool_stream_state_e
  */
-int sound_pool_stream_get_state(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_get_state(sound_pool_h pool, unsigned id,
                sound_pool_stream_state_e *state);
 
 /**
@@ -499,7 +499,7 @@ int sound_pool_stream_get_state(sound_pool_h pool, unsigned id,
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_set_loop(sound_pool_h pool, unsigned id, unsigned loop);
+sound_pool_error_e sound_pool_stream_set_loop(sound_pool_h pool, unsigned id, unsigned loop);
 
 /**
  * @brief Gets stream @a loop parameter by stream @a id.
@@ -525,7 +525,7 @@ int sound_pool_stream_set_loop(sound_pool_h pool, unsigned id, unsigned loop);
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_get_loop(sound_pool_h pool, unsigned id, unsigned *loop);
+sound_pool_error_e sound_pool_stream_get_loop(sound_pool_h pool, unsigned id, unsigned *loop);
 
 /**
  * @brief Sets stream volume parameters by stream @a id.
@@ -552,7 +552,7 @@ int sound_pool_stream_get_loop(sound_pool_h pool, unsigned id, unsigned *loop);
  * @see sound_pool_set_volume
  * @see sound_pool_get_volume
  */
-int sound_pool_stream_set_volume(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_set_volume(sound_pool_h pool, unsigned id,
                float volume);
 
 /**
@@ -577,7 +577,7 @@ int sound_pool_stream_set_volume(sound_pool_h pool, unsigned id,
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_get_volume(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_get_volume(sound_pool_h pool, unsigned id,
                float *volume);
 
 /**
@@ -602,7 +602,7 @@ int sound_pool_stream_get_volume(sound_pool_h pool, unsigned id,
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_set_priority(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_set_priority(sound_pool_h pool, unsigned id,
                unsigned priority);
 
 /**
@@ -627,7 +627,7 @@ int sound_pool_stream_set_priority(sound_pool_h pool, unsigned id,
  * @see sound_pool_load_source_from_file()
  * @see sound_pool_stream_play()
  */
-int sound_pool_stream_get_priority(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_get_priority(sound_pool_h pool, unsigned id,
                unsigned *priority);
 
 /**
@@ -658,7 +658,7 @@ int sound_pool_stream_get_priority(sound_pool_h pool, unsigned id,
  * @see sound_pool_stream_play()
  * @see sound_pool_stream_state_change_cb
  */
-int sound_pool_stream_set_state_change_callback(sound_pool_h pool, unsigned id,
+sound_pool_error_e sound_pool_stream_set_state_change_callback(sound_pool_h pool, unsigned id,
                sound_pool_stream_state_change_cb callback, void *user_data);
 
 /**
@@ -683,7 +683,7 @@ int sound_pool_stream_set_state_change_callback(sound_pool_h pool, unsigned id,
  * @see sound_pool_stream_play()
  * @see sound_pool_stream_state_change_cb
  */
-int sound_pool_stream_unset_state_change_callback(sound_pool_h pool,
+sound_pool_error_e sound_pool_stream_unset_state_change_callback(sound_pool_h pool,
                unsigned id);
 
 /**
diff --git a/include/sound_pool_private.h b/include/sound_pool_private.h
new file mode 100644 (file)
index 0000000..2b3af54
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_SOUNDPOOL_PRIVATE_H__
+#define __TIZEN_SOUNDPOOL_PRIVATE_H__
+
+#include <glib.h>
+#include <dlog.h>
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#include "sound_pool.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "TIZEN_SOUND_POOL"
+
+#ifdef COLORED_LOG
+#define FONT_COLOR_RESET    "\033[0m"
+#define FONT_COLOR_RED      "\033[31m"
+#define FONT_COLOR_GREEN    "\033[32m"
+#define FONT_COLOR_YELLOW   "\033[33m"
+#define FONT_COLOR_BLUE     "\033[34m"
+#define FONT_COLOR_PURPLE   "\033[35m"
+#define FONT_COLOR_CYAN     "\033[36m"
+#define FONT_COLOR_GRAY     "\033[37m"
+#else
+#define FONT_COLOR_RESET
+#define FONT_COLOR_RED
+#define FONT_COLOR_GREEN
+#define FONT_COLOR_YELLOW
+#define FONT_COLOR_BLUE
+#define FONT_COLOR_PURPLE
+#define FONT_COLOR_CYAN
+#define FONT_COLOR_GRAY
+#endif
+
+/**
+ * @brief Max amount of sound pools which could be created.
+ *
+ * @since_tizen 3.0
+ */
+#define SOUND_POOL_MAX_POOLS_AMOUNT 32U
+
+#define SP_DEBUG(fmt, arg...)                             \
+       do {                                                  \
+               LOGD(FONT_COLOR_RESET""fmt"", ##arg);             \
+       } while (0)
+
+#define SP_INFO(fmt, arg...)                              \
+       do {                                                  \
+               LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET,     \
+                               ##arg);                                   \
+       } while (0)
+
+#define SP_ERROR(fmt, arg...)                             \
+       do {                                                  \
+               LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET,       \
+                               ##arg);                                   \
+       } while (0)
+
+#define SP_DEBUF_FENTER()                                 \
+       do {                                                  \
+               LOGD(FONT_COLOR_YELLOW"<Enter>"FONT_COLOR_RESET); \
+       } while (0)
+
+#define SP_DEBUG_FLEAVE()                                 \
+       do {                                                  \
+               LOGD(FONT_COLOR_PURPLE"<Leave>"FONT_COLOR_RESET); \
+       } while (0)
+
+#define SP_INST_CHECK(expr, ret_code)                     \
+       do {                                                  \
+               SP_RETVM_IF(NULL == expr, ret_code, #ret_code);   \
+       } while (0)
+
+#define SP_RETM_IF(expr, fmt, arg...)                     \
+       do {                                                  \
+               if (expr) {                                       \
+                       LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET,   \
+                               ##arg);                                   \
+                       SP_DEBUG_FLEAVE();                            \
+                       return;                                       \
+               }                                                 \
+       } while (0)
+
+#define SP_RETVM_IF(expr, val, fmt, arg...)               \
+       do {                                                  \
+               if (expr) {                                       \
+                       LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET,   \
+                               ##arg);                                   \
+                       SP_DEBUG_FLEAVE();                            \
+                       return(val);                                  \
+               }                                                 \
+       } while (0)
+
+#define GOTO_FAIL(msg, label)                             \
+       do {                                                  \
+               SP_ERROR(msg);                                    \
+               goto label;                                       \
+       } while (0)
+
+#define SP_SAFE_GFREE(src) { if (src) { g_free(src); src = NULL; } }
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_SOUNDPOOL_PRIVATE_H__ */
index 5d3ff1f..0f74e31 100644 (file)
@@ -17,7 +17,7 @@ BuildRequires: pkgconfig(freealut)
 Tizen Sound Pool Module allowing sounds playing for audio resources.
 
 %package devel
-Summary:    Tizen Sound Pool Module allowing sounds playing for audio resources (Development).
+Summary:    Tizen Module allowing sounds playing for audio resources (Development)
 Group:      Multimedia/Framework
 Requires:   %{name} = %{version}-%{release}
 
@@ -31,7 +31,7 @@ cp %{SOURCE1001} .
 %build
 export CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage"
 export CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage"
-export LDLAGS="$LDLAGS -lgcov"
+export LDFLAGS="$LDFLAGS -lgcov"
 
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 %cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
diff --git a/src/priority.c b/src/priority.c
new file mode 100644 (file)
index 0000000..9399567
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file priority.c
+ * @brief This file include implementation of prioritization of streams in the
+ * SoundPool.
+ */
+
+#include "internal/priority.h"
+
+static gint __stream_stream_proirity_cmp(gconstpointer a, gconstpointer b);
+
+static gint __stream_stream_proirity_cmp(gconstpointer a, gconstpointer b)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!a, 0, "Firs pointer is NULL.");
+       SP_RETVM_IF(!b, 0, "Second pointer is NULL.");
+       sound_stream_t *stream_a = (sound_stream_t *)a;
+       sound_stream_t *stream_b = (sound_stream_t *)b;
+
+       SP_DEBUG_FLEAVE();
+       if (stream_a->priority != stream_b->priority)
+               return (stream_b->priority - stream_a->priority);
+       return (stream_a->id - stream_b->id);
+}
+
+sound_pool_error_e _sound_stream_priority_create(sound_pool_t *pool,
+               stream_priority_manager_t **mgr)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Stream priority "
+                       "manager can't be created for NULL sound pool");
+       SP_RETVM_IF(!mgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
+                       "stream priority manager. Manager pointer is NULL");
+
+       stream_priority_manager_t *_mgr = NULL;
+       SP_RETVM_IF(!(_mgr = g_try_malloc0(sizeof(*_mgr))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create stream priority manager.");
+
+       int ret = SOUND_POOL_ERROR_NONE;
+
+       _mgr->priority_queue = NULL;
+       _mgr->pool = pool;
+       pool->mgr_priority = _mgr;
+
+       *mgr = _mgr;
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_stream_priority_destroy(stream_priority_manager_t *mgr)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!mgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle priority "
+                       "manager, it is NULL.");
+
+       int ret = SOUND_POOL_ERROR_NONE;
+
+       if (mgr->priority_queue) {
+               g_list_free(mgr->priority_queue);
+               mgr->priority_queue = NULL;
+       }
+
+       mgr->pool = NULL;
+
+       SP_SAFE_GFREE(mgr);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_stream_priority_add_stream(
+               stream_priority_manager_t *mgr, sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       int ret = SOUND_POOL_ERROR_NONE;
+       SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       mgr->priority_queue = g_list_append(mgr->priority_queue,(gpointer)stream);
+       _sound_stream_priority_update_playback(mgr);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_stream_priority_remove_stream(
+               stream_priority_manager_t *mgr, sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       int ret = SOUND_POOL_ERROR_NONE;
+
+       GList* to_delete;
+       to_delete = g_list_find(mgr->priority_queue, (gpointer)stream);
+       SP_RETVM_IF(NULL == to_delete, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't find to deleting link to stream [id:%d] from priority queue.",
+                       stream->id);
+
+       mgr->priority_queue = g_list_delete_link(mgr->priority_queue, to_delete);
+       _sound_stream_priority_update_playback(mgr);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_stream_priority_check(stream_priority_manager_t *mgr,
+               sound_stream_t *stream, gboolean *out)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(out, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(mgr->pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(mgr->pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(g_hash_table_lookup(mgr->pool->sources,
+                       stream->parent_source->tag_name), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE);
+       *out = FALSE;
+       int ret = SOUND_POOL_ERROR_NONE;
+
+       int position = g_list_index(mgr->priority_queue, (gconstpointer)stream);
+       SP_RETVM_IF(-1 == position, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't find stream in priority queue[%s]", stream->parent_source->tag_name);
+
+       if (position < mgr->pool->max_streams)
+               *out = TRUE;
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+void _sound_stream_priority_update_playback(stream_priority_manager_t *mgr)
+{
+       SP_DEBUF_FENTER();
+       SP_RETM_IF(!mgr, "Priority manager pointer is NULL.");
+       SP_RETM_IF(!mgr->pool, "Pool pointer is NULL.");
+       SP_RETM_IF(!mgr->pool->cbmgr, "Callback manager pointer is NULL.");
+       gboolean can_run = FALSE;
+
+       if (mgr->pool->state == SOUND_POOL_STATE_INACTIVE) {
+               SP_INFO("No need to update priority, Sound pool is INACTIVE.");
+               return;
+       }
+
+       mgr->priority_queue = g_list_sort(mgr->priority_queue,
+                       __stream_stream_proirity_cmp);
+
+       GList *iter = mgr->priority_queue;
+       for (; iter != NULL; iter = iter->next) {
+               sound_stream_t *stream = (sound_stream_t *)iter->data;
+
+               if (SOUND_POOL_ERROR_NONE != _sound_stream_priority_check(mgr, stream,
+                               &can_run))
+                       continue;
+               if (TRUE == can_run) {
+                       if (SOUND_POOL_STREAM_STATE_PLAYING != stream->state)
+                               _sound_stream_play(stream);
+               } else {
+                       if (SOUND_POOL_STREAM_STATE_PLAYING == stream->state)
+                               _sound_stream_pause(stream);
+                       stream->state_previous = stream->state;
+                       stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
+                       if (_stream_cb_manager_register_event(mgr->pool->cbmgr, stream) !=
+                                       SOUND_POOL_ERROR_NONE)
+                               SP_DEBUG("State changing event wasn't registered."
+                                               "Callbacks will be not called");
+               }
+       }
+
+       SP_DEBUG_FLEAVE();
+}
index f720f45..6236e6e 100644 (file)
  * limitations under the License.
  */
 
+/**
+ * @file sound_pool.c
+ * @brief This file include implementation of public API for the SoundPool.
+ */
+
 #include "sound_pool.h"
+#include "sound_pool_private.h"
+
+#include "internal/soundpool.h"
+#include "internal/source.h"
+#include "internal/stream.h"
 
 /*
 * Public Implementation
 */
+
+static unsigned int sound_pool_amount = 0;
+
+sound_pool_error_e sound_pool_create(unsigned max_streams, sound_pool_h *pool)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(max_streams == 0, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                               "Max streams count should be greater then 0.");
+       SP_RETVM_IF(SOUND_POOL_MAX_POOLS_AMOUNT < (sound_pool_amount+1),
+                       SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Max pools count should be no more than %d.",
+                       SOUND_POOL_MAX_POOLS_AMOUNT);
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       sound_pool_t *_pool = NULL;
+       const int ret = _sound_pool_create(max_streams, &_pool);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                       "Error while creating sound pool instance.");
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       *pool = _pool;
+       ++sound_pool_amount;
+       SP_INFO("Number of created pools is [%u]", sound_pool_amount);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_destroy(sound_pool_h pool)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_destroy((sound_pool_t *)pool);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                       "Error occurred when destroying the sound pool");
+       --sound_pool_amount;
+       SP_INFO("Number of pools is [%u]", sound_pool_amount);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_load_source_from_file(sound_pool_h pool,
+               const char *file_name, const char *tag)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_source_t *_src = NULL;
+       int ret = _sound_source_create(_pool, tag, &_src);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                       "Error while creating sound source instance.");
+
+       ret = _sound_source_load_from_file(_src, file_name);
+       if (ret != SOUND_POOL_ERROR_NONE) {
+               SP_ERROR("Error occurred when loading sound source from file");
+               if (_sound_source_destroy(_src) != SOUND_POOL_ERROR_NONE)
+                       SP_ERROR("Error occurred during removal of sound source[%s].", tag);
+       }
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_unload_source(sound_pool_h pool, const char *tag)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_source_t *_source = NULL;
+       int ret = _sound_pool_get_source_by_tag(_pool, tag, &_source);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound source [%s] from the sound pool", tag);
+       SP_INST_CHECK(_source, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_source_destroy(_source);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "destroying sound source [%s]", tag);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_play(sound_pool_h pool, const char *tag,
+               unsigned loop, float volume, unsigned priority,
+               sound_pool_stream_state_change_cb callback, void *data, unsigned *id)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(id, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_source_t *_source = NULL;
+       int ret = _sound_pool_get_source_by_tag(_pool, tag, &_source);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound source [%s] from the sound pool", tag);
+       SP_INST_CHECK(_source, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       sound_stream_t *_stream = NULL;
+       ret = _sound_stream_create(_source, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                       "Error while creating sound source instance.");
+
+       ret = _sound_stream_set_loop(_stream, loop);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream loop parameter", tag);
+
+       ret = _sound_stream_set_volume(_stream, volume);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream volume parameter", tag);
+
+       if (callback) {
+               ret = _sound_stream_set_callback(_stream, callback, data);
+               SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                               "setting sound stream callback", tag);
+       }
+
+       ret = _sound_stream_set_priority(_stream, priority);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream priority parameter", tag);
+
+       *id = _stream->id;
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_pause(sound_pool_h pool, unsigned id)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_pause(_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "pausing sound stream [%u]", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_resume(sound_pool_h pool, unsigned id)
+{
+       SP_DEBUF_FENTER();
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_resume(_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "resuming sound stream [%u]", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_stop(sound_pool_h pool, unsigned id)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_stop(_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "stopping sound stream [%u]", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_get_state(sound_pool_h pool, sound_pool_state_e *state)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_get_state(pool, state);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting state of the sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_activate(sound_pool_h pool)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_activate((sound_pool_t *)pool);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "activating sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_deactivate(sound_pool_h pool)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_deactivate((sound_pool_t *)pool);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "deactivating sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_set_volume(sound_pool_h pool, float volume)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_set_volume((sound_pool_t *)pool, volume);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting volume for sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_get_volume(sound_pool_h pool, float *volume)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_get_volume((sound_pool_t *)pool, volume);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting volume for sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_get_state(sound_pool_h pool, unsigned id,
+               sound_pool_stream_state_e *state)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_get_state(_stream, state);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] state", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_set_loop(sound_pool_h pool, unsigned id,
+               unsigned loop)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_set_loop(_stream, loop);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream [%u] loop parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_get_loop(sound_pool_h pool, unsigned id,
+               unsigned *loop)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_get_loop(_stream, loop);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] loop parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_set_volume(sound_pool_h pool, unsigned id,
+               float volume)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_set_volume(_stream, volume);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream [%u] volume parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_get_volume(sound_pool_h pool, unsigned id,
+               float *volume)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_get_volume(_stream, volume);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] volume parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_set_priority(sound_pool_h pool,
+               unsigned id, unsigned priority)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_set_priority(_stream, priority);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream [%u] priority parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_get_priority(sound_pool_h pool,
+               unsigned id, unsigned *priority)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_get_priority(_stream, priority);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] priority parameter", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_set_state_change_callback(sound_pool_h pool,
+               sound_pool_state_change_cb callback, void *data)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret =
+                       _sound_pool_set_callback((sound_pool_t *)pool, callback, data);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting state changing callback for sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_unset_state_change_callback(sound_pool_h pool)
+{
+       SP_DEBUF_FENTER();
+
+       const int ret = _sound_pool_unset_callback((sound_pool_t *)pool);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "unsetting state changing callback for sound pool");
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_set_state_change_callback(
+               sound_pool_h pool, unsigned id,
+               sound_pool_stream_state_change_cb callback, void *data)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_set_callback(_stream, callback, data);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "setting sound stream [%u] state changing callback", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e sound_pool_stream_unset_state_change_callback(
+               sound_pool_h pool, unsigned id)
+{
+       SP_DEBUF_FENTER();
+
+       sound_pool_t *_pool = (sound_pool_t *)pool;
+       sound_stream_t *_stream = NULL;
+       int ret = _sound_pool_get_stream_by_id(_pool, id, &_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "getting sound stream [%u] from the sound pool", id);
+       SP_INST_CHECK(_stream, SOUND_POOL_ERROR_INVALID_OPERATION);
+
+       ret = _sound_stream_unset_callback(_stream);
+       SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret, "Error occurred when "
+                       "unsetting sound stream [%u] state changing callback", id);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
diff --git a/src/soundpool.c b/src/soundpool.c
new file mode 100644 (file)
index 0000000..631a3aa
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file soundpool.c
+ * @brief This file include implementation of protected API for the SoundPool.
+ */
+
+#include "internal/soundpool.h"
+
+#include "internal/priority.h"
+#include "internal/stream_cb_manager.h"
+
+#include "internal/source.h"
+#include "internal/stream.h"
+
+#define DEFAULT_VOLUME_VALUE 1.0f
+
+static ALCdevice *device = NULL;
+static void __stream_activate_iter(gpointer key, gpointer value,
+               gpointer user_data);
+static void __stream_deactivate_iter(gpointer key, gpointer value,
+               gpointer user_data);
+
+static void __stream_activate_iter(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       SP_DEBUF_FENTER();
+       SP_RETM_IF(!user_data, "Empty user data.");
+       SP_RETM_IF(!value, "Empty sound stream data.");
+       guint *len = (guint*)user_data;
+       sound_stream_t *stream = (sound_stream_t *)value;
+
+       gboolean can_run = TRUE;
+       if (SOUND_POOL_ERROR_NONE
+                       == _sound_stream_priority_check(stream->parent_source->parent_pool->mgr_priority,
+                                       stream, &can_run))
+               if (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED && TRUE == can_run) {
+                       alSourcePlay(stream->al_source);
+                       (*len)++;
+               }
+
+       SP_DEBUG_FLEAVE();
+}
+
+static void __stream_deactivate_iter(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       SP_DEBUF_FENTER();
+       SP_RETM_IF(!user_data, "Empty user data.");
+       SP_RETM_IF(!value, "Empty sound stream data.");
+       guint *len = (guint*)user_data;
+       sound_stream_t *stream = (sound_stream_t *)value;
+
+       if (stream->state == SOUND_POOL_STREAM_STATE_PLAYING) {
+               alSourcePause(stream->al_source);
+               (*len)++;
+       }
+
+       SP_DEBUG_FLEAVE();
+}
+
+sound_pool_error_e _sound_pool_create(size_t max_streams, sound_pool_t **pool)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(max_streams == 0, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Max streams count should be greater than 0.");
+
+       sound_pool_t *_pool = NULL;
+       SP_RETVM_IF(!(_pool = g_try_malloc0(sizeof(*_pool))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create sound pool");
+       SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
+                       "sound pool. Pool pointer is NULL");
+
+       int ret = SOUND_POOL_ERROR_NONE;
+       _pool->al_context = NULL;
+       _pool->al_context = alcCreateContext(alcOpenDevice(NULL), NULL);
+       if (!_pool->al_context) {
+               ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
+               GOTO_FAIL("Memory alloc failure. Can't create OpenAL Context", cfail);
+       }
+
+       _pool->sources = NULL;
+       _pool->streams = NULL;
+
+       _pool->sources = g_hash_table_new(g_str_hash, g_str_equal);
+       if (!_pool->sources) {
+               ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
+               GOTO_FAIL("Memory alloc failure. Can't create internal sources hash "
+                               "table in sound pool", cfail);
+       }
+
+       _pool->streams = g_hash_table_new(g_int_hash, g_int_equal);
+       if (!_pool->streams) {
+               ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
+               GOTO_FAIL("Memory alloc failure. Can't create internal streams hash "
+                               "table in sound pool", cfail);
+       }
+
+       _pool->max_streams = max_streams;
+       _pool->volume = DEFAULT_VOLUME_VALUE;
+       _pool->max_stream_index = 0;
+       _pool->state = SOUND_POOL_STATE_INACTIVE;
+       _pool->state_cb_info.callback = NULL;
+       _pool->state_cb_info.user_data = NULL;
+
+       _pool->cbmgr = NULL;
+       ret = _stream_cb_manager_create(_pool, &_pool->cbmgr);
+       if (ret != SOUND_POOL_ERROR_NONE)
+               GOTO_FAIL("Error occurred when trying to create stream state changing "
+               "callback manager instance", cfail);
+
+       _pool->mgr_priority = NULL;
+       ret = _sound_stream_priority_create(_pool, &_pool->mgr_priority);
+       if (ret != SOUND_POOL_ERROR_NONE)
+               GOTO_FAIL("Error occurred initialising of priorities.", cfail);
+
+       *pool = _pool;
+       SP_DEBUG_FLEAVE();
+       return ret;
+
+cfail:
+       _sound_pool_destroy(_pool);
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       _sound_pool_deactivate(pool);
+
+       if (pool->cbmgr) {
+               const int ret = _stream_cb_manager_destroy(pool->cbmgr);
+               SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                               "Error occurred when " "trying to destroy sound pool callback manager.");
+               pool->cbmgr = NULL;
+       }
+
+       if (pool->sources) {
+               GHashTableIter iter;
+               gpointer key, value;
+               g_hash_table_iter_init(&iter, pool->sources);
+               while (g_hash_table_iter_next(&iter, &key, &value)) {
+                       guint size_before = g_hash_table_size(pool->sources);
+                       _sound_source_destroy((sound_source_t*)value);
+                       guint size_after = g_hash_table_size(pool->sources);
+                       if (size_before != size_after)
+                               g_hash_table_iter_init(&iter, pool->sources);
+               }
+               g_hash_table_unref(pool->sources);
+               pool->sources = NULL;
+       }
+
+       if (pool->streams) {
+               g_hash_table_unref(pool->streams);
+               pool->streams = NULL;
+       }
+
+       if (pool->mgr_priority) {
+               const int ret = _sound_stream_priority_destroy(pool->mgr_priority);
+               SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
+                               "Error occurred when trying to destroy priority manager.");
+               pool->mgr_priority = NULL;
+       }
+
+       if (pool->al_context) {
+               ALCdevice *device = alcGetContextsDevice(pool->al_context);
+               alcMakeContextCurrent(NULL);
+               alcDestroyContext(pool->al_context);
+               alcCloseDevice(device);
+       }
+
+       SP_SAFE_GFREE(pool);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       SP_RETVM_IF(pool->state == SOUND_POOL_STATE_ACTIVE,
+                       SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Already activated sound pool can't be activated again.");
+
+       sound_pool_state_e old_state = pool->state;
+       pool->state = SOUND_POOL_STATE_ACTIVE;
+
+       /* Generate array of all AlSources in pool */
+       GPtrArray *streams = NULL;
+       if (g_hash_table_size(pool->streams) > 0) {
+               SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                               SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+               guint len = 0;
+               g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
+               SP_INFO("Resuming [%d] number of streams.", len);
+       }
+
+       if (streams)
+               g_ptr_array_free(streams, TRUE);
+
+       SP_INFO("Sound pool has been activated");
+
+       if (pool->state_cb_info.callback)
+               pool->state_cb_info.callback(pool, old_state, pool->state,
+                               pool->state_cb_info.user_data);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(pool->state == SOUND_POOL_STATE_INACTIVE,
+                       SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Already deactivated sound pool can't be deactivated again.");
+
+       sound_pool_state_e old_state = pool->state;
+       pool->state = SOUND_POOL_STATE_INACTIVE;
+
+       /* Generate array of all AlSources in pool */
+       GPtrArray *streams = NULL;
+       if (g_hash_table_size(pool->streams) > 0) {
+               SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                               SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+               guint len = 0;
+               g_hash_table_foreach(pool->streams, __stream_deactivate_iter, &len);
+               SP_INFO("Suspending [%d] number of streams.", len);
+       }
+
+       if (streams)
+               g_ptr_array_free(streams, TRUE);
+
+       SP_INFO("Sound pool has been deactivated");
+
+       if (pool->state_cb_info.callback)
+               pool->state_cb_info.callback(pool, old_state, pool->state,
+                               pool->state_cb_info.user_data);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
+               sound_pool_state_e *state)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       *state = pool->state;
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
+                       SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Sound pool volume is not in [0.0..1.0] range.");
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+       alListenerf(AL_GAIN, volume);
+       pool->volume = volume;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       *volume = pool->volume;
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
+               sound_pool_state_change_cb callback, void *data)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       pool->state_cb_info.callback = callback;
+       pool->state_cb_info.user_data = data;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       pool->state_cb_info.callback = NULL;
+       pool->state_cb_info.user_data = NULL;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
diff --git a/src/source.c b/src/source.c
new file mode 100644 (file)
index 0000000..d9584dd
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file source.c
+ * @brief This file include implementation of protected API
+ * for the sound sources(OpenAL buffers) as part of SoundPool.
+ */
+
+#include "internal/source.h"
+#include "internal/stream.h"
+
+#include <AL/alut.h>
+
+static int __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src);
+static int __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src);
+
+static int __sound_pool_add_source(sound_pool_t *pool, sound_source_t *src)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
+                       "pool to add the source is corrupted: NULL sources hash table");
+       SP_RETVM_IF(!src->tag_name, SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Source to be added to sound pool is corrupted: NULL tag name");
+       SP_RETVM_IF(src->parent_pool != pool, SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Sound source can't be added to the pool different to the pool for"
+                       " which sound source was created");
+       SP_RETVM_IF(g_hash_table_contains(pool->sources, src->tag_name),
+                       SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Tag already exists in sources hash table.");
+
+       SP_RETVM_IF(!g_hash_table_insert(pool->sources, src->tag_name, src),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Error occurred when adding "
+                       "the source tagged [%s] to the sound pool", src->tag_name);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+static int __sound_pool_remove_source(sound_pool_t *pool, sound_source_t *src)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       if (src->parent_pool == pool && src->tag_name) {
+               if (!g_hash_table_steal(pool->sources, src->tag_name)) {
+                       SP_DEBUG("Tag [%s] doesn't exist in sources hash table",
+                                       src->tag_name);
+                       SP_DEBUG_FLEAVE();
+                       return SOUND_POOL_ERROR_NONE;
+               }
+               GHashTableIter iter;
+               gpointer key, value;
+               g_hash_table_iter_init(&iter, pool->streams);
+               while (g_hash_table_iter_next(&iter, &key, &value)) {
+                       guint size_before = g_hash_table_size(pool->streams);
+                       gchar *tag = (gchar*)key;
+                       sound_stream_t *stream = (sound_stream_t*)value;
+                       SP_INFO("(%s)(%s)", src->tag_name, stream->parent_source->tag_name);
+                       if (src == stream->parent_source)
+                               _sound_stream_destroy((sound_stream_t*)value);
+                       guint size_after = g_hash_table_size(pool->streams);
+                       if (size_before != size_after)
+                               g_hash_table_iter_init(&iter, pool->streams);
+               }
+       } else {
+                       SP_DEBUG("Source wasn't removed from sound pool as it isn't known by "
+                                       "the pool for which operation is performed, or tag corrupted");
+       }
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_source_create(sound_pool_t *pool, const char *tag,
+               sound_source_t **src)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound source in NULL sound pool");
+       SP_RETVM_IF(!tag, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound source with NULL tag name");
+       SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound source. Source pointer is NULL");
+       SP_RETVM_IF(strnlen(tag, MAX_TAG_LEN + 1) == MAX_TAG_LEN + 1,
+                       SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create sound source "
+                       "with tag name longer than %u", MAX_TAG_LEN);
+       SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
+                       "pool to create source is corrupted: NULL sources hash table.");
+       SP_RETVM_IF(g_hash_table_contains(pool->sources, tag),
+                       SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Tag already exists in sources hash table.");
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION,
+                       "Can't set current context.");
+
+       sound_source_t *_src = NULL;
+       SP_RETVM_IF(!(_src = g_try_malloc0(sizeof(*_src))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create sound _src");
+
+       int ret = SOUND_POOL_ERROR_NONE;
+       alGenBuffers(1, &_src->al_buffer);
+       if (alGetError() != AL_NO_ERROR) {
+               ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
+               GOTO_FAIL("OpenAL error occurred when trying to generate Buffer id", cfail);
+       }
+
+       _src->parent_pool = pool;
+       _src->tag_name = NULL;
+       _src->tag_name = g_strndup(tag, MAX_TAG_LEN);
+
+       ret = __sound_pool_add_source(pool, _src);
+       if (ret != SOUND_POOL_ERROR_NONE)
+               GOTO_FAIL("Error occurred when trying to add source to pool", cfail);
+
+       *src = _src;
+       SP_DEBUG_FLEAVE();
+       return ret;
+
+cfail:
+       ret = _sound_source_destroy(_src);
+       SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret, ret, "Error occurred during removal "
+                       "of sound source[%s].", tag);
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_source_destroy(sound_source_t *src)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't destroy NULL sound source");
+
+       /* If parent pool exists, then source has to be removed from the pool */
+       if (src->parent_pool && __sound_pool_remove_source(src->parent_pool, src)
+                       != SOUND_POOL_ERROR_NONE)
+               SP_DEBUG("Source wasn't removed from sound pool.");
+
+       SP_DEBUG("Deleting OpenAL buffer with id [%u]", src->al_buffer);
+       alDeleteBuffers(1, &src->al_buffer);
+
+       SP_SAFE_GFREE(src->tag_name);
+       SP_SAFE_GFREE(src);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_source_load_from_file(sound_source_t *src,
+               const char *fname)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(fname, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(src->parent_pool, SOUND_POOL_ERROR_INVALID_OPERATION);
+       SP_RETVM_IF(!alcMakeContextCurrent(src->parent_pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current AL context.");
+
+       int ret = SOUND_POOL_ERROR_NONE;
+       ALenum format;
+       ALsizei size;
+       ALvoid* data = NULL;
+       ALsizei freq;
+       ALboolean loop;
+
+       alutLoadWAVFile((ALbyte*)fname, &format, &data, &size, &freq, &loop);
+       SP_RETVM_IF(alGetError() != AL_NO_ERROR || !data,
+                       SOUND_POOL_ERROR_NO_SUCH_FILE, "Can't load audio file. No such "
+                       "file [%s]", fname);
+
+       alBufferData(src->al_buffer, format, data, size, freq);
+       if (alGetError() != AL_NO_ERROR) {
+               SP_ERROR("Can't create audio buffer from file [%s]", fname);
+               ret = SOUND_POOL_ERROR_INVALID_OPERATION;
+       }
+
+       alutUnloadWAV(format, data, size, freq);
+
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_pool_get_source_by_tag(sound_pool_t *pool,
+               const char *tag, sound_source_t **src)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(tag, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(src, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(!pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER, "Corrupted "
+                       "sound pool. Sources hash table is NULL");
+
+       *src = (sound_source_t *)g_hash_table_lookup(pool->sources, tag);
+       SP_RETVM_IF(!(*src), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE, "Tag doesn't "
+                       "exist in sources hash table");
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
diff --git a/src/stream.c b/src/stream.c
new file mode 100644 (file)
index 0000000..aa5fa68
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file stream.c
+ * @brief This file include implementation of protected API
+ * for the sound streams(OpenAL sources) as part of SoundPool.
+ */
+
+#include "internal/stream.h"
+#include "internal/priority.h"
+
+#include "internal/stream_cb_manager.h"
+
+#define DEFAULT_STREAM_PRIORITY 255U
+#define DEFAULT_STREAM_LOOP     1U
+#define DEFAULT_STREAM_VOLUME   1.0f
+
+static const char *__stringify_stream_state(sound_pool_stream_state_e state);
+static void __al_source_state_cb(ALuint source, ALenum state, ALvoid *data);
+static int __sound_pool_add_stream(sound_pool_t *pool, sound_stream_t *stream);
+static int __sound_pool_remove_stream(sound_pool_t *pool, sound_stream_t *stream);
+
+static const char *__stringify_stream_state(sound_pool_stream_state_e state)
+{
+       switch (state) {
+       case SOUND_POOL_STREAM_STATE_NONE:
+               return "SOUND_POOL_STREAM_STATE_NONE";
+       case SOUND_POOL_STREAM_STATE_PLAYING:
+               return "SOUND_POOL_STREAM_STATE_PLAYING";
+       case SOUND_POOL_STREAM_STATE_PAUSED:
+               return "SOUND_POOL_STREAM_STATE_PAUSED";
+       case SOUND_POOL_STREAM_STATE_SUSPENDED:
+               return "SOUND_POOL_STREAM_STATE_SUSPENDED";
+       case SOUND_POOL_STREAM_STATE_STOPPED:
+               return "SOUND_POOL_STREAM_STATE_STOPPED";
+       case SOUND_POOL_STREAM_STATE_FINISHED:
+               return "SOUND_POOL_STREAM_STATE_FINISHED";
+       default:
+               return "";
+       }
+}
+
+static void __al_source_state_cb(ALuint source, ALenum state, ALvoid *data)
+{
+       SP_DEBUF_FENTER();
+
+       sound_stream_t *stream = (sound_stream_t *)data;
+       SP_RETM_IF(!stream, "Can't handle stream in OpenAL callback, it is NULL");
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_RETM_IF(!pool, "Can't handle stream in OpenAL callback, stream's sound "
+                       "pool is NULL");
+
+       stream->state_previous = stream->state;
+
+       switch (state) {
+       case AL_INITIAL:
+               stream->state = SOUND_POOL_STREAM_STATE_NONE;
+               break;
+       case AL_PLAYING:
+               stream->state = SOUND_POOL_STREAM_STATE_PLAYING;
+               break;
+       case AL_PAUSED:
+               if (pool->state == SOUND_POOL_STATE_INACTIVE)
+                       stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
+               else if (pool->state == SOUND_POOL_STATE_ACTIVE)
+                       stream->state = SOUND_POOL_STREAM_STATE_PAUSED;
+               break;
+       case AL_STOPPED:
+               if (stream->stopped)
+                       stream->state = SOUND_POOL_STREAM_STATE_STOPPED;
+               else
+                       stream->state = SOUND_POOL_STREAM_STATE_FINISHED;
+               break;
+       default:
+               SP_ERROR("Invalid OpenAl state value [%#04x]", state);
+               return;
+       }
+
+       SP_INFO("Stream [%s:%d] state changed from [%s] to [%s]",
+                       stream->parent_source->tag_name, stream->id,
+                       __stringify_stream_state(stream->state_previous),
+                       __stringify_stream_state(stream->state));
+
+       SP_RETM_IF(_stream_cb_manager_register_event(pool->cbmgr, stream) !=
+                       SOUND_POOL_ERROR_NONE, "State changing event wasn't registered."
+                       "Callbacks will be not called");
+
+       SP_DEBUG_FLEAVE();
+}
+
+static int __sound_pool_add_stream(sound_pool_t *pool, sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(!pool->streams, SOUND_POOL_ERROR_INVALID_OPERATION, "Sound "
+                       "pool to add the stream is corrupted: NULL streams hash table");
+       stream->id = ++(pool->max_stream_index);
+       SP_DEBUG("Id assigned to the stream is [%u]", stream->id);
+       SP_RETVM_IF(g_hash_table_contains(pool->streams, (gpointer)&stream->id),
+                       SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Stream ID already exists in streams hash table.");
+       SP_RETVM_IF(stream->parent_source->parent_pool != pool,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Sound stream can't be added "
+                       "to the pool different to the pool for which sound stream was created");
+
+       SP_RETVM_IF(!g_hash_table_insert(pool->streams, (gpointer)&stream->id, stream),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Error occurred when adding "
+                       "the stream [%u] to the sound pool", stream->id);
+
+       int ret = _sound_stream_priority_add_stream(pool->mgr_priority, stream);
+       SP_RETVM_IF(SOUND_POOL_ERROR_NONE != ret, ret, "Error occurred when adding "
+                       "the stream [%u] to the priority queue.", stream->id);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+static int __sound_pool_remove_stream(sound_pool_t *pool, sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(pool->mgr_priority, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       if (stream->parent_source->parent_pool == pool) {
+               if (!g_hash_table_remove(pool->streams, &stream->id)
+                               || SOUND_POOL_ERROR_NONE
+                                               != _sound_stream_priority_remove_stream(pool->mgr_priority,
+                                                               stream))
+                       SP_DEBUG("Id [%u] doesn't exist in streams hash table", stream->id);
+               else
+                       SP_INFO("[%u] sound stream was removed from pool", stream->id);
+       } else {
+               SP_DEBUG("Stream wasn't removed from sound pool as it isn't known by "
+                               "the pool for which operation is performed");
+       }
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_create(sound_source_t *src,
+               sound_stream_t **stream)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!src, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound stream in NULL sound source");
+       SP_RETVM_IF(!stream, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound stream. Stream pointer is NULL");
+       SP_RETVM_IF(!src->parent_pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't create sound stream. Source's pool is NULL");
+
+       SP_RETVM_IF(!alcMakeContextCurrent(src->parent_pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       sound_stream_t *_stream = NULL;
+       SP_RETVM_IF(!(_stream = g_try_malloc0(sizeof(*_stream))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create sound stream");
+
+       _stream->parent_source = src;
+       _stream->priority = DEFAULT_STREAM_PRIORITY;
+       _stream->loop = DEFAULT_STREAM_LOOP;
+       _stream->volume = DEFAULT_STREAM_VOLUME;
+       _stream->state_previous = SOUND_POOL_STREAM_STATE_NONE;
+       _stream->state = SOUND_POOL_STREAM_STATE_NONE;
+       _stream->stopped = FALSE;
+       _stream->state_cb_info.callback = NULL;
+       _stream->state_cb_info.user_data = NULL;
+
+       int ret = SOUND_POOL_ERROR_NONE;
+       alGenSources((ALsizei)1, &_stream->al_source);
+       if (alGetError() != AL_NO_ERROR) {
+               ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
+               GOTO_FAIL("OpenAL error occurred when trying to generate OpenAL Source",
+                               cfail);
+       }
+
+       alSourcei(_stream->al_source, AL_BUFFER, src->al_buffer);
+       if (alGetError() != AL_NO_ERROR) {
+               ret = SOUND_POOL_ERROR_INVALID_OPERATION;
+               GOTO_FAIL("OpenAL error occurred when trying to assign OpenAL Buffer "
+                               "to OpenAL Source", cfail);
+       }
+
+       alSourcep(_stream->al_source, AL_SOURCE_STATE_CALLBACK,
+                       (ALvoid *)__al_source_state_cb);
+       if (alGetError() != AL_NO_ERROR) {
+               ret = SOUND_POOL_ERROR_INVALID_OPERATION;
+               GOTO_FAIL("OpenAL error occurred when trying to assign OpenAL Callback "
+                               "to OpenAL Source", cfail);
+       }
+
+       alSourcep(_stream->al_source, AL_SOURCE_STATE_CALLBACK_DATA, (ALvoid *)_stream);
+       if (alGetError() != AL_NO_ERROR) {
+               ret = SOUND_POOL_ERROR_INVALID_OPERATION;
+               GOTO_FAIL("OpenAL error occurred when trying to assign OpenAL Callback "
+                               "Data to OpenAL Source", cfail);
+       }
+
+       ret = __sound_pool_add_stream(src->parent_pool, _stream);
+       if (ret != SOUND_POOL_ERROR_NONE)
+               GOTO_FAIL("Error occurred when trying to add source to pool", cfail);
+
+       *stream = _stream;
+       SP_DEBUG_FLEAVE();
+       return ret;
+
+cfail:
+       _sound_stream_destroy(_stream);
+       SP_DEBUG_FLEAVE();
+       return ret;
+}
+
+sound_pool_error_e _sound_stream_destroy(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!stream, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't destroy NULL sound stream");
+       SP_RETVM_IF(!stream->parent_source->parent_pool, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Empty parent pool pointer.");
+
+       if (stream->parent_source) {
+               if (__sound_pool_remove_stream(stream->parent_source->parent_pool,
+                               stream) != SOUND_POOL_ERROR_NONE)
+                       SP_DEBUG("Stream[%s] wasn't removed from sound pool. Continue destroying",
+                                       stream->parent_source->tag_name);
+               if (alcMakeContextCurrent(stream->parent_source->parent_pool->al_context)) {
+                       alSourcei(stream->al_source, AL_BUFFER, 0);
+                       alDeleteSources(1, &stream->al_source);
+                       SP_DEBUG("Deleting OpenAL source with id [%u]", stream->al_source);
+               } else {
+                       SP_DEBUG("Can't set current context for deleting OpenAL source with id [%u]",
+                                       stream->al_source);
+               }
+       }
+
+       SP_SAFE_GFREE(stream);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_play(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(stream->state != SOUND_POOL_STREAM_STATE_SUSPENDED &&
+                       stream->state != SOUND_POOL_STREAM_STATE_PAUSED &&
+                       stream->state != SOUND_POOL_STREAM_STATE_NONE,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't play stream[%s] in [%s] "
+                       "state", stream->parent_source->tag_name, __stringify_stream_state(stream->state));
+       SP_RETVM_IF(stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED &&
+                       pool->state == SOUND_POOL_STATE_INACTIVE,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't play suspended stream "
+                       "in inactive sound pool");
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       if (pool->state == SOUND_POOL_STATE_INACTIVE &&
+                       stream->state == SOUND_POOL_STREAM_STATE_NONE) {
+               stream->state_previous = stream->state;
+               stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
+               if (_stream_cb_manager_register_event(pool->cbmgr, stream) !=
+                               SOUND_POOL_ERROR_NONE)
+                       SP_DEBUG("State changing event wasn't registered."
+                                       "Callbacks will be not called");
+               SP_DEBUG("Don't play due to SoundPool is in inactive state.");
+       } else {
+               alSourcePlay(stream->al_source);
+       }
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_pause(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(stream->state != SOUND_POOL_STREAM_STATE_SUSPENDED &&
+                       stream->state != SOUND_POOL_STREAM_STATE_PLAYING,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't pause stream in [%s] "
+                       "state", __stringify_stream_state(stream->state));
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       if (pool->state == SOUND_POOL_STATE_INACTIVE &&
+                       stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED) {
+               stream->state_previous = stream->state;
+               stream->state = SOUND_POOL_STREAM_STATE_PAUSED;
+               if (_stream_cb_manager_register_event(pool->cbmgr, stream) !=
+                               SOUND_POOL_ERROR_NONE)
+                       SP_DEBUG("State changing event wasn't registered."
+                                       "Callbacks will be not called");
+               SP_DEBUG("Don't paused due to SoundPool is in inactive state.");
+       } else {
+               alSourcePause(stream->al_source);
+       }
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_resume(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(stream->state != SOUND_POOL_STREAM_STATE_PAUSED,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't resume stream in [%s] "
+                       "state", __stringify_stream_state(stream->state));
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       if (pool->state == SOUND_POOL_STATE_INACTIVE &&
+                       stream->state == SOUND_POOL_STREAM_STATE_PAUSED)
+       {
+               stream->state_previous = stream->state;
+               stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
+               if (_stream_cb_manager_register_event(pool->cbmgr, stream) !=
+                               SOUND_POOL_ERROR_NONE)
+                       SP_DEBUG("State changing event wasn't registered."
+                                       "Callbacks will be not called");
+               SP_DEBUG("Don't resumed due to SoundPool is in inactive state.");
+       } else {
+               alSourcePlay(stream->al_source);
+       }
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_stop(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(stream->state != SOUND_POOL_STREAM_STATE_PLAYING &&
+                       stream->state != SOUND_POOL_STREAM_STATE_SUSPENDED &&
+                       stream->state != SOUND_POOL_STREAM_STATE_PAUSED,
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't stop stream in [%s] "
+                       "state", __stringify_stream_state(stream->state));
+
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       stream->stopped = TRUE;
+       alSourceStop(stream->al_source);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_set_loop(sound_stream_t *stream, unsigned loop)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       alSourcei(stream->al_source, AL_LOOP_COUNT, (ALint)loop);
+       stream->loop = loop;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_get_loop(sound_stream_t *stream, unsigned *loop)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(loop, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       *loop = stream->loop;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_set_volume(sound_stream_t *stream, float volume)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
+                       SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Volume for sound stream should be in range 0.0..1.0.");
+       sound_pool_t *pool = stream->parent_source->parent_pool;
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
+                       SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
+
+       alSourcef(stream->al_source, AL_GAIN, volume);
+
+       stream->volume = volume;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_get_volume(sound_stream_t *stream, float *volume)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       *volume = stream->volume;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_get_state(sound_stream_t *stream,
+               sound_pool_stream_state_e *state)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       *state = stream->state;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_set_priority(sound_stream_t *stream, unsigned rank)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source->parent_pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream->parent_source->parent_pool->mgr_priority, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       stream->priority = rank;
+       if (stream->parent_source->parent_pool->state == SOUND_POOL_STATE_INACTIVE) {
+               if (stream->state == SOUND_POOL_STREAM_STATE_NONE) {
+                       stream->state_previous = stream->state;
+                       stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
+                       if (_stream_cb_manager_register_event(
+                                       stream->parent_source->parent_pool->cbmgr, stream)
+                                       != SOUND_POOL_ERROR_NONE)
+                               SP_DEBUG(
+                                               "State changing event wasn't registered." "Callbacks"
+                                               " will be not called");
+               }
+               SP_DEBUG("No need to update priority, Sound pool is INACTIVE.");
+               return SOUND_POOL_ERROR_NONE;
+       }
+
+       _sound_stream_priority_update_playback(stream->parent_source->parent_pool->mgr_priority);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_get_priority(sound_stream_t *stream, unsigned *rank)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(rank, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       *rank = stream->priority;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_set_callback(sound_stream_t *stream,
+               sound_pool_stream_state_change_cb callback, void *data)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       stream->state_cb_info.callback = callback;
+       stream->state_cb_info.user_data = data;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_stream_unset_callback(sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       stream->state_cb_info.callback = NULL;
+       stream->state_cb_info.user_data = NULL;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _sound_pool_get_stream_by_id(sound_pool_t *pool, unsigned id,
+               sound_stream_t **stream)
+{
+       SP_DEBUF_FENTER();
+       SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
+       SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
+
+       SP_RETVM_IF(!pool->streams, SOUND_POOL_ERROR_INVALID_OPERATION, "Corrupted "
+                       "sound pool. Sources hash table is NULL");
+
+       *stream = (sound_stream_t *)g_hash_table_lookup(pool->streams, &id);
+       SP_RETVM_IF(!(*stream), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE, "Tag doesn't "
+                       "exist in sources hash table");
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
diff --git a/src/stream_cb_manager.c b/src/stream_cb_manager.c
new file mode 100644 (file)
index 0000000..9e08c2b
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file stream_cb_manager.c
+ * @brief This file include implementation of protected API for the stream
+ * callback manager as part of SoundPool.
+ */
+
+#include "internal/stream_cb_manager.h"
+
+static gpointer __sound_pool_callback_isolator(gpointer user_data);
+static void __thread_cancel_cleanup();
+static void __queue_destroy_item(gpointer data);
+
+static void __queue_destroy_item(gpointer data)
+{
+       SP_DEBUF_FENTER();
+
+       SP_SAFE_GFREE(data);
+
+       SP_DEBUG_FLEAVE();
+}
+
+static void __thread_cancel_cleanup(void *user_data)
+{
+       SP_DEBUF_FENTER();
+
+       stream_cb_manager_t *cbmgr = (stream_cb_manager_t *)user_data;
+       g_async_queue_unref(cbmgr->isolator_callback_queue);
+       pthread_mutex_destroy(&cbmgr->isolator_data_mutex);
+       pthread_cond_destroy(&cbmgr->isolator_data_cond);
+
+       SP_SAFE_GFREE(cbmgr);
+
+       SP_DEBUG_FLEAVE();
+}
+
+static gpointer __sound_pool_callback_isolator(gpointer user_data)
+{
+       SP_DEBUF_FENTER();
+       int err = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+       if (err != 0)
+               SP_INFO("Can't setup cancel type for isolation thread with error [%d].", err);
+       err = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+       if (err != 0)
+               SP_INFO("Can't setup cancel state for isolation thread with error [%d].", err);
+       SP_RETVM_IF(!user_data, NULL, "User data is NULL. Terminate callback thread");
+
+       stream_cb_manager_t *cbmgr = (stream_cb_manager_t *)user_data;
+       pthread_cleanup_push(__thread_cancel_cleanup,  user_data);
+       pthread_mutex_lock(&cbmgr->isolator_data_mutex);
+       gboolean runing = cbmgr->isolator_loop_run;
+       pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
+
+       while (runing) {
+               pthread_mutex_lock(&cbmgr->isolator_data_mutex);
+               while (!cbmgr->isolator_state_changed)
+                       pthread_cond_wait(&cbmgr->isolator_data_cond, &cbmgr->isolator_data_mutex);
+               pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
+
+               /* Iterate streams have been pushed to the queue and call for each
+                  state changed callback for each stream */
+               stream_cb_manager_event_data_t *event_data = NULL;
+               while ((event_data = (stream_cb_manager_event_data_t *)
+                               g_async_queue_try_pop(cbmgr->isolator_callback_queue))) {
+
+                       sound_pool_t* _pool = cbmgr->pool;
+                       if (NULL != event_data->stream->state_cb_info.callback) {
+                               event_data->stream->state_cb_info.callback(_pool,
+                                               event_data->stream->parent_source->tag_name,
+                                               event_data->stream->id, event_data->state_previous,
+                                               event_data->state,
+                                               event_data->stream->state_cb_info.user_data);
+                       }
+                       /* If SoundPool final state is FINISHED or STOPPED, then release item */
+                       if (event_data->state == SOUND_POOL_STREAM_STATE_FINISHED ||
+                                       event_data->state == SOUND_POOL_STREAM_STATE_STOPPED)
+                               _sound_stream_destroy(event_data->stream);
+                       SP_SAFE_GFREE(event_data);
+               }
+
+               pthread_mutex_lock(&cbmgr->isolator_data_mutex);
+               cbmgr->isolator_state_changed = FALSE;
+               pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
+
+               pthread_mutex_lock(&cbmgr->isolator_data_mutex);
+               runing = cbmgr->isolator_loop_run;
+               pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
+       }
+
+       pthread_cleanup_pop(0);
+       SP_DEBUG_FLEAVE();
+       return NULL;
+}
+
+sound_pool_error_e _stream_cb_manager_create(sound_pool_t *pool,
+               stream_cb_manager_t **cbmgr)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Stream callback "
+                       "manager can't be created for NULL sound pool");
+       SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
+                       "stream state changing callback manager. Manager pointer is NULL");
+
+       stream_cb_manager_t *_cbmgr = NULL;
+       SP_RETVM_IF(!(_cbmgr = g_try_malloc0(sizeof(*_cbmgr))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create stream callback manager");
+
+       _cbmgr->isolator_callback_queue = g_async_queue_new_full(__queue_destroy_item);
+
+       int err = pthread_mutex_init(&_cbmgr->isolator_data_mutex, NULL);
+       SP_RETVM_IF(err != 0, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Error while initialize mutex for isolation thread with error[%d]", err);
+
+       _cbmgr->isolator_state_changed = FALSE;
+       _cbmgr->isolator_loop_run = TRUE;
+
+       err = pthread_cond_init(&_cbmgr->isolator_data_cond, NULL);
+       SP_RETVM_IF(err != 0, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Error while initialize condition for isolation thread with error[%d]", err);
+
+       err = pthread_create(&_cbmgr->isolator_thread, NULL, &__sound_pool_callback_isolator, (void*)_cbmgr);
+       SP_RETVM_IF(err != 0, SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Error while thread creating for isolation thread with error[%d]", err);
+
+       _cbmgr->pool = pool;
+       pool->cbmgr = _cbmgr;
+       *cbmgr = _cbmgr;
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _stream_cb_manager_destroy(stream_cb_manager_t *cbmgr)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle callback "
+                       "manager, it is NULL.");
+
+
+       pthread_t thread = cbmgr->isolator_thread;
+
+       int err = pthread_kill(thread, 0);
+       if (0 == err) {
+               err = pthread_cancel(thread);
+               if (0 != err) {
+                       SP_ERROR("Error while cancelling of isolation thread[%d].", err);
+                       g_async_queue_unref(cbmgr->isolator_callback_queue);
+                       pthread_mutex_destroy(&cbmgr->isolator_data_mutex);
+                       pthread_cond_destroy(&cbmgr->isolator_data_cond);
+                       SP_SAFE_GFREE(cbmgr);
+                       SP_DEBUG_FLEAVE();
+                       return SOUND_POOL_ERROR_INVALID_OPERATION;
+               }
+       } else {
+               SP_ERROR("Invalid isolation thread[%d].", err);
+               g_async_queue_unref(cbmgr->isolator_callback_queue);
+               pthread_mutex_destroy(&cbmgr->isolator_data_mutex);
+               pthread_cond_destroy(&cbmgr->isolator_data_cond);
+               SP_SAFE_GFREE(cbmgr);
+               SP_DEBUG_FLEAVE();
+               return SOUND_POOL_ERROR_INVALID_OPERATION;
+       }
+
+       void *ret;
+       err = pthread_join(thread, &ret);
+       if (0 != err)
+               SP_ERROR("Error while joining of isolation thread[%d].", err);
+       if (ret == PTHREAD_CANCELED)
+               SP_INFO("Isolation thread canceled.");
+       else
+               SP_INFO("Routine joining of isolation thread.");
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}
+
+sound_pool_error_e _stream_cb_manager_register_event(stream_cb_manager_t *cbmgr,
+               sound_stream_t *stream)
+{
+       SP_DEBUF_FENTER();
+       SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't handle callback manager, it is NULL.");
+       SP_RETVM_IF(!stream, SOUND_POOL_ERROR_INVALID_PARAMETER,
+                       "Can't handle stream in callback manager, it is NULL.");
+
+       stream_cb_manager_event_data_t *event_data = NULL;
+       SP_RETVM_IF(!(event_data = g_try_malloc0(sizeof(stream_cb_manager_event_data_t))),
+                       SOUND_POOL_ERROR_OUT_OF_MEMORY,
+                       "Memory alloc failure. Can't create stream callback event data structure.");
+       event_data->stream = stream;
+       event_data->state = stream->state;
+       event_data->state_previous = stream->state_previous;
+
+       g_async_queue_push(cbmgr->isolator_callback_queue, (gpointer)(event_data));
+       pthread_mutex_lock(&cbmgr->isolator_data_mutex);
+       cbmgr->isolator_state_changed = TRUE;
+       pthread_cond_signal(&cbmgr->isolator_data_cond);
+       pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
+
+       SP_DEBUG_FLEAVE();
+       return SOUND_POOL_ERROR_NONE;
+}