2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "CAudioIODef.h"
24 using namespace tizen_media_audio;
28 * class CAudioSessionHandler
30 int CAudioSessionHandler::__sCaptureRef = 0;
32 int CAudioSessionHandler::__pcmCaptureCountInc() {
35 actual = __sCaptureRef;
36 } while (!__sync_bool_compare_and_swap(&__sCaptureRef, actual, actual + 1));
37 AUDIO_IO_LOGD("CaptureRefCount+1 > [%d]", __sCaptureRef);
41 int CAudioSessionHandler::__pcmCaptureCountDec() {
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);
54 int CAudioSessionHandler::__pcmCaptureCountGet() {
55 AUDIO_IO_LOGD("CaptureRefCount > [%d]", __sCaptureRef);
59 int CAudioSessionHandler::__sFocusRef = 0;
61 int CAudioSessionHandler::__focusIdCountInc() {
65 } while (!__sync_bool_compare_and_swap(&__sFocusRef, actual, actual + 1));
66 AUDIO_IO_LOGD("FocusRefCount+1 > [%d]", __sFocusRef);
70 int CAudioSessionHandler::__focusIdCountDec() {
74 } while (!__sync_bool_compare_and_swap(&__sFocusRef, actual, actual - 1));
75 AUDIO_IO_LOGD("FocusRefCount-1 > [%d]", __sFocusRef);
79 int CAudioSessionHandler::__focusIdCountGet() {
80 /* AUDIO_IO_LOGD("FocusRefCount > [%d]", __sFocusRef); */
84 CAudioSessionHandler::CAudioSessionHandler(EAudioSessionType sessionType, CAudioInfo& audioInfo, IAudioSessionEventListener* listener) :
87 __mAudioSession(sessionType),
88 __mMultimediaSession(MM_SESSION_TYPE_MEDIA),
89 __mpEventListener(listener),
93 __mAcquiredFocus(FOCUS_NONE),
94 __mReasonForChange(NULL),
95 __mAdditionalInfo(NULL) {
96 __mAudioInfo = audioInfo;
99 CAudioSessionHandler::~CAudioSessionHandler() {
102 CAudioError CAudioSessionHandler::__convertStreamType(EAudioSessionType type1, MMSessionType type2, int *index) {
106 assert(index != NULL);
108 if (type1 == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
109 for (i = 0 ; i < sizeof(__STREAM_TYPE_TABLE_IN) / sizeof(__STREAM_TYPE_TABLE_IN[0]) ; i++) {
110 if (__STREAM_TYPE_TABLE_IN[i].type == type2) {
116 for (i = 0 ; i < sizeof(__STREAM_TYPE_TABLE_OUT) / sizeof(__STREAM_TYPE_TABLE_OUT[0]) ; i++) {
117 if (__STREAM_TYPE_TABLE_OUT[i].type == type2) {
125 RET_ERROR_MSG(CAudioError::EError::ERROR_NOT_SUPPORTED, "Does not support session type.");
128 RET_ERROR(CAudioError::EError::ERROR_NONE);
131 CAudioError CAudioSessionHandler::__getAsmInformation(MMSessionType *type, int *options) {
132 assert(type != NULL);
133 assert(options != NULL);
135 MMSessionType currentSession = MM_SESSION_TYPE_MEDIA;
136 int sessionOptions = 0;
138 /* Read session information */
140 if ((ret = _mm_session_util_read_information(-1, (int*)¤tSession, &sessionOptions)) < 0) {
141 if (ret == (int) MM_ERROR_INVALID_HANDLE) {
142 RET_ERROR_MSG(CAudioError::EError::ERROR_INVALID_HANDLE, "Failed _mm_session_util_read_information(). Invalid handle");
144 RET_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed _mm_session_util_read_information(). Not exist");
148 *type = currentSession;
149 *options = sessionOptions;
151 RET_ERROR(CAudioError::EError::ERROR_NONE);
154 bool CAudioSessionHandler::__isFocusRequired(MMSessionType type, int options) {
155 if ((options & MM_SESSION_OPTION_PAUSE_OTHERS)
156 || ((type != MM_SESSION_TYPE_MEDIA) && (type != MM_SESSION_TYPE_MEDIA_RECORD)))
162 bool CAudioSessionHandler::__isFocusDisableReacquisitionRequired(MMSessionType type, int options) {
163 if ((type == MM_SESSION_TYPE_MEDIA) &&
164 !(options & MM_SESSION_OPTION_RESUME_BY_SYSTEM_OR_MEDIA_PAUSED))
170 int CAudioSessionHandler::getId() {
174 int CAudioSessionHandler::getOptions() {
178 CAudioSessionHandler::EAudioSessionType CAudioSessionHandler::getAudioSession() {
179 return __mAudioSession;
182 MMSessionType CAudioSessionHandler::getMultimediaSession() {
183 return __mMultimediaSession;
186 void CAudioSessionHandler::getInternalVoipStreamInfo(sound_stream_info_h *stream_info) {
189 if ((ret = sound_manager_get_internal_voip_stream_information(stream_info))) {
190 if (ret == SOUND_MANAGER_ERROR_NO_DATA) {
191 AUDIO_IO_LOGW("there's no internal voip stream info.");
193 AUDIO_IO_LOGE("failed to sound_manager_get_internal_voip_stream_information(), ret(0x%x)", ret);
199 unsigned int CAudioSessionHandler::getSubscribeId() {
200 return __mSubscribeId;
203 CAudioInfo CAudioSessionHandler::getAudioInfo() {
207 void CAudioSessionHandler::__sound_pcm_signal_cb(mm_sound_signal_name_t signal, int value, void *user_data) {
210 AUDIO_IO_LOGD("[signal:%d], [value:%d], [user_data:%p]", signal, value, user_data);
212 CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
213 if (pHandler->__mpEventListener != NULL)
214 pHandler->__mpEventListener->onSignal(pHandler, signal, value);
217 void CAudioSessionHandler::initialize() throw(CAudioError) {
219 if (__mIsInit == true) {
223 MMSessionType currentSession = MM_SESSION_TYPE_MEDIA;
224 int sessionOptions = 0; // Mix with others by default
226 CAudioError err = __getAsmInformation(¤tSession, &sessionOptions);
227 if (err == CAudioError::EError::ERROR_NONE) {
228 if (currentSession == MM_SESSION_TYPE_REPLACED_BY_STREAM) {
230 AUDIO_IO_LOGD("Stream info. was created outside, skip audio focus concept internally!");
232 // Session was configured before, use focus callback
234 AUDIO_IO_LOGD("Use audio focus concept internally!");
237 if (err == CAudioError::EError::ERROR_INVALID_HANDLE) {
238 // No session, No stream_info, No focus watch callback before
239 // Use focus watch callback with signal subscribe
241 int errorCode = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &__mSubscribeId, __sound_pcm_signal_cb, static_cast<void*>(this));
242 if (errorCode != MM_ERROR_NONE || __mSubscribeId == 0) {
243 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_subscribe_signal() err:0x%x, __mSubscribeId:%u",
244 errorCode, __mSubscribeId);
247 AUDIO_IO_LOGD("Subscribed mm_sound signal [id:%d]", __mSubscribeId);
249 sessionOptions = 0; // Mix with others by default
251 AUDIO_IO_LOGD("Use audio focus(watch) concept internally!");
254 AUDIO_IO_LOGD("Skip audio focus concept!");
257 if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
258 AUDIO_IO_LOGD("Set default \"Media_Record\" type");
259 currentSession = MM_SESSION_TYPE_MEDIA_RECORD;
261 AUDIO_IO_LOGD("Set default \"Media\" type");
262 currentSession = MM_SESSION_TYPE_MEDIA;
266 // Updates session information
267 __mMultimediaSession = currentSession;
268 __mOptions = sessionOptions;
270 if (this->__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
271 __pcmCaptureCountInc();
277 void CAudioSessionHandler::finalize() {
279 if (__mIsInit == false) {
283 if (__mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE) {
284 __pcmCaptureCountDec();
287 if (__mSubscribeId > 0) {
288 AUDIO_IO_LOGD("Unsubscribed mm_sound signal [id:%d]", __mSubscribeId);
289 mm_sound_unsubscribe_signal(__mSubscribeId);
293 __mpEventListener = NULL;
298 bool CAudioSessionHandler::isSkipSession() {
299 if (__mMultimediaSession == MM_SESSION_TYPE_REPLACED_BY_STREAM ||
300 __mMultimediaSession == MM_SESSION_TYPE_VOIP ||
301 __mMultimediaSession == MM_SESSION_TYPE_CALL ||
302 __mMultimediaSession == MM_SESSION_TYPE_VIDEOCALL) {
303 AUDIO_IO_LOGD("__mMultimediaSession is [%d], skip session", __mMultimediaSession);
310 void CAudioSessionHandler::__sound_pcm_focus_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
311 const char *reason_for_change, int option, const char *additional_info, void *user_data) {
314 AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
315 id, focus_type, state, reason_for_change, additional_info, user_data);
317 /* FIXME: disable it temporarily */
318 #ifndef DISABLE_SESSION_BACK_COMP
320 CAudioSessionHandler* pHandler = static_cast<CAudioSessionHandler*>(user_data);
322 if (state == FOCUS_IS_RELEASED)
323 pHandler->__mAcquiredFocus &= ~focus_type;
324 else if (state == FOCUS_IS_ACQUIRED)
325 pHandler->__mAcquiredFocus |= focus_type;
326 pHandler->__mReasonForChange = (char *)reason_for_change;
327 pHandler->__mAdditionalInfo = (char *)additional_info;
329 if (pHandler->__mpEventListener != NULL)
330 pHandler->__mpEventListener->onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
335 void CAudioSessionHandler::__sound_pcm_focus_watch_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state,
336 const char *reason_for_change, const char *additional_info, void *user_data) {
337 AUDIO_IO_LOGD("[id:%d], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s], [user_data:%p]",
338 id, focus_type, state, reason_for_change, additional_info, user_data);
340 CAudioSessionHandler::__sound_pcm_focus_cb(-1, focus_type, state, reason_for_change, 0, additional_info, user_data);
345 void CAudioSessionHandler::registerSound() throw(CAudioError) {
346 if (__mIsInit == false) {
347 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
350 if (__mUseFocus == true) {
352 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Already registered [id:%d]", __mId);
357 if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
359 CAudioError err = __convertStreamType(__mAudioSession, __mMultimediaSession, &index);
360 if (err != CAudioError::EError::ERROR_NONE) {
364 errorCode = mm_sound_focus_get_id(&__mId);
365 if (errorCode != MM_ERROR_NONE) {
366 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_focus_get_id() err:0x%x", errorCode);
369 // Register focus callback
370 errorCode = mm_sound_register_focus_for_session(__mId,
372 __mAudioSession == EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE ? __STREAM_TYPE_TABLE_IN[index].name : __STREAM_TYPE_TABLE_OUT[index].name,
373 __sound_pcm_focus_cb,
374 static_cast<void*>(this));
375 if (errorCode != MM_ERROR_NONE) {
376 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_register_focus_for_session() err:0x%x", errorCode);
379 if (__isFocusDisableReacquisitionRequired(__mMultimediaSession, __mOptions)) {
380 errorCode = mm_sound_set_focus_reacquisition_for_session(__mId, false);
381 if (errorCode != MM_ERROR_NONE) {
382 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_reacquisition() err:0x%x", errorCode);
388 AUDIO_IO_LOGD("Focus callback registered successfully [id:%d]", __mId);
389 } else if (!(__mOptions & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
390 // Register focus watch callback
391 errorCode = mm_sound_set_focus_watch_callback_for_session(getpid(), FOCUS_FOR_BOTH, __sound_pcm_focus_watch_cb, static_cast<void*>(this), &__mId);
393 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_set_focus_watch_callback_for_session() err:0x%x", errorCode);
398 AUDIO_IO_LOGD("Focus watch callback registered successfully [id:%d]", __mId);
403 void CAudioSessionHandler::unregisterSound() throw(CAudioError) {
404 if (__mIsInit == false) {
405 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
408 if (__mUseFocus == true && __mId >= 0) {
411 if (__isFocusRequired(__mMultimediaSession, __mOptions)) {
412 // Unregister focus callback
413 errorCode = mm_sound_unregister_focus(__mId);
414 if (errorCode != MM_ERROR_NONE) {
415 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unregister_focus() err:0x%x", errorCode);
420 AUDIO_IO_LOGD("Focus callback unregistered successfully [id:%d]", __mId);
422 } else if (!(__mOptions & MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
423 // Unregister focus watch callback.
424 errorCode = mm_sound_unset_focus_watch_callback(__mId);
426 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_unset_focus_watch_callback() err:0x%x", errorCode);
431 AUDIO_IO_LOGD("Focus watch callback unregistered successfully [id:%d]", __mId);
434 __mAcquiredFocus = FOCUS_NONE;
438 void CAudioSessionHandler::updatePlaying() throw(CAudioError) {
439 if (__mIsInit == false) {
440 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
443 if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
445 int ret = MM_ERROR_NONE;
447 if (__mAcquiredFocus == FOCUS_FOR_BOTH) {
448 AUDIO_IO_LOGW("Focus was already acquired, skip it...");
451 focus_type |= (FOCUS_FOR_BOTH & ~__mAcquiredFocus);
452 if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
453 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 */
455 ret = mm_sound_acquire_focus(__mId, (mm_sound_focus_type_e)focus_type, "audio-io acquire focus");
456 if (ret != MM_ERROR_NONE) {
457 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_POLICY_BLOCKED, "Failed mm_sound_acquire_focus() err:0x%x", ret);
459 __mAcquiredFocus = FOCUS_FOR_BOTH;
460 AUDIO_IO_LOGD("Focus acquired successfully [id:%d]", __mId);
465 void CAudioSessionHandler::updateStop() throw(CAudioError) {
466 if (__mIsInit == false) {
467 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioSessionHandler");
470 if (__mUseFocus && __isFocusRequired(__mMultimediaSession, __mOptions)) {
472 int ret = MM_ERROR_NONE;
473 if (__mAcquiredFocus == FOCUS_NONE) {
474 AUDIO_IO_LOGW("Focus was already released, skip it...");
477 if (__mMultimediaSession == MM_SESSION_TYPE_MEDIA)
478 ret = mm_sound_release_focus_with_option(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, 1, "audio-io release focus"); /* option: 1 for no-resume */
480 ret = mm_sound_release_focus(__mId, (mm_sound_focus_type_e)__mAcquiredFocus, "audio-io release focus");
481 if (ret != MM_ERROR_NONE) {
482 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed mm_sound_release_focus() err:0x%x", ret);
484 __mAcquiredFocus = FOCUS_NONE;
485 AUDIO_IO_LOGD("Focus released successfully [id:%d]", __mId);
490 void CAudioSessionHandler::disableSessionHandler() throw(CAudioError) {
491 CAudioSessionHandler::updateStop();
492 CAudioSessionHandler::unregisterSound();
494 CAudioSessionHandler::__mUseFocus = false;
498 * class IAudioSessionEventListener
500 IAudioSessionEventListener::EInterruptCode IAudioSessionEventListener::convertInterruptedCode(int code, const char *reason_for_change) {
501 EInterruptCode e = EInterruptCode::INTERRUPT_BY_MEDIA;
504 case FOCUS_IS_ACQUIRED:
505 e = EInterruptCode::INTERRUPT_COMPLETED;
508 case FOCUS_IS_RELEASED:
509 if (!strcmp(reason_for_change, "media")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
510 if (!strcmp(reason_for_change, "radio")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
511 if (!strcmp(reason_for_change, "loopback")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
512 if (!strcmp(reason_for_change, "system")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
513 if (!strcmp(reason_for_change, "alarm")) e = EInterruptCode::INTERRUPT_BY_ALARM;
514 if (!strcmp(reason_for_change, "notification")) e = EInterruptCode::INTERRUPT_BY_NOTIFICATION;
515 if (!strcmp(reason_for_change, "emergency")) e = EInterruptCode::INTERRUPT_BY_EMERGENCY;
516 if (!strcmp(reason_for_change, "voice-information")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
517 if (!strcmp(reason_for_change, "voice-recognition")) e = EInterruptCode::INTERRUPT_BY_MEDIA;
518 if (!strcmp(reason_for_change, "ringtone-voip")) e = EInterruptCode::INTERRUPT_BY_CALL;
519 if (!strcmp(reason_for_change, "ringtone-call")) e = EInterruptCode::INTERRUPT_BY_CALL;
520 if (!strcmp(reason_for_change, "voip")) e = EInterruptCode::INTERRUPT_BY_CALL;
521 if (!strcmp(reason_for_change, "call-voice")) e = EInterruptCode::INTERRUPT_BY_CALL;
522 if (!strcmp(reason_for_change, "call-video")) e = EInterruptCode::INTERRUPT_BY_CALL;