#include <mm.h>
#include <pthread.h>
#include <assert.h>
+#include <glib.h>
#include "CAudioIODef.h"
-#define AUDIO_IO_DEBUG
-
using namespace std;
using namespace tizen_media_audio;
mpAudioSessionHandler(NULL),
mpPulseAudioClient(NULL),
__mMutex(PTHREAD_MUTEX_INITIALIZER),
+ __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
__mCond(PTHREAD_COND_INITIALIZER),
__mIsInit(false),
__mForceIgnore(false) {
+ mInterruptCode = IAudioSessionEventListener::EInterruptCode::INTERRUPT_MAX;
+ mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
mByPolicy = false;
+ mIsInterrupted = false;
}
CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
mpAudioSessionHandler(NULL),
mpPulseAudioClient(NULL),
__mMutex(PTHREAD_MUTEX_INITIALIZER),
+ __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
__mCond(PTHREAD_COND_INITIALIZER),
__mIsInit(false),
__mForceIgnore(false) {
mAudioInfo = audioInfo;
+ mInterruptCode = IAudioSessionEventListener::EInterruptCode::INTERRUPT_MAX;
+ mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
mByPolicy = false;
+ mIsInterrupted = false;
}
CAudioIO::~CAudioIO() {
return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)? true : false);
}
-void CAudioIO::internalLock() throw (CAudioError) {
+void CAudioIO::internalLock() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
if (pthread_mutex_lock(&__mMutex) != 0) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
}
+
#ifdef _AUDIO_IO_DEBUG_TIMING_
- AUDIO_IO_LOGD(COLOR_RED "LOCK" COLOR_END);
+ AUDIO_IO_LOGD(COLOR_RED "%p LOCKED" COLOR_END, &__mMutex);
#endif
}
-void CAudioIO::internalUnlock() throw (CAudioError) {
+void CAudioIO::internalUnlock() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
}
#ifdef _AUDIO_IO_DEBUG_TIMING_
- AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK" COLOR_END);
+ AUDIO_IO_LOGD(COLOR_GREEN "%p UNLOCKED" COLOR_END, &__mMutex);
#endif
}
-void CAudioIO::internalWait() throw (CAudioError) {
+void CAudioIO::internalWait() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
#endif
- pthread_cond_wait(&__mCond, &__mMutex);
+ pthread_mutex_lock(&__mCondMutex);
+ pthread_cond_wait(&__mCond, &__mCondMutex);
+ pthread_mutex_unlock(&__mCondMutex);
}
-void CAudioIO::internalSignal() throw (CAudioError) {
+void CAudioIO::internalSignal() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
#endif
+ pthread_mutex_lock(&__mCondMutex);
pthread_cond_signal(&__mCond);
+ pthread_mutex_unlock(&__mCondMutex);
}
bool CAudioIO::isForceIgnore() {
return __mForceIgnore;
}
-void CAudioIO::initialize() throw (CAudioError) {
+void CAudioIO::initialize() {
if (__mIsInit == true) {
return;
}
AUDIO_IO_LOGD("finalize");
+ bool error_occured = false;
int ret = pthread_mutex_destroy(&__mMutex);
if (ret != 0) {
- THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret);
+ AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mMutex, ret);
+ error_occured = true;
+ }
+ ret = pthread_mutex_destroy(&__mCondMutex);
+ if (ret != 0) {
+ AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret);
+ error_occured = true;
}
+
ret = pthread_cond_destroy(&__mCond);
if (ret != 0) {
- THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret);
+ AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret);
+ error_occured = true;
}
+ if (error_occured)
+ THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed");
+
__mIsInit = false;
}
mState = state;
mByPolicy = byPolicy;
- AUDIO_IO_LOGD("current(%d), previous(%d), by_policy(%d)", mState, mStatePrev, mByPolicy);
+ if (mState == mStatePrev)
+ return;
+
+ const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
+
+ AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
+ state_string[static_cast<int>(mStatePrev)],
+ static_cast<int>(mStatePrev),
+ state_string[static_cast<int>(mState)],
+ static_cast<int>(mState),
+ mByPolicy);
if (mStateChangedCallback.onStateChanged != NULL) {
mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
onStateChanged(state, false);
}
-void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) {
+CAudioInfo::EAudioIOState CAudioIO::getState() {
+ return mState;
+}
+
+int CAudioIO::sendInterrupt(void* user_data) {
+ CAudioIO *pCaudioIo = (CAudioIO *)user_data;
+
+ if (pCaudioIo && pCaudioIo->mInterruptCallback.onInterrupt) {
+ AUDIO_IO_LOGD("sending interrupt [%d]", static_cast<int>(pCaudioIo->mInterruptCode));
+ pCaudioIo->mInterruptCallback.onInterrupt(pCaudioIo->mInterruptCode, pCaudioIo->mInterruptCallback.mUserData);
+ }
+ return 0;
+}
+
+int caudio_gsource_callback(void *user_data) {
+ CAudioIO::sendInterrupt(user_data);
+ return 0;
+}
+
+void CAudioIO::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type,
+ mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info) {
assert(pHandler);
int session_option = pHandler->getOptions();
}
if (state == FOCUS_IS_RELEASED) {
- // Focus handle(id) of the other application was released, do resume if possible
- internalLock();
-
- mpPulseAudioClient->cork(false);
- onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
-
- internalUnlock();
-
+ // Focus handle(id) of the other application was released, notify resume
// Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
state = FOCUS_IS_ACQUIRED;
} else if (state == FOCUS_IS_ACQUIRED) {
// Focus handle(id) of the other application was acquired, do pause if possible
internalLock();
-
- if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
- if (mpPulseAudioClient->drain() == false) {
- AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
- }
+ if (mpPulseAudioClient) {
+ mpPulseAudioClient->cork(true);
}
-
- mpPulseAudioClient->cork(true);
- onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
-
+ mIsInterrupted = true;
internalUnlock();
// Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
if (state == FOCUS_IS_RELEASED) {
// Focus handle(id) was released, do pause here
internalLock();
-
- if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
- if (mpPulseAudioClient->drain() == false) {
- AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
- }
+ if (mpPulseAudioClient) {
+ mpPulseAudioClient->cork(true);
}
- mpPulseAudioClient->cork(true);
- onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
-
+ mIsInterrupted = true;
internalUnlock();
} else if (state == FOCUS_IS_ACQUIRED) {
// Focus handle(id) was acquired again,
// check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...)
// do resume here and call interrupt completed callback to application.
- internalLock();
-
- mpPulseAudioClient->cork(false);
- onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
-
- internalUnlock();
}
}
if (mInterruptCallback.onInterrupt != NULL) {
IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::EInterruptCode::INTERRUPT_COMPLETED;
e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change);
- mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
+
+ if (EInterruptCode::INTERRUPT_COMPLETED == e) {
+ mInterruptCode = e;
+ g_idle_add(caudio_gsource_callback, this);
+ } else {
+ mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
+ }
}
}
assert(pHandler);
if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
- if (value == 1 && pHandler->getSubscribeId() >= 0) {
+ if (value == 1 && pHandler->getSubscribeId() > 0) {
// Unregister focus watch callback & disable session handler
pHandler->disableSessionHandler();
AUDIO_IO_LOGD("Session handler disabled by signal");
}
}
-void CAudioIO::prepare() throw (CAudioError) {
+void CAudioIO::prepare() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
-
+ if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN) {
+ AUDIO_IO_LOGD("Prepare for Audio in");
+ } else if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_OUT) {
+ AUDIO_IO_LOGD("Prepare for Audio Out");
+ }
try {
- AUDIO_IO_LOGD("prepare");
+ if (mIsInterrupted) {
+ AUDIO_IO_LOGE("This is preparing during interrupted!!!");
+ bool isSkip = mpAudioSessionHandler->isSkipSession();
+ if (__mForceIgnore == false && isSkip == false && mpAudioSessionHandler->getId() >= 0) {
+ AUDIO_IO_LOGE("Session updatePlaying!!!");
+ mpAudioSessionHandler->updatePlaying();
+ }
+
+ if (mpPulseAudioClient && mpPulseAudioClient->isCorked()) {
+ AUDIO_IO_LOGE("Uncork!");
+ mpPulseAudioClient->cork(false);
+ }
+ mIsInterrupted = false;
+ }
+
+ AUDIO_IO_LOGD("------> prepare done");
/* Do nothing */
- } catch (CAudioError e) {
- throw e;
+ } catch (CAudioError& e) {
+ throw;
}
}
-void CAudioIO::unprepare() throw (CAudioError) {
+void CAudioIO::unprepare() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
try {
- AUDIO_IO_LOGD("unprepare");
+ AUDIO_IO_LOGD("unprepare ----->");
/* Do nothing */
- } catch (CAudioError e) {
- throw e;
+ } catch (CAudioError& e) {
+ throw;
}
}
-void CAudioIO::pause() throw (CAudioError) {
+void CAudioIO::pause() {
if (__mIsInit == false || IsReady() == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
}
AUDIO_IO_LOGD("pause");
mpPulseAudioClient->cork(true);
internalUnlock();
- } catch (CAudioError e) {
+ } catch (CAudioError& e) {
internalUnlock();
- throw e;
+ throw;
}
}
-void CAudioIO::resume() throw (CAudioError) {
+void CAudioIO::resume() {
if (__mIsInit == false || IsReady() == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
}
AUDIO_IO_LOGD("resume");
mpPulseAudioClient->cork(false);
internalUnlock();
- } catch (CAudioError e) {
+ } catch (CAudioError& e) {
internalUnlock();
- throw e;
+ throw;
}
}
-void CAudioIO::drain() throw (CAudioError) {
+void CAudioIO::drain() {
if (__mIsInit == false || IsReady() == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
}
try {
- internalLock();
- AUDIO_IO_LOGD("drain");
- mpPulseAudioClient->drain();
- internalUnlock();
- } catch (CAudioError e) {
- internalUnlock();
- throw e;
+ if (mpPulseAudioClient->isInThread()) {
+ mpPulseAudioClient->drain();
+ } else {
+ internalLock();
+ mpPulseAudioClient->drain();
+ internalUnlock();
+ }
+ } catch (CAudioError& e) {
+ if (!mpPulseAudioClient->isInThread()) {
+ internalUnlock();
+ }
+ throw;
}
}
-void CAudioIO::flush() throw (CAudioError) {
+void CAudioIO::flush() {
if (__mIsInit == false || IsReady() == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
}
try {
- internalLock();
- AUDIO_IO_LOGD("flush");
- mpPulseAudioClient->flush();
- internalUnlock();
- } catch (CAudioError e) {
- internalUnlock();
- throw e;
+ if (mpPulseAudioClient->isInThread()) {
+ mpPulseAudioClient->flush();
+ } else {
+ internalLock();
+ mpPulseAudioClient->flush();
+ internalUnlock();
+ }
+ } catch (CAudioError& e) {
+ if (!mpPulseAudioClient->isInThread()) {
+ internalUnlock();
+ }
+ throw;
}
}
-CAudioInfo& CAudioIO::getAudioInfo() throw (CAudioError) {
+CAudioInfo& CAudioIO::getAudioInfo() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
return mAudioInfo;
}
-void CAudioIO::setStreamCallback(SStreamCallback callback) throw (CAudioError) {
+void CAudioIO::setStreamCallback(SStreamCallback callback) {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
mStreamCallback = callback;
}
-CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw (CAudioError) {
+CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
return mStreamCallback;
}
-void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError) {
+void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
mStateChangedCallback = callback;
}
-CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw (CAudioError) {
+CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
return mStateChangedCallback;
}
-void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw (CAudioError) {
+void CAudioIO::setInterruptCallback(SInterruptCallback callback) {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
mInterruptCallback = callback;
}
-CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw (CAudioError) {
+CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() {
if (__mIsInit == false) {
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
}
return mInterruptCallback;
}
-
-void CAudioIO::ignoreSession() throw (CAudioError) {
- if (__mIsInit == false) {
+void CAudioIO::ignoreSession() {
+ if (__mIsInit == false)
THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
- }
try {
internalLock();
- if (mpPulseAudioClient != NULL && mpPulseAudioClient->isCorked() == false) {
+ if (mpPulseAudioClient != NULL && mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING)
THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started");
- }
- bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
- if (isSkip == false && mpAudioSessionHandler->getId() >= 0) {
- mpAudioSessionHandler->unregisterSound();
- __mForceIgnore = true;
- }
+ abandonInternalFocus();
internalUnlock();
- } catch (CAudioError e) {
+ } catch (CAudioError& e) {
internalUnlock();
- throw e;
+ throw;
+ }
+}
+
+void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
+ if (stream_info == NULL)
+ THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL");
+
+ if (__mIsInit == false)
+ THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
+
+ try {
+ if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
+ THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started");
+
+ abandonInternalFocus();
+
+ int errorCode = SOUND_MANAGER_ERROR_NONE;
+ CAudioInfo::EAudioType audioType = CAudioInfo::EAudioType::AUDIO_IN_TYPE_MEDIA;
+ char *type = NULL;
+ int index = -1;
+ bool avail = false;
+
+ if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
+ THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode);
+
+ if (!avail)
+ THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported");
+
+ if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
+ THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode);
+
+ if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
+ getAudioInfo().convertInputStreamType2AudioType(type, &audioType);
+ else
+ getAudioInfo().convertOutputStreamType2AudioType(type, &audioType);
+ getAudioInfo().setAudioType(audioType);
+
+ if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
+ THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode);
+
+ getAudioInfo().setAudioIndex(index);
+
+ AUDIO_IO_LOGD("stream info(%p) is set", stream_info);
+ } catch (CAudioError& e) {
+ throw;
+ }
+}
+
+void CAudioIO::setInternalStreamInfo() {
+ if (__mIsInit == false)
+ THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
+
+ try {
+ if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
+ THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started");
+
+ if (mpAudioSessionHandler &&
+ mpAudioSessionHandler->getMultimediaSession() == MM_SESSION_TYPE_VOIP) {
+ sound_stream_info_h stream_info = NULL;
+ mpAudioSessionHandler->getInternalVoipStreamInfo(&stream_info);
+ AUDIO_IO_LOGD("get internal VOIP stream info(%p)", stream_info);
+ setStreamInfo(stream_info);
+ }
+ } catch (CAudioError& e) {
+ throw;
+ }
+}
+
+void CAudioIO::abandonInternalFocus() {
+ bool isSkip = mpAudioSessionHandler->isSkipSession();
+ int id = mpAudioSessionHandler->getId();
+
+ try {
+ if (isSkip == false && id >= 0)
+ mpAudioSessionHandler->unregisterSound();
+
+ mpAudioSessionHandler->finalize();
+ __mForceIgnore = true;
+ } catch (CAudioError& e) {
+ throw;
}
}