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 prioritization of streams in the
23 #include "internal/priority.h"
24 #include "internal/stream_cb_manager.h"
26 static gint __sound_stream_priority_cmp(gconstpointer a, gconstpointer b);
28 static gint __sound_stream_priority_cmp(gconstpointer a, gconstpointer b)
31 SP_RETVM_IF(!a, 0, "Firs pointer is NULL.");
32 SP_RETVM_IF(!b, 0, "Second pointer is NULL.");
33 sound_stream_t *stream_a = (sound_stream_t *)a;
34 sound_stream_t *stream_b = (sound_stream_t *)b;
37 if (stream_a->priority != stream_b->priority)
38 return (stream_b->priority - stream_a->priority);
39 return (stream_a->id - stream_b->id);
42 sound_pool_error_e _sound_stream_priority_create(sound_pool_t *pool,
43 stream_priority_manager_t **mgr)
46 SP_RETVM_IF(!pool, SOUND_POOL_ERROR_INVALID_PARAMETER, "Stream priority "
47 "manager can't be created for NULL sound pool");
48 SP_RETVM_IF(!mgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't create "
49 "stream priority manager. Manager pointer is NULL");
51 stream_priority_manager_t *_mgr = NULL;
52 SP_RETVM_IF(!(_mgr = g_try_malloc0(sizeof(*_mgr))),
53 SOUND_POOL_ERROR_OUT_OF_MEMORY,
54 "Memory alloc failure. Can't create stream priority manager.");
56 _mgr->priority_queue = NULL;
58 pool->mgr_priority = _mgr;
63 return SOUND_POOL_ERROR_NONE;
66 sound_pool_error_e _sound_stream_priority_destroy(stream_priority_manager_t *mgr)
69 SP_RETVM_IF(!mgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle priority "
70 "manager, it is NULL.");
72 if (mgr->priority_queue) {
73 g_list_free(mgr->priority_queue);
74 mgr->priority_queue = NULL;
82 return SOUND_POOL_ERROR_NONE;
85 sound_pool_error_e _sound_stream_priority_add_stream(
86 stream_priority_manager_t *mgr, sound_stream_t *stream)
89 SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
90 SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
92 mgr->priority_queue = g_list_append(mgr->priority_queue, (gpointer)stream);
93 _sound_stream_priority_update_playback(mgr);
96 return SOUND_POOL_ERROR_NONE;
99 sound_pool_error_e _sound_stream_priority_remove_stream(
100 stream_priority_manager_t *mgr, sound_stream_t *stream)
103 SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
104 SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
107 to_delete = g_list_find(mgr->priority_queue, (gpointer)stream);
108 SP_RETVM_IF(NULL == to_delete, SOUND_POOL_ERROR_INVALID_PARAMETER,
109 "Can't find to deleting link to stream [id:%d] from priority queue.",
111 mgr->priority_queue = g_list_delete_link(mgr->priority_queue, to_delete);
112 _sound_stream_priority_update_playback(mgr);
115 return SOUND_POOL_ERROR_NONE;
119 * Checks selected stream for availability of playing. It depends
120 * on its position in priority queue and current state of other streams.
121 * The queue is analyzed downwards to lower priorities skipping all paused
122 * streams until first suspended stream is found.
124 sound_pool_error_e _sound_stream_priority_check(stream_priority_manager_t *mgr,
125 sound_stream_t *stream, gboolean *out)
128 SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
129 SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
130 SP_INST_CHECK(out, SOUND_POOL_ERROR_INVALID_PARAMETER);
131 SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
132 SP_INST_CHECK(mgr->pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
133 SP_INST_CHECK(mgr->pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
134 SP_INST_CHECK(g_hash_table_lookup(mgr->pool->sources,
135 stream->parent_source->tag_name), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE);
136 SP_RETVM_IF(NULL == mgr->priority_queue, SOUND_POOL_ERROR_INVALID_PARAMETER,
137 "Can't perform checking stream [%s] due to priority queue is NULL.",
138 stream->parent_source->tag_name);
141 sound_stream_t *ref_stream = (sound_stream_t*)(mgr->priority_queue->data);
142 gboolean flag_target_priority = FALSE;
143 gboolean flag_terminator = FALSE;
144 unsigned rank = ref_stream->priority;
146 if (rank == stream->priority) {
149 GList *iter = mgr->priority_queue;
150 for (; iter != NULL && !flag_terminator; iter = iter->next) {
151 sound_stream_t *str = (sound_stream_t *)iter->data;
152 if ((ref_stream->priority > str->priority)) {
153 if (flag_target_priority) {
154 flag_terminator = TRUE;
157 rank = ref_stream->priority;
161 if (SOUND_POOL_STREAM_STATE_PLAYING == str->state ||
162 SOUND_POOL_STREAM_STATE_SUSPENDED == str->state) {
163 rank = str->priority;
164 flag_target_priority = TRUE;
168 if (rank == stream->priority)
173 return SOUND_POOL_ERROR_NONE;
176 void _sound_stream_priority_update_playback(stream_priority_manager_t *mgr)
179 SP_RETM_IF(!mgr, "Priority manager pointer is NULL.");
180 SP_RETM_IF(!mgr->pool, "Pool pointer is NULL.");
181 SP_RETM_IF(!mgr->pool->cbmgr, "Callback manager pointer is NULL.");
182 gboolean can_run = FALSE;
184 if (mgr->pool->state == SOUND_POOL_STATE_INACTIVE) {
185 SP_INFO("No need to update streams state based on priority, "
186 "because of Sound pool is INACTIVE.");
190 mgr->priority_queue = g_list_sort(mgr->priority_queue,
191 __sound_stream_priority_cmp);
193 GList *iter = mgr->priority_queue;
194 for (; iter != NULL; iter = iter->next) {
195 sound_stream_t *stream = (sound_stream_t *)iter->data;
197 if (SOUND_POOL_ERROR_NONE != _sound_stream_priority_check(mgr, stream,
202 switch (stream->state) {
203 case SOUND_POOL_STREAM_STATE_PLAYING:
204 if (SOUND_POOL_STREAM_PRIORITY_POLICY_MUTE == stream->priority_policy && stream->mute) {
205 SP_INFO("stream[%d] with priority[%d] was Playing with mute, now unmute",
206 stream->id, stream->priority);
207 _sound_stream_set_mute(stream, FALSE);
210 case SOUND_POOL_STREAM_STATE_NONE:
211 case SOUND_POOL_STREAM_STATE_SUSPENDED:
212 SP_INFO("stream[%d] with priority[%d] was Suspended(pool deactivate) or initial created, now play",
213 stream->id, stream->priority);
214 _sound_stream_play(stream);
219 } else { /* Can't run */
220 if (SOUND_POOL_STREAM_PRIORITY_POLICY_MUTE == stream->priority_policy) {
222 switch (stream->state) {
223 case SOUND_POOL_STREAM_STATE_PLAYING:
225 SP_INFO("stream[%d] with priority[%d] was Playing, now mute",
226 stream->id, stream->priority);
227 _sound_stream_set_mute(stream, TRUE);
230 case SOUND_POOL_STREAM_STATE_NONE:
231 case SOUND_POOL_STREAM_STATE_SUSPENDED:
232 SP_INFO("stream[%d] with priority[%d] was Suspended(pool deactivate) or initial created, now play with mute",
233 stream->id, stream->priority);
234 _sound_stream_set_mute(stream, TRUE);
235 _sound_stream_play(stream);
242 /* suspended policy */
243 switch (stream->state) {
244 case SOUND_POOL_STREAM_STATE_PLAYING:
245 SP_INFO("stream[%d] with priority[%d] was Playing, now Suspend",
246 stream->id, stream->priority);
247 _sound_stream_suspend(stream);
249 case SOUND_POOL_STREAM_STATE_NONE:
250 /* This case handles newly created streams in active pool, but with
251 too low priority for transition to playing state: */
252 _sound_stream_send_event(stream, SOUND_POOL_STREAM_STATE_SUSPENDED);