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.
18 * @file stream_cb_manager.c
19 * @brief This file include implementation of protected API for the stream
20 * callback manager as part of SoundPool.
23 #include "internal/stream_cb_manager.h"
25 static gpointer __sound_pool_callback_isolator(gpointer user_data);
26 static void __thread_cancel_cleanup();
27 static void __queue_destroy_item(gpointer data);
29 static void __queue_destroy_item(gpointer data)
38 static void __thread_cancel_cleanup(void *user_data)
42 stream_cb_manager_t *cbmgr = (stream_cb_manager_t *)user_data;
43 g_async_queue_unref(cbmgr->isolator_callback_queue);
45 pthread_cond_broadcast(&cbmgr->isolator_data_cond);
46 pthread_cond_destroy(&cbmgr->isolator_data_cond);
47 pthread_mutex_destroy(&cbmgr->isolator_data_mutex);
54 sound_pool_error_e _stream_cb_manager_process_pending_events(stream_cb_manager_t *cbmgr)
57 SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle callback "
58 "manager, it is NULL.");
60 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
61 if (cbmgr->isolator_state_changed) {
62 cbmgr->isolator_force_run = TRUE;
63 SP_INFO("waiting for isolator callback thread completion");
64 pthread_cond_wait(&cbmgr->isolator_force_run_cond, &cbmgr->isolator_data_mutex);
66 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
69 return SOUND_POOL_ERROR_NONE;
72 sound_pool_error_e _stream_cb_manager_signal_completed_events(stream_cb_manager_t *cbmgr)
75 SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle callback "
76 "manager, it is NULL.");
78 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
79 cbmgr->isolator_state_changed = FALSE;
80 if (cbmgr->isolator_force_run) {
81 SP_INFO("Signal indicating isolator callback completed the task");
82 pthread_cond_signal(&cbmgr->isolator_force_run_cond);
84 cbmgr->isolator_force_run = FALSE;
85 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
88 return SOUND_POOL_ERROR_NONE;
91 static gpointer __sound_pool_callback_isolator(gpointer user_data)
94 int err = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
96 SP_INFO("Can't setup cancel type for isolation thread with error [%d].", err);
97 err = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
99 SP_INFO("Can't setup cancel state for isolation thread with error [%d].", err);
100 SP_RETVM_IF(!user_data, NULL, "User data is NULL. Terminate callback thread");
102 stream_cb_manager_t *cbmgr = (stream_cb_manager_t *)user_data;
103 pthread_cleanup_push(__thread_cancel_cleanup, user_data);
104 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
105 gboolean runing = cbmgr->isolator_loop_run;
106 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
109 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
110 while (!cbmgr->isolator_state_changed)
111 pthread_cond_wait(&cbmgr->isolator_data_cond, &cbmgr->isolator_data_mutex);
112 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
114 /* Iterate streams have been pushed to the queue and call for each
115 state changed callback for each stream */
116 stream_cb_manager_event_data_t *event_data = NULL;
117 while ((event_data = (stream_cb_manager_event_data_t *)
118 g_async_queue_try_pop(cbmgr->isolator_callback_queue))) {
120 sound_pool_t* _pool = cbmgr->pool;
121 if (NULL != event_data->callback) {
122 event_data->callback(_pool,
123 event_data->stream_id, event_data->state_previous,
125 event_data->user_data);
127 SP_SAFE_GFREE(event_data);
129 /* Signal indicating isolator callback thread completed the events */
130 _stream_cb_manager_signal_completed_events(cbmgr);
132 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
133 runing = cbmgr->isolator_loop_run;
134 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
137 pthread_cleanup_pop(0);
142 sound_pool_error_e _stream_cb_manager_create(sound_pool_t *pool,
143 stream_cb_manager_t **cbmgr)
148 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
149 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Stream callback "
150 "manager can't be created for NULL sound pool");
151 SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
152 "stream state changing callback manager. Manager pointer is NULL");
154 stream_cb_manager_t *_cbmgr = NULL;
155 SP_RETVM_IF(!(_cbmgr = g_try_malloc0(sizeof(*_cbmgr))),
156 SOUND_POOL_ERROR_OUT_OF_MEMORY,
157 "Memory alloc failure. Can't create stream callback manager");
159 _cbmgr->isolator_callback_queue = g_async_queue_new_full(__queue_destroy_item);
161 err = pthread_mutex_init(&_cbmgr->isolator_data_mutex, NULL);
164 SP_ERROR("Error while initialize mutex for isolation thread with error[%d].", err);
165 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
166 GOTO_FAIL("", creturn);
169 _cbmgr->isolator_state_changed = FALSE;
170 _cbmgr->isolator_loop_run = TRUE;
171 _cbmgr->isolator_force_run = FALSE;
173 err = pthread_cond_init(&_cbmgr->isolator_data_cond, NULL);
176 SP_ERROR("Error while initialize condition for isolation thread with error[%d].", err);
177 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
178 GOTO_FAIL("", creturn);
180 err = pthread_cond_init(&_cbmgr->isolator_force_run_cond, NULL);
183 SP_ERROR("Error while initialize condition for isolation thread with error[%d].", err);
184 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
185 GOTO_FAIL("", creturn);
187 err = pthread_create(&_cbmgr->isolator_thread, NULL, &__sound_pool_callback_isolator, (void*)_cbmgr);
190 SP_ERROR("Error while thread creating for isolation thread with error[%d].", err);
191 ret = SOUND_POOL_ERROR_OUT_OF_MEMORY;
192 GOTO_FAIL("", creturn);
196 pool->cbmgr = _cbmgr;
201 return SOUND_POOL_ERROR_NONE;
204 if (_cbmgr->isolator_callback_queue)
205 g_async_queue_unref(_cbmgr->isolator_callback_queue);
206 if (&_cbmgr->isolator_data_mutex)
207 pthread_mutex_destroy(&_cbmgr->isolator_data_mutex);
208 if (&_cbmgr->isolator_data_cond)
209 pthread_cond_destroy(&_cbmgr->isolator_data_cond);
210 SP_SAFE_GFREE(_cbmgr);
216 sound_pool_error_e _stream_cb_manager_destroy(stream_cb_manager_t *cbmgr)
221 SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle callback "
222 "manager, it is NULL.");
223 sound_pool_error_e ret = SOUND_POOL_ERROR_NONE;
225 pthread_t thread = cbmgr->isolator_thread;
227 /* Wait for completing the isolator callback thread events */
228 _stream_cb_manager_process_pending_events(cbmgr);
229 err = pthread_kill(thread, 0);
231 err = pthread_cancel(thread);
233 SP_ERROR("Error while cancelling of isolation thread[%d].", err);
234 ret = SOUND_POOL_ERROR_INVALID_OPERATION;
235 GOTO_FAIL("", creturn);
238 SP_ERROR("Invalid isolation thread[%d].", err);
239 ret = SOUND_POOL_ERROR_INVALID_OPERATION;
240 GOTO_FAIL("", creturn);
243 err = pthread_join(thread, &return_val);
245 SP_ERROR("Error while joining of isolation thread[%d].", err);
246 if (return_val == PTHREAD_CANCELED)
247 SP_INFO("Isolation thread canceled.");
249 ret = SOUND_POOL_ERROR_NONE;
250 GOTO_FAIL("Routine joining of isolation thread.", creturn);
257 g_async_queue_unref(cbmgr->isolator_callback_queue);
258 pthread_mutex_destroy(&cbmgr->isolator_data_mutex);
259 pthread_cond_destroy(&cbmgr->isolator_data_cond);
260 SP_SAFE_GFREE(cbmgr);
265 sound_pool_error_e _stream_cb_manager_register_event(stream_cb_manager_t *cbmgr,
266 sound_stream_t *stream)
269 SP_RETVM_IF(!cbmgr, SOUND_POOL_ERROR_INVALID_PARAMETER,
270 "Can't handle callback manager, it is NULL.");
271 SP_RETVM_IF(!stream, SOUND_POOL_ERROR_INVALID_PARAMETER,
272 "Can't handle stream in callback manager, it is NULL.");
274 stream_cb_manager_event_data_t *event_data = NULL;
275 SP_RETVM_IF(!(event_data = g_try_malloc0(sizeof(stream_cb_manager_event_data_t))),
276 SOUND_POOL_ERROR_OUT_OF_MEMORY,
277 "Memory alloc failure. Can't create stream callback event data structure.");
278 event_data->stream_id = stream->id;
279 event_data->callback = stream->state_cb_info.callback;
280 event_data->user_data = stream->state_cb_info.user_data;
281 event_data->state = stream->state;
282 event_data->state_previous = stream->state_previous;
284 g_async_queue_push(cbmgr->isolator_callback_queue, (gpointer)(event_data));
285 pthread_mutex_lock(&cbmgr->isolator_data_mutex);
286 cbmgr->isolator_state_changed = TRUE;
287 pthread_cond_signal(&cbmgr->isolator_data_cond);
288 pthread_mutex_unlock(&cbmgr->isolator_data_mutex);
291 return SOUND_POOL_ERROR_NONE;