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();
265 CAudioIO::onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
266 } catch (CAudioError e) {
272 void CAudioOutput::drain() throw (CAudioError) {
273 if (IsInit() == false || IsReady() == false) {
274 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
279 } 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) {
298 int CAudioOutput::getBufferSize() throw (CAudioError) {
299 if (IsInit() == false) {
300 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
303 if (IsReady() == false) {
304 AUDIO_IO_LOGD("Warning: Did not prepare CAudioOutput, then return zero");
312 size = mpPulseAudioClient->getBufferSize();
314 } catch (CAudioError err) {
322 int CAudioOutput::write(const void* buffer, unsigned int length) throw (CAudioError) {
323 if (IsInit() == false || IsReady() == false) {
324 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
327 if (buffer == NULL) {
328 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%d", buffer, length);
332 * Check skip condition.
333 * If accessibility screen reader (VOICE type with NoSession), no need to check, always do write.
335 if (mpAudioSessionHandler->isSkipSessionEvent() == false) {
336 /* Check whether voicerecorder is running */
339 vconf_get_int(VCONFKEY_RECORDER_STATE, &vrState);
340 if (vrState == VCONFKEY_RECORDER_STATE_RECORDING) {
341 THROW_ERROR_MSG(CAudioError::ERROR_POLICY_BLOCKED, "During Voicerecording --> MUTE");
345 /* When write() is called in PulseAudio callback, bypass a pcm data to PulseAudioClient (For Asynchronous) */
346 if (mpPulseAudioClient->isInThread() == true) {
347 int ret = mpPulseAudioClient->write(buffer, length);
353 /* For synchronization */
356 // Sets synchronous flag
357 mIsUsedSyncWrite = true;
359 unsigned int lengthIter = length;
361 while (lengthIter > 0) {
364 while ((l = mpPulseAudioClient->getWritableSize()) == 0) {
365 #ifdef _AUDIO_IO_DEBUG_TIMING_
366 AUDIO_IO_LOGD("writableSize is [%d].. wait", l);
372 THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "The Writable size is invalid");
375 if (static_cast<unsigned int>(l) > lengthIter) {
379 #ifdef _AUDIO_IO_DEBUG_TIMING_
380 AUDIO_IO_LOGD("PulseAudioClient->write(buffer:%p, length:%d)", buffer, l);
383 r = mpPulseAudioClient->write(buffer, l);
385 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", r);
388 buffer = static_cast<const uint8_t*>(buffer) + l;
390 }//end of while (length > 0)
391 } catch (CAudioError e) {
392 // Unsets synchronous flag
393 mIsUsedSyncWrite = false;
398 // Unsets synchronous flag
399 mIsUsedSyncWrite = false;