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 ALCdevice *device = NULL;
33 static void __stream_activate_iter(gpointer key, gpointer value,
35 static void __stream_deactivate_iter(gpointer key, gpointer value,
38 static void __stream_activate_iter(gpointer key, gpointer value,
42 SP_RETM_IF(!user_data, "Empty user data.");
43 SP_RETM_IF(!value, "Empty sound stream data.");
44 guint *len = (guint*)user_data;
45 sound_stream_t *stream = (sound_stream_t *)value;
47 gboolean can_run = TRUE;
48 if (SOUND_POOL_ERROR_NONE
49 == _sound_stream_priority_check(stream->parent_source->parent_pool->mgr_priority,
51 if (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED && TRUE == can_run) {
52 alSourcePlay(stream->al_source);
59 static void __stream_deactivate_iter(gpointer key, gpointer value,
63 SP_RETM_IF(!user_data, "Empty user data.");
64 SP_RETM_IF(!value, "Empty sound stream data.");
65 guint *len = (guint*)user_data;
66 sound_stream_t *stream = (sound_stream_t *)value;
68 if (stream->state == SOUND_POOL_STREAM_STATE_PLAYING) {
69 alSourcePause(stream->al_source);
76 sound_pool_error_e _sound_pool_create(size_t max_streams, sound_pool_t **pool)
79 SP_RETVM_IF(max_streams == 0, SOUND_POOL_ERROR_INVALID_PARAMETER,
80 "Max streams count should be greater than 0.");
82 sound_pool_t *_pool = NULL;
83 SP_RETVM_IF(!(_pool = g_try_malloc0(sizeof(*_pool))),
84 SOUND_POOL_ERROR_OUT_OF_MEMORY,
85 "Memory alloc failure. Can't create sound pool");
86 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
87 "sound pool. Pool pointer is NULL");
89 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
90 _pool->al_context = NULL;
91 _pool->al_context = alcCreateContext(alcOpenDevice(NULL), NULL);
92 if (!_pool->al_context) {
93 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
94 GOTO_FAIL("Memory alloc failure. Can't create OpenAL Context", cfail);
97 _pool->sources = NULL;
98 _pool->streams = NULL;
100 _pool->sources = g_hash_table_new(g_str_hash, g_str_equal);
101 if (!_pool->sources) {
102 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
103 GOTO_FAIL("Memory alloc failure. Can't create internal sources hash "
104 "table in sound pool", cfail);
107 _pool->streams = g_hash_table_new(g_int_hash, g_int_equal);
108 if (!_pool->streams) {
109 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
110 GOTO_FAIL("Memory alloc failure. Can't create internal streams hash "
111 "table in sound pool", cfail);
114 _pool->max_streams = max_streams;
115 _pool->volume = DEFAULT_VOLUME_VALUE;
116 _pool->max_stream_index = 0;
117 _pool->state = SOUND_POOL_STATE_INACTIVE;
118 _pool->state_cb_info.callback = NULL;
119 _pool->state_cb_info.user_data = NULL;
122 ret = _stream_cb_manager_create(_pool, &_pool->cbmgr);
123 if (ret != SOUND_POOL_ERROR_NONE)
124 GOTO_FAIL("Error occurred when trying to create stream state changing "
125 "callback manager instance", cfail);
127 _pool->mgr_priority = NULL;
128 ret = _sound_stream_priority_create(_pool, &_pool->mgr_priority);
129 if (ret != SOUND_POOL_ERROR_NONE)
130 GOTO_FAIL("Error occurred initialising of priorities.", cfail);
137 _sound_pool_destroy(_pool);
142 sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
145 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
146 _sound_pool_deactivate(pool);
149 sound_pool_error_e ret = _stream_cb_manager_destroy(pool->cbmgr);
150 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
151 "Error occurred when " "trying to destroy sound pool callback manager.");
158 g_hash_table_iter_init(&iter, pool->sources);
159 while (g_hash_table_iter_next(&iter, &key, &value)) {
160 guint size_before = g_hash_table_size(pool->sources);
161 _sound_source_destroy((sound_source_t*)value);
162 guint size_after = g_hash_table_size(pool->sources);
163 if (size_before != size_after)
164 g_hash_table_iter_init(&iter, pool->sources);
166 g_hash_table_unref(pool->sources);
167 pool->sources = NULL;
171 g_hash_table_unref(pool->streams);
172 pool->streams = NULL;
175 if (pool->mgr_priority) {
176 sound_pool_error_e ret = _sound_stream_priority_destroy(pool->mgr_priority);
177 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
178 "Error occurred when trying to destroy priority manager.");
179 pool->mgr_priority = NULL;
182 if (pool->al_context) {
183 ALCdevice *device = alcGetContextsDevice(pool->al_context);
184 alcMakeContextCurrent(NULL);
185 alcDestroyContext(pool->al_context);
186 alcCloseDevice(device);
192 return SOUND_POOL_ERROR_NONE;
195 sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
198 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
200 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_ACTIVE,
201 SOUND_POOL_ERROR_INVALID_OPERATION,
202 "Already activated sound pool can't be activated again.");
204 sound_pool_state_e old_state = pool->state;
205 pool->state = SOUND_POOL_STATE_ACTIVE;
207 /* Generate array of all AlSources in pool */
208 GPtrArray *streams = NULL;
209 if (g_hash_table_size(pool->streams) > 0) {
210 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
211 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
213 g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
214 SP_INFO("Resuming [%d] number of streams.", len);
218 g_ptr_array_free(streams, TRUE);
220 SP_INFO("Sound pool has been activated");
222 if (pool->state_cb_info.callback)
223 pool->state_cb_info.callback(pool, old_state, pool->state,
224 pool->state_cb_info.user_data);
227 return SOUND_POOL_ERROR_NONE;
230 sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
233 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
234 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_INACTIVE,
235 SOUND_POOL_ERROR_INVALID_OPERATION,
236 "Already deactivated sound pool can't be deactivated again.");
238 sound_pool_state_e old_state = pool->state;
239 pool->state = SOUND_POOL_STATE_INACTIVE;
241 /* Generate array of all AlSources in pool */
242 GPtrArray *streams = NULL;
243 if (g_hash_table_size(pool->streams) > 0) {
244 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
245 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
247 g_hash_table_foreach(pool->streams, __stream_deactivate_iter, &len);
248 SP_INFO("Suspending [%d] number of streams.", len);
252 g_ptr_array_free(streams, TRUE);
254 SP_INFO("Sound pool has been deactivated");
256 if (pool->state_cb_info.callback)
257 pool->state_cb_info.callback(pool, old_state, pool->state,
258 pool->state_cb_info.user_data);
261 return SOUND_POOL_ERROR_NONE;
264 sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
265 sound_pool_state_e *state)
268 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
269 SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
270 *state = pool->state;
272 return SOUND_POOL_ERROR_NONE;
275 sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
278 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
279 SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
280 SOUND_POOL_ERROR_INVALID_PARAMETER,
281 "Sound pool volume is not in [0.0..1.0] range.");
283 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
284 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
285 alListenerf(AL_GAIN, volume);
286 pool->volume = volume;
289 return SOUND_POOL_ERROR_NONE;
292 sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
295 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
296 SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
297 *volume = pool->volume;
299 return SOUND_POOL_ERROR_NONE;
302 sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
303 sound_pool_state_change_cb callback, void *data)
306 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
307 SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
309 pool->state_cb_info.callback = callback;
310 pool->state_cb_info.user_data = data;
313 return SOUND_POOL_ERROR_NONE;
316 sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
319 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
321 pool->state_cb_info.callback = NULL;
322 pool->state_cb_info.user_data = NULL;
325 return SOUND_POOL_ERROR_NONE;