[0.6.37] do not set acquired flag to true in case of focus callback for resumption
[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 <vconf.h>
27 #include <vconf-internal-sound-keys.h>
28
29 #include "mm_player_utils.h"
30 #include "mm_player_priv.h"
31 #include "mm_player_sound_focus.h"
32
33 #define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \
34 do { \
35         if (!x_player_sound_focus) { \
36                 LOGD("no sound focus instance");\
37                 return MM_ERROR_SOUND_NOT_INITIALIZED; \
38         } \
39 } while (0);
40
41 void __mmplayer_sound_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data)
42 {
43         MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data;
44         MMPLAYER_RETURN_IF_FAIL(sound_focus);
45
46         LOGD("sound signal callback %d / %d", signal, value);
47
48         if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS && value == 1)
49                 _mmplayer_sound_unregister(sound_focus);
50 }
51
52 static void
53 __mmplayer_sound_device_connected_cb_func(MMSoundDevice_t device_h, bool is_connected, void *user_data)
54 {
55         mm_player_t* player = (mm_player_t*) user_data;
56         MMPLAYER_RETURN_IF_FAIL(player);
57
58         mm_sound_device_type_e device_type;
59         int ret;
60
61         LOGW("device_connected_cb is called, device_h[0x%x], is_connected[%d]\n", device_h, is_connected);
62
63         /* get device type with device_h*/
64         ret = mm_sound_get_device_type(device_h, &device_type);
65
66         if (!is_connected && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
67                 && (player->sound_focus.focus_id > 0 || player->sound_focus.watch_id > 0)) {
68                 switch (device_type) {
69                 case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
70                 case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
71                 case MM_SOUND_DEVICE_TYPE_HDMI:
72                 case MM_SOUND_DEVICE_TYPE_USB_AUDIO:
73                 {
74                         int result = MM_ERROR_NONE;
75                         LOGW("pause immediately");
76
77                         player->sound_focus.by_asm_cb = TRUE;
78                         player->sound_focus.focus_changed_msg = MM_PLAYER_FOCUS_CHANGED_BY_EARJACK_UNPLUG;
79
80                         result = _mmplayer_pause((MMHandleType)player);
81                         if (result != MM_ERROR_NONE) {
82                                 LOGE("focus_id [%d], watch_id [%d], connected_id [%d], change_state result[%d]",
83                                         player->sound_focus.focus_id, player->sound_focus.watch_id,
84                                         player->sound_focus.connected_id, ret);
85                         }
86                         player->sound_focus.by_asm_cb = FALSE;
87                 }
88                 break;
89
90                 default:
91                         LOGD("do nothing");
92                 }
93         }
94 }
95
96 const gchar *
97 __mmplayer_sound_get_stream_type(gint type)
98 {
99         switch (type) {
100         case MM_SESSION_TYPE_CALL:
101         case MM_SESSION_TYPE_VIDEOCALL:
102         case MM_SESSION_TYPE_VOIP:
103                 return "ringtone-voip";
104         case MM_SESSION_TYPE_MEDIA:
105                 return "media";
106         case MM_SESSION_TYPE_NOTIFY:
107                 return "notification";
108         case MM_SESSION_TYPE_ALARM:
109                 return "alarm";
110         case MM_SESSION_TYPE_EMERGENCY:
111                 return "emergency";
112         default:
113                 LOGW("unexpected case!\n");
114                 return "media";
115         }
116
117         return "media";
118 }
119
120 int
121 _mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus)
122 {
123         int ret = MM_ERROR_NONE;
124
125         MMPLAYER_FENTER();
126         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
127
128         if (sound_focus->acquired) {
129                 LOGW("focus is already acquired. can't acquire again.");
130                 return MM_ERROR_NONE;
131         }
132
133         if (_mmplayer_is_using_internal_sound_focus(sound_focus)) {
134
135                 ret = mm_sound_acquire_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player acquire focus");
136                 if (ret != MM_ERROR_NONE) {
137                         LOGE("failed to acquire sound focus\n");
138                         return ret;
139                 }
140
141                 sound_focus->acquired = TRUE;
142
143                 ret = mm_sound_update_focus_status(sound_focus->focus_id, 1);
144                 if (ret != MM_ERROR_NONE)
145                         LOGE("failed to update focus status\n");
146         }
147
148         MMPLAYER_FLEAVE();
149         return ret;
150 }
151
152 int
153 _mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus)
154 {
155         int ret = MM_ERROR_NONE;
156
157         MMPLAYER_FENTER();
158         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
159
160         if (!sound_focus->acquired) {
161                 LOGW("focus is not acquired. no need to release.");
162                 return MM_ERROR_NONE;
163         }
164
165         if (_mmplayer_is_using_internal_sound_focus(sound_focus)) {
166                 ret = mm_sound_release_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player release focus");
167                 if (ret != MM_ERROR_NONE) {
168                         LOGE("failed to release sound focus\n");
169                         return ret;
170                 }
171
172                 sound_focus->acquired = FALSE;
173
174                 ret = mm_sound_update_focus_status(sound_focus->focus_id, 0);
175                 if (ret != MM_ERROR_NONE)
176                         LOGE("failed to update focus status\n");
177         }
178
179         MMPLAYER_FLEAVE();
180         return MM_ERROR_NONE;
181 }
182
183 gint
184 _mmplayer_sound_register(MMPlayerSoundFocus* sound_focus,
185                 mm_sound_focus_changed_cb focus_cb, mm_sound_focus_changed_watch_cb watch_cb, void* param)
186 {
187         gint pid = -1;
188         gint ret = MM_ERROR_NONE;
189         const gchar *stream_type = NULL;
190         mm_player_t* player = MM_PLAYER_CAST(param);
191
192         MMPLAYER_FENTER();
193         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
194         MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_ARGUMENT);
195
196         /* check if it's running on the media_server */
197         if (sound_focus->pid > 0)
198                 pid = sound_focus->pid;
199         else
200                 return MM_ERROR_INVALID_ARGUMENT;
201
202         LOGD("sound register focus pid[%d]", pid);
203         /* read session information */
204         ret = _mm_session_util_read_information(pid, &sound_focus->session_type, &sound_focus->session_flags);
205         LOGW("Read Session Type -> ret:0x%X \n", ret);
206
207         if (ret == MM_ERROR_INVALID_HANDLE) {
208                 /* case 1. if there is no session */
209                 LOGW("subscribe_id=%d\n", sound_focus->subscribe_id);
210
211                 if (sound_focus->subscribe_id == 0) {
212                         ret = mm_sound_subscribe_signal_for_daemon(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, pid, &sound_focus->subscribe_id,
213                                                                         (mm_sound_signal_callback)__mmplayer_sound_signal_callback, (void*)sound_focus);
214                         if (ret != MM_ERROR_NONE) {
215                                 LOGE("mm_sound_subscribe_signal is failed\n");
216                                 return MM_ERROR_POLICY_BLOCKED;
217                         }
218
219                         LOGD("register focus watch callback for the value is 0, sub_cb id %d\n", sound_focus->subscribe_id);
220                         /* register watch callback */
221                         ret = mm_sound_set_focus_watch_callback_for_session(pid ,
222                                         FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id);
223                         if (ret != MM_ERROR_NONE) {
224                                 LOGE("mm_sound_set_focus_watch_callback is failed\n");
225                                 return MM_ERROR_POLICY_BLOCKED;
226                         }
227                         /* register device connected callback */
228                         ret = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG,
229                                         (mm_sound_device_connected_cb)__mmplayer_sound_device_connected_cb_func, (void*)param, &sound_focus->connected_id);
230                         if (ret != MM_ERROR_NONE) {
231                                 LOGE("mm_sound_add_device_connected_callback is failed\n");
232                                 return MM_ERROR_POLICY_BLOCKED;
233                         }
234                         LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
235                 }
236                 ret = MM_ERROR_NONE;
237         } else if (ret == MM_ERROR_NONE) {
238                 /* case 2. if sessoin exists */
239                 /* in this case, this process is using stream info created by using sound-manager,
240                  * we're going to skip working on backward compatibility of session. */
241                 if (sound_focus->session_type == MM_SESSION_TYPE_REPLACED_BY_STREAM) {
242                         LOGW("this process is using stream info. skip it..");
243                 } else {
244                         /* interpret session information */
245                         stream_type = __mmplayer_sound_get_stream_type(sound_focus->session_type);
246                         LOGD("fid [%d] wid [%d] type[%s], flags[0x%02X]\n",
247                                 sound_focus->focus_id, sound_focus->watch_id, stream_type, sound_focus->session_flags);
248
249                         if (sound_focus->focus_id == 0) {
250                                 /* get unique id */
251                                 ret = mm_sound_focus_get_id(&sound_focus->focus_id);
252                                 if (ret != MM_ERROR_NONE) {
253                                         LOGE("failed to get unique focus id\n");
254                                         return MM_ERROR_POLICY_BLOCKED;
255                                 }
256
257                                 /* register sound focus callback */
258                                 ret = mm_sound_register_focus_for_session(sound_focus->focus_id, pid,
259                                                 stream_type, focus_cb, (void*)param);
260                                 if (ret != MM_ERROR_NONE) {
261                                         LOGE("mm_sound_register_focus is failed\n");
262                                         return MM_ERROR_POLICY_BLOCKED;
263                                 }
264                         }
265
266                         if ((sound_focus->watch_id == 0) &&
267                                 (strstr(stream_type, "media")) &&
268                                 !(sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS) &&
269                                 !(sound_focus->session_flags & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
270                                 LOGD("register focus watch callback\n");
271                                 /* register watch callback */
272                                 ret = mm_sound_set_focus_watch_callback_for_session(pid,
273                                                 FOCUS_FOR_BOTH, watch_cb, (void*)param, &sound_focus->watch_id);
274                                 if (ret != MM_ERROR_NONE) {
275                                         LOGE("mm_sound_set_focus_watch_callback is failed\n");
276                                         return MM_ERROR_POLICY_BLOCKED;
277                                 }
278                         }
279
280                         if ((strstr(stream_type, "media")) && (sound_focus->connected_id == 0)) {
281                                 /* register device connected callback */
282                                 ret = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG,
283                                                 (mm_sound_device_connected_cb)__mmplayer_sound_device_connected_cb_func, (void*)param, &sound_focus->connected_id);
284                                 if (ret != MM_ERROR_NONE) {
285                                         LOGE("mm_sound_add_device_connected_callback is failed\n");
286                                         return MM_ERROR_POLICY_BLOCKED;
287                                 }
288                                 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
289                         }
290
291                         ret = mm_player_set_attribute(player, NULL, "sound_stream_type", stream_type, strlen(stream_type), (char *)NULL);
292                         if (ret != MM_ERROR_NONE) {
293                                 LOGE("mm_player_set_attribute for sound_stream_type is failed\n");
294                                 return ret;
295                         }
296                 }
297                 ret = MM_ERROR_NONE;
298         } else {
299                 LOGE("_mm_session_util_read_information is failed");
300                 ret =  MM_ERROR_POLICY_BLOCKED;
301         }
302
303         MMPLAYER_FLEAVE();
304         return ret;
305 }
306
307 gint
308 _mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus)
309 {
310         int ret = MM_ERROR_NONE;
311
312         MMPLAYER_FENTER();
313
314         MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
315
316         LOGD("unregister sound focus callback\n");
317
318         if (sound_focus->focus_id > 0) {
319                 ret = mm_sound_unregister_focus(sound_focus->focus_id);
320                 if (ret != MM_ERROR_NONE)
321                         LOGE("failed to mm_sound_unregister_focus() %d", sound_focus->focus_id);
322                 sound_focus->focus_id = 0;
323         }
324
325         if (sound_focus->watch_id > 0) {
326                 ret = mm_sound_unset_focus_watch_callback(sound_focus->watch_id);
327                 if (ret != MM_ERROR_NONE)
328                         LOGE("failed to mm_sound_unset_focus_watch_callback() %d", sound_focus->watch_id);
329                 sound_focus->watch_id = 0;
330         }
331
332         if (sound_focus->subscribe_id > 0) {
333                 mm_sound_unsubscribe_signal(sound_focus->subscribe_id);
334                 sound_focus->subscribe_id = 0;
335         }
336         if (sound_focus->connected_id > 0) {
337                 ret = mm_sound_remove_device_connected_callback(sound_focus->connected_id);
338                 if (ret != MM_ERROR_NONE)
339                         LOGE("failed to mm_sound_remove_device_connected_callback() %d", sound_focus->connected_id);
340                 sound_focus->connected_id = 0;
341         }
342
343         MMPLAYER_FLEAVE();
344
345         return MM_ERROR_NONE;
346 }
347
348 bool _mmplayer_is_using_internal_sound_focus(MMPlayerSoundFocus* sound_focus)
349 {
350         MMPLAYER_RETURN_VAL_IF_FAIL(sound_focus, false);
351
352         /* Perhaps, already got release signal or application may use stream focus directly */
353         if (sound_focus->focus_id == 0)
354                 return false;
355
356         if ((sound_focus->session_type == MM_SESSION_TYPE_MEDIA && sound_focus->session_flags & MM_SESSION_OPTION_PAUSE_OTHERS) ||
357                 (sound_focus->session_type == MM_SESSION_TYPE_NOTIFY) ||
358                 (sound_focus->session_type == MM_SESSION_TYPE_ALARM) ||
359                 (sound_focus->session_type == MM_SESSION_TYPE_EMERGENCY))
360                 return true;
361         else
362                 return false;
363 }