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.
18 #include "CAudioIODef.h"
22 using namespace tizen_media_audio;
27 CAudioOutput::CAudioOutput(CAudioInfo& info) :
29 __mIsUsedSyncWrite(false),
33 CAudioOutput::CAudioOutput(
34 unsigned int sampleRate,
35 CAudioInfo::EChannel channel,
36 CAudioInfo::ESampleType sampleType,
37 CAudioInfo::EAudioType audioType) :
38 __mIsUsedSyncWrite(false),
40 mAudioInfo = CAudioInfo(sampleRate, channel, sampleType, audioType, -1);
43 CAudioOutput::~CAudioOutput() {
46 void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) {
50 * Does not call CAudioIO::onStream() for synchronization
51 * if a user is using write()
53 if (__mIsUsedSyncWrite == true) {
54 #ifdef _AUDIO_IO_DEBUG_TIMING_
55 AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%d]", pClient, length);
62 * Accrues callback function
64 #ifdef _AUDIO_IO_DEBUG_TIMING_
65 AUDIO_IO_LOGD("pClient:[%p], length:[%d]", pClient, length);
67 CAudioIO::onStream(pClient, length);
70 void CAudioOutput::onInterrupt(CAudioSessionHandler* pHandler, int id, mm_sound_focus_type_e focus_type,
71 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]",
74 pHandler, focus_type, state, reason_for_change, additional_info);
75 CAudioIO::onInterrupt(pHandler, id, focus_type, state, reason_for_change, additional_info);
78 void CAudioOutput::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
80 AUDIO_IO_LOGD("[pHandler:0x%x], [signal:%d], [value:%d]", pHandler, signal, value);
81 CAudioIO::onSignal(pHandler, signal, value);
84 void CAudioOutput::__setInit(bool flag) {
88 bool CAudioOutput::__IsInit() {
89 return (CAudioIO::isInit() == true && __mIsInit == true);
92 bool CAudioOutput::__IsReady() {
93 return CAudioIO::IsReady();
96 void CAudioOutput::initialize() throw(CAudioError) {
97 if (__IsInit() == true) {
102 CAudioIO::initialize();
104 // Create ASM Handler
105 mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::EAudioSessionType::AUDIO_SESSION_TYPE_PLAYBACK, mAudioInfo, this);
106 if (mpAudioSessionHandler == NULL) {
107 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY,
108 "Failed to allocate CAudioSessionHandler object");
111 // Initialize ASM Handler
112 mpAudioSessionHandler->initialize();
115 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
116 } catch (CAudioError err) {
122 void CAudioOutput::finalize() {
123 if (__IsInit() == false) {
124 AUDIO_IO_LOGD("Did not initialize");
128 SAFE_FINALIZE(mpAudioSessionHandler);
129 SAFE_DELETE(mpAudioSessionHandler);
131 CAudioIO::finalize();
136 void CAudioOutput::prepare() throw(CAudioError) {
137 if (__IsInit() == false) {
138 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
141 if (__IsReady() == true) {
142 AUDIO_IO_LOGD("Already prepared CAudioOutput");
149 // Check to invalid AudioType
150 CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType();
151 if (audioType < CAudioInfo::EAudioType::AUDIO_OUT_TYPE_MEDIA || audioType >= CAudioInfo::EAudioType::AUDIO_TYPE_MAX) {
152 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT,
153 "The audioType is invalid [type:%d]", static_cast<int>(audioType));
156 if (mpAudioSessionHandler->getId() < 0) { // Did not registerSound()
157 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false) {
158 // Register ASM Listener
159 AUDIO_IO_LOGD("Register ASM Listener");
160 mpAudioSessionHandler->registerSound();
165 AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT");
166 CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT;
167 CPulseStreamSpec spec(streamSpec, mAudioInfo);
169 // Create PulseAudio Handler
170 mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK, spec, this);
171 if (mpPulseAudioClient == NULL) {
172 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY,
173 "Failed to allocate CPulseAudioClient object");
176 // Initialize PulseAudio Handler
177 mpPulseAudioClient->initialize();
179 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false)
180 mpAudioSessionHandler->updatePlaying();
185 } catch (CAudioError e) {
191 void CAudioOutput::unprepare() throw(CAudioError) {
192 if (__IsInit() == false) {
193 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
194 "Did not initialize CAudioOutput");
197 if (__IsReady() == false) {
198 AUDIO_IO_LOGD("Already unprepared");
203 CAudioIO::unprepare();
207 SAFE_FINALIZE(mpPulseAudioClient);
208 SAFE_DELETE(mpPulseAudioClient);
210 if (mpAudioSessionHandler->getId() >= 0) {
211 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false)
212 mpAudioSessionHandler->updateStop();
214 if (mpAudioSessionHandler->isSkipSession() == false)
215 mpAudioSessionHandler->unregisterSound();
220 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
221 } catch (CAudioError e) {
227 void CAudioOutput::pause() throw(CAudioError) {
228 if (__IsInit() == false || __IsReady() == false) {
229 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
230 "Did not initialize or prepare CAudioOutput");
233 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING) {
234 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE,
235 "Can't pause if not in Running state");
238 if (mpPulseAudioClient->isInThread() == true) {
239 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't pause in thread");
247 /* Updates ASM to STOP */
248 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false)
249 mpAudioSessionHandler->updateStop();
253 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
254 } catch (CAudioError e) {
260 void CAudioOutput::resume() throw(CAudioError) {
261 if (__IsInit() == false || __IsReady() == false) {
262 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
263 "Did not initialize or prepare CAudioOutput");
266 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED) {
267 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE,
268 "Can't resume if not in Paused state");
271 if (mpPulseAudioClient->isInThread() == true) {
272 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't resume in thread");
278 if (isForceIgnore() == false && mpAudioSessionHandler->isSkipSession() == false)
279 mpAudioSessionHandler->updatePlaying();
285 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
286 } catch (CAudioError e) {
292 void CAudioOutput::drain() throw(CAudioError) {
293 if (__IsInit() == false || __IsReady() == false) {
294 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
295 "Did not initialize or prepare CAudioOutput");
300 } catch (CAudioError e) {
305 void CAudioOutput::flush() throw(CAudioError) {
306 if (__IsInit() == false || __IsReady() == false) {
307 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
308 "Did not initialize or prepare CAudioOutput");
313 } catch (CAudioError e) {
318 int CAudioOutput::getBufferSize() throw(CAudioError) {
319 if (__IsInit() == false) {
320 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
321 "Did not initialize or prepare CAudioOutput");
324 /* FIXME : return calculated size here to satisfy backward compatibility */
325 return (mAudioInfo.getSampleRate() * DEFAULT_PERIOD_SIZE) / 1000 * mAudioInfo.getSampleSize();
328 size_t CAudioOutput::write(const void* buffer, size_t length) throw(CAudioError) {
329 if (__IsInit() == false || __IsReady() == false) {
330 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
331 "Did not initialize or prepare CAudioOutput");
334 if (buffer == NULL) {
335 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT,
336 "Parameters are invalid - buffer:%p, length:%zu", buffer, length);
338 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING) {
339 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION,
340 "Can't write if not in Running state");
343 /* When write() is called in PulseAudio callback, bypass a pcm data to CPulseAudioClient (For Asynchronous) */
344 if (mpPulseAudioClient->isInThread() == true) {
345 int ret = mpPulseAudioClient->write(buffer, length);
347 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION,
348 "The written result is invalid ret:%d", ret);
351 #ifdef _AUDIO_IO_DEBUG_TIMING_
352 AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%d)", buffer, length);
359 /* For synchronization */
362 // If another thread did call unprepare, do not write
363 if (mpPulseAudioClient == NULL)
364 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
365 "Did not initialize CPulseAudioClient");
367 // Sets synchronous flag
368 __mIsUsedSyncWrite = true;
370 size_t lengthIter = length;
372 while (lengthIter > 0) {
375 while ((l = mpPulseAudioClient->getWritableSize()) == 0) {
376 #ifdef _AUDIO_IO_DEBUG_TIMING_
377 AUDIO_IO_LOGD("writableSize is [%d].. wait", l);
382 if (l > lengthIter) {
386 #ifdef _AUDIO_IO_DEBUG_TIMING_
387 AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%d)", buffer, l);
390 int ret = mpPulseAudioClient->write(buffer, l);
392 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION,
393 "The written result is invalid ret:%d", ret);
396 buffer = static_cast<const uint8_t*>(buffer) + l;
398 } // End of while (length > 0)
400 __mIsUsedSyncWrite = false;
403 } catch (CAudioError e) {
404 __mIsUsedSyncWrite = false;