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 <mm_session.h>
24 #include <mm_session_private.h>
26 #include "internal/soundpool.h"
28 #include "internal/priority.h"
29 #include "internal/stream_cb_manager.h"
31 #include "internal/source.h"
32 #include "internal/stream.h"
34 #define DEFAULT_VOLUME_VALUE 1.0f
36 static void __stream_activate_iter(gpointer key, gpointer value,
38 static void __stream_deactivate_iter(gpointer key, gpointer value,
41 static void __stream_activate_iter(gpointer key, gpointer value,
45 SP_RETM_IF(!user_data, "Empty user data.");
46 SP_RETM_IF(!value, "Empty sound stream data.");
47 guint *len = (guint*)user_data;
48 sound_stream_t *stream = (sound_stream_t *)value;
50 gboolean can_run = TRUE;
51 if (SOUND_POOL_ERROR_NONE
52 == _sound_stream_priority_check(stream->parent_source->parent_pool->mgr_priority,
54 if (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED && TRUE == can_run) {
55 alSourcePlay(stream->al_source);
62 static void __stream_deactivate_iter(gpointer key, gpointer value,
66 SP_RETM_IF(!user_data, "Empty user data.");
67 SP_RETM_IF(!value, "Empty sound stream data.");
68 guint *len = (guint*)user_data;
69 sound_stream_t *stream = (sound_stream_t *)value;
71 if (stream->state == SOUND_POOL_STREAM_STATE_PLAYING) {
72 alSourcePause(stream->al_source);
78 static void __stream_stop_iter(gpointer key, gpointer value,
82 SP_RETM_IF(!user_data, "Empty user data.");
83 SP_RETM_IF(!value, "Empty sound stream data.");
84 guint *len = (guint*)user_data;
85 sound_stream_t *stream = (sound_stream_t *)value;
87 if ((stream->state == SOUND_POOL_STREAM_STATE_PLAYING)
88 || (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED)
89 || (stream->state == SOUND_POOL_STREAM_STATE_PAUSED)) {
90 alSourceStop(stream->al_source);
96 sound_pool_error_e _sound_pool_create(sound_pool_t **pool)
99 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
101 sound_pool_t *_pool = NULL;
102 SP_RETVM_IF(!(_pool = g_try_malloc0(sizeof(*_pool))),
103 SOUND_POOL_ERROR_OUT_OF_MEMORY,
104 "Memory alloc failure. Can't create sound pool");
105 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
106 "sound pool. Pool pointer is NULL");
108 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
109 _pool->al_context = NULL;
110 _pool->al_context = alcCreateContext(alcOpenDevice(NULL), NULL);
111 if (!_pool->al_context) {
112 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
113 GOTO_FAIL("Memory alloc failure. Can't create OpenAL Context", cfail);
116 _pool->sources = NULL;
117 _pool->streams = NULL;
119 _pool->sources = g_hash_table_new(g_str_hash, g_str_equal);
120 if (!_pool->sources) {
121 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
122 GOTO_FAIL("Memory alloc failure. Can't create internal sources hash "
123 "table in sound pool", cfail);
126 _pool->streams = g_hash_table_new(g_int_hash, g_int_equal);
127 if (!_pool->streams) {
128 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
129 GOTO_FAIL("Memory alloc failure. Can't create internal streams hash "
130 "table in sound pool", cfail);
133 _pool->volume = DEFAULT_VOLUME_VALUE;
134 _pool->max_stream_index = 0;
135 _pool->state = SOUND_POOL_STATE_INACTIVE;
136 _pool->state_cb_info.callback = NULL;
137 _pool->state_cb_info.user_data = NULL;
140 ret = _stream_cb_manager_create(_pool, &_pool->cbmgr);
141 if (ret != SOUND_POOL_ERROR_NONE)
142 GOTO_FAIL("Error occurred when trying to create stream state changing "
143 "callback manager instance", cfail);
145 _pool->mgr_priority = NULL;
146 ret = _sound_stream_priority_create(_pool, &_pool->mgr_priority);
147 if (ret != SOUND_POOL_ERROR_NONE)
148 GOTO_FAIL("Error occurred initialising of priorities.", cfail);
155 _sound_pool_destroy(_pool);
160 sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
163 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
164 _sound_pool_stop_streams(pool);
169 g_hash_table_iter_init(&iter, pool->sources);
170 while (g_hash_table_iter_next(&iter, &key, &value)) {
171 guint size_before = g_hash_table_size(pool->sources);
172 _sound_source_destroy((sound_source_t*)value);
173 guint size_after = g_hash_table_size(pool->sources);
174 if (size_before != size_after)
175 g_hash_table_iter_init(&iter, pool->sources);
177 g_hash_table_unref(pool->sources);
178 pool->sources = NULL;
182 sound_pool_error_e ret = _stream_cb_manager_destroy(pool->cbmgr);
183 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
184 "Error occurred when " "trying to destroy sound pool callback manager.");
189 g_hash_table_unref(pool->streams);
190 pool->streams = NULL;
193 if (pool->mgr_priority) {
194 sound_pool_error_e ret = _sound_stream_priority_destroy(pool->mgr_priority);
195 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
196 "Error occurred when trying to destroy priority manager.");
197 pool->mgr_priority = NULL;
200 if (pool->al_context) {
201 ALCdevice *device = alcGetContextsDevice(pool->al_context);
202 alcMakeContextCurrent(NULL);
203 alcDestroyContext(pool->al_context);
205 alcCloseDevice(device);
211 return SOUND_POOL_ERROR_NONE;
214 sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
217 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
219 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_ACTIVE,
220 SOUND_POOL_ERROR_INVALID_OPERATION,
221 "Already activated sound pool can't be activated again.");
223 sound_pool_state_e old_state = pool->state;
224 pool->state = SOUND_POOL_STATE_ACTIVE;
226 _sound_stream_priority_update_playback(pool->mgr_priority);
228 if (g_hash_table_size(pool->streams) > 0) {
229 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
230 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
232 g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
233 SP_INFO("Resuming [%d] number of streams.", len);
236 SP_INFO("Sound pool has been activated");
238 if (pool->state_cb_info.callback)
239 pool->state_cb_info.callback(pool, old_state, pool->state,
240 pool->state_cb_info.user_data);
243 return SOUND_POOL_ERROR_NONE;
246 sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
249 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
250 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_INACTIVE,
251 SOUND_POOL_ERROR_INVALID_OPERATION,
252 "Already deactivated sound pool can't be deactivated again.");
254 sound_pool_state_e old_state = pool->state;
256 /* Wait for completing the isoloator callback thread events */
257 _stream_cb_manager_process_pending_events(pool->cbmgr);
259 pool->state = SOUND_POOL_STATE_INACTIVE;
261 if (g_hash_table_size(pool->streams) > 0) {
262 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
263 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
265 g_hash_table_foreach(pool->streams, __stream_deactivate_iter, &len);
266 SP_INFO("Suspending [%d] number of streams.", len);
269 SP_INFO("Sound pool has been deactivated");
271 if (pool->state_cb_info.callback)
272 pool->state_cb_info.callback(pool, old_state, pool->state,
273 pool->state_cb_info.user_data);
276 return SOUND_POOL_ERROR_NONE;
279 sound_pool_error_e _sound_pool_stop_streams(sound_pool_t *pool)
282 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
284 pool->state = SOUND_POOL_STATE_INACTIVE;
286 if (g_hash_table_size(pool->streams) > 0) {
287 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
288 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
290 g_hash_table_foreach(pool->streams, __stream_stop_iter, &len);
291 SP_INFO("Stopping [%d] number of streams.", len);
294 SP_INFO("Sound pool has been stopped");
297 return SOUND_POOL_ERROR_NONE;
299 sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
300 sound_pool_state_e *state)
303 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
304 SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
305 *state = pool->state;
307 return SOUND_POOL_ERROR_NONE;
310 sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
313 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
314 SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
315 SOUND_POOL_ERROR_INVALID_PARAMETER,
316 "Sound pool volume is not in [0.0..1.0] range.");
318 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
319 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
320 alListenerf(AL_GAIN, volume);
321 pool->volume = volume;
324 return SOUND_POOL_ERROR_NONE;
327 sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
330 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
331 SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
332 *volume = pool->volume;
334 return SOUND_POOL_ERROR_NONE;
337 sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
338 sound_pool_state_changed_cb callback, void *data)
341 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
342 SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
344 pool->state_cb_info.callback = callback;
345 pool->state_cb_info.user_data = data;
348 return SOUND_POOL_ERROR_NONE;
351 sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
354 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
356 pool->state_cb_info.callback = NULL;
357 pool->state_cb_info.user_data = NULL;
360 return SOUND_POOL_ERROR_NONE;
363 void _sound_pool_disable_session_backward_compatibility(void)
365 int mm_ret = MM_ERROR_NONE;
366 int session_type = 0;
367 int session_options = 0;
369 /* read session information */
370 mm_ret = _mm_session_util_read_information(-1, &session_type, &session_options);
371 if (mm_ret == MM_ERROR_NONE) {
373 SP_INFO(" Session exists:session_type %d, session_option %d", session_type, session_options);
376 if ((_mm_session_util_write_information((int)getpid(), MM_SESSION_TYPE_REPLACED_BY_STREAM, 0)))
377 SP_INFO("failed to _mm_session_util_write_information for MM_SESSION_TYPE_REPLACED_BY_STREAM");