2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * @brief This file include implementation of protected API for the SoundPool.
22 #include "internal/soundpool.h"
24 #include "internal/priority.h"
25 #include "internal/stream_cb_manager.h"
27 #include "internal/source.h"
28 #include "internal/stream.h"
30 #define DEFAULT_VOLUME_VALUE 1.0f
32 static void __stream_activate_iter(gpointer key, gpointer value,
34 static void __stream_deactivate_iter(gpointer key, gpointer value,
37 static void __stream_activate_iter(gpointer key, gpointer value,
41 SP_RETM_IF(!user_data, "Empty user data.");
42 SP_RETM_IF(!value, "Empty sound stream data.");
43 guint *len = (guint*)user_data;
44 sound_stream_t *stream = (sound_stream_t *)value;
46 gboolean can_run = TRUE;
47 if (SOUND_POOL_ERROR_NONE
48 == _sound_stream_priority_check(stream->parent_source->parent_pool->mgr_priority,
50 if (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED && TRUE == can_run) {
51 alSourcePlay(stream->al_source);
58 static void __stream_deactivate_iter(gpointer key, gpointer value,
62 SP_RETM_IF(!user_data, "Empty user data.");
63 SP_RETM_IF(!value, "Empty sound stream data.");
64 guint *len = (guint*)user_data;
65 sound_stream_t *stream = (sound_stream_t *)value;
67 if (stream->state == SOUND_POOL_STREAM_STATE_PLAYING) {
68 alSourcePause(stream->al_source);
75 sound_pool_error_e _sound_pool_create(sound_pool_t **pool)
78 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
80 sound_pool_t *_pool = NULL;
81 SP_RETVM_IF(!(_pool = g_try_malloc0(sizeof(*_pool))),
82 SOUND_POOL_ERROR_OUT_OF_MEMORY,
83 "Memory alloc failure. Can't create sound pool");
84 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
85 "sound pool. Pool pointer is NULL");
87 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
88 _pool->al_context = NULL;
89 _pool->al_context = alcCreateContext(alcOpenDevice(NULL), NULL);
90 if (!_pool->al_context) {
91 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
92 GOTO_FAIL("Memory alloc failure. Can't create OpenAL Context", cfail);
95 _pool->sources = NULL;
96 _pool->streams = NULL;
98 _pool->sources = g_hash_table_new(g_str_hash, g_str_equal);
99 if (!_pool->sources) {
100 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
101 GOTO_FAIL("Memory alloc failure. Can't create internal sources hash "
102 "table in sound pool", cfail);
105 _pool->streams = g_hash_table_new(g_int_hash, g_int_equal);
106 if (!_pool->streams) {
107 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
108 GOTO_FAIL("Memory alloc failure. Can't create internal streams hash "
109 "table in sound pool", cfail);
112 _pool->volume = DEFAULT_VOLUME_VALUE;
113 _pool->max_stream_index = 0;
114 _pool->state = SOUND_POOL_STATE_INACTIVE;
115 _pool->state_cb_info.callback = NULL;
116 _pool->state_cb_info.user_data = NULL;
119 ret = _stream_cb_manager_create(_pool, &_pool->cbmgr);
120 if (ret != SOUND_POOL_ERROR_NONE)
121 GOTO_FAIL("Error occurred when trying to create stream state changing "
122 "callback manager instance", cfail);
124 _pool->mgr_priority = NULL;
125 ret = _sound_stream_priority_create(_pool, &_pool->mgr_priority);
126 if (ret != SOUND_POOL_ERROR_NONE)
127 GOTO_FAIL("Error occurred initialising of priorities.", cfail);
134 _sound_pool_destroy(_pool);
139 sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
142 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
143 _sound_pool_deactivate(pool);
146 sound_pool_error_e ret = _stream_cb_manager_destroy(pool->cbmgr);
147 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
148 "Error occurred when " "trying to destroy sound pool callback manager.");
155 g_hash_table_iter_init(&iter, pool->sources);
156 while (g_hash_table_iter_next(&iter, &key, &value)) {
157 guint size_before = g_hash_table_size(pool->sources);
158 _sound_source_destroy((sound_source_t*)value);
159 guint size_after = g_hash_table_size(pool->sources);
160 if (size_before != size_after)
161 g_hash_table_iter_init(&iter, pool->sources);
163 g_hash_table_unref(pool->sources);
164 pool->sources = NULL;
168 g_hash_table_unref(pool->streams);
169 pool->streams = NULL;
172 if (pool->mgr_priority) {
173 sound_pool_error_e ret = _sound_stream_priority_destroy(pool->mgr_priority);
174 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
175 "Error occurred when trying to destroy priority manager.");
176 pool->mgr_priority = NULL;
179 if (pool->al_context) {
180 ALCdevice *device = alcGetContextsDevice(pool->al_context);
181 alcMakeContextCurrent(NULL);
182 alcDestroyContext(pool->al_context);
183 alcCloseDevice(device);
189 return SOUND_POOL_ERROR_NONE;
192 sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
195 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
197 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_ACTIVE,
198 SOUND_POOL_ERROR_INVALID_OPERATION,
199 "Already activated sound pool can't be activated again.");
201 sound_pool_state_e old_state = pool->state;
202 pool->state = SOUND_POOL_STATE_ACTIVE;
204 /* Generate array of all AlSources in pool */
205 GPtrArray *streams = NULL;
206 if (g_hash_table_size(pool->streams) > 0) {
207 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
208 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
210 g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
211 SP_INFO("Resuming [%d] number of streams.", len);
215 g_ptr_array_free(streams, TRUE);
217 SP_INFO("Sound pool has been activated");
219 if (pool->state_cb_info.callback)
220 pool->state_cb_info.callback(pool, old_state, pool->state,
221 pool->state_cb_info.user_data);
224 return SOUND_POOL_ERROR_NONE;
227 sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
230 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
231 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_INACTIVE,
232 SOUND_POOL_ERROR_INVALID_OPERATION,
233 "Already deactivated sound pool can't be deactivated again.");
235 sound_pool_state_e old_state = pool->state;
236 pool->state = SOUND_POOL_STATE_INACTIVE;
238 /* Generate array of all AlSources in pool */
239 GPtrArray *streams = NULL;
240 if (g_hash_table_size(pool->streams) > 0) {
241 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
242 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
244 g_hash_table_foreach(pool->streams, __stream_deactivate_iter, &len);
245 SP_INFO("Suspending [%d] number of streams.", len);
249 g_ptr_array_free(streams, TRUE);
251 SP_INFO("Sound pool has been deactivated");
253 if (pool->state_cb_info.callback)
254 pool->state_cb_info.callback(pool, old_state, pool->state,
255 pool->state_cb_info.user_data);
258 return SOUND_POOL_ERROR_NONE;
261 sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
262 sound_pool_state_e *state)
265 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
266 SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
267 *state = pool->state;
269 return SOUND_POOL_ERROR_NONE;
272 sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
275 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
276 SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
277 SOUND_POOL_ERROR_INVALID_PARAMETER,
278 "Sound pool volume is not in [0.0..1.0] range.");
280 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
281 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
282 alListenerf(AL_GAIN, volume);
283 pool->volume = volume;
286 return SOUND_POOL_ERROR_NONE;
289 sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
292 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
293 SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
294 *volume = pool->volume;
296 return SOUND_POOL_ERROR_NONE;
299 sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
300 sound_pool_state_change_cb callback, void *data)
303 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
304 SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
306 pool->state_cb_info.callback = callback;
307 pool->state_cb_info.user_data = data;
310 return SOUND_POOL_ERROR_NONE;
313 sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
316 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
318 pool->state_cb_info.callback = NULL;
319 pool->state_cb_info.user_data = NULL;
322 return SOUND_POOL_ERROR_NONE;