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.",
112 mgr->priority_queue = g_list_delete_link(mgr->priority_queue, to_delete);
113 _sound_stream_priority_update_playback(mgr);
116 return SOUND_POOL_ERROR_NONE;
120 * Checks selected stream for availability of playing. It depends
121 * on its position in priority queue and current state of other streams.
122 * The queue is analyzed downwards to lower priorities skipping all paused
123 * streams until first suspended stream is found.
125 sound_pool_error_e _sound_stream_priority_check(stream_priority_manager_t *mgr,
126 sound_stream_t *stream, gboolean *out)
129 SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
130 SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
131 SP_INST_CHECK(out, SOUND_POOL_ERROR_INVALID_PARAMETER);
132 SP_INST_CHECK(stream->parent_source, SOUND_POOL_ERROR_INVALID_PARAMETER);
133 SP_INST_CHECK(mgr->pool, SOUND_POOL_ERROR_INVALID_PARAMETER);
134 SP_INST_CHECK(mgr->pool->sources, SOUND_POOL_ERROR_INVALID_PARAMETER);
135 SP_INST_CHECK(g_hash_table_lookup(mgr->pool->sources,
136 stream->parent_source->tag_name), SOUND_POOL_ERROR_KEY_NOT_AVAILABLE);
137 SP_RETVM_IF(NULL == mgr->priority_queue, SOUND_POOL_ERROR_INVALID_PARAMETER,
138 "Can't perform checking stream [%s] due to priority queue is NULL.",
139 stream->parent_source->tag_name);
142 sound_stream_t *ref_stream = (sound_stream_t*)(mgr->priority_queue->data);
143 gboolean flag_target_priority = FALSE;
144 gboolean flag_terminator = FALSE;
145 unsigned rank = ref_stream->priority;
147 if (rank == stream->priority) {
150 GList *iter = mgr->priority_queue;
151 for (; iter != NULL && !flag_terminator; iter = iter->next) {
152 sound_stream_t *str = (sound_stream_t *)iter->data;
153 if ((ref_stream->priority > str->priority)) {
154 if (flag_target_priority) {
155 flag_terminator = TRUE;
158 rank = ref_stream->priority;
162 if (SOUND_POOL_STREAM_STATE_PLAYING == str->state ||
163 SOUND_POOL_STREAM_STATE_SUSPENDED == str->state) {
164 rank = str->priority;
165 flag_target_priority = TRUE;
169 if (rank == stream->priority)
174 return SOUND_POOL_ERROR_NONE;
177 void _sound_stream_priority_update_playback(stream_priority_manager_t *mgr)
180 SP_RETM_IF(!mgr, "Priority manager pointer is NULL.");
181 SP_RETM_IF(!mgr->pool, "Pool pointer is NULL.");
182 SP_RETM_IF(!mgr->pool->cbmgr, "Callback manager pointer is NULL.");
183 gboolean can_run = FALSE;
185 if (mgr->pool->state == SOUND_POOL_STATE_INACTIVE) {
186 SP_INFO("No need to update streams state based on priority, "
187 "because of Sound pool is INACTIVE.");
191 mgr->priority_queue = g_list_sort(mgr->priority_queue,
192 __sound_stream_priority_cmp);
194 GList *iter = mgr->priority_queue;
195 for (; iter != NULL; iter = iter->next) {
196 sound_stream_t *stream = (sound_stream_t *)iter->data;
198 if (SOUND_POOL_ERROR_NONE != _sound_stream_priority_check(mgr, stream,
201 if (TRUE == can_run) {
202 if (SOUND_POOL_STREAM_STATE_PLAYING != stream->state &&
203 SOUND_POOL_STREAM_STATE_PAUSED != stream->state)
204 _sound_stream_play(stream);
205 } else if (SOUND_POOL_STREAM_STATE_PLAYING == stream->state) {
206 _sound_stream_pause(stream);
207 stream->state_previous = stream->state;
208 stream->state = SOUND_POOL_STREAM_STATE_SUSPENDED;
209 if (_stream_cb_manager_register_event(mgr->pool->cbmgr, stream) !=
210 SOUND_POOL_ERROR_NONE)
211 SP_DEBUG("State changing event wasn't registered."
212 "Callbacks will be not called");