Disable session backward compatibility with soundpool
[platform/core/api/sound-pool.git] / src / soundpool.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * @file soundpool.c
19  * @brief This file include implementation of protected API for the SoundPool.
20  */
21 #include <unistd.h>
22 #include <mm_session.h>
23 #include <mm_sound.h>
24 #include <mm_session_private.h>
25
26 #include "internal/soundpool.h"
27
28 #include "internal/priority.h"
29 #include "internal/stream_cb_manager.h"
30
31 #include "internal/source.h"
32 #include "internal/stream.h"
33
34 #define DEFAULT_VOLUME_VALUE 1.0f
35
36 static void __stream_activate_iter(gpointer key, gpointer value,
37                 gpointer user_data);
38 static void __stream_deactivate_iter(gpointer key, gpointer value,
39                 gpointer user_data);
40
41 static void __stream_activate_iter(gpointer key, gpointer value,
42                 gpointer user_data)
43 {
44         SP_DEBUG_FENTER();
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;
49
50         gboolean can_run = TRUE;
51         if (SOUND_POOL_ERROR_NONE
52                         == _sound_stream_priority_check(stream->parent_source->parent_pool->mgr_priority,
53                                         stream, &can_run))
54                 if (stream->state == SOUND_POOL_STREAM_STATE_SUSPENDED && TRUE == can_run) {
55                         alSourcePlay(stream->al_source);
56                         (*len)++;
57                 }
58
59         SP_DEBUG_FLEAVE();
60 }
61
62 static void __stream_deactivate_iter(gpointer key, gpointer value,
63                 gpointer user_data)
64 {
65         SP_DEBUG_FENTER();
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;
70
71         if (stream->state == SOUND_POOL_STREAM_STATE_PLAYING) {
72                 alSourcePause(stream->al_source);
73                 (*len)++;
74         }
75
76         SP_DEBUG_FLEAVE();
77 }
78
79 sound_pool_error_e _sound_pool_create(sound_pool_t **pool)
80 {
81         SP_DEBUG_FENTER();
82         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
83
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");
90
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);
97         }
98
99         _pool->sources = NULL;
100         _pool->streams = NULL;
101
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);
107         }
108
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);
114         }
115
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;
121
122         _pool->cbmgr = 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);
127
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);
132
133         *pool = _pool;
134         SP_DEBUG_FLEAVE();
135         return ret;
136
137 cfail:
138         _sound_pool_destroy(_pool);
139         SP_DEBUG_FLEAVE();
140         return ret;
141 }
142
143 sound_pool_error_e _sound_pool_destroy(sound_pool_t *pool)
144 {
145         SP_DEBUG_FENTER();
146         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
147         _sound_pool_deactivate(pool);
148
149         if (pool->cbmgr) {
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.");
153                 pool->cbmgr = NULL;
154         }
155
156         if (pool->sources) {
157                 GHashTableIter iter;
158                 gpointer key, value;
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);
166                 }
167                 g_hash_table_unref(pool->sources);
168                 pool->sources = NULL;
169         }
170
171         if (pool->streams) {
172                 g_hash_table_unref(pool->streams);
173                 pool->streams = NULL;
174         }
175
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;
181         }
182
183         if (pool->al_context) {
184                 ALCdevice *device = alcGetContextsDevice(pool->al_context);
185                 alcMakeContextCurrent(NULL);
186                 alcDestroyContext(pool->al_context);
187                 if (device)
188                         alcCloseDevice(device);
189         }
190
191         SP_SAFE_GFREE(pool);
192
193         SP_DEBUG_FLEAVE();
194         return SOUND_POOL_ERROR_NONE;
195 }
196
197 sound_pool_error_e _sound_pool_activate(sound_pool_t *pool)
198 {
199         SP_DEBUG_FENTER();
200         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
201
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.");
205
206         sound_pool_state_e old_state = pool->state;
207         pool->state = SOUND_POOL_STATE_ACTIVE;
208
209         _sound_stream_priority_update_playback(pool->mgr_priority);
210
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.");
214                 guint len = 0;
215                 g_hash_table_foreach(pool->streams, __stream_activate_iter, &len);
216                 SP_INFO("Resuming [%d] number of streams.", len);
217         }
218
219         SP_INFO("Sound pool has been activated");
220
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);
224
225         SP_DEBUG_FLEAVE();
226         return SOUND_POOL_ERROR_NONE;
227 }
228
229 sound_pool_error_e _sound_pool_deactivate(sound_pool_t *pool)
230 {
231         SP_DEBUG_FENTER();
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.");
236
237         sound_pool_state_e old_state = pool->state;
238         pool->state = SOUND_POOL_STATE_INACTIVE;
239
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.");
243                 guint len = 0;
244                 g_hash_table_foreach(pool->streams, __stream_deactivate_iter, &len);
245                 SP_INFO("Suspending [%d] number of streams.", len);
246         }
247
248         SP_INFO("Sound pool has been deactivated");
249
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);
253
254         SP_DEBUG_FLEAVE();
255         return SOUND_POOL_ERROR_NONE;
256 }
257
258 sound_pool_error_e _sound_pool_get_state(sound_pool_t *pool,
259                 sound_pool_state_e *state)
260 {
261         SP_DEBUG_FENTER();
262         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
263         SP_INST_CHECK(state, SOUND_POOL_ERROR_INVALID_PARAMETER);
264         *state = pool->state;
265         SP_DEBUG_FLEAVE();
266         return SOUND_POOL_ERROR_NONE;
267 }
268
269 sound_pool_error_e _sound_pool_set_volume(sound_pool_t *pool, float volume)
270 {
271         SP_DEBUG_FENTER();
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.");
276
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;
281
282         SP_DEBUG_FLEAVE();
283         return SOUND_POOL_ERROR_NONE;
284 }
285
286 sound_pool_error_e _sound_pool_get_volume(sound_pool_t *pool, float *volume)
287 {
288         SP_DEBUG_FENTER();
289         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
290         SP_INST_CHECK(volume, SOUND_POOL_ERROR_INVALID_PARAMETER);
291         *volume = pool->volume;
292         SP_DEBUG_FLEAVE();
293         return SOUND_POOL_ERROR_NONE;
294 }
295
296 sound_pool_error_e _sound_pool_set_callback(sound_pool_t *pool,
297                 sound_pool_state_changed_cb callback, void *data)
298 {
299         SP_DEBUG_FENTER();
300         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
301         SP_INST_CHECK(callback, SOUND_POOL_ERROR_INVALID_PARAMETER);
302
303         pool->state_cb_info.callback = callback;
304         pool->state_cb_info.user_data = data;
305
306         SP_DEBUG_FLEAVE();
307         return SOUND_POOL_ERROR_NONE;
308 }
309
310 sound_pool_error_e _sound_pool_unset_callback(sound_pool_t *pool)
311 {
312         SP_DEBUG_FENTER();
313         SP_INST_CHECK(pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
314
315         pool->state_cb_info.callback = NULL;
316         pool->state_cb_info.user_data = NULL;
317
318         SP_DEBUG_FLEAVE();
319         return SOUND_POOL_ERROR_NONE;
320 }
321
322 void _sound_pool_disable_session_backward_compatibility(void)
323 {
324         int mm_ret = MM_ERROR_NONE;
325         int session_type = 0;
326         int session_options = 0;
327
328         /* read session information */
329         mm_ret = _mm_session_util_read_information(-1, &session_type, &session_options);
330         if (mm_ret == MM_ERROR_NONE) {
331                 /* Session exists */
332                 SP_INFO(" Session exists:session_type %d, session_option %d", session_type, session_options);
333         }
334
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");
337 }