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.
19 #include "CAudioIODef.h"
22 using namespace tizen_media_audio;
28 CAudioOutput::CAudioOutput(CAudioInfo& info) : CAudioIO(info), mIsUsedSyncWrite(false) {
31 CAudioOutput::CAudioOutput(
32 unsigned int sampleRate,
33 CAudioInfo::EChannel channel,
34 CAudioInfo::ESampleType sampleType,
35 CAudioInfo::EAudioType audioType) : mIsUsedSyncWrite(false) {
36 mAudioInfo = CAudioInfo(sampleRate, channel, sampleType, audioType, -1);
39 CAudioOutput::~CAudioOutput() {
43 void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) {
47 * Does not call CAudioIO::onStream() for synchronization
48 * if a user is using write()
50 if (mIsUsedSyncWrite == true) {
51 #ifdef _AUDIO_IO_DEBUG_TIMING_
52 AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%d]", pClient, length);
59 * Accrues callback function
61 #ifdef _AUDIO_IO_DEBUG_TIMING_
62 AUDIO_IO_LOGD("pClient:[%p], length:[%d]", pClient, length);
64 CAudioIO::onStream(pClient, length);
67 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) {
69 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);
70 CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
73 void CAudioOutput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
75 AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value);
76 CAudioIO::onSignal(pHandler, signal, value);
79 void CAudioOutput::setInit(bool flag) {
83 bool CAudioOutput::IsInit() {
84 return (CAudioIO::isInit() == true && mIsInit == true);
87 bool CAudioOutput::IsReady() {
88 return CAudioIO::IsReady();
91 void CAudioOutput::initialize() throw (CAudioError) {
92 if (IsInit() == true) {
97 CAudioIO::initialize();
100 mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this);
101 if (mpAudioSessionHandler == NULL) {
102 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object");
105 // Initialize ASM Handler
106 mpAudioSessionHandler->initialize();
109 CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE);
110 } catch (CAudioError err) {
116 void CAudioOutput::finalize() {
117 if (IsInit() == false) {
118 AUDIO_IO_LOGD("Did not initialize");
122 SAFE_FINALIZE(mpAudioSessionHandler);
123 SAFE_DELETE(mpAudioSessionHandler);
125 CAudioIO::finalize();
130 void CAudioOutput::prepare() throw (CAudioError) {
131 if (IsInit() == false) {
132 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
135 if (IsReady() == true) {
136 AUDIO_IO_LOGD("Already prepared CAudioOutput");
143 // Check to invalid AudioType
144 CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType();
145 if (audioType < CAudioInfo::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::AUDIO_TYPE_MAX) {
146 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [type:%d]", static_cast<int>(audioType));
149 if (mpAudioSessionHandler->getId() < 0) { //Did not registerSound()
150 if (isForceIgnore() == false) {
151 // Register ASM Listener
152 AUDIO_IO_LOGD("Register ASM Listener");
153 mpAudioSessionHandler->registerSound();
158 AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID");
159 CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID;
160 CPulseStreamSpec spec(streamSpec, mAudioInfo);
162 // Create PulseAudio Handler
163 mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::STREAM_DIRECTION_PLAYBACK, spec, this);
164 if (mpPulseAudioClient == NULL) {
165 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object");
168 // Initialize PulseAudio Handler
169 mpPulseAudioClient->initialize();
171 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
172 /* Updates ASM to PLAYING */
173 mpAudioSessionHandler->updatePlaying();
179 } catch (CAudioError e) {
185 void CAudioOutput::unprepare() throw (CAudioError) {
186 if (IsInit() == false) {
187 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
190 if (IsReady() == false) {
191 AUDIO_IO_LOGD("Already unprepared");
196 CAudioIO::unprepare();
200 SAFE_FINALIZE(mpPulseAudioClient);
201 SAFE_DELETE(mpPulseAudioClient);
203 if (mpAudioSessionHandler->getId() >= 0) {
204 /* Updates ASM to STOP */
205 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
206 mpAudioSessionHandler->updateStop();
209 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
210 if (isSkip == false) {
211 mpAudioSessionHandler->unregisterSound();
217 CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_IDLE);
218 } catch (CAudioError e) {
224 void CAudioOutput::pause() throw (CAudioError) {
225 if (IsInit() == false || IsReady() == false) {
226 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
234 /* Updates ASM to STOP */
235 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
236 mpAudioSessionHandler->updateStop();
241 CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED);
242 } catch (CAudioError e) {
248 void CAudioOutput::resume() throw (CAudioError) {
249 if (IsInit() == false || IsReady() == false) {
250 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
256 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
258 /* Updates ASM to PLAYING */
259 mpAudioSessionHandler->updatePlaying();
266 CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
267 } catch (CAudioError e) {
273 void CAudioOutput::drain() throw (CAudioError) {
274 if (IsInit() == false || IsReady() == false) {
275 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
280 } catch (CAudioError e) {
285 void CAudioOutput::flush() throw (CAudioError) {
286 if (IsInit() == false || IsReady() == false) {
287 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
292 } catch (CAudioError e) {
297 int CAudioOutput::getBufferSize() throw (CAudioError) {
298 if (IsInit() == false) {
299 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
302 if (IsReady() == false) {
303 AUDIO_IO_LOGD("Warning: Did not prepare CAudioOutput, then return zero");
310 size = mpPulseAudioClient->getBufferSize();
311 } catch (CAudioError err) {
318 size_t CAudioOutput::write(const void* buffer, size_t length) throw (CAudioError) {
319 if (IsInit() == false || IsReady() == false) {
320 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
323 if (buffer == NULL) {
324 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%zu", buffer, length);
328 * Check skip condition.
329 * If accessibility screen reader (VOICE type with NoSession), no need to check, always do write.
331 if (mpAudioSessionHandler->isSkipSessionEvent() == false) {
332 /* Check whether voicerecorder is running */
335 vconf_get_int(VCONFKEY_RECORDER_STATE, &vrState);
336 if (vrState == VCONFKEY_RECORDER_STATE_RECORDING) {
337 THROW_ERROR_MSG(CAudioError::ERROR_POLICY_BLOCKED, "During Voicerecording --> MUTE");
341 /* When write() is called in PulseAudio callback, bypass a pcm data to PulseAudioClient (For Asynchronous) */
342 if (mpPulseAudioClient->isInThread() == true) {
343 int ret = mpPulseAudioClient->write(buffer, length);
350 /* For synchronization */
353 // Sets synchronous flag
354 mIsUsedSyncWrite = true;
356 size_t lengthIter = length;
358 while (lengthIter > 0) {
361 while ((l = mpPulseAudioClient->getWritableSize()) == 0) {
362 #ifdef _AUDIO_IO_DEBUG_TIMING_
363 AUDIO_IO_LOGD("writableSize is [%d].. wait", l);
368 if (l > lengthIter) {
372 #ifdef _AUDIO_IO_DEBUG_TIMING_
373 AUDIO_IO_LOGD("PulseAudioClient->write(buffer:%p, length:%d)", buffer, l);
376 int r = mpPulseAudioClient->write(buffer, l);
378 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", r);
381 buffer = static_cast<const uint8_t*>(buffer) + l;
383 } // End of while (length > 0)
385 // Unsets synchronous flag
386 mIsUsedSyncWrite = false;
388 } catch (CAudioError e) {
389 // Unsets synchronous flag
390 mIsUsedSyncWrite = false;