Add session mutex lock
[platform/core/api/audio-io.git] / src / cpp / CAudioSessionHandler.cpp
index 7895e31..ceaf3ce 100644 (file)
@@ -81,6 +81,38 @@ int CAudioSessionHandler::__focusIdCountGet() {
     return __sFocusRef;
 }
 
+void CAudioSessionHandler::__lockFocusIdMutex() {
+    if (pthread_mutex_lock(&__mFocusIdMutex) != 0)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock() - FocusId Mutex");
+#ifdef _AUDIO_IO_DEBUG_TIMING_
+    AUDIO_IO_LOGD(COLOR_RED "LOCK - FocusId Mutex" COLOR_END);
+#endif
+}
+
+void CAudioSessionHandler::__unlockFocusIdMutex() {
+    if (pthread_mutex_unlock(&__mFocusIdMutex) != 0)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_unlock() - FocusId Mutex");
+#ifdef _AUDIO_IO_DEBUG_TIMING_
+    AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK - FocusId Mutex" COLOR_END);
+#endif
+}
+
+void CAudioSessionHandler::__lockFocusCBMutex() {
+    if (pthread_mutex_lock(&__mFocusCBMutex) != 0)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock() - FocusCB Mutex");
+#ifdef _AUDIO_IO_DEBUG_TIMING_
+    AUDIO_IO_LOGD(COLOR_RED "LOCK - FocusCB Mutex" COLOR_END);
+#endif
+}
+
+void CAudioSessionHandler::__unlockFocusCBMutex() {
+    if (pthread_mutex_unlock(&__mFocusCBMutex) != 0)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_unlock() - FocusCB Mutex");
+#ifdef _AUDIO_IO_DEBUG_TIMING_
+    AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK - FocusCB Mutex" COLOR_END);
+#endif
+}
+
 CAudioSessionHandler::CAudioSessionHandler(EAudioSessionType sessionType, CAudioInfo& audioInfo, IAudioSessionEventListener* listener) :
     __mId(-1),
     __mOptions(0),
@@ -88,12 +120,13 @@ CAudioSessionHandler::CAudioSessionHandler(EAudioSessionType sessionType, CAudio
     __mMultimediaSession(MM_SESSION_TYPE_MEDIA),
     __mpEventListener(listener),
     __mIsInit(false),
-    __mSubscribeId(-1),
+    __mSubscribeId(0),
     __mUseFocus(false),
-    __mFocusType(FOCUS_NONE),
-    __mState(FOCUS_IS_RELEASED),
+    __mAcquiredFocus(FOCUS_NONE),
     __mReasonForChange(NULL),
-    __mAdditionalInfo(NULL) {
+    __mAdditionalInfo(NULL),
+    __mFocusIdMutex(PTHREAD_MUTEX_INITIALIZER),
+    __mFocusCBMutex(PTHREAD_MUTEX_INITIALIZER) {
     __mAudioInfo = audioInfo;
 }
 
@@ -139,11 +172,10 @@ CAudioError CAudioSessionHandler::__getAsmInformation(MMSessionType *type, int *
     /* Read session information */
     int ret = 0;
     if ((ret = _mm_session_util_read_information(-1, (int*)&currentSession, &sessionOptions)) < 0) {
-        if (ret == (int) MM_ERROR_INVALID_HANDLE) {
+        if (ret == (int) MM_ERROR_INVALID_HANDLE)
             RET_ERROR_MSG(CAudioError::EError::ERROR_INVALID_HANDLE, "Failed _mm_session_util_read_information(). Invalid handle");
-        } else {
+        else
             RET_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed _mm_session_util_read_information(). Not exist");
-        }
     }
 
     *type    = currentSession;
@@ -160,6 +192,30 @@ bool CAudioSessionHandler::__isFocusRequired(MMSessionType type, int options) {
         return false;
 }
 
+bool CAudioSessionHandler::__isFocusDisableReacquisitionRequired(MMSessionType type, int options) {
+    if ((type == MM_SESSION_TYPE_MEDIA) &&
+        !(options & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED))
+        return true;
+
+    return false;
+}
+
+bool CAudioSessionHandler::__checkNeedBlock(const char *focus_acquired_by) {
+    assert(focus_acquired_by != NULL);
+
+    if (!strcmp(focus_acquired_by, "alarm") ||
+        !strcmp(focus_acquired_by, "ringtone-voip") ||
+        !strcmp(focus_acquired_by, "ringtone-call") ||
+        !strcmp(focus_acquired_by, "voip") ||
+        !strcmp(focus_acquired_by, "call-voice") ||
+        !strcmp(focus_acquired_by, "call-video")) {
+        AUDIO_IO_LOGW("Blocked by session policy, focus_acquired_by[%s]", focus_acquired_by);
+        return true;
+    }
+
+    return false;
+}
+
 int CAudioSessionHandler::getId() {
     return __mId;
 }
@@ -176,7 +232,20 @@ MMSessionType CAudioSessionHandler::getMultimediaSession() {
     return __mMultimediaSession;
 }
 
-int CAudioSessionHandler::getSubscribeId() {
+void CAudioSessionHandler::getInternalVoipStreamInfo(sound_stream_info_h *stream_info) {
+#if 0
+    int ret;
+    if ((ret = sound_manager_get_internal_voip_stream_information(stream_info))) {
+        if (ret == SOUND_MANAGER_ERROR_NO_DATA)
+            AUDIO_IO_LOGW("there's no internal voip stream info.");
+        else
+            AUDIO_IO_LOGE("failed to sound_manager_get_internal_voip_stream_information(), ret(0x%x)", ret);
+    }
+#endif
+    return;
+}
+
+unsigned int CAudioSessionHandler::getSubscribeId() {
     return __mSubscribeId;
 }
 
@@ -187,19 +256,17 @@ CAudioInfo CAudioSessionHandler::getAudioInfo() {
 void CAudioSessionHandler::__sound_pcm_signal_cb(mm_sound_signal_name_t signal, int value, void *user_data) {
     assert(user_data);
 
-    AUDIO_IO_LOGD("[signal:%d], [value:%d], [user_data:0x%x]", signal, value, user_data);
+    AUDIO_IO_LOGD("[signal:%d], [value:%d], [user_data:%p]", signal, value, user_data);
 
     CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
-    if (pHandler->__mpEventListener != NULL) {
+    if (pHandler->__mpEventListener != NULL)
         pHandler->__mpEventListener->onSignal(pHandler, signal, value);
-    }
 }
 
-void CAudioSessionHandler::initialize() throw(CAudioError) {
+void CAudioSessionHandler::initialize() {
     AUDIO_IO_LOGD("");
-    if (__mIsInit == true) {
+    if (__mIsInit == true)
         return;
-    }
 
     MMSessionType currentSession = MM_SESSION_TYPE_MEDIA;
     int           sessionOptions = 0;  // Mix with others by default
@@ -218,14 +285,13 @@ void CAudioSessionHandler::initialize() throw(CAudioError) {
         if (err == CAudioError::EError::ERROR_INVALID_HANDLE) {
             // No session, No stream_info, No focus watch callback before
             // Use focus watch callback with signal subscribe
-            unsigned int subscribe_id;
-            int errorCode = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &subscribe_id, __sound_pcm_signal_cb, static_cast<void*>(this));
-            if (errorCode != MM_ERROR_NONE) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_subscribe_signal() err:0x%x", errorCode);
-            }
 
-            __mSubscribeId = (int)subscribe_id;
-            AUDIO_IO_LOGD("Subscribed mm_sound signal");
+            int errorCode = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &__mSubscribeId, __sound_pcm_signal_cb, static_cast<void*>(this));
+            if (errorCode != MM_ERROR_NONE || __mSubscribeId == 0)
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_subscribe_signal() err:0x%x, __mSubscribeId:%u",
+                                       errorCode, __mSubscribeId);
+
+            AUDIO_IO_LOGD("Subscribed mm_sound signal [id:%d]", __mSubscribeId);
 
             sessionOptions = 0;  // Mix with others by default
             __mUseFocus = true;
@@ -248,104 +314,92 @@ void CAudioSessionHandler::initialize() throw(CAudioError) {
     __mMultimediaSession = currentSession;
     __mOptions           = sessionOptions;
 
-    if (this->__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
+    if (this->__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE)
         __pcmCaptureCountInc();
-    }
 
     __mIsInit = true;
 }
 
 void CAudioSessionHandler::finalize() {
     AUDIO_IO_LOGD("");
-    if (__mIsInit == false) {
+    if (__mIsInit == false)
         return;
-    }
 
-    if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
+    if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE)
         __pcmCaptureCountDec();
-    }
 
-    if (__mSubscribeId >= 0) {
+    unregisterSound();
+
+    if (__mSubscribeId > 0) {
+        AUDIO_IO_LOGD("Unsubscribed mm_sound signal [id:%d]", __mSubscribeId);
         mm_sound_unsubscribe_signal(__mSubscribeId);
+        __mSubscribeId = 0;
     }
 
+    __mpEventListener = NULL;
+
     __mIsInit = false;
 }
 
-bool CAudioSessionHandler::isSkipSessionEvent() throw(CAudioError) {
-    bool ret = false;
-
-    // To be regarded...
-#if 0
-    /* Only Support below Event */
-    if (mEvent != ASM_EVENT_CALL              && mEvent != ASM_EVENT_VOIP              &&
-        mEvent != ASM_EVENT_VIDEOCALL         && mEvent != ASM_EVENT_VOICE_RECOGNITION &&
-        mEvent != ASM_EVENT_MMCAMCORDER_AUDIO && mEvent != ASM_EVENT_MMCAMCORDER_VIDEO) {
-        // Check AudioType
-        switch (__mAudioInfo.getAudioType()) {
-        case CAudioInfo::AUDIO_IN_TYPE_MEDIA:
-        case CAudioInfo::AUDIO_IN_TYPE_VOICECONTROL:
-            ret = false;
-            break;
-
-        case CAudioInfo::AUDIO_IN_TYPE_MIRRORING:
-        case CAudioInfo::AUDIO_IN_TYPE_LOOPBACK:
-            ret = true;
-            break;
-
-        default:
-            return false;
-        }
-
-        if (ret == true) {
-            int captureCount = CAudioSessionHandler::__pcmCaptureCountGet();
-            if (captureCount == 1) {/* If this is last one */
-                /* Recover session information to MEDIA */
-                int sessionResult = _mm_session_util_write_information(-1, MM_SESSION_TYPE_MEDIA, __mOptions);
-                if (sessionResult != 0) {
-                    THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "Failed _mm_session_util_write_information() ret:%d", sessionResult);
-                }
-            }
-        }
+bool CAudioSessionHandler::isSkipSession() {
+    if (__mMultimediaSession == MM_SESSION_TYPE_REPLACED_BY_STREAM ||
+        __mMultimediaSession == MM_SESSION_TYPE_VOIP ||
+        __mMultimediaSession == MM_SESSION_TYPE_CALL ||
+        __mMultimediaSession == MM_SESSION_TYPE_VIDEOCALL) {
+        AUDIO_IO_LOGD("__mMultimediaSession is [%d], skip session", __mMultimediaSession);
+        return true;
     }
-#endif
 
-    return ret;
+    return false;
 }
 
-void CAudioSessionHandler::__sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) {
+void CAudioSessionHandler::__sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
+                                                const char *reason_for_change, int option, const char *additional_info, void *user_data) {
     assert(user_data);
 
-    AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:0x%x]", id, focus_type, state, reason_for_change, additional_info, user_data);
+    AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
+                  id, focus_type, state, reason_for_change, additional_info, user_data);
+
+/* FIXME: disable it temporarily */
+#ifndef DISABLE_SESSION_BACK_COMP
 
     CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
-    pHandler->__mFocusType       = focus_type;
-    pHandler->__mState           = state;
+
+    pHandler->__lockFocusCBMutex();
+
+    if (state == FOCUS_IS_RELEASED)
+        pHandler->__mAcquiredFocus &= ~focus_type;
+    else if (state == FOCUS_IS_ACQUIRED)
+        pHandler->__mAcquiredFocus |= focus_type;
     pHandler->__mReasonForChange = (char *)reason_for_change;
     pHandler->__mAdditionalInfo  = (char *)additional_info;
 
-    if (pHandler->__mpEventListener != NULL) {
+    if (pHandler->__mpEventListener != NULL)
         pHandler->__mpEventListener->onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
-    }
 
+    pHandler->__unlockFocusCBMutex();
+#endif
     return;
 }
 
-void CAudioSessionHandler::__sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) {
-    AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:0x%x]", id, focus_type, state, reason_for_change, additional_info, user_data);
+void CAudioSessionHandler::__sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
+                                                      const char *reason_for_change, const char *additional_info, void *user_data) {
+    AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
+                  id, focus_type, state, reason_for_change, additional_info, user_data);
 
-    CAudioSessionHandler::__sound_pcm_focus_cb(-1, focus_type, state, reason_for_change, additional_info, user_data);
+    CAudioSessionHandler::__sound_pcm_focus_cb(-1, focus_type, state, reason_for_change, 0, additional_info, user_data);
 
     return;
 }
 
-void CAudioSessionHandler::registerSound() throw(CAudioError) {
-    if (__mIsInit == false) {
+void CAudioSessionHandler::registerSound() {
+    if (__mIsInit == false)
         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
-    }
 
     if (__mUseFocus == true) {
+        __lockFocusIdMutex();
         if (__mId >= 0) {
+            __unlockFocusIdMutex();
             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Already registered [id:%d]", __mId);
         }
 
@@ -353,14 +407,17 @@ void CAudioSessionHandler::registerSound() throw(CAudioError) {
 
         if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
             int index = 0;
+
             CAudioError err = __convertStreamType(__mAudioSession, __mMultimediaSession, &index);
             if (err != CAudioError::EError::ERROR_NONE) {
+                __unlockFocusIdMutex();
                 throw err;
             }
 
             errorCode = mm_sound_focus_get_id(&__mId);
             if (errorCode != MM_ERROR_NONE) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_focus_get_id() err:0x%x", errorCode);
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_focus_get_id() err:0x%x", errorCode);
             }
 
             // Register focus callback
@@ -370,7 +427,16 @@ void CAudioSessionHandler::registerSound() throw(CAudioError) {
                                                 __sound_pcm_focus_cb,
                                                 static_cast<void*>(this));
             if (errorCode != MM_ERROR_NONE) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_register_focus_for_session() err:0x%x", errorCode);
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_register_focus_for_session() err:0x%x", errorCode);
+            }
+
+            if (__isFocusDisableReacquisitionRequired(__mMultimediaSession, __mOptions)) {
+                errorCode = mm_sound_set_focus_reacquisition_for_session(__mId, false);
+                if (errorCode != MM_ERROR_NONE) {
+                    __unlockFocusIdMutex();
+                    THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_reacquisition() err:0x%x", errorCode);
+                }
             }
 
             __focusIdCountInc();
@@ -380,33 +446,32 @@ void CAudioSessionHandler::registerSound() throw(CAudioError) {
             // Register focus watch callback
             errorCode = mm_sound_set_focus_watch_callback_for_session(getpid(), FOCUS_FOR_BOTH, __sound_pcm_focus_watch_cb, static_cast<void*>(this), &__mId);
             if (errorCode < 0) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_set_focus_watch_callback_for_session() err:0x%x", errorCode);
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_watch_callback_for_session() err:0x%x", errorCode);
             }
 
             __focusIdCountInc();
 
             AUDIO_IO_LOGD("Focus watch callback registered successfully [id:%d]", __mId);
         }
+        __unlockFocusIdMutex();
     }
 }
 
-void CAudioSessionHandler::unregisterSound() throw(CAudioError) {
-    if (__mIsInit == false) {
+void CAudioSessionHandler::unregisterSound() {
+    if (__mIsInit == false)
         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
-    }
-
-    if (__mUseFocus == true) {
-        if (__mId < 0) {
-            THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Did not register [id:%d]", __mId);
-        }
 
+    __lockFocusIdMutex();
+    if (__mUseFocus == true && __mId >= 0) {
         int errorCode = 0;
 
         if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
             // Unregister focus callback
             errorCode = mm_sound_unregister_focus(__mId);
             if (errorCode != MM_ERROR_NONE) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_unregister_focus() err:0x%x", errorCode);
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unregister_focus() err:0x%x", errorCode);
             }
 
             __focusIdCountDec();
@@ -417,7 +482,8 @@ void CAudioSessionHandler::unregisterSound() throw(CAudioError) {
             // Unregister focus watch callback.
             errorCode = mm_sound_unset_focus_watch_callback(__mId);
             if (errorCode < 0) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_unset_focus_watch_callback() err:0x%x", errorCode);
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unset_focus_watch_callback() err:0x%x", errorCode);
             }
 
             __focusIdCountDec();
@@ -425,42 +491,132 @@ void CAudioSessionHandler::unregisterSound() throw(CAudioError) {
             AUDIO_IO_LOGD("Focus watch callback unregistered successfully [id:%d]", __mId);
             __mId = -1;
         }
+        __mAcquiredFocus = FOCUS_NONE;
     }
+    __unlockFocusIdMutex();
 }
 
-void CAudioSessionHandler::updatePlaying() throw(CAudioError) {
-    if (__mIsInit == false) {
+void CAudioSessionHandler::updatePlaying() {
+    if (__mIsInit == false)
         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
+
+    __lockFocusIdMutex();
+    if (!__mUseFocus || __mId < 0) {
+        __unlockFocusIdMutex();
+        return;
     }
 
     if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
         if (__mId >= 0) {
-            int ret = mm_sound_acquire_focus(__mId, FOCUS_FOR_BOTH, "audio-io acquire focus");
+            int ret = MM_ERROR_NONE;
+            int focus_type = 0;
+            bool is_focus_cb_thread;
+
+            if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread))) {
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed mm_sound_focus_is_cb_thread() err:0x%x", ret);
+            }
+
+            if (!is_focus_cb_thread)
+                __lockFocusCBMutex();
+
+            if (__mAcquiredFocus == FOCUS_FOR_BOTH) {
+                AUDIO_IO_LOGW("Focus was already acquired, skip it...");
+                if (!is_focus_cb_thread)
+                    __unlockFocusCBMutex();
+                __unlockFocusIdMutex();
+                return;
+            }
+
+            focus_type |= (FOCUS_FOR_BOTH & ~__mAcquiredFocus);
+            if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
+                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 */
+            else
+                ret = mm_sound_acquire_focus(__mId, (mm_sound_focus_type_e)focus_type, "audio-io acquire focus");
             if (ret != MM_ERROR_NONE) {
+                if (!is_focus_cb_thread)
+                    __unlockFocusCBMutex();
+                __unlockFocusIdMutex();
                 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_acquire_focus() err:0x%x", ret);
             }
+            __mAcquiredFocus = FOCUS_FOR_BOTH;
             AUDIO_IO_LOGD("Focus acquired successfully [id:%d]", __mId);
+
+            if (!is_focus_cb_thread)
+                __unlockFocusCBMutex();
         }
+    } else {
+        int ret = MM_ERROR_NONE;
+        char *stream_type = NULL;
+        char *ext_info = NULL;
+        int option = 0;
+
+        if ((ret = mm_sound_get_stream_type_of_acquired_focus(FOCUS_FOR_BOTH, &stream_type, &option, &ext_info))) {
+            __unlockFocusIdMutex();
+            return;
+        }
+
+        AUDIO_IO_LOGD("Focus is acquired by stream_type[%s], option[%d], ext_info[%s]", stream_type, option, ext_info);
+
+        if (__checkNeedBlock((const char*)stream_type)) {
+            free(stream_type);
+            free(ext_info);
+            __unlockFocusIdMutex();
+            THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Blocked by an acquired focus");
+        }
+        free(stream_type);
+        free(ext_info);
     }
+    __unlockFocusIdMutex();
 }
 
-void CAudioSessionHandler::updateStop() throw(CAudioError) {
-    if (__mIsInit == false) {
+void CAudioSessionHandler::updateStop() {
+    if (__mIsInit == false)
         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
-    }
 
     if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
+        __lockFocusIdMutex();
         if (__mId >= 0) {
-            int ret = mm_sound_release_focus(__mId, FOCUS_FOR_BOTH, "audio-io release focus");
+            int ret = MM_ERROR_NONE;
+            bool is_focus_cb_thread;
+
+            if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread))) {
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed mm_sound_focus_is_cb_thread() err:0x%x", ret);
+            }
+
+            if (!is_focus_cb_thread)
+                __lockFocusCBMutex();
+
+            if (__mAcquiredFocus == FOCUS_NONE) {
+                AUDIO_IO_LOGW("Focus was already released, skip it...");
+                if (!is_focus_cb_thread)
+                    __unlockFocusCBMutex();
+                __unlockFocusIdMutex();
+                return;
+            }
+
+            if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
+                ret = mm_sound_release_focus_with_option(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, 1, "audio-io release focus"); /* option: 1 for no-resume */
+            else
+                ret = mm_sound_release_focus(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, "audio-io release focus");
             if (ret != MM_ERROR_NONE) {
-                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_release_focus() err:0x%x", ret);
+                if (!is_focus_cb_thread)
+                    __unlockFocusCBMutex();
+                __unlockFocusIdMutex();
+                THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_release_focus() err:0x%x", ret);
             }
+            __mAcquiredFocus = FOCUS_NONE;
             AUDIO_IO_LOGD("Focus released successfully [id:%d]", __mId);
+
+            if (!is_focus_cb_thread)
+                __unlockFocusCBMutex();
         }
+        __unlockFocusIdMutex();
     }
 }
 
-void CAudioSessionHandler::disableSessionHandler() throw(CAudioError) {
+void CAudioSessionHandler::disableSessionHandler() {
     CAudioSessionHandler::updateStop();
     CAudioSessionHandler::unregisterSound();
 
@@ -471,10 +627,9 @@ void CAudioSessionHandler::disableSessionHandler() throw(CAudioError) {
  * class IAudioSessionEventListener
  */
 IAudioSessionEventListener::EInterruptCode IAudioSessionEventListener::convertInterruptedCode(int code, const char *reason_for_change) {
-    EInterruptCode e = EInterruptCode::INTERRUPT_COMPLETED;
+    EInterruptCode e = EInterruptCode::INTERRUPT_BY_MEDIA;
 
-    switch (code)
-    {
+    switch (code) {
     case FOCUS_IS_ACQUIRED:
         e = EInterruptCode::INTERRUPT_COMPLETED;
         break;
@@ -487,13 +642,14 @@ IAudioSessionEventListener::EInterruptCode IAudioSessionEventListener::convertIn
         if (!strcmp(reason_for_change, "alarm"))              e = EInterruptCode::INTERRUPT_BY_ALARM;
         if (!strcmp(reason_for_change, "notification"))       e = EInterruptCode::INTERRUPT_BY_NOTIFICATION;
         if (!strcmp(reason_for_change, "emergency"))          e = EInterruptCode::INTERRUPT_BY_EMERGENCY;
-        if (!strcmp(reason_for_change, "voice-information"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "voice-recognition"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "ringtone-voip"))      e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "ringtone-call"))      e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "voip"))               e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "call-voice"))         e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
-        if (!strcmp(reason_for_change, "call-video"))         e = EInterruptCode::INTERRUPT_BY_MEDIA;  //for what?
+        if (!strcmp(reason_for_change, "voice-information"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;
+        if (!strcmp(reason_for_change, "voice-recognition"))  e = EInterruptCode::INTERRUPT_BY_MEDIA;
+        if (!strcmp(reason_for_change, "voice-recognition-service")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
+        if (!strcmp(reason_for_change, "ringtone-voip"))      e = EInterruptCode::INTERRUPT_BY_CALL;
+        if (!strcmp(reason_for_change, "ringtone-call"))      e = EInterruptCode::INTERRUPT_BY_CALL;
+        if (!strcmp(reason_for_change, "voip"))               e = EInterruptCode::INTERRUPT_BY_CALL;
+        if (!strcmp(reason_for_change, "call-voice"))         e = EInterruptCode::INTERRUPT_BY_CALL;
+        if (!strcmp(reason_for_change, "call-video"))         e = EInterruptCode::INTERRUPT_BY_CALL;
         break;
     }