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) :
30 __mIsUsedSyncWrite(false),
34 CAudioOutput::CAudioOutput(
35 unsigned int sampleRate,
36 CAudioInfo::EChannel channel,
37 CAudioInfo::ESampleType sampleType,
38 CAudioInfo::EAudioType audioType) :
39 __mIsUsedSyncWrite(false),
41 mAudioInfo = CAudioInfo(sampleRate, channel, sampleType, audioType, -1);
44 CAudioOutput::~CAudioOutput() {
47 void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) {
51 * Does not call CAudioIO::onStream() for synchronization
52 * if a user is using write()
54 if (__mIsUsedSyncWrite == true) {
55 #ifdef _AUDIO_IO_DEBUG_TIMING_
56 AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%d]", pClient, length);
63 * Accrues callback function
65 #ifdef _AUDIO_IO_DEBUG_TIMING_
66 AUDIO_IO_LOGD("pClient:[%p], length:[%d]", pClient, length);
68 CAudioIO::onStream(pClient, length);
71 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) {
73 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);
74 CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
77 void CAudioOutput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
79 AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value);
80 CAudioIO::onSignal(pHandler, signal, value);
83 void CAudioOutput::__setInit(bool flag) {
87 bool CAudioOutput::__IsInit() {
88 return (CAudioIO::isInit() == true && __mIsInit == true);
91 bool CAudioOutput::__IsReady() {
92 return CAudioIO::IsReady();
95 void CAudioOutput::initialize() throw(CAudioError) {
96 if (__IsInit() == true) {
101 CAudioIO::initialize();
103 // Create ASM Handler
104 mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::EAudioSessionType::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this);
105 if (mpAudioSessionHandler == NULL) {
106 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CAudioSessionHandler object");
109 // Initialize ASM Handler
110 mpAudioSessionHandler->initialize();
113 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
114 } catch (CAudioError err) {
120 void CAudioOutput::finalize() {
121 if (__IsInit() == false) {
122 AUDIO_IO_LOGD("Did not initialize");
126 SAFE_FINALIZE(mpAudioSessionHandler);
127 SAFE_DELETE(mpAudioSessionHandler);
129 CAudioIO::finalize();
134 void CAudioOutput::prepare() throw(CAudioError) {
135 if (__IsInit() == false) {
136 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
139 if (__IsReady() == true) {
140 AUDIO_IO_LOGD("Already prepared CAudioOutput");
147 // Check to invalid AudioType
148 CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType();
149 if (audioType < CAudioInfo::EAudioType::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::EAudioType::AUDIO_TYPE_MAX) {
150 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "The audioType is invalid [type:%d]", static_cast<int>(audioType));
153 if (mpAudioSessionHandler->getId() < 0) { //Did not registerSound()
154 if (isForceIgnore() == false) {
155 // Register ASM Listener
156 AUDIO_IO_LOGD("Register ASM Listener");
157 mpAudioSessionHandler->registerSound();
162 AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_MID");
163 CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_MID;
164 CPulseStreamSpec spec(streamSpec, mAudioInfo);
166 // Create PulseAudio Handler
167 mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK, spec, this);
168 if (mpPulseAudioClient == NULL) {
169 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object");
172 // Initialize PulseAudio Handler
173 mpPulseAudioClient->initialize();
175 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
176 /* Updates ASM to PLAYING */
177 mpAudioSessionHandler->updatePlaying();
183 } catch (CAudioError e) {
189 void CAudioOutput::unprepare() throw(CAudioError) {
190 if (__IsInit() == false) {
191 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
194 if (__IsReady() == false) {
195 AUDIO_IO_LOGD("Already unprepared");
200 CAudioIO::unprepare();
204 SAFE_FINALIZE(mpPulseAudioClient);
205 SAFE_DELETE(mpPulseAudioClient);
207 if (mpAudioSessionHandler->getId() >= 0) {
208 /* Updates ASM to STOP */
209 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
210 mpAudioSessionHandler->updateStop();
213 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
214 if (isSkip == false) {
215 mpAudioSessionHandler->unregisterSound();
221 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
222 } catch (CAudioError e) {
228 void CAudioOutput::pause() throw(CAudioError) {
229 if (__IsInit() == false || __IsReady() == false) {
230 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
238 /* Updates ASM to STOP */
239 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
240 mpAudioSessionHandler->updateStop();
245 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
246 } catch (CAudioError e) {
252 void CAudioOutput::resume() throw(CAudioError) {
253 if (__IsInit() == false || __IsReady() == false) {
254 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
260 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSessionEvent() == false) {
261 /* Updates ASM to PLAYING */
262 mpAudioSessionHandler->updatePlaying();
269 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
270 } catch (CAudioError e) {
276 void CAudioOutput::drain() throw(CAudioError) {
277 if (__IsInit() == false || __IsReady() == false) {
278 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
283 } catch (CAudioError e) {
288 void CAudioOutput::flush() throw(CAudioError) {
289 if (__IsInit() == false || __IsReady() == false) {
290 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
295 } catch (CAudioError e) {
300 int CAudioOutput::getBufferSize() throw(CAudioError) {
301 if (__IsInit() == false) {
302 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
305 if (__IsReady() == false) {
306 AUDIO_IO_LOGD("Warning: Did not prepare CAudioOutput, then return zero");
313 size = mpPulseAudioClient->getBufferSize();
314 } catch (CAudioError err) {
321 size_t CAudioOutput::write(const void* buffer, size_t length) throw(CAudioError) {
322 if (__IsInit() == false || __IsReady() == false) {
323 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioOutput");
326 if (buffer == NULL) {
327 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameters are invalid - buffer:%p, length:%zu", buffer, length);
330 /* When write() is called in PulseAudio callback, bypass a pcm data to PulseAudioClient (For Asynchronous) */
331 if (mpPulseAudioClient->isInThread() == true) {
332 int ret = mpPulseAudioClient->write(buffer, length);
334 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", ret);
340 /* For synchronization */
343 // Sets synchronous flag
344 __mIsUsedSyncWrite = true;
346 size_t lengthIter = length;
348 while (lengthIter > 0) {
351 while ((l = mpPulseAudioClient->getWritableSize()) == 0) {
352 #ifdef _AUDIO_IO_DEBUG_TIMING_
353 AUDIO_IO_LOGD("writableSize is [%d].. wait", l);
358 if (l > lengthIter) {
362 #ifdef _AUDIO_IO_DEBUG_TIMING_
363 AUDIO_IO_LOGD("PulseAudioClient->write(buffer:%p, length:%d)", buffer, l);
366 int ret = mpPulseAudioClient->write(buffer, l);
368 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "The written result is invalid ret:%d", ret);
371 buffer = static_cast<const uint8_t*>(buffer) + l;
373 } // End of while (length > 0)
375 // Unsets synchronous flag
376 __mIsUsedSyncWrite = false;
378 } catch (CAudioError e) {
379 // Unsets synchronous flag
380 __mIsUsedSyncWrite = false;