Manage focus cb thread and focus watch cb thread separately
[platform/core/multimedia/libmm-sound.git] / mm_sound_focus.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <mm_debug.h>
25
26 #include "include/mm_sound.h"
27 #include "include/mm_sound_client.h"
28
29 #define RETURN_ERROR_IF_FOCUS_CB_THREAD(x_thread) \
30 { \
31         int ret = MM_ERROR_NONE; \
32         bool result = false; \
33         ret = mm_sound_client_is_focus_cb_thread(x_thread, &result, NULL); \
34         if (ret) \
35                 return ret; \
36         if (result) { \
37                 debug_error("it might be called in the thread of focus callback, it is not allowed"); \
38                 return MM_ERROR_SOUND_INVALID_OPERATION; \
39         } \
40 } \
41
42 EXPORT_API
43 int mm_sound_focus_is_cb_thread(bool *result, bool *is_for_watching)
44 {
45         int ret = MM_ERROR_NONE;
46
47         debug_fenter();
48
49         if (result == NULL) {
50                 debug_error("argument is not valid");
51                 return MM_ERROR_INVALID_ARGUMENT;
52         }
53
54         ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), result, is_for_watching);
55         if (!ret) {
56                 if (*result)
57                         debug_msg("it might be called in the thread of focus callback");
58                 if (is_for_watching && *is_for_watching)
59                         debug_msg("it's in the focus watch callback");
60         }
61
62         debug_fleave();
63
64         return ret;
65 }
66
67 EXPORT_API
68 int mm_sound_register_focus(const char *stream_type, mm_sound_focus_changed_cb callback, void *user_data, int *id)
69 {
70         int ret = MM_ERROR_NONE;
71
72         debug_fenter();
73
74         RETURN_ERROR_IF_FOCUS_CB_THREAD(g_thread_self());
75
76         if (id == NULL || callback == NULL) {
77                 debug_error("argument is not valid");
78                 return MM_ERROR_INVALID_ARGUMENT;
79         }
80
81         ret = mm_sound_client_register_focus(getpid(), stream_type, callback, user_data, id);
82         if (ret)
83                 debug_error("Could not register focus, ret[0x%x]", ret);
84
85         debug_fleave();
86
87         return ret;
88 }
89
90 EXPORT_API
91 int mm_sound_unregister_focus(int id)
92 {
93         int ret = MM_ERROR_NONE;
94         bool result = false;
95
96         debug_fenter();
97
98         if (id <= 0) {
99                 debug_error("argument is not valid");
100                 return MM_ERROR_INVALID_ARGUMENT;
101         }
102
103         mm_sound_client_is_focus_cb_thread(g_thread_self(), &result, NULL);
104         if (!result) {
105                 if ((ret = mm_sound_client_unregister_focus(id)))
106                         debug_error("Could not unregister focus, ret = %x", ret);
107         } else {
108                 ret = mm_sound_client_execute_focus_func_in_main_context(IDLE_EVENT_TYPE_UNREGISTER_FOCUS, id);
109         }
110
111         debug_fleave();
112
113         return ret;
114 }
115
116 EXPORT_API
117 int mm_sound_set_focus_reacquisition(int id, bool reacquisition)
118 {
119         int ret = MM_ERROR_NONE;
120
121         debug_fenter();
122
123         if (id < 0) {
124                 debug_error("argument is not valid");
125                 return MM_ERROR_INVALID_ARGUMENT;
126         }
127
128         if ((ret = mm_sound_client_set_focus_reacquisition(id, reacquisition)))
129                 debug_error("Could not set focus reacquisition, ret[0x%x]", ret);
130
131         debug_fleave();
132
133         return ret;
134 }
135
136 EXPORT_API
137 int mm_sound_get_focus_reacquisition(int id, bool *reacquisition)
138 {
139         int ret = MM_ERROR_NONE;
140
141         debug_fenter();
142
143         if (id < 0 || !reacquisition) {
144                 debug_error("argument is not valid");
145                 return MM_ERROR_INVALID_ARGUMENT;
146         }
147
148         ret = mm_sound_client_get_focus_reacquisition(id, reacquisition);
149         if (ret)
150                 debug_error("Could not get focus reacquisition, ret[0x%x]", ret);
151
152         debug_fleave();
153
154         return ret;
155 }
156
157 EXPORT_API
158 int mm_sound_get_stream_type_of_acquired_focus(int focus_type, char **stream_type, int *option, char **ext_info)
159 {
160         int ret = MM_ERROR_NONE;
161
162         debug_fenter();
163
164         if (stream_type == NULL) {
165                 debug_error("argument is not valid");
166                 return MM_ERROR_INVALID_ARGUMENT;
167         }
168
169         ret = mm_sound_client_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
170         if (ret)
171                 debug_error("Could not get acquired focus stream type, ret[0x%x]", ret);
172
173         debug_fleave();
174
175         return ret;
176 }
177
178 EXPORT_API
179 int mm_sound_acquire_focus(int id, mm_sound_focus_type_e focus_type, const char *ext_info)
180 {
181         int ret = MM_ERROR_NONE;
182
183         debug_fenter();
184
185         RETURN_ERROR_IF_FOCUS_CB_THREAD(g_thread_self());
186
187         if (id < 0) {
188                 debug_error("argument is not valid");
189                 return MM_ERROR_INVALID_ARGUMENT;
190         }
191         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
192                 debug_error("argument is not valid");
193                 return MM_ERROR_INVALID_ARGUMENT;
194         }
195
196         ret = mm_sound_client_acquire_focus(id, focus_type, 0, ext_info);
197         if (ret)
198                 debug_error("Could not acquire focus, ret[0x%x]", ret);
199
200         debug_fleave();
201
202         return ret;
203 }
204
205 EXPORT_API
206 int mm_sound_release_focus(int id, mm_sound_focus_type_e focus_type, const char *ext_info)
207 {
208         int ret = MM_ERROR_NONE;
209
210         debug_fenter();
211
212         RETURN_ERROR_IF_FOCUS_CB_THREAD(g_thread_self());
213
214         if (id < 0) {
215                 debug_error("argument is not valid");
216                 return MM_ERROR_INVALID_ARGUMENT;
217         }
218         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
219                 debug_error("argument is not valid");
220                 return MM_ERROR_INVALID_ARGUMENT;
221         }
222
223         ret = mm_sound_client_release_focus(id, focus_type, 0, ext_info);
224         if (ret)
225                 debug_error("Could not release focus, ret[0x%x]", ret);
226
227         debug_fleave();
228
229         return ret;
230 }
231
232 EXPORT_API
233 int mm_sound_acquire_focus_with_option(int id, mm_sound_focus_type_e focus_type, int option, const char *ext_info)
234 {
235         int ret = MM_ERROR_NONE;
236
237         debug_fenter();
238
239         if (id < 0) {
240                 debug_error("id is not valid");
241                 return MM_ERROR_INVALID_ARGUMENT;
242         }
243
244         if (option < 0) {
245                 debug_error("option is not valid");
246                 return MM_ERROR_INVALID_ARGUMENT;
247         }
248
249         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
250                 debug_error("focus type is not valid");
251                 return MM_ERROR_INVALID_ARGUMENT;
252         }
253
254         ret = mm_sound_client_acquire_focus(id, focus_type, option, ext_info);
255         if (ret)
256                 debug_error("Could not acquire focus, ret[0x%x]", ret);
257
258         debug_fleave();
259
260         return ret;
261 }
262
263 EXPORT_API
264 int mm_sound_release_focus_with_option(int id, mm_sound_focus_type_e focus_type, int option, const char *ext_info)
265 {
266         int ret = MM_ERROR_NONE;
267
268         debug_fenter();
269
270         if (id < 0) {
271                 debug_error("id is not valid");
272                 return MM_ERROR_INVALID_ARGUMENT;
273         }
274
275         if (option < 0) {
276                 debug_error("option is not valid");
277                 return MM_ERROR_INVALID_ARGUMENT;
278         }
279
280         if (focus_type < FOCUS_FOR_PLAYBACK || focus_type > FOCUS_FOR_BOTH) {
281                 debug_error("focus type is not valid");
282                 return MM_ERROR_INVALID_ARGUMENT;
283         }
284
285         ret = mm_sound_client_release_focus(id, focus_type, option, ext_info);
286         if (ret)
287                 debug_error("Could not release focus, ret[0x%x]", ret);
288
289         debug_fleave();
290
291         return ret;
292 }
293
294 EXPORT_API
295 int mm_sound_update_focus_status(int id, unsigned int status)
296 {
297         int ret = MM_ERROR_NONE;
298
299         if ((ret = mm_sound_client_update_stream_focus_status(id, status)))
300                 debug_error("failed to mm_sound_client_update_stream_focus_status(), id(%d), status(%d, ret[0x%x]",
301                                         id, status, ret);
302
303         return ret;
304 }
305
306 EXPORT_API
307 int mm_sound_deliver_focus(int src_id, int dst_id, mm_sound_focus_type_e focus_type)
308 {
309         int ret = MM_ERROR_NONE;
310
311         if ((ret = mm_sound_client_deliver_focus(src_id, dst_id, focus_type)))
312                 debug_error("failed to mm_sound_client_deliver_focus(), ret[0x%x]", ret);
313
314         return ret;
315 }
316
317 EXPORT_API
318 int mm_sound_set_focus_watch_callback(mm_sound_focus_type_e focus_type, mm_sound_focus_changed_watch_cb callback, void *user_data, int *id)
319 {
320         int ret = MM_ERROR_NONE;
321
322         debug_fenter();
323
324         RETURN_ERROR_IF_FOCUS_CB_THREAD(g_thread_self());
325
326         if (callback == NULL || id == NULL) {
327                 debug_error("argument is not valid");
328                 return MM_ERROR_INVALID_ARGUMENT;
329         }
330         ret = mm_sound_client_set_focus_watch_callback(getpid(), focus_type, callback, user_data, id);
331         if (ret)
332                 debug_error("Could not set focus watch callback, ret[0x%x]", ret);
333
334         debug_fleave();
335
336         return ret;
337 }
338
339 EXPORT_API
340 int mm_sound_unset_focus_watch_callback(int id)
341 {
342         int ret = MM_ERROR_NONE;
343         bool result = false;
344
345         debug_fenter();
346
347         if (id < 0) {
348                 debug_error("argument is not valid");
349                 return MM_ERROR_INVALID_ARGUMENT;
350         }
351
352         if ((ret = mm_sound_client_request_unset_focus_watch_callback(id))) {
353                 debug_error("failed to mm_sound_client_request_unset_focus_watch_callback, ret[0x%x]", ret);
354                 return ret;
355         }
356
357         mm_sound_client_is_focus_cb_thread(g_thread_self(), &result, NULL);
358         if (!result) {
359                 if ((ret = mm_sound_client_unset_focus_watch_callback(id)))
360                         debug_error("Could not unset focus watch callback, id(%d), ret[0x%x]", id, ret);
361         } else {
362                 ret = mm_sound_client_execute_focus_func_in_main_context(IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB, id);
363                 debug_msg("mm_sound_client_execute_focus_func_in_main_context() is called, id(%d), ret[0x%x]", id, ret);
364         }
365
366         debug_fleave();
367
368         return ret;
369 }