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);
79 sound_pool_error_e _sound_pool_create(sound_pool_t **pool)
82 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
84 sound_pool_t *_pool = NULL;
85 SP_RETVM_IF(!(_pool = g_try_malloc0(sizeof(*_pool))),
86 SOUND_POOL_ERROR_OUT_OF_MEMORY,
87 "Memory alloc failure. Can't create sound pool");
88 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
89 "sound pool. Pool pointer is NULL");
91 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
92 _pool->al_context = NULL;
93 _pool->al_context = alcCreateContext(alcOpenDevice(NULL), NULL);
94 if (!_pool->al_context) {
95 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
96 GOTO_FAIL("Memory alloc failure. Can't create OpenAL Context", cfail);
99 _pool->sources = NULL;
100 _pool->streams = NULL;
102 _pool->sources = g_hash_table_new(g_str_hash, g_str_equal);
103 if (!_pool->sources) {
104 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
105 GOTO_FAIL("Memory alloc failure. Can't create internal sources hash "
106 "table in sound pool", cfail);
109 _pool->streams = g_hash_table_new(g_int_hash, g_int_equal);
110 if (!_pool->streams) {
111 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
112 GOTO_FAIL("Memory alloc failure. Can't create internal streams hash "
113 "table in sound pool", cfail);
116 _pool->volume = DEFAULT_VOLUME_VALUE;
117 _pool->max_stream_index = 0;
118 _pool->state = SOUND_POOL_STATE_INACTIVE;
119 _pool->state_cb_info.callback = NULL;
120 _pool->state_cb_info.user_data = NULL;
123 ret = _stream_cb_manager_create(_pool, &_pool->cbmgr);
124 if (ret != SOUND_POOL_ERROR_NONE)
125 GOTO_FAIL("Error occurred when trying to create stream state changing "
126 "callback manager instance", cfail);
128 _pool->mgr_priority = NULL;
129 ret = _sound_stream_priority_create(_pool, &_pool->mgr_priority);
130 if (ret != SOUND_POOL_ERROR_NONE)
131 GOTO_FAIL("Error occurred initialising of priorities.", cfail);
138 _sound_pool_destroy(_pool);
143 sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
146 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
147 _sound_pool_deactivate(pool);
150 sound_pool_error_e ret = _stream_cb_manager_destroy(pool->cbmgr);
151 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
152 "Error occurred when " "trying to destroy sound pool callback manager.");
159 g_hash_table_iter_init(&iter, pool->sources);
160 while (g_hash_table_iter_next(&iter, &key, &value)) {
161 guint size_before = g_hash_table_size(pool->sources);
162 _sound_source_destroy((sound_source_t*)value);
163 guint size_after = g_hash_table_size(pool->sources);
164 if (size_before != size_after)
165 g_hash_table_iter_init(&iter, pool->sources);
167 g_hash_table_unref(pool->sources);
168 pool->sources = NULL;
172 g_hash_table_unref(pool->streams);
173 pool->streams = NULL;
176 if (pool->mgr_priority) {
177 sound_pool_error_e ret = _sound_stream_priority_destroy(pool->mgr_priority);
178 SP_RETVM_IF(ret != SOUND_POOL_ERROR_NONE, ret,
179 "Error occurred when trying to destroy priority manager.");
180 pool->mgr_priority = NULL;
183 if (pool->al_context) {
184 ALCdevice *device = alcGetContextsDevice(pool->al_context);
185 alcMakeContextCurrent(NULL);
186 alcDestroyContext(pool->al_context);
188 alcCloseDevice(device);
194 return SOUND_POOL_ERROR_NONE;
197 sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
200 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
202 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_ACTIVE,
203 SOUND_POOL_ERROR_INVALID_OPERATION,
204 "Already activated sound pool can't be activated again.");
206 sound_pool_state_e old_state = pool->state;
207 pool->state = SOUND_POOL_STATE_ACTIVE;
209 _sound_stream_priority_update_playback(pool->mgr_priority);
211 if (g_hash_table_size(pool->streams) > 0) {
212 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
213 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
215 g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
216 SP_INFO("Resuming [%d] number of streams.", len);
219 SP_INFO("Sound pool has been activated");
221 if (pool->state_cb_info.callback)
222 pool->state_cb_info.callback(pool, old_state, pool->state,
223 pool->state_cb_info.user_data);
226 return SOUND_POOL_ERROR_NONE;
229 sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
232 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
233 SP_RETVM_IF(pool->state == SOUND_POOL_STATE_INACTIVE,
234 SOUND_POOL_ERROR_INVALID_OPERATION,
235 "Already deactivated sound pool can't be deactivated again.");
237 sound_pool_state_e old_state = pool->state;
238 pool->state = SOUND_POOL_STATE_INACTIVE;
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);
248 SP_INFO("Sound pool has been deactivated");
250 if (pool->state_cb_info.callback)
251 pool->state_cb_info.callback(pool, old_state, pool->state,
252 pool->state_cb_info.user_data);
255 return SOUND_POOL_ERROR_NONE;
258 sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
259 sound_pool_state_e *state)
262 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
263 SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
264 *state = pool->state;
266 return SOUND_POOL_ERROR_NONE;
269 sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
272 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
273 SP_RETVM_IF((volume < 0.0f || volume > 1.0f),
274 SOUND_POOL_ERROR_INVALID_PARAMETER,
275 "Sound pool volume is not in [0.0..1.0] range.");
277 SP_RETVM_IF(!alcMakeContextCurrent(pool->al_context),
278 SOUND_POOL_ERROR_INVALID_OPERATION, "Can't set current context.");
279 alListenerf(AL_GAIN, volume);
280 pool->volume = volume;
283 return SOUND_POOL_ERROR_NONE;
286 sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
289 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
290 SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
291 *volume = pool->volume;
293 return SOUND_POOL_ERROR_NONE;
296 sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
297 sound_pool_state_changed_cb callback, void *data)
300 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
301 SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
303 pool->state_cb_info.callback = callback;
304 pool->state_cb_info.user_data = data;
307 return SOUND_POOL_ERROR_NONE;
310 sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
313 SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
315 pool->state_cb_info.callback = NULL;
316 pool->state_cb_info.user_data = NULL;
319 return SOUND_POOL_ERROR_NONE;
322 void _sound_pool_disable_session_backward_compatibility(void)
324 int mm_ret = MM_ERROR_NONE;
325 int session_type = 0;
326 int session_options = 0;
328 /* read session information */
329 mm_ret = _mm_session_util_read_information(-1, &session_type, &session_options);
330 if (mm_ret == MM_ERROR_NONE) {
332 SP_INFO(" Session exists:session_type %d, session_option %d", session_type, session_options);
335 if ((_mm_session_util_write_information((int)getpid(), MM_SESSION_TYPE_REPLACED_BY_STREAM, 0)))
336 SP_INFO("failed to _mm_session_util_write_information for MM_SESSION_TYPE_REPLACED_BY_STREAM");