fixed building failure
[platform/core/multimedia/libmm-player.git] / src / mm_player_sound_focus.c
1 /*
2  * libmm-player
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7  * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <dlog.h>
25 #include <mm_error.h>
26 #include "mm_player_utils.h"
27 #include "mm_player_priv.h"
28 #include "mm_player_sound_focus.h"
29
30 #define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \
31 do { \
32         if (!x_player_sound_focus) { \
33                 LOGD("no sound focus instance");\
34                 return MM_ERROR_SOUND_NOT_INITIALIZED; \
35         } \
36 } while (0);
37
38 void __mmplayer_sound_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data)
39 {
40         MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data;
41         MMPLAYER_RETURN_IF_FAIL(sound_focus);
42
43         LOGD("sound signal callback %d / %d", signal, value);
44
45         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS && value == 1)
46                 _mmplayer_sound_unregister(sound_focus);
47 }
48
49 static void
50 __mmplayer_sound_device_connected_cb_func(MMSoundDevice_t device_h, bool is_connected, void *user_data)
51 {
52         mm_player_t* player = (mm_player_t*) user_data;
53         MMPLAYER_RETURN_IF_FAIL(player);
54
55         mm_sound_device_type_e device_type;
56         int ret;
57
58         LOGW("device_connected_cb is called, device_h[0x%x], is_connected[%d]\n", device_h, is_connected);
59
60         /* get device type with device_h*/
61         ret = mm_sound_get_device_type(device_h, &device_type);
62
63         if (!is_connected && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
64                 && (player->sound_focus.focus_id > 0 || player->sound_focus.watch_id > 0)) {
65                 switch (device_type) {
66                 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
67                 case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
68                 case MM_SOUND_DEVICE_TYPE_HDMI:
69                 case MM_SOUND_DEVICE_TYPE_USB_AUDIO:
70                 {
71                         int result = MM_ERROR_NONE;
72                         LOGW("pause immediately");
73
74                         player->sound_focus.by_asm_cb = TRUE;
75                         player->sound_focus.focus_changed_msg = MM_PLAYER_FOCUS_CHANGED_BY_EARJACK_UNPLUG;
76
77                         result = _mmplayer_pause((MMHandleType)player);
78                         if (result != MM_ERROR_NONE) {
79                                 LOGE("focus_id [%d], watch_id [%d], connected_id [%d], change_state result[%d]",
80                                         player->sound_focus.focus_id, player->sound_focus.watch_id,
81                                         player->sound_focus.connected_id, ret);
82                         }
83                         player->sound_focus.by_asm_cb = FALSE;
84                 }
85                 break;
86
87                 default:
88                         LOGD("do nothing");
89                 }
90         }
91 }
92
93 const gchar *
94 __mmplayer_sound_get_stream_type(gint type)
95 {
96         switch (type) {
97         case MM_SESSION_TYPE_CALL:
98         case MM_SESSION_TYPE_VIDEOCALL:
99         case MM_SESSION_TYPE_VOIP:
100                 return "ringtone-voip";
101         case MM_SESSION_TYPE_MEDIA:
102                 return "media";
103         case MM_SESSION_TYPE_NOTIFY:
104                 return "notification";
105         case MM_SESSION_TYPE_ALARM:
106                 return "alarm";
107         case MM_SESSION_TYPE_EMERGENCY:
108                 return "emergency";
109         default:
110                 LOGW("unexpected case!\n");
111                 return "media";
112         }
113 }
114
115 static bool
116 __mmplayer_check_need_block(const char *focus_acquired_by)
117 {
118         if (!focus_acquired_by)
119                 return false;
120
121         if (!strcmp(focus_acquired_by, "alarm") ||
122                 !strcmp(focus_acquired_by, "ringtone-voip") ||
123                 !strcmp(focus_acquired_by, "ringtone-call") ||
124                 !strcmp(focus_acquired_by, "voip") ||
125                 !strcmp(focus_acquired_by, "call-voice") ||
126                 !strcmp(focus_acquired_by, "call-video")) {
127                 LOGW("Blocked by session policy, focus_acquired_by[%s]", focus_acquired_by);
128                 return true;
129         }
130
131         return false;
132 }
133
134 int
135 _mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus)
136 {
137         int ret = MM_ERROR_NONE;
138
139         MMPLAYER_FENTER();
140         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
141
142         if (sound_focus->acquired) {
143                 LOGW("focus is already acquired. can't acquire again.");
144                 return MM_ERROR_NONE;
145         }
146
147         if (_mmplayer_is_using_internal_sound_focus(sound_focus)) {
148                 if (sound_focus->session_type == MM_SESSION_TYPE_MEDIA)
149                         /* option: 1 for no-resume */
150                         ret = mm_sound_acquire_focus_with_option(sound_focus->focus_id, FOCUS_FOR_BOTH, 1, "mm-player acquire focus");
151                 else
152                         ret = mm_sound_acquire_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player acquire focus");
153
154                 if (ret != MM_ERROR_NONE) {
155                         LOGE("failed to acquire sound focus [0x%X]", ret);
156                         return ret;
157                 }
158
159                 sound_focus->acquired = TRUE;
160
161                 ret = mm_sound_update_focus_status(sound_focus->focus_id, 1);
162                 if (ret != MM_ERROR_NONE)
163                         LOGE("failed to update focus status [0x%X]", ret);
164         } else {
165                 if (sound_focus->watch_id > 0) {
166                         char *stream_type = NULL;
167                         char *ext_info = NULL;
168                         int option = 0;
169
170                         ret = mm_sound_get_stream_type_of_acquired_focus(FOCUS_FOR_BOTH, &stream_type, &option, &ext_info);
171                         if (ret == MM_ERROR_NONE) {
172                                 LOGD("Focus is acquired by stream_type[%s], option[%d], ext_info[%s]", stream_type, option, ext_info);
173                                 if (__mmplayer_check_need_block((const char*)stream_type)) {
174                                         LOGE("Blocked by an acquired focus[%s]", stream_type);
175                                         ret = MM_ERROR_POLICY_INTERNAL;
176                                 }
177                         } else {
178                                 LOGW("failed to get stream type of acquired focus [0x%X]", ret);
179                                 if (ret == MM_ERROR_SOUND_NO_DATA) /* there is no acquired focus, it is normal case */
180                                         ret = MM_ERROR_NONE;
181                         }
182
183                         if (stream_type) free(stream_type);
184                         if (ext_info) free(ext_info);
185                 }
186         }
187
188         MMPLAYER_FLEAVE();
189         return ret;
190 }
191
192 int
193 _mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus)
194 {
195         int ret = MM_ERROR_NONE;
196
197         MMPLAYER_FENTER();
198         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
199
200         if (!sound_focus->acquired) {
201                 LOGW("focus is not acquired. no need to release.");
202                 return MM_ERROR_NONE;
203         }
204
205         if (_mmplayer_is_using_internal_sound_focus(sound_focus)) {
206                 if (sound_focus->session_type == MM_SESSION_TYPE_MEDIA)
207                         /* option: 1 for no-resume */
208                         ret = mm_sound_release_focus_with_option(sound_focus->focus_id, FOCUS_FOR_BOTH, 1, "mm-player release focus");
209                 else
210                         ret = mm_sound_release_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player release focus");
211
212                 if (ret != MM_ERROR_NONE) {
213                         LOGE("failed to release sound focus\n");
214                         return ret;
215                 }
216
217                 sound_focus->acquired = FALSE;
218
219                 ret = mm_sound_update_focus_status(sound_focus->focus_id, 0);
220                 if (ret != MM_ERROR_NONE)
221                         LOGE("failed to update focus status\n");
222         }
223
224         MMPLAYER_FLEAVE();
225         return MM_ERROR_NONE;
226 }
227
228 gint
229 _mmplayer_sound_register(MMPlayerSoundFocus* sound_focus,
230                 mm_sound_focus_changed_cb focus_cb, mm_sound_focus_changed_watch_cb watch_cb, void* param)
231 {
232         gint pid = -1;
233         gint ret = MM_ERROR_NONE;
234         const gchar *stream_type = NULL;
235         mm_player_t* player = MM_PLAYER_CAST(param);
236
237         MMPLAYER_FENTER();
238         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
239         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_ARGUMENT);
240
241         /* check if it's running on the media_server */
242         if (sound_focus->pid > 0)
243                 pid = sound_focus->pid;
244         else
245                 return MM_ERROR_INVALID_ARGUMENT;
246
247         LOGD("sound register focus pid[%d]", pid);
248         /* read session information */
249         ret = _mm_session_util_read_information(pid, &sound_focus->session_type, &sound_focus->session_flags);
250         LOGW("Read Session Type -> ret:0x%X \n", ret);
251
252         if (ret == MM_ERROR_INVALID_HANDLE) {
253                 /* case 1. if there is no session */
254                 LOGW("subscribe_id=%d\n", sound_focus->subscribe_id);
255
256                 if (sound_focus->subscribe_id == 0) {
257                         ret = mm_sound_subscribe_signal_for_daemon(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, pid, &sound_focus->subscribe_id,
258                                                                         (mm_sound_signal_callback)__mmplayer_sound_signal_callback, (void*)sound_focus);
259                         if (ret != MM_ERROR_NONE) {
260                                 LOGE("mm_sound_subscribe_signal is failed\n");
261                                 return MM_ERROR_POLICY_BLOCKED;
262                         }
263
264                         LOGD("register focus watch callback for the value is 0, sub_cb id %d\n", sound_focus->subscribe_id);
265                         /* register watch callback */
266                         ret = mm_sound_set_focus_watch_callback_for_session(pid ,
267                                         FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id);
268                         if (ret != MM_ERROR_NONE) {
269                                 LOGE("mm_sound_set_focus_watch_callback is failed\n");
270                                 return MM_ERROR_POLICY_BLOCKED;
271                         }
272                         /* register device connected callback */
273                         ret = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG,
274                                         (mm_sound_device_connected_cb)__mmplayer_sound_device_connected_cb_func, (void*)param, &sound_focus->connected_id);
275                         if (ret != MM_ERROR_NONE) {
276                                 LOGE("mm_sound_add_device_connected_callback is failed\n");
277                                 return MM_ERROR_POLICY_BLOCKED;
278                         }
279                         LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
280                 }
281                 ret = MM_ERROR_NONE;
282         } else if (ret == MM_ERROR_NONE) {
283                 /* case 2. if sessoin exists */
284                 /* in this case, this process is using stream info created by using sound-manager,
285                  * we're going to skip working on backward compatibility of session. */
286                 if (sound_focus->session_type == MM_SESSION_TYPE_REPLACED_BY_STREAM) {
287                         LOGW("this process is using stream info. skip it..");
288                 } else {
289                         /* interpret session information */
290                         stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type);
291                         LOGD("fid [%d] wid [%d] type[%s], flags[0x%02X]\n",
292                                 sound_focus->focus_id, sound_focus->watch_id, stream_type, sound_focus->session_flags);
293
294                         if (sound_focus->focus_id == 0) {
295                                 /* get unique id */
296                                 ret = mm_sound_focus_get_id(&sound_focus->focus_id);
297                                 if (ret != MM_ERROR_NONE) {
298                                         LOGE("failed to get unique focus id\n");
299                                         return MM_ERROR_POLICY_BLOCKED;
300                                 }
301
302                                 /* register sound focus callback */
303                                 ret = mm_sound_register_focus_for_session(sound_focus->focus_id, pid,
304                                                 stream_type, focus_cb, (void*)param);
305                                 if (ret != MM_ERROR_NONE) {
306                                         LOGE("mm_sound_register_focus is failed\n");
307                                         return MM_ERROR_POLICY_BLOCKED;
308                                 }
309                         }
310
311                         if ((sound_focus->watch_id == 0) &&
312                                 (strstr(stream_type, "media")) &&
313                                 !(sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS) &&
314                                 !(sound_focus->session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
315                                 LOGD("register focus watch callback\n");
316                                 /* register watch callback */
317                                 ret = mm_sound_set_focus_watch_callback_for_session(pid,
318                                                 FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id);
319                                 if (ret != MM_ERROR_NONE) {
320                                         LOGE("mm_sound_set_focus_watch_callback is failed\n");
321                                         return MM_ERROR_POLICY_BLOCKED;
322                                 }
323                         }
324
325                         if ((strstr(stream_type, "media")) && (sound_focus->connected_id == 0)) {
326                                 /* register device connected callback */
327                                 ret = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG,
328                                                 (mm_sound_device_connected_cb)__mmplayer_sound_device_connected_cb_func, (void*)param, &sound_focus->connected_id);
329                                 if (ret != MM_ERROR_NONE) {
330                                         LOGE("mm_sound_add_device_connected_callback is failed\n");
331                                         return MM_ERROR_POLICY_BLOCKED;
332                                 }
333                                 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
334                         }
335
336                         ret = mm_player_set_attribute(player, NULL, "sound_stream_type", stream_type, strlen(stream_type), (char *)NULL);
337                         if (ret != MM_ERROR_NONE) {
338                                 LOGE("mm_player_set_attribute for sound_stream_type is failed\n");
339                                 return ret;
340                         }
341                 }
342                 ret = MM_ERROR_NONE;
343         } else {
344                 LOGE("_mm_session_util_read_information is failed");
345                 ret =  MM_ERROR_POLICY_BLOCKED;
346         }
347
348         MMPLAYER_FLEAVE();
349         return ret;
350 }
351
352 gint
353 _mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus)
354 {
355         int ret = MM_ERROR_NONE;
356
357         MMPLAYER_FENTER();
358
359         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
360         MMPLAYER_SOUND_FOCUS_LOCK(sound_focus);
361
362         LOGD("unregister sound focus callback\n");
363
364         if (sound_focus->focus_id > 0) {
365                 ret = mm_sound_unregister_focus(sound_focus->focus_id);
366                 if (ret != MM_ERROR_NONE)
367                         LOGE("failed to mm_sound_unregister_focus() %d", sound_focus->focus_id);
368                 sound_focus->focus_id = 0;
369         }
370
371         if (sound_focus->watch_id > 0) {
372                 ret = mm_sound_unset_focus_watch_callback(sound_focus->watch_id);
373                 if (ret != MM_ERROR_NONE)
374                         LOGE("failed to mm_sound_unset_focus_watch_callback() %d", sound_focus->watch_id);
375                 sound_focus->watch_id = 0;
376         }
377
378         if (sound_focus->subscribe_id > 0) {
379                 mm_sound_unsubscribe_signal(sound_focus->subscribe_id);
380                 sound_focus->subscribe_id = 0;
381         }
382         if (sound_focus->connected_id > 0) {
383                 ret = mm_sound_remove_device_connected_callback(sound_focus->connected_id);
384                 if (ret != MM_ERROR_NONE)
385                         LOGE("failed to mm_sound_remove_device_connected_callback() %d", sound_focus->connected_id);
386                 sound_focus->connected_id = 0;
387         }
388
389         MMPLAYER_SOUND_FOCUS_UNLOCK(sound_focus);
390         MMPLAYER_FLEAVE();
391
392         return MM_ERROR_NONE;
393 }
394
395 bool _mmplayer_is_using_internal_sound_focus(MMPlayerSoundFocus* sound_focus)
396 {
397         MMPLAYER_RETURN_VAL_IF_FAIL(sound_focus, false);
398
399         /* Perhaps, already got release signal or application may use stream focus directly */
400         if (sound_focus->focus_id == 0)
401                 return false;
402
403         if ((sound_focus->session_type == MM_SESSION_TYPE_MEDIA && sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS) ||
404                 (sound_focus->session_type == MM_SESSION_TYPE_NOTIFY) ||
405                 (sound_focus->session_type == MM_SESSION_TYPE_ALARM) ||
406                 (sound_focus->session_type == MM_SESSION_TYPE_EMERGENCY))
407                 return true;
408         else
409                 return false;
410 }