X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcpp%2FCAudioOutput.cpp;h=96b7531eb3daaa593bf8e5b54c36325103ff3aa2;hb=907fc08da90dfa673c95794b5bf7b7980e8c3d76;hp=396b4f1cb31c23a9e540aa1aa12008c505de005f;hpb=aae671cb5d6dcc26137b13873182ff83802d0de0;p=platform%2Fcore%2Fapi%2Faudio-io.git diff --git a/src/cpp/CAudioOutput.cpp b/src/cpp/CAudioOutput.cpp index 396b4f1..96b7531 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,300 +71,224 @@ 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) { - 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); - 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); - 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; - } try { 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"); - } - - // Initialize ASM Handler - mpAudioSessionHandler->initialize(); - - setInit(true); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); - } catch (CAudioError err) { + __setInit(true); + } catch (CAudioError& e) { finalize(); - throw err; + throw; } + + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); } void CAudioOutput::finalize() { - if (IsInit() == false) { + if (__IsInit() == false) { AUDIO_IO_LOGD("Did not initialize"); return; } - SAFE_FINALIZE(mpAudioSessionHandler); - SAFE_DELETE(mpAudioSessionHandler); - 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 - AUDIO_IO_LOGD("Register ASM Listener"); - mpAudioSessionHandler->registerSound(); - } + 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; } - - // Init StreamSpec - AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID"); - CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID; +#endif CPulseStreamSpec spec(streamSpec, mAudioInfo); - // 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"); - } - - // Initialize PulseAudio Handler + internalLock(); + mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK, spec, this); mpPulseAudioClient->initialize(); - - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - /* Updates ASM to PLAYING */ - mpAudioSessionHandler->updatePlaying(); - } - +#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 e; + throw; + } catch (const std::bad_alloc&) { +//LCOV_EXCL_START + internalUnlock(); + THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object"); +//LCOV_EXCL_STOP } } -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 { - CAudioIO::unprepare(); + CAudioIO::unprepare(); + try { internalLock(); - + if (mpPulseAudioClient && mpPulseAudioClient->isInThread()) + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't unprepare inside pulseaudio thread"); 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(); - - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE); - } catch (CAudioError e) { + } 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"); - } - - try { - CAudioIO::pause(); + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE); +} - internalLock(); +void CAudioOutput::pause() { + if (__IsInit() == false || __IsReady() == false) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); - /* Updates ASM to STOP */ - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { - mpAudioSessionHandler->updateStop(); - } + 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"); - internalUnlock(); + if (mpPulseAudioClient->isInThread() == true) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't pause in thread"); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED); - } catch (CAudioError e) { - internalUnlock(); - throw e; - } + CAudioIO::pause(); + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED); } -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 (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED) + THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, + "Can't resume if not in Paused state"); - if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) { + if (mpPulseAudioClient->isInThread() == true) + THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't resume in thread"); - /* Updates ASM to PLAYING */ - mpAudioSessionHandler->updatePlaying(); - } - - internalUnlock(); - - CAudioIO::resume(); - CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING); - } catch (CAudioError e) { - internalUnlock(); - throw e; - } + CAudioIO::resume(); + CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING); } -void CAudioOutput::drain() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput"); - } - - try { - CAudioIO::drain(); - } catch (CAudioError e) { - internalUnlock(); - throw e; - } -} +void CAudioOutput::drain() { + if (__IsInit() == false || __IsReady() == false) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); -void CAudioOutput::flush() throw (CAudioError) { - if (IsInit() == false || IsReady() == false) { - THROW_ERROR_MSG(CAudioError::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::flush(); - } catch (CAudioError e) { - internalUnlock(); - throw e; - } + CAudioIO::drain(); } -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; - } +void CAudioOutput::flush() { + if (__IsInit() == false || __IsReady() == false) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); - int size = 0; + CAudioIO::flush(); +} - try { - internalLock(); - size = mpPulseAudioClient->getBufferSize(); - internalUnlock(); - } catch (CAudioError err) { - internalUnlock(); - throw err; - } +int CAudioOutput::getBufferSize() { + if (__IsInit() == false) + THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, + "Did not initialize or prepare CAudioOutput"); - 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:%d", buffer, length); - } + if (buffer == NULL) + 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); +#ifdef _AUDIO_IO_DEBUG_TIMING_ + AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%d)", buffer, length); +#endif + return length; } - /* For synchronization */ - internalLock(); + try { + /* For synchronization */ + internalLock(); - // Sets synchronous flag - mIsUsedSyncWrite = true; + // 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; - size_t lengthIter = length; - try { while (lengthIter > 0) { size_t l; @@ -368,32 +299,31 @@ size_t CAudioOutput::write(const void* buffer, size_t length) throw (CAudioError internalWait(); } - if (l > lengthIter) { + if (l > lengthIter) l = lengthIter; - } #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(); - throw e; - } - // Unsets synchronous flag - mIsUsedSyncWrite = false; - internalUnlock(); + sched_yield(); + } catch (CAudioError& e) { + __mIsUsedSyncWrite = false; + internalUnlock(); + throw; + } return length; }