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.
21 #include "CAudioIODef.h"
23 #define AUDIO_IO_DEBUG
26 using namespace tizen_media_audio;
32 CAudioIO::CAudioIO() :
33 mpAudioSessionHandler(NULL),
34 mpPulseAudioClient(NULL),
36 __mForceIgnore(false) {
37 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
38 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
42 CAudioIO::CAudioIO(CAudioInfo& audioInfo) : mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL), __mIsInit(false), __mForceIgnore(false) {
43 mAudioInfo = audioInfo;
44 mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
45 mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
49 CAudioIO::~CAudioIO() {
52 void CAudioIO::setInit(bool flag) {
56 bool CAudioIO::isInit() {
60 bool CAudioIO::IsReady() {
61 return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)? true : false);
64 void CAudioIO::internalLock() throw (CAudioError) {
65 if (__mIsInit == false) {
66 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
69 if (pthread_mutex_lock(&__mMutex) != 0) {
70 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
72 #ifdef _AUDIO_IO_DEBUG_TIMING_
73 AUDIO_IO_LOGD(COLOR_RED "LOCK" COLOR_END);
77 void CAudioIO::internalUnlock() throw (CAudioError) {
78 if (__mIsInit == false) {
79 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
82 if (pthread_mutex_unlock(&__mMutex) != 0) {
83 THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
85 #ifdef _AUDIO_IO_DEBUG_TIMING_
86 AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK" COLOR_END);
90 void CAudioIO::internalWait() throw (CAudioError) {
91 if (__mIsInit == false) {
92 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
95 #ifdef _AUDIO_IO_DEBUG_TIMING_
96 AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
99 pthread_cond_wait(&__mCond, &__mMutex);
102 void CAudioIO::internalSignal() throw (CAudioError) {
103 if (__mIsInit == false) {
104 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
107 #ifdef _AUDIO_IO_DEBUG_TIMING_
108 AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
111 pthread_cond_signal(&__mCond);
114 bool CAudioIO::isForceIgnore() {
115 return __mForceIgnore;
118 void CAudioIO::initialize() throw (CAudioError) {
119 if (__mIsInit == true) {
123 AUDIO_IO_LOGD("initialize");
125 int ret = pthread_mutex_init(&__mMutex, NULL);
127 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()");
130 ret = pthread_cond_init(&__mCond, NULL);
132 THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()");
138 void CAudioIO::finalize() {
139 if (__mIsInit == false) {
143 AUDIO_IO_LOGD("finalize");
145 int ret = pthread_mutex_destroy(&__mMutex);
147 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret);
150 ret = pthread_cond_destroy(&__mCond);
152 THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret);
158 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
159 assert(__mIsInit == true);
160 assert(pClient != NULL);
163 #ifdef _AUDIO_IO_DEBUG_TIMING_
164 AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
167 if (mStreamCallback.onStream != NULL) {
168 mStreamCallback.onStream(length, mStreamCallback.mUserData);
172 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
173 assert(__mIsInit == true);
174 assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
178 mByPolicy = byPolicy;
180 AUDIO_IO_LOGD("current(%d), previous(%d), by_policy(%d)", mState, mStatePrev, mByPolicy);
182 if (mStateChangedCallback.onStateChanged != NULL) {
183 mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
187 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
188 onStateChanged(state, false);
191 void CAudioIO::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) {
194 int session_option = pHandler->getOptions();
197 ///////////////////////////////////////
198 // Triggered by 'focus watch callback'
199 ///////////////////////////////////////
201 if (session_option & (MM_SESSION_OPTION_PAUSE_OTHERS | MM_SESSION_OPTION_UNINTERRUPTIBLE)) {
202 AUDIO_IO_LOGD("Session option is pausing others or uninterruptible, skip...");
206 if (state == FOCUS_IS_RELEASED) {
207 // Focus handle(id) of the other application was released, do resume if possible
210 mpPulseAudioClient->cork(false);
211 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
215 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
216 state = FOCUS_IS_ACQUIRED;
217 } else if (state == FOCUS_IS_ACQUIRED) {
218 // Focus handle(id) of the other application was acquired, do pause if possible
221 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
222 if (mpPulseAudioClient->drain() == false) {
223 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
227 mpPulseAudioClient->cork(true);
228 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
232 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
233 state = FOCUS_IS_RELEASED;
236 ///////////////////////////////////////
237 // Triggered by 'focus callback'
238 ///////////////////////////////////////
240 if (pHandler->getId() != id) {
241 AUDIO_IO_LOGW("Id is different, why? [mId : %d]", pHandler->getId());
244 if (session_option & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
245 AUDIO_IO_LOGD("Session option is uninterruptible, skip...");
249 if (state == FOCUS_IS_RELEASED) {
250 // Focus handle(id) was released, do pause here
253 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::EStreamDirection::STREAM_DIRECTION_PLAYBACK) {
254 if (mpPulseAudioClient->drain() == false) {
255 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
259 mpPulseAudioClient->cork(true);
260 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED);
263 } else if (state == FOCUS_IS_ACQUIRED) {
264 // Focus handle(id) was acquired again,
265 // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...)
266 // do resume here and call interrupt completed callback to application.
269 mpPulseAudioClient->cork(false);
270 onStateChanged(CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING);
276 if (mInterruptCallback.onInterrupt != NULL) {
277 IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::EInterruptCode::INTERRUPT_COMPLETED;
278 e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change);
279 mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
283 void CAudioIO::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
286 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
287 if (value == 1 && pHandler->getSubscribeId() >= 0) {
288 // Unregister focus watch callback & disable session handler
289 pHandler->disableSessionHandler();
290 AUDIO_IO_LOGD("Session handler disabled by signal");
291 } else if (value == 0) {
292 // Currently do nothing...
297 void CAudioIO::prepare() throw (CAudioError) {
298 if (__mIsInit == false) {
299 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
303 AUDIO_IO_LOGD("prepare");
305 } catch (CAudioError e) {
310 void CAudioIO::unprepare() throw (CAudioError) {
311 if (__mIsInit == false) {
312 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
316 AUDIO_IO_LOGD("unprepare");
318 } catch (CAudioError e) {
323 void CAudioIO::pause() throw (CAudioError) {
324 if (__mIsInit == false || IsReady() == false) {
325 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
330 AUDIO_IO_LOGD("pause");
331 mpPulseAudioClient->cork(true);
333 } catch (CAudioError e) {
339 void CAudioIO::resume() throw (CAudioError) {
340 if (__mIsInit == false || IsReady() == false) {
341 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
346 AUDIO_IO_LOGD("resume");
347 mpPulseAudioClient->cork(false);
349 } catch (CAudioError e) {
355 void CAudioIO::drain() throw (CAudioError) {
356 if (__mIsInit == false || IsReady() == false) {
357 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
362 AUDIO_IO_LOGD("drain");
363 mpPulseAudioClient->drain();
365 } catch (CAudioError e) {
371 void CAudioIO::flush() throw (CAudioError) {
372 if (__mIsInit == false || IsReady() == false) {
373 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
378 AUDIO_IO_LOGD("flush");
379 mpPulseAudioClient->flush();
381 } catch (CAudioError e) {
387 CAudioInfo& CAudioIO::getAudioInfo() throw (CAudioError) {
388 if (__mIsInit == false) {
389 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
395 void CAudioIO::setStreamCallback(SStreamCallback callback) throw (CAudioError) {
396 if (__mIsInit == false) {
397 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
400 mStreamCallback = callback;
403 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw (CAudioError) {
404 if (__mIsInit == false) {
405 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
408 return mStreamCallback;
411 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError) {
412 if (__mIsInit == false) {
413 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
416 mStateChangedCallback = callback;
419 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw (CAudioError) {
420 if (__mIsInit == false) {
421 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
424 return mStateChangedCallback;
427 void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw (CAudioError) {
428 if (__mIsInit == false) {
429 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
432 mInterruptCallback = callback;
435 CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw (CAudioError) {
436 if (__mIsInit == false) {
437 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
440 return mInterruptCallback;
444 void CAudioIO::ignoreSession() throw (CAudioError) {
445 if (__mIsInit == false) {
446 THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
452 if (mpPulseAudioClient != NULL && mpPulseAudioClient->isCorked() == false) {
453 THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started");
456 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
457 if (isSkip == false && mpAudioSessionHandler->getId() >= 0) {
458 mpAudioSessionHandler->unregisterSound();
459 __mForceIgnore = true;
463 } catch (CAudioError e) {