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