Fix for coding rule
[platform/core/api/sound-pool.git] / src / priority.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 priority.c
19  * @brief This file include implementation of prioritization of streams in the
20  * SoundPool.
21  */
22
23 #include "internal/priority.h"
24 #include "internal/stream_cb_manager.h"
25
26 static gint __sound_stream_priority_cmp(gconstpointer a, gconstpointer b);
27
28 static gint __sound_stream_priority_cmp(gconstpointer a, gconstpointer b)
29 {
30         SP_DEBUG_FENTER();
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;
35
36         SP_DEBUG_FLEAVE();
37         if (stream_a->priority != stream_b->priority)
38                 return (stream_b->priority - stream_a->priority);
39         return (stream_a->id - stream_b->id);
40 }
41
42 sound_pool_error_e _sound_stream_priority_create(sound_pool_t *pool,
43                 stream_priority_manager_t **mgr)
44 {
45         SP_DEBUG_FENTER();
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");
50
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.");
55
56         _mgr->priority_queue = NULL;
57         _mgr->pool = pool;
58         pool->mgr_priority = _mgr;
59
60         *mgr = _mgr;
61
62         SP_DEBUG_FLEAVE();
63         return SOUND_POOL_ERROR_NONE;
64 }
65
66 sound_pool_error_e _sound_stream_priority_destroy(stream_priority_manager_t *mgr)
67 {
68         SP_DEBUG_FENTER();
69         SP_RETVM_IF(!mgr, SOUND_POOL_ERROR_INVALID_PARAMETER, "Can't handle priority "
70                         "manager, it is NULL.");
71
72         if (mgr->priority_queue) {
73                 g_list_free(mgr->priority_queue);
74                 mgr->priority_queue = NULL;
75         }
76
77         mgr->pool = NULL;
78
79         SP_SAFE_GFREE(mgr);
80
81         SP_DEBUG_FLEAVE();
82         return SOUND_POOL_ERROR_NONE;
83 }
84
85 sound_pool_error_e _sound_stream_priority_add_stream(
86                 stream_priority_manager_t *mgr, sound_stream_t *stream)
87 {
88         SP_DEBUG_FENTER();
89         SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
90         SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
91
92         mgr->priority_queue = g_list_append(mgr->priority_queue, (gpointer)stream);
93         _sound_stream_priority_update_playback(mgr);
94
95         SP_DEBUG_FLEAVE();
96         return SOUND_POOL_ERROR_NONE;
97 }
98
99 sound_pool_error_e _sound_stream_priority_remove_stream(
100                 stream_priority_manager_t *mgr, sound_stream_t *stream)
101 {
102         SP_DEBUG_FENTER();
103         SP_INST_CHECK(mgr, SOUND_POOL_ERROR_INVALID_PARAMETER);
104         SP_INST_CHECK(stream, SOUND_POOL_ERROR_INVALID_PARAMETER);
105
106         GList* to_delete;
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.",
110                         stream->id);
111
112         mgr->priority_queue = g_list_delete_link(mgr->priority_queue, to_delete);
113         _sound_stream_priority_update_playback(mgr);
114
115         SP_DEBUG_FLEAVE();
116         return SOUND_POOL_ERROR_NONE;
117 }
118
119 /*
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.
124 */
125 sound_pool_error_e _sound_stream_priority_check(stream_priority_manager_t *mgr,
126                 sound_stream_t *stream, gboolean *out)
127 {
128         SP_DEBUG_FENTER();
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);
140         *out = FALSE;
141
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;
146
147         if (rank == stream->priority) {
148                 *out = TRUE;
149         } else {
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;
156                                         continue;
157                                 }
158                                 rank = ref_stream->priority;
159                                 ref_stream = str;
160                         }
161
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;
166                         }
167                 }
168
169                 if (rank == stream->priority)
170                         *out = TRUE;
171         }
172
173         SP_DEBUG_FLEAVE();
174         return SOUND_POOL_ERROR_NONE;
175 }
176
177 void _sound_stream_priority_update_playback(stream_priority_manager_t *mgr)
178 {
179         SP_DEBUG_FENTER();
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;
184
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.");
188                 return;
189         }
190
191         mgr->priority_queue = g_list_sort(mgr->priority_queue,
192                         __sound_stream_priority_cmp);
193
194         GList *iter = mgr->priority_queue;
195         for (; iter != NULL; iter = iter->next) {
196                 sound_stream_t *stream = (sound_stream_t *)iter->data;
197
198                 if (SOUND_POOL_ERROR_NONE != _sound_stream_priority_check(mgr, stream,
199                                 &can_run))
200                         continue;
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");
213                 }
214         }
215
216         SP_DEBUG_FLEAVE();
217 }