Add session mutex lock
[platform/core/api/audio-io.git] / src / cpp / CAudioSessionHandler.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <unistd.h>
19 #include <mm_error.h>
20 #include "CAudioIODef.h"
21
22
23 using namespace std;
24 using namespace tizen_media_audio;
25
26
27 /**
28  * class CAudioSessionHandler
29  */
30 int CAudioSessionHandler::__sCaptureRef = 0;
31
32 int CAudioSessionHandler::__pcmCaptureCountInc() {
33     int actual;
34     do {
35         actual = __sCaptureRef;
36     } while (!__sync_bool_compare_and_swap(&__sCaptureRef, actual, actual + 1));
37     AUDIO_IO_LOGD("CaptureRefCount+1 > [%d]", __sCaptureRef);
38     return __sCaptureRef;
39 }
40
41 int CAudioSessionHandler::__pcmCaptureCountDec() {
42     int actual;
43     do {
44         actual = __sCaptureRef;
45     } while (!__sync_bool_compare_and_swap(&__sCaptureRef, actual, actual - 1));
46     AUDIO_IO_LOGD("CaptureRefCount-1 > [%d]", __sCaptureRef);
47     if (__sCaptureRef < 0) {
48         AUDIO_IO_LOGE("A CaptureRef[%d] is not valid! Something is wrong!", __sCaptureRef);
49         __sCaptureRef = 0;
50     }
51     return __sCaptureRef;
52 }
53
54 int CAudioSessionHandler::__pcmCaptureCountGet() {
55     AUDIO_IO_LOGD("CaptureRefCount > [%d]", __sCaptureRef);
56     return __sCaptureRef;
57 }
58
59 int CAudioSessionHandler::__sFocusRef = 0;
60
61 int CAudioSessionHandler::__focusIdCountInc() {
62     int actual;
63     do {
64         actual = __sFocusRef;
65     } while (!__sync_bool_compare_and_swap(&__sFocusRef, actual, actual + 1));
66     AUDIO_IO_LOGD("FocusRefCount+1 > [%d]", __sFocusRef);
67     return __sFocusRef;
68 }
69
70 int CAudioSessionHandler::__focusIdCountDec() {
71     int actual;
72     do {
73         actual = __sFocusRef;
74     } while (!__sync_bool_compare_and_swap(&__sFocusRef, actual, actual - 1));
75     AUDIO_IO_LOGD("FocusRefCount-1 > [%d]", __sFocusRef);
76     return __sFocusRef;
77 }
78
79 int CAudioSessionHandler::__focusIdCountGet() {
80     /* AUDIO_IO_LOGD("FocusRefCount > [%d]", __sFocusRef); */
81     return __sFocusRef;
82 }
83
84 void CAudioSessionHandler::__lockFocusIdMutex() {
85     if (pthread_mutex_lock(&__mFocusIdMutex) != 0)
86         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock() - FocusId Mutex");
87 #ifdef _AUDIO_IO_DEBUG_TIMING_
88     AUDIO_IO_LOGD(COLOR_RED "LOCK - FocusId Mutex" COLOR_END);
89 #endif
90 }
91
92 void CAudioSessionHandler::__unlockFocusIdMutex() {
93     if (pthread_mutex_unlock(&__mFocusIdMutex) != 0)
94         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_unlock() - FocusId Mutex");
95 #ifdef _AUDIO_IO_DEBUG_TIMING_
96     AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK - FocusId Mutex" COLOR_END);
97 #endif
98 }
99
100 void CAudioSessionHandler::__lockFocusCBMutex() {
101     if (pthread_mutex_lock(&__mFocusCBMutex) != 0)
102         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock() - FocusCB Mutex");
103 #ifdef _AUDIO_IO_DEBUG_TIMING_
104     AUDIO_IO_LOGD(COLOR_RED "LOCK - FocusCB Mutex" COLOR_END);
105 #endif
106 }
107
108 void CAudioSessionHandler::__unlockFocusCBMutex() {
109     if (pthread_mutex_unlock(&__mFocusCBMutex) != 0)
110         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_unlock() - FocusCB Mutex");
111 #ifdef _AUDIO_IO_DEBUG_TIMING_
112     AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK - FocusCB Mutex" COLOR_END);
113 #endif
114 }
115
116 CAudioSessionHandler::CAudioSessionHandler(EAudioSessionType sessionType, CAudioInfo& audioInfo, IAudioSessionEventListener* listener) :
117     __mId(-1),
118     __mOptions(0),
119     __mAudioSession(sessionType),
120     __mMultimediaSession(MM_SESSION_TYPE_MEDIA),
121     __mpEventListener(listener),
122     __mIsInit(false),
123     __mSubscribeId(0),
124     __mUseFocus(false),
125     __mAcquiredFocus(FOCUS_NONE),
126     __mReasonForChange(NULL),
127     __mAdditionalInfo(NULL),
128     __mFocusIdMutex(PTHREAD_MUTEX_INITIALIZER),
129     __mFocusCBMutex(PTHREAD_MUTEX_INITIALIZER) {
130     __mAudioInfo = audioInfo;
131 }
132
133 CAudioSessionHandler::~CAudioSessionHandler() {
134 }
135
136 CAudioError CAudioSessionHandler::__convertStreamType(EAudioSessionType type1, MMSessionType type2, int *index) {
137     unsigned int i;
138     int idx = -1;
139
140     assert(index != NULL);
141
142     if (type1 == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
143         for (i = 0 ; i < sizeof(__STREAM_TYPE_TABLE_IN) / sizeof(__STREAM_TYPE_TABLE_IN[0]) ; i++) {
144             if (__STREAM_TYPE_TABLE_IN[i].type == type2) {
145                 idx = i;
146                 break;
147             }
148         }
149     } else {
150         for (i = 0 ; i < sizeof(__STREAM_TYPE_TABLE_OUT) / sizeof(__STREAM_TYPE_TABLE_OUT[0]) ; i++) {
151             if (__STREAM_TYPE_TABLE_OUT[i].type == type2) {
152                 idx = i;
153                 break;
154             }
155         }
156     }
157
158     if (idx < 0) {
159         RET_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "Does not support session type.");
160     }
161     *index = idx;
162     RET_ERROR(CAudioError::EError::ERROR_NONE);
163 }
164
165 CAudioError CAudioSessionHandler::__getAsmInformation(MMSessionType *type, int *options) {
166     assert(type != NULL);
167     assert(options != NULL);
168
169     MMSessionType currentSession = MM_SESSION_TYPE_MEDIA;
170     int           sessionOptions = 0;
171
172     /* Read session information */
173     int ret = 0;
174     if ((ret = _mm_session_util_read_information(-1, (int*)&currentSession, &sessionOptions)) < 0) {
175         if (ret == (int) MM_ERROR_INVALID_HANDLE)
176             RET_ERROR_MSG(CAudioError::EError::ERROR_INVALID_HANDLE, "Failed _mm_session_util_read_information(). Invalid handle");
177         else
178             RET_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed _mm_session_util_read_information(). Not exist");
179     }
180
181     *type    = currentSession;
182     *options = sessionOptions;
183
184     RET_ERROR(CAudioError::EError::ERROR_NONE);
185 }
186
187 bool CAudioSessionHandler::__isFocusRequired(MMSessionType type, int options) {
188     if ((options & MM_SESSION_OPTION_PAUSE_OTHERS)
189         || ((type != MM_SESSION_TYPE_MEDIA) && (type != MM_SESSION_TYPE_MEDIA_RECORD)))
190         return true;
191     else
192         return false;
193 }
194
195 bool CAudioSessionHandler::__isFocusDisableReacquisitionRequired(MMSessionType type, int options) {
196     if ((type == MM_SESSION_TYPE_MEDIA) &&
197         !(options & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED))
198         return true;
199
200     return false;
201 }
202
203 bool CAudioSessionHandler::__checkNeedBlock(const char *focus_acquired_by) {
204     assert(focus_acquired_by != NULL);
205
206     if (!strcmp(focus_acquired_by, "alarm") ||
207         !strcmp(focus_acquired_by, "ringtone-voip") ||
208         !strcmp(focus_acquired_by, "ringtone-call") ||
209         !strcmp(focus_acquired_by, "voip") ||
210         !strcmp(focus_acquired_by, "call-voice") ||
211         !strcmp(focus_acquired_by, "call-video")) {
212         AUDIO_IO_LOGW("Blocked by session policy, focus_acquired_by[%s]", focus_acquired_by);
213         return true;
214     }
215
216     return false;
217 }
218
219 int CAudioSessionHandler::getId() {
220     return __mId;
221 }
222
223 int CAudioSessionHandler::getOptions() {
224     return __mOptions;
225 }
226
227 CAudioSessionHandler::EAudioSessionType CAudioSessionHandler::getAudioSession() {
228     return __mAudioSession;
229 }
230
231 MMSessionType CAudioSessionHandler::getMultimediaSession() {
232     return __mMultimediaSession;
233 }
234
235 void CAudioSessionHandler::getInternalVoipStreamInfo(sound_stream_info_h *stream_info) {
236 #if 0
237     int ret;
238     if ((ret = sound_manager_get_internal_voip_stream_information(stream_info))) {
239         if (ret == SOUND_MANAGER_ERROR_NO_DATA)
240             AUDIO_IO_LOGW("there's no internal voip stream info.");
241         else
242             AUDIO_IO_LOGE("failed to sound_manager_get_internal_voip_stream_information(), ret(0x%x)", ret);
243     }
244 #endif
245     return;
246 }
247
248 unsigned int CAudioSessionHandler::getSubscribeId() {
249     return __mSubscribeId;
250 }
251
252 CAudioInfo CAudioSessionHandler::getAudioInfo() {
253     return __mAudioInfo;
254 }
255
256 void CAudioSessionHandler::__sound_pcm_signal_cb(mm_sound_signal_name_t signal, int value, void *user_data) {
257     assert(user_data);
258
259     AUDIO_IO_LOGD("[signal:%d], [value:%d], [user_data:%p]", signal, value, user_data);
260
261     CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
262     if (pHandler->__mpEventListener != NULL)
263         pHandler->__mpEventListener->onSignal(pHandler, signal, value);
264 }
265
266 void CAudioSessionHandler::initialize() {
267     AUDIO_IO_LOGD("");
268     if (__mIsInit == true)
269         return;
270
271     MMSessionType currentSession = MM_SESSION_TYPE_MEDIA;
272     int           sessionOptions = 0;  // Mix with others by default
273
274     CAudioError err = __getAsmInformation(&currentSession, &sessionOptions);
275     if (err == CAudioError::EError::ERROR_NONE) {
276         if (currentSession == MM_SESSION_TYPE_REPLACED_BY_STREAM) {
277             __mUseFocus = false;
278             AUDIO_IO_LOGD("Stream info. was created outside, skip audio focus concept internally!");
279         } else {
280             // Session was configured before, use focus callback
281             __mUseFocus = true;
282             AUDIO_IO_LOGD("Use audio focus concept internally!");
283         }
284     } else {
285         if (err == CAudioError::EError::ERROR_INVALID_HANDLE) {
286             // No session, No stream_info, No focus watch callback before
287             // Use focus watch callback with signal subscribe
288
289             int errorCode = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &__mSubscribeId, __sound_pcm_signal_cb, static_cast<void*>(this));
290             if (errorCode != MM_ERROR_NONE || __mSubscribeId == 0)
291                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_subscribe_signal() err:0x%x, __mSubscribeId:%u",
292                                        errorCode, __mSubscribeId);
293
294             AUDIO_IO_LOGD("Subscribed mm_sound signal [id:%d]", __mSubscribeId);
295
296             sessionOptions = 0;  // Mix with others by default
297             __mUseFocus = true;
298             AUDIO_IO_LOGD("Use audio focus(watch) concept internally!");
299         } else {
300             __mUseFocus = false;
301             AUDIO_IO_LOGD("Skip audio focus concept!");
302         }
303
304         if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
305             AUDIO_IO_LOGD("Set default \"Media_Record\" type");
306             currentSession = MM_SESSION_TYPE_MEDIA_RECORD;
307         } else {
308             AUDIO_IO_LOGD("Set default \"Media\" type");
309             currentSession = MM_SESSION_TYPE_MEDIA;
310         }
311     }
312
313     // Updates session information
314     __mMultimediaSession = currentSession;
315     __mOptions           = sessionOptions;
316
317     if (this->__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE)
318         __pcmCaptureCountInc();
319
320     __mIsInit = true;
321 }
322
323 void CAudioSessionHandler::finalize() {
324     AUDIO_IO_LOGD("");
325     if (__mIsInit == false)
326         return;
327
328     if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE)
329         __pcmCaptureCountDec();
330
331     unregisterSound();
332
333     if (__mSubscribeId > 0) {
334         AUDIO_IO_LOGD("Unsubscribed mm_sound signal [id:%d]", __mSubscribeId);
335         mm_sound_unsubscribe_signal(__mSubscribeId);
336         __mSubscribeId = 0;
337     }
338
339     __mpEventListener = NULL;
340
341     __mIsInit = false;
342 }
343
344 bool CAudioSessionHandler::isSkipSession() {
345     if (__mMultimediaSession == MM_SESSION_TYPE_REPLACED_BY_STREAM ||
346         __mMultimediaSession == MM_SESSION_TYPE_VOIP ||
347         __mMultimediaSession == MM_SESSION_TYPE_CALL ||
348         __mMultimediaSession == MM_SESSION_TYPE_VIDEOCALL) {
349         AUDIO_IO_LOGD("__mMultimediaSession is [%d], skip session", __mMultimediaSession);
350         return true;
351     }
352
353     return false;
354 }
355
356 void CAudioSessionHandler::__sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
357                                                 const char *reason_for_change, int option, const char *additional_info, void *user_data) {
358     assert(user_data);
359
360     AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
361                   id, focus_type, state, reason_for_change, additional_info, user_data);
362
363 /* FIXME: disable it temporarily */
364 #ifndef DISABLE_SESSION_BACK_COMP
365
366     CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
367
368     pHandler->__lockFocusCBMutex();
369
370     if (state == FOCUS_IS_RELEASED)
371         pHandler->__mAcquiredFocus &= ~focus_type;
372     else if (state == FOCUS_IS_ACQUIRED)
373         pHandler->__mAcquiredFocus |= focus_type;
374     pHandler->__mReasonForChange = (char *)reason_for_change;
375     pHandler->__mAdditionalInfo  = (char *)additional_info;
376
377     if (pHandler->__mpEventListener != NULL)
378         pHandler->__mpEventListener->onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
379
380     pHandler->__unlockFocusCBMutex();
381 #endif
382     return;
383 }
384
385 void CAudioSessionHandler::__sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
386                                                       const char *reason_for_change, const char *additional_info, void *user_data) {
387     AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
388                   id, focus_type, state, reason_for_change, additional_info, user_data);
389
390     CAudioSessionHandler::__sound_pcm_focus_cb(-1, focus_type, state, reason_for_change, 0, additional_info, user_data);
391
392     return;
393 }
394
395 void CAudioSessionHandler::registerSound() {
396     if (__mIsInit == false)
397         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
398
399     if (__mUseFocus == true) {
400         __lockFocusIdMutex();
401         if (__mId >= 0) {
402             __unlockFocusIdMutex();
403             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Already registered [id:%d]", __mId);
404         }
405
406         int errorCode = 0;
407
408         if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
409             int index = 0;
410
411             CAudioError err = __convertStreamType(__mAudioSession, __mMultimediaSession, &index);
412             if (err != CAudioError::EError::ERROR_NONE) {
413                 __unlockFocusIdMutex();
414                 throw err;
415             }
416
417             errorCode = mm_sound_focus_get_id(&__mId);
418             if (errorCode != MM_ERROR_NONE) {
419                 __unlockFocusIdMutex();
420                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_focus_get_id() err:0x%x", errorCode);
421             }
422
423             // Register focus callback
424             errorCode = mm_sound_register_focus_for_session(__mId,
425                                                 getpid(),
426                                                 __mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE ? __STREAM_TYPE_TABLE_IN[index].name : __STREAM_TYPE_TABLE_OUT[index].name,
427                                                 __sound_pcm_focus_cb,
428                                                 static_cast<void*>(this));
429             if (errorCode != MM_ERROR_NONE) {
430                 __unlockFocusIdMutex();
431                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_register_focus_for_session() err:0x%x", errorCode);
432             }
433
434             if (__isFocusDisableReacquisitionRequired(__mMultimediaSession, __mOptions)) {
435                 errorCode = mm_sound_set_focus_reacquisition_for_session(__mId, false);
436                 if (errorCode != MM_ERROR_NONE) {
437                     __unlockFocusIdMutex();
438                     THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_reacquisition() err:0x%x", errorCode);
439                 }
440             }
441
442             __focusIdCountInc();
443
444             AUDIO_IO_LOGD("Focus callback registered successfully [id:%d]", __mId);
445         } else if (!(__mOptions & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
446             // Register focus watch callback
447             errorCode = mm_sound_set_focus_watch_callback_for_session(getpid(), FOCUS_FOR_BOTH, __sound_pcm_focus_watch_cb, static_cast<void*>(this), &__mId);
448             if (errorCode < 0) {
449                 __unlockFocusIdMutex();
450                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_watch_callback_for_session() err:0x%x", errorCode);
451             }
452
453             __focusIdCountInc();
454
455             AUDIO_IO_LOGD("Focus watch callback registered successfully [id:%d]", __mId);
456         }
457         __unlockFocusIdMutex();
458     }
459 }
460
461 void CAudioSessionHandler::unregisterSound() {
462     if (__mIsInit == false)
463         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
464
465     __lockFocusIdMutex();
466     if (__mUseFocus == true && __mId >= 0) {
467         int errorCode = 0;
468
469         if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
470             // Unregister focus callback
471             errorCode = mm_sound_unregister_focus(__mId);
472             if (errorCode != MM_ERROR_NONE) {
473                 __unlockFocusIdMutex();
474                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unregister_focus() err:0x%x", errorCode);
475             }
476
477             __focusIdCountDec();
478
479             AUDIO_IO_LOGD("Focus callback unregistered successfully [id:%d]", __mId);
480             __mId = -1;
481         } else if (!(__mOptions & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
482             // Unregister focus watch callback.
483             errorCode = mm_sound_unset_focus_watch_callback(__mId);
484             if (errorCode < 0) {
485                 __unlockFocusIdMutex();
486                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unset_focus_watch_callback() err:0x%x", errorCode);
487             }
488
489             __focusIdCountDec();
490
491             AUDIO_IO_LOGD("Focus watch callback unregistered successfully [id:%d]", __mId);
492             __mId = -1;
493         }
494         __mAcquiredFocus = FOCUS_NONE;
495     }
496     __unlockFocusIdMutex();
497 }
498
499 void CAudioSessionHandler::updatePlaying() {
500     if (__mIsInit == false)
501         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
502
503     __lockFocusIdMutex();
504     if (!__mUseFocus || __mId < 0) {
505         __unlockFocusIdMutex();
506         return;
507     }
508
509     if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
510         if (__mId >= 0) {
511             int ret = MM_ERROR_NONE;
512             int focus_type = 0;
513             bool is_focus_cb_thread;
514
515             if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread))) {
516                 __unlockFocusIdMutex();
517                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed mm_sound_focus_is_cb_thread() err:0x%x", ret);
518             }
519
520             if (!is_focus_cb_thread)
521                 __lockFocusCBMutex();
522
523             if (__mAcquiredFocus == FOCUS_FOR_BOTH) {
524                 AUDIO_IO_LOGW("Focus was already acquired, skip it...");
525                 if (!is_focus_cb_thread)
526                     __unlockFocusCBMutex();
527                 __unlockFocusIdMutex();
528                 return;
529             }
530
531             focus_type |= (FOCUS_FOR_BOTH & ~__mAcquiredFocus);
532             if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
533                 ret = mm_sound_acquire_focus_with_option(__mId, (mm_sound_focus_type_e)focus_type, 1, "audio-io acquire focus"); /* option: 1 for no-resume */
534             else
535                 ret = mm_sound_acquire_focus(__mId, (mm_sound_focus_type_e)focus_type, "audio-io acquire focus");
536             if (ret != MM_ERROR_NONE) {
537                 if (!is_focus_cb_thread)
538                     __unlockFocusCBMutex();
539                 __unlockFocusIdMutex();
540                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_acquire_focus() err:0x%x", ret);
541             }
542             __mAcquiredFocus = FOCUS_FOR_BOTH;
543             AUDIO_IO_LOGD("Focus acquired successfully [id:%d]", __mId);
544
545             if (!is_focus_cb_thread)
546                 __unlockFocusCBMutex();
547         }
548     } else {
549         int ret = MM_ERROR_NONE;
550         char *stream_type = NULL;
551         char *ext_info = NULL;
552         int option = 0;
553
554         if ((ret = mm_sound_get_stream_type_of_acquired_focus(FOCUS_FOR_BOTH, &stream_type, &option, &ext_info))) {
555             __unlockFocusIdMutex();
556             return;
557         }
558
559         AUDIO_IO_LOGD("Focus is acquired by stream_type[%s], option[%d], ext_info[%s]", stream_type, option, ext_info);
560
561         if (__checkNeedBlock((const char*)stream_type)) {
562             free(stream_type);
563             free(ext_info);
564             __unlockFocusIdMutex();
565             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Blocked by an acquired focus");
566         }
567         free(stream_type);
568         free(ext_info);
569     }
570     __unlockFocusIdMutex();
571 }
572
573 void CAudioSessionHandler::updateStop() {
574     if (__mIsInit == false)
575         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
576
577     if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
578         __lockFocusIdMutex();
579         if (__mId >= 0) {
580             int ret = MM_ERROR_NONE;
581             bool is_focus_cb_thread;
582
583             if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread))) {
584                 __unlockFocusIdMutex();
585                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed mm_sound_focus_is_cb_thread() err:0x%x", ret);
586             }
587
588             if (!is_focus_cb_thread)
589                 __lockFocusCBMutex();
590
591             if (__mAcquiredFocus == FOCUS_NONE) {
592                 AUDIO_IO_LOGW("Focus was already released, skip it...");
593                 if (!is_focus_cb_thread)
594                     __unlockFocusCBMutex();
595                 __unlockFocusIdMutex();
596                 return;
597             }
598
599             if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
600                 ret = mm_sound_release_focus_with_option(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, 1, "audio-io release focus"); /* option: 1 for no-resume */
601             else
602                 ret = mm_sound_release_focus(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, "audio-io release focus");
603             if (ret != MM_ERROR_NONE) {
604                 if (!is_focus_cb_thread)
605                     __unlockFocusCBMutex();
606                 __unlockFocusIdMutex();
607                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_release_focus() err:0x%x", ret);
608             }
609             __mAcquiredFocus = FOCUS_NONE;
610             AUDIO_IO_LOGD("Focus released successfully [id:%d]", __mId);
611
612             if (!is_focus_cb_thread)
613                 __unlockFocusCBMutex();
614         }
615         __unlockFocusIdMutex();
616     }
617 }
618
619 void CAudioSessionHandler::disableSessionHandler() {
620     CAudioSessionHandler::updateStop();
621     CAudioSessionHandler::unregisterSound();
622
623     CAudioSessionHandler::__mUseFocus = false;
624 }
625
626 /**
627  * class IAudioSessionEventListener
628  */
629 IAudioSessionEventListener::EInterruptCode IAudioSessionEventListener::convertInterruptedCode(int code, const char *reason_for_change) {
630     EInterruptCode e = EInterruptCode::INTERRUPT_BY_MEDIA;
631
632     switch (code) {
633     case FOCUS_IS_ACQUIRED:
634         e = EInterruptCode::INTERRUPT_COMPLETED;
635         break;
636
637     case FOCUS_IS_RELEASED:
638         if (!strcmp(reason_for_change, "media"))              e = EInterruptCode::INTERRUPT_BY_MEDIA;
639         if (!strcmp(reason_for_change, "radio"))              e = EInterruptCode::INTERRUPT_BY_MEDIA;
640         if (!strcmp(reason_for_change, "loopback"))           e = EInterruptCode::INTERRUPT_BY_MEDIA;
641         if (!strcmp(reason_for_change, "system"))             e = EInterruptCode::INTERRUPT_BY_MEDIA;
642         if (!strcmp(reason_for_change, "alarm"))              e = EInterruptCode::INTERRUPT_BY_ALARM;
643         if (!strcmp(reason_for_change, "notification"))       e = EInterruptCode::INTERRUPT_BY_NOTIFICATION;
644         if (!strcmp(reason_for_change, "emergency"))          e = EInterruptCode::INTERRUPT_BY_EMERGENCY;
645         if (!strcmp(reason_for_change, "voice-information"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;
646         if (!strcmp(reason_for_change, "voice-recognition"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;
647         if (!strcmp(reason_for_change, "voice-recognition-service")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
648         if (!strcmp(reason_for_change, "ringtone-voip"))      e = EInterruptCode::INTERRUPT_BY_CALL;
649         if (!strcmp(reason_for_change, "ringtone-call"))      e = EInterruptCode::INTERRUPT_BY_CALL;
650         if (!strcmp(reason_for_change, "voip"))               e = EInterruptCode::INTERRUPT_BY_CALL;
651         if (!strcmp(reason_for_change, "call-voice"))         e = EInterruptCode::INTERRUPT_BY_CALL;
652         if (!strcmp(reason_for_change, "call-video"))         e = EInterruptCode::INTERRUPT_BY_CALL;
653         break;
654     }
655
656     return e;
657 }