X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcpp%2FCAudioOutput.cpp;h=f96f78fdbe9db2336ebd235758ab59af8797c9c5;hb=e80f5c2cd31f1f5c238b6a82849bd31b64107e7b;hp=e42cb286118ec448721df701b48fb00c9132f992;hpb=a742a76e1ce141317c5dbfbb472707801f0d91de;p=platform%2Fcore%2Fapi%2Faudio-io.git diff --git a/src/cpp/CAudioOutput.cpp b/src/cpp/CAudioOutput.cpp index e42cb28..f96f78f 100644 --- a/src/cpp/CAudioOutput.cpp +++ b/src/cpp/CAudioOutput.cpp @@ -15,29 +15,36 @@ */ -#include +#include + #include "CAudioIODef.h" +#include using namespace std; using namespace tizen_media_audio; - /** * class CAudioOutput */ -CAudioOutput::CAudioOutput(CAudioInfo& info) : CAudioIO(info), mIsUsedSyncWrite(false) { +CAudioOutput::CAudioOutput(CAudioInfo& info) : + CAudioIO(info), + __mIsUsedSyncWrite(false), + __mIsInit(false) { + mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_OUT; } CAudioOutput::CAudioOutput( unsigned int sampleRate, CAudioInfo::EChannel channel, CAudioInfo::ESampleType sampleType, - CAudioInfo::EAudioType audioType) : mIsUsedSyncWrite(false) { + CAudioInfo::EAudioType audioType) : + __mIsUsedSyncWrite(false), + __mIsInit(false) { + mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_OUT; mAudioInfo = CAudioInfo(sampleRate, channel, sampleType, audioType, -1); } CAudioOutput::~CAudioOutput() { - } void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) { @@ -47,7 +54,7 @@ void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) { * Does not call CAudioIO::onStream() for synchronization * if a user is using write() */ - if (mIsUsedSyncWrite == true) { + if (__mIsUsedSyncWrite == true) { #ifdef _AUDIO_IO_DEBUG_TIMING_ AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%d]", pClient, length); #endif @@ -64,32 +71,34 @@ void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) { CAudioIO::onStream(pClient, length); } -void CAudioOutput::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) { +void CAudioOutput::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); - AUDIO_IO_LOGD("[pHandler:0x%x], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s]", pHandler, focus_type, state, reason_for_change, additional_info); + AUDIO_IO_LOGD("[pHandler:%p], [focus_type:%d], [state:%d], [reason_for_change:%s], [additional_info:%s]", + pHandler, focus_type, state, reason_for_change, additional_info); CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info); } void CAudioOutput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) { assert(pHandler); - AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value); + AUDIO_IO_LOGD("[pHandler:%p], [signal:%d], [value:%d]", pHandler, signal, value); CAudioIO::onSignal(pHandler, signal, value); } -void CAudioOutput::setInit(bool flag) { - mIsInit = flag; +void CAudioOutput::__setInit(bool flag) { + __mIsInit = flag; } -bool CAudioOutput::IsInit() { - return (CAudioIO::isInit() == true && mIsInit == true); +bool CAudioOutput::__IsInit() { + return (CAudioIO::isInit() == true && __mIsInit == true); } -bool CAudioOutput::IsReady() { +bool CAudioOutput::__IsReady() { return CAudioIO::IsReady(); } -void CAudioOutput::initialize() throw (CAudioError) { - if (IsInit() == true) { +void CAudioOutput::initialize() { + if (__IsInit() == true) { return; } @@ -97,24 +106,24 @@ void CAudioOutput::initialize() throw (CAudioError) { CAudioIO::initialize(); // Create ASM Handler - mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this); - if (mpAudioSessionHandler == NULL) { - THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object"); - } + mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::EAudioSessionType::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this); // Initialize ASM Handler mpAudioSessionHandler->initialize(); - setInit(true); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); - } catch (CAudioError err) { + __setInit(true); + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); + } catch (CAudioError& e) { finalize(); - throw err; + throw; + } catch (const std::bad_alloc&) { + finalize(); + THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object"); } } void CAudioOutput::finalize() { - if (IsInit() == false) { + if (__IsInit() == false) { AUDIO_IO_LOGD("Did not initialize"); return; } @@ -124,75 +133,101 @@ void CAudioOutput::finalize() { CAudioIO::finalize(); - setInit(false); + __setInit(false); } -void CAudioOutput::prepare() throw (CAudioError) { - if (IsInit() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); +void CAudioOutput::prepare() { + if (__IsInit() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); } - if (IsReady() == true) { + if (__IsReady() == true) { AUDIO_IO_LOGD("Already prepared CAudioOutput"); + CAudioIO::prepare(); return; } - try { - internalLock(); - - // Check to invalid AudioType - CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType(); - if (audioType < CAudioInfo::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::AUDIO_TYPE_MAX) { - THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [type:%d]", static_cast(audioType)); - } + /* Check invalid AudioType */ + CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType(); + if (audioType < CAudioInfo::EAudioType::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::EAudioType::AUDIO_TYPE_MAX) { + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, + "The audioType is invalid [type:%d]", static_cast(audioType)); + } - if (mpAudioSessionHandler->getId() < 0) { //Did not registerSound() - if (isForceIgnore() == false) { - // Register ASM Listener + try { + if (mpAudioSessionHandler->getId() < 0) { // Did not registerSound() + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) { + /* Register ASM Listener */ AUDIO_IO_LOGD("Register ASM Listener"); mpAudioSessionHandler->registerSound(); } } - // Init StreamSpec - AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID"); - CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID; - CPulseStreamSpec spec(streamSpec, mAudioInfo); + CAudioIO::setInternalStreamInfo(); - // Create PulseAudio Handler - mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::STREAM_DIRECTION_PLAYBACK, spec, this); - if (mpPulseAudioClient == NULL) { - THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object"); + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) + mpAudioSessionHandler->updatePlaying(); + } catch (CAudioError& e) { + throw; + } + + try { + /* Init StreamSpec */ + CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT; +#ifndef DISABLE_MOBILE_BACK_COMP + if (!mStreamCallback.onStream) { + AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT"); + streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT; + } else { + AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC"); + streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC; } +#endif + CPulseStreamSpec spec(streamSpec, mAudioInfo); - // Initialize PulseAudio Handler - mpPulseAudioClient->initialize(); + internalLock(); - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - /* Updates ASM to PLAYING */ - mpAudioSessionHandler->updatePlaying(); - } + /* Create PulseAudio Handler */ + mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK, spec, this); + /* Initialize PulseAudio Handler */ + mpPulseAudioClient->initialize(); +#ifndef DISABLE_MOBILE_BACK_COMP + /* Uncork stream which is created with CORKED flag */ + mpPulseAudioClient->cork(false); +#endif internalUnlock(); CAudioIO::prepare(); - } catch (CAudioError e) { + } catch (CAudioError& e) { + SAFE_FINALIZE(mpPulseAudioClient); + SAFE_DELETE(mpPulseAudioClient); + internalUnlock(); + throw; + } catch (const std::bad_alloc&) { internalUnlock(); - throw e; + THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object"); } } -void CAudioOutput::unprepare() throw (CAudioError) { - if (IsInit() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); +void CAudioOutput::unprepare() { + if (__IsInit() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize CAudioOutput"); } - if (IsReady() == false) { + if (__IsReady() == false) { AUDIO_IO_LOGD("Already unprepared"); return; } try { + if (mpAudioSessionHandler->getId() >= 0 && !mIsInterrupted) { + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) { + if (mStreamCallback.onStream == NULL) + CAudioIO::drain(); + } + } CAudioIO::unprepare(); internalLock(); @@ -200,164 +235,159 @@ void CAudioOutput::unprepare() throw (CAudioError) { SAFE_FINALIZE(mpPulseAudioClient); SAFE_DELETE(mpPulseAudioClient); - if (mpAudioSessionHandler->getId() >= 0) { - /* Updates ASM to STOP */ - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - mpAudioSessionHandler->updateStop(); - } - - bool isSkip = mpAudioSessionHandler->isSkipSessionEvent(); - if (isSkip == false) { - mpAudioSessionHandler->unregisterSound(); - } - } + internalUnlock(); + } catch (CAudioError& e) { internalUnlock(); + throw; + } - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); - } catch (CAudioError e) { + try { + if (mpAudioSessionHandler->getId() >= 0) { + if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) + mpAudioSessionHandler->updateStop(); + } + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); + } catch (CAudioError& e) { internalUnlock(); - throw e; + throw; } } -void CAudioOutput::pause() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); +void CAudioOutput::pause() { + if (__IsInit() == false || __IsReady() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } - try { - CAudioIO::pause(); - - internalLock(); + if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, + "Can't pause if not in Running state"); + } - /* Updates ASM to STOP */ - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - mpAudioSessionHandler->updateStop(); - } + if (mpPulseAudioClient->isInThread() == true) { + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't pause in thread"); + } - internalUnlock(); + try { + CAudioIO::pause(); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); - } catch (CAudioError e) { - internalUnlock(); - throw e; + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED); + } catch (CAudioError& e) { + throw; } } -void CAudioOutput::resume() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); +void CAudioOutput::resume() { + if (__IsInit() == false || __IsReady() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } - try { - internalLock(); - - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - - /* Updates ASM to PLAYING */ - mpAudioSessionHandler->updatePlaying(); - } + if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, + "Can't resume if not in Paused state"); + } - internalUnlock(); + if (mpPulseAudioClient->isInThread() == true) { + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't resume in thread"); + } + try { CAudioIO::resume(); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); - } catch (CAudioError e) { - internalUnlock(); - throw e; + + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING); + } catch (CAudioError& e) { + throw; } } -void CAudioOutput::drain() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); +void CAudioOutput::drain() { + if (__IsInit() == false || __IsReady() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } + if (mStreamCallback.onStream) + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "async type don't support drain"); + try { CAudioIO::drain(); - } catch (CAudioError e) { - internalUnlock(); - throw e; + } catch (CAudioError& e) { + throw; } } -void CAudioOutput::flush() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); +void CAudioOutput::flush() { + if (__IsInit() == false || __IsReady() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } try { CAudioIO::flush(); - } catch (CAudioError e) { - internalUnlock(); - throw e; + } catch (CAudioError& e) { + throw; } } -int CAudioOutput::getBufferSize() throw (CAudioError) { - if (IsInit() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput"); - } - - if (IsReady() == false) { - AUDIO_IO_LOGD("Warning: Did not prepare CAudioOutput, then return zero"); - return 0; +int CAudioOutput::getBufferSize() { + if (__IsInit() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } - int size = 0; - - try { - internalLock(); - size = mpPulseAudioClient->getBufferSize(); - internalUnlock(); - } catch (CAudioError err) { - internalUnlock(); - throw err; - } - - return size; + /* FIXME : return calculated size here to satisfy backward compatibility */ + return (mAudioInfo.getSampleRate() * DEFAULT_PERIOD_SIZE) / 1000 * mAudioInfo.getSampleSize(); } -size_t CAudioOutput::write(const void* buffer, size_t length) throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); +size_t CAudioOutput::write(const void* buffer, size_t length) { + if (__IsInit() == false || __IsReady() == false) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); } if (buffer == NULL) { - THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%zu", buffer, length); + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, + "Parameters are invalid - buffer:%p, length:%zu", buffer, length); } - - /* - * Check skip condition. - * If accessibility screen reader (VOICE type with NoSession), no need to check, always do write. - */ - if (mpAudioSessionHandler->isSkipSessionEvent() == false) { - /* Check whether voicerecorder is running */ - int vrState = 0; - - vconf_get_int(VCONFKEY_RECORDER_STATE, &vrState); - if (vrState == VCONFKEY_RECORDER_STATE_RECORDING) { - THROW_ERROR_MSG(CAudioError::ERROR_POLICY_BLOCKED, "During Voicerecording --> MUTE"); - } + if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, + "Can't write if not in Running state"); } - /* When write() is called in PulseAudio callback, bypass a pcm data to PulseAudioClient (For Asynchronous) */ - if (mpPulseAudioClient->isInThread() == true) { + /* When write() is called in PulseAudio callback, bypass a pcm data to CPulseAudioClient (For Asynchronous) */ + if (mpPulseAudioClient && mpPulseAudioClient->isInThread() == true) { int ret = mpPulseAudioClient->write(buffer, length); - if (ret == 0) { - return length; + if (ret < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, + "The written result is invalid ret:%d", ret); } - } - /* For synchronization */ - internalLock(); +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%d)", buffer, length); +#endif - // Sets synchronous flag - mIsUsedSyncWrite = true; + return length; + } - size_t lengthIter = length; try { + /* For synchronization */ + internalLock(); + if (mIsInterrupted) { + THROW_ERROR_MSG(CAudioError::EError::ERROR_POLICY_BLOCKED, "audio io is interrupted"); + } + + // If another thread did call unprepare, do not write + if (mpPulseAudioClient == NULL) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize CPulseAudioClient"); + + // Sets synchronous flag + __mIsUsedSyncWrite = true; + + size_t lengthIter = length; + while (lengthIter > 0) { size_t l; @@ -373,27 +403,27 @@ size_t CAudioOutput::write(const void* buffer, size_t length) throw (CAudioError } #ifdef _AUDIO_IO_DEBUG_TIMING_ - AUDIO_IO_LOGD("PulseAudioClient->write(buffer:%p, length:%d)", buffer, l); + AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%d)", buffer, l); #endif - int r = mpPulseAudioClient->write(buffer, l); - if (r < 0) { - THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", r); + int ret = mpPulseAudioClient->write(buffer, l); + if (ret < 0) { + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, + "The written result is invalid ret:%d", ret); } buffer = static_cast(buffer) + l; lengthIter -= l; - }//end of while (length > 0) - } catch (CAudioError e) { - // Unsets synchronous flag - mIsUsedSyncWrite = false; + } // End of while (length > 0) + + __mIsUsedSyncWrite = false; + internalUnlock(); + sched_yield(); + } catch (CAudioError& e) { + __mIsUsedSyncWrite = false; internalUnlock(); - throw e; + throw; } - // Unsets synchronous flag - mIsUsedSyncWrite = false; - internalUnlock(); - return length; }