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.
20 #include "CAudioIODef.h"
24 using namespace tizen_media_audio;
30 CAudioOutput::CAudioOutput(CAudioInfo& info) :
32 __mIsUsedSyncWrite(false),
34 mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_OUT;
37 void CAudioOutput::onStream(CPulseAudioClient* pClient, size_t length) {
41 * Does not call CAudioIO::onStream() for synchronization
42 * if a user is using write()
44 if (__mIsUsedSyncWrite) {
45 #ifdef _AUDIO_IO_DEBUG_TIMING_
46 AUDIO_IO_LOGD("Sync Write Mode! - signal! - pClient:[%p], length:[%zu]", pClient, length);
53 * Accrues callback function
55 #ifdef _AUDIO_IO_DEBUG_TIMING_
56 AUDIO_IO_LOGD("pClient:[%p], length:[%zu]", pClient, length);
58 CAudioIO::onStream(pClient, length);
61 void CAudioOutput::__setInit(bool flag) noexcept {
65 bool CAudioOutput::__IsInit() noexcept {
66 return (CAudioIO::isInit() && __mIsInit);
69 bool CAudioOutput::__IsReady() noexcept {
70 return CAudioIO::IsReady();
73 void CAudioOutput::initialize() {
78 CAudioIO::initialize();
80 } catch (const CAudioError& e) {
85 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
88 void CAudioOutput::finalize() {
90 AUDIO_IO_LOGD("Did not initialize");
99 void CAudioOutput::prepare() {
101 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize CAudioOutput");
104 AUDIO_IO_LOGD("Already prepared CAudioOutput");
109 /* Check invalid AudioType */
110 CAudioInfo::EAudioType audioType = mAudioInfo.getAudioType();
111 if (audioType < CAudioInfo::EAudioType::AUDIO_OUT_TYPE_MEDIA ||
112 audioType >= CAudioInfo::EAudioType::AUDIO_TYPE_MAX)
113 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT,
114 "The audioType is invalid [type:%d]", static_cast<int>(audioType));
117 /* Init StreamSpec */
118 CPulseStreamSpec::EStreamLatency streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT;
119 #ifndef DISABLE_MOBILE_BACK_COMP
120 if (!mStreamCallback.onStream) {
121 AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT");
122 streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT;
124 AUDIO_IO_LOGD("Set Stream Spec : CPulseStreamSpec::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC");
125 streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_DEFAULT_ASYNC;
128 /* Override the default value by audio type */
129 if (audioType == CAudioInfo::EAudioType::AUDIO_OUT_TYPE_VOIP)
130 streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_VOIP;
131 else if (audioType == CAudioInfo::EAudioType::AUDIO_OUT_TYPE_MEDIA_NETWORK_SOURCE)
132 streamSpec = CPulseStreamSpec::EStreamLatency::STREAM_LATENCY_OUTPUT_HIGH;
134 CPulseStreamSpec spec(streamSpec, mAudioInfo);
137 mpPulseAudioClient = new CPulseAudioClient(CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK, spec, this);
138 mpPulseAudioClient->initialize();
139 #ifndef DISABLE_MOBILE_BACK_COMP
140 /* Uncork stream which is created with CORKED flag */
141 mpPulseAudioClient->cork(false);
146 } catch (const CAudioError& e) {
147 SAFE_FINALIZE(mpPulseAudioClient);
148 SAFE_DELETE(mpPulseAudioClient);
151 } catch (const std::bad_alloc&) {
154 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed to allocate CPulseAudioClient object");
159 void CAudioOutput::unprepare() {
161 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
162 "Did not initialize CAudioOutput");
165 AUDIO_IO_LOGD("Already unprepared");
169 CAudioIO::unprepare();
173 if (mpPulseAudioClient && mpPulseAudioClient->isInThread())
174 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't unprepare inside pulseaudio thread");
175 SAFE_FINALIZE(mpPulseAudioClient);
176 SAFE_DELETE(mpPulseAudioClient);
178 } catch (const CAudioError& e) {
183 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE);
186 void CAudioOutput::pause() {
187 if (!__IsInit() || !__IsReady())
188 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
189 "Did not initialize or prepare CAudioOutput");
191 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING)
192 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE,
193 "Can't pause if not in Running state");
195 if (mpPulseAudioClient->isInThread() )
196 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't pause in thread");
199 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
202 void CAudioOutput::resume() {
203 if (!__IsInit() || !__IsReady())
204 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
205 "Did not initialize or prepare CAudioOutput");
207 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)
208 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE,
209 "Can't resume if not in Paused state");
211 if (mpPulseAudioClient->isInThread())
212 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_OPERATION, "Can't resume in thread");
215 CAudioIO::onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
218 void CAudioOutput::drain() {
219 if (!__IsInit() || !__IsReady())
220 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
221 "Did not initialize or prepare CAudioOutput");
223 if (mStreamCallback.onStream)
224 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "async type don't support drain");
229 void CAudioOutput::flush() {
230 if (!__IsInit() || !__IsReady())
231 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
232 "Did not initialize or prepare CAudioOutput");
237 int CAudioOutput::getBufferSize() {
239 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
240 "Did not initialize or prepare CAudioOutput");
242 /* FIXME : return calculated size here to satisfy backward compatibility */
243 return (mAudioInfo.getSampleRate() * DEFAULT_PERIOD_SIZE) / 1000 * mAudioInfo.getSampleSize();
246 size_t CAudioOutput::write(const void* buffer, size_t length) {
247 if (!__IsInit() || !__IsReady())
248 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
249 "Did not initialize or prepare CAudioOutput");
252 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT,
253 "Parameters are invalid - buffer:%p, length:%zu", buffer, length);
255 if (CAudioIO::getState() != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING)
256 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION,
257 "Can't write if not in Running state");
259 /* When write() is called in PulseAudio callback, bypass a pcm data to CPulseAudioClient (For Asynchronous) */
260 if (mpPulseAudioClient && mpPulseAudioClient->isInThread()) {
261 int ret = mpPulseAudioClient->write(buffer, length);
263 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION,
264 "The written result is invalid ret:%d", ret);
265 #ifdef _AUDIO_IO_DEBUG_TIMING_
266 AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%zu)", buffer, length);
272 /* For synchronization */
275 // If another thread did call unprepare, do not write
276 if (!mpPulseAudioClient)
277 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED,
278 "Did not initialize CPulseAudioClient");
280 // Sets synchronous flag
281 __mIsUsedSyncWrite = true;
283 size_t lengthIter = length;
285 while (lengthIter > 0) {
288 while ((l = mpPulseAudioClient->getWritableSize()) == 0) {
289 #ifdef _AUDIO_IO_DEBUG_TIMING_
290 AUDIO_IO_LOGD("writableSize is [%zu].. wait", l);
298 #ifdef _AUDIO_IO_DEBUG_TIMING_
299 AUDIO_IO_LOGD("CPulseAudioClient->write(buffer:%p, length:%zu)", buffer, l);
302 int ret = mpPulseAudioClient->write(buffer, l);
304 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION,//LCOV_EXCL_LINE
305 "The written result is invalid ret:%d", ret); //LCOV_EXCL_LINE
307 buffer = static_cast<const uint8_t*>(buffer) + l;
309 } // End of while (length > 0)
311 __mIsUsedSyncWrite = false;
315 } catch (const CAudioError& e) {
316 __mIsUsedSyncWrite = false;