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>
27 #include <vconf-internal-sound-keys.h>
29 #include "mm_player_utils.h"
30 #include "mm_player_priv.h"
31 #include "mm_player_sound_focus.h"
33 #define MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(x_player_sound_focus) \
35 if (!x_player_sound_focus) { \
36 LOGD("no sound focus instance");\
37 return MM_ERROR_SOUND_NOT_INITIALIZED; \
41 void __mmplayer_sound_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data)
43 MMPlayerSoundFocus *sound_focus = (MMPlayerSoundFocus*)user_data;
44 MMPLAYER_RETURN_IF_FAIL(sound_focus);
46 LOGD("sound signal callback %d / %d", signal, value);
48 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS && value == 1)
49 _mmplayer_sound_unregister(sound_focus);
53 __mmplayer_sound_device_connected_cb_func(MMSoundDevice_t device_h, bool is_connected, void *user_data)
55 mm_player_t* player = (mm_player_t*) user_data;
56 MMPLAYER_RETURN_IF_FAIL(player);
58 mm_sound_device_type_e device_type;
61 LOGW("device_connected_cb is called, device_h[0x%x], is_connected[%d]\n", device_h, is_connected);
63 /* get device type with device_h*/
64 ret = mm_sound_get_device_type(device_h, &device_type);
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:
74 int result = MM_ERROR_NONE;
75 LOGW("pause immediately");
77 player->sound_focus.by_asm_cb = TRUE;
78 player->sound_focus.focus_changed_msg = MM_PLAYER_FOCUS_CHANGED_BY_EARJACK_UNPLUG;
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);
86 player->sound_focus.by_asm_cb = FALSE;
97 __mmplayer_sound_get_stream_type(gint 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:
106 case MM_SESSION_TYPE_NOTIFY:
107 return "notification";
108 case MM_SESSION_TYPE_ALARM:
110 case MM_SESSION_TYPE_EMERGENCY:
113 LOGW("unexpected case!\n");
121 _mmplayer_sound_acquire_focus(MMPlayerSoundFocus* sound_focus)
123 int ret = MM_ERROR_NONE;
126 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
128 if (sound_focus->acquired) {
129 LOGW("focus is already acquired. can't acquire again.");
130 return MM_ERROR_NONE;
133 if (_mmplayer_is_using_internal_sound_focus(sound_focus)) {
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");
141 sound_focus->acquired = TRUE;
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");
153 _mmplayer_sound_release_focus(MMPlayerSoundFocus* sound_focus)
155 int ret = MM_ERROR_NONE;
158 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
160 if (!sound_focus->acquired) {
161 LOGW("focus is not acquired. no need to release.");
162 return MM_ERROR_NONE;
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");
172 sound_focus->acquired = FALSE;
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");
180 return MM_ERROR_NONE;
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)
188 gint ret = MM_ERROR_NONE;
189 const gchar *stream_type = NULL;
190 mm_player_t* player = MM_PLAYER_CAST(param);
193 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_ARGUMENT);
196 /* check if it's running on the media_server */
197 if (sound_focus->pid > 0)
198 pid = sound_focus->pid;
200 return MM_ERROR_INVALID_ARGUMENT;
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);
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);
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;
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;
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;
234 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
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..");
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);
249 if (sound_focus->focus_id == 0) {
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;
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;
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;
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;
288 LOGD("register device connected callback for the value is 0, sub_cb id %d\n", sound_focus->connected_id);
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");
299 LOGE("_mm_session_util_read_information is failed");
300 ret = MM_ERROR_POLICY_BLOCKED;
308 _mmplayer_sound_unregister(MMPlayerSoundFocus* sound_focus)
310 int ret = MM_ERROR_NONE;
314 MMPLAYER_CHECK_SOUND_FOCUS_INSTANCE(sound_focus);
316 LOGD("unregister sound focus callback\n");
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;
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;
332 if (sound_focus->subscribe_id > 0) {
333 mm_sound_unsubscribe_signal(sound_focus->subscribe_id);
334 sound_focus->subscribe_id = 0;
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;
345 return MM_ERROR_NONE;
348 bool _mmplayer_is_using_internal_sound_focus(MMPlayerSoundFocus* sound_focus)
350 MMPLAYER_RETURN_VAL_IF_FAIL(sound_focus, false);
352 /* Perhaps, already got release signal or application may use stream focus directly */
353 if (sound_focus->focus_id == 0)
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))