4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <sys/types.h>
26 #include "mm_player_utils.h"
27 #include "mm_player_priv.h"
28 #include "mm_player_sound_focus.h"
30 #define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \
32 if (!x_player_sound_focus) { \
33 LOGD("no sound focus instance");\
34 return MM_ERROR_SOUND_NOT_INITIALIZED; \
38 void __mmplayer_sound_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data)
40 MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data;
41 MMPLAYER_RETURN_IF_FAIL(sound_focus);
43 LOGD("sound signal callback %d / %d", signal, value);
45 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS && value == 1)
46 _mmplayer_sound_unregister(sound_focus);
50 __mmplayer_sound_device_connected_cb_func(MMSoundDevice_t device_h, bool is_connected, void *user_data)
52 mm_player_t* player = (mm_player_t*) user_data;
53 MMPLAYER_RETURN_IF_FAIL(player);
55 mm_sound_device_type_e device_type;
58 LOGW("device_connected_cb is called, device_h[0x%x], is_connected[%d]\n", device_h, is_connected);
60 /* get device type with device_h*/
61 ret = mm_sound_get_device_type(device_h, &device_type);
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:
71 int result = MM_ERROR_NONE;
72 LOGW("pause immediately");
74 player->sound_focus.by_asm_cb = TRUE;
75 player->sound_focus.focus_changed_msg = MM_PLAYER_FOCUS_CHANGED_BY_EARJACK_UNPLUG;
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);
83 player->sound_focus.by_asm_cb = FALSE;
94 __mmplayer_sound_get_stream_type(gint 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:
103 case MM_SESSION_TYPE_NOTIFY:
104 return "notification";
105 case MM_SESSION_TYPE_ALARM:
107 case MM_SESSION_TYPE_EMERGENCY:
110 LOGW("unexpected case!\n");
116 __mmplayer_check_need_block(const char *focus_acquired_by)
118 if (!focus_acquired_by)
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);
135 _mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus)
137 int ret = MM_ERROR_NONE;
140 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
142 if (sound_focus->acquired) {
143 LOGW("focus is already acquired. can't acquire again.");
144 return MM_ERROR_NONE;
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");
152 ret = mm_sound_acquire_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player acquire focus");
154 if (ret != MM_ERROR_NONE) {
155 LOGE("failed to acquire sound focus [0x%X]", ret);
159 sound_focus->acquired = TRUE;
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);
165 if (sound_focus->watch_id > 0) {
166 char *stream_type = NULL;
167 char *ext_info = NULL;
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;
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 */
183 if (stream_type) free(stream_type);
184 if (ext_info) free(ext_info);
193 _mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus)
195 int ret = MM_ERROR_NONE;
198 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
200 if (!sound_focus->acquired) {
201 LOGW("focus is not acquired. no need to release.");
202 return MM_ERROR_NONE;
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");
210 ret = mm_sound_release_focus(sound_focus->focus_id, FOCUS_FOR_BOTH, "mm-player release focus");
212 if (ret != MM_ERROR_NONE) {
213 LOGE("failed to release sound focus\n");
217 sound_focus->acquired = FALSE;
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");
225 return MM_ERROR_NONE;
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)
233 gint ret = MM_ERROR_NONE;
234 const gchar *stream_type = NULL;
235 mm_player_t* player = MM_PLAYER_CAST(param);
238 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_ARGUMENT);
241 /* check if it's running on the media_server */
242 if (sound_focus->pid > 0)
243 pid = sound_focus->pid;
245 return MM_ERROR_INVALID_ARGUMENT;
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);
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);
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;
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;
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;
279 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
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..");
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);
294 if (sound_focus->focus_id == 0) {
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;
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;
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;
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;
333 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
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");
344 LOGE("_mm_session_util_read_information is failed");
345 ret = MM_ERROR_POLICY_BLOCKED;
353 _mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus)
355 int ret = MM_ERROR_NONE;
359 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
360 MMPLAYER_SOUND_FOCUS_LOCK(sound_focus);
362 LOGD("unregister sound focus callback\n");
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;
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;
378 if (sound_focus->subscribe_id > 0) {
379 mm_sound_unsubscribe_signal(sound_focus->subscribe_id);
380 sound_focus->subscribe_id = 0;
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;
389 MMPLAYER_SOUND_FOCUS_UNLOCK(sound_focus);
392 return MM_ERROR_NONE;
395 bool _mmplayer_is_using_internal_sound_focus(MMPlayerSoundFocus* sound_focus)
397 MMPLAYER_RETURN_VAL_IF_FAIL(sound_focus, false);
399 /* Perhaps, already got release signal or application may use stream focus directly */
400 if (sound_focus->focus_id == 0)
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))