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 <audio-session-manager.h>
22 #include "CAudioIODef.h"
24 #define AUDIO_IO_DEBUG
27 using namespace tizen_media_audio;
33 CAudioIO::CAudioIO() :
34 mpAudioSessionHandler(NULL),
35 mpPulseAudioClient(NULL),
37 __mForceIgnore(false) {
38 mState = CAudioInfo::AUDIO_IO_STATE_NONE;
39 mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE;
43 CAudioIO::CAudioIO(CAudioInfo& audioInfo) : mpAudioSessionHandler(NULL), mpPulseAudioClient(NULL), __mIsInit(false), __mForceIgnore(false) {
44 mAudioInfo = audioInfo;
45 mState = CAudioInfo::AUDIO_IO_STATE_NONE;
46 mStatePrev = CAudioInfo::AUDIO_IO_STATE_NONE;
50 CAudioIO::~CAudioIO() {
53 void CAudioIO::setInit(bool flag) {
57 bool CAudioIO::isInit() {
61 bool CAudioIO::IsReady() {
62 return ((mState == CAudioInfo::AUDIO_IO_STATE_RUNNING || mState == CAudioInfo::AUDIO_IO_STATE_PAUSED)? true : false);
65 void CAudioIO::internalLock() throw (CAudioError) {
66 if (__mIsInit == false) {
67 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
70 if (pthread_mutex_lock(&__mMutex) != 0) {
71 THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
73 #ifdef _AUDIO_IO_DEBUG_TIMING_
74 AUDIO_IO_LOGD(COLOR_RED "LOCK" COLOR_END);
78 void CAudioIO::internalUnlock() throw (CAudioError) {
79 if (__mIsInit == false) {
80 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
83 if (pthread_mutex_unlock(&__mMutex) != 0) {
84 THROW_ERROR_MSG(CAudioError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
86 #ifdef _AUDIO_IO_DEBUG_TIMING_
87 AUDIO_IO_LOGD(COLOR_GREEN "UNLOCK" COLOR_END);
91 void CAudioIO::internalWait() throw (CAudioError) {
92 if (__mIsInit == false) {
93 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
96 #ifdef _AUDIO_IO_DEBUG_TIMING_
97 AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
100 pthread_cond_wait(&__mCond, &__mMutex);
103 void CAudioIO::internalSignal() throw (CAudioError) {
104 if (__mIsInit == false) {
105 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
108 #ifdef _AUDIO_IO_DEBUG_TIMING_
109 AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
112 pthread_cond_signal(&__mCond);
115 bool CAudioIO::isForceIgnore() {
116 return __mForceIgnore;
119 void CAudioIO::initialize() throw (CAudioError) {
120 if (__mIsInit == true) {
124 AUDIO_IO_LOGD("initialize");
126 int ret = pthread_mutex_init(&__mMutex, NULL);
128 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()");
131 ret = pthread_cond_init(&__mCond, NULL);
133 THROW_ERROR_MSG(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()");
139 void CAudioIO::finalize() {
140 if (__mIsInit == false) {
144 AUDIO_IO_LOGD("finalize");
146 int ret = pthread_mutex_destroy(&__mMutex);
148 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_destroy() ret:%d", ret);
151 ret = pthread_cond_destroy(&__mCond);
153 THROW_ERROR_MSG_FORMAT(CAudioError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_destroy() ret:%d", ret);
159 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
160 assert(__mIsInit == true);
161 assert(pClient != NULL);
164 #ifdef _AUDIO_IO_DEBUG_TIMING_
165 AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
168 if (mStreamCallback.onStream != NULL) {
169 mStreamCallback.onStream(length, mStreamCallback.mUserData);
173 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
174 assert(__mIsInit == true);
179 mByPolicy = byPolicy;
181 AUDIO_IO_LOGD("current(%d), previous(%d), by_policy(%d)", mState, mStatePrev, mByPolicy);
183 if (mStateChangedCallback.onStateChanged != NULL) {
184 mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
188 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
189 onStateChanged(state, false);
192 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) {
195 int session_option = pHandler->getOptions();
198 ///////////////////////////////////////
199 // Triggered by 'focus watch callback'
200 ///////////////////////////////////////
202 if (session_option & (ASM_SESSION_OPTION_PAUSE_OTHERS | ASM_SESSION_OPTION_UNINTERRUPTIBLE)) {
203 AUDIO_IO_LOGD("Session option is pausing others or uninterruptible, skip...");
207 if (state == FOCUS_IS_RELEASED) {
208 // Focus handle(id) of the other application was released, do resume if possible
211 mpPulseAudioClient->cork(false);
212 onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
216 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
217 state = FOCUS_IS_ACQUIRED;
218 } else if (state == FOCUS_IS_ACQUIRED) {
219 // Focus handle(id) of the other application was acquired, do pause if possible
222 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) {
223 if (mpPulseAudioClient->drain() == false) {
224 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
228 mpPulseAudioClient->cork(true);
229 onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED);
233 // Focus watch callback doesn't have focus handle, but it need to convert & report to application for convenience
234 state = FOCUS_IS_RELEASED;
237 ///////////////////////////////////////
238 // Triggered by 'focus callback'
239 ///////////////////////////////////////
241 if (pHandler->getId() != id) {
242 AUDIO_IO_LOGW("Id is different, why? [mId : %d]", pHandler->getId());
245 if (session_option & ASM_SESSION_OPTION_UNINTERRUPTIBLE) {
246 AUDIO_IO_LOGD("Session option is uninterruptible, skip...");
250 if (state == FOCUS_IS_RELEASED) {
251 // Focus handle(id) was released, do pause here
254 if (mpPulseAudioClient->getStreamDirection() == CPulseAudioClient::STREAM_DIRECTION_PLAYBACK) {
255 if (mpPulseAudioClient->drain() == false) {
256 AUDIO_IO_LOGE("Failed CPulseAudioClient::drain()");
260 mpPulseAudioClient->cork(true);
261 onStateChanged(CAudioInfo::AUDIO_IO_STATE_PAUSED);
264 } else if (state == FOCUS_IS_ACQUIRED) {
265 // Focus handle(id) was acquired again,
266 // check reason_for_change ("call-voice","call-video","voip","alarm","notification", ...)
267 // do resume here and call interrupt completed callback to application.
270 mpPulseAudioClient->cork(false);
271 onStateChanged(CAudioInfo::AUDIO_IO_STATE_RUNNING);
277 if (mInterruptCallback.onInterrupt != NULL) {
278 IAudioSessionEventListener::EInterruptCode e = IAudioSessionEventListener::INTERRUPT_COMPLETED;
279 e = IAudioSessionEventListener::convertInterruptedCode(state, reason_for_change);
280 mInterruptCallback.onInterrupt(e, mInterruptCallback.mUserData);
284 void CAudioIO::onSignal(CAudioSessionHandler* pHandler, mm_sound_signal_name_t signal, int value) {
287 if (signal == MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS) {
288 if (value == 1 && pHandler->getSubscribeId() >= 0) {
289 // Unregister focus watch callback & disable session handler
290 pHandler->disableSessionHandler();
291 AUDIO_IO_LOGD("Session handler disabled by signal");
292 } else if (value == 0) {
293 // Currently do nothing...
298 void CAudioIO::prepare() throw (CAudioError) {
299 if (__mIsInit == false) {
300 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
304 AUDIO_IO_LOGD("prepare");
306 } catch (CAudioError e) {
311 void CAudioIO::unprepare() throw (CAudioError) {
312 if (__mIsInit == false) {
313 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
317 AUDIO_IO_LOGD("unprepare");
319 } catch (CAudioError e) {
324 void CAudioIO::pause() throw (CAudioError) {
325 if (__mIsInit == false || IsReady() == false) {
326 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
331 AUDIO_IO_LOGD("pause");
332 mpPulseAudioClient->cork(true);
334 } catch (CAudioError e) {
340 void CAudioIO::resume() throw (CAudioError) {
341 if (__mIsInit == false || IsReady() == false) {
342 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
347 AUDIO_IO_LOGD("resume");
348 mpPulseAudioClient->cork(false);
350 } catch (CAudioError e) {
356 void CAudioIO::drain() throw (CAudioError) {
357 if (__mIsInit == false || IsReady() == false) {
358 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
363 AUDIO_IO_LOGD("drain");
364 mpPulseAudioClient->drain();
366 } catch (CAudioError e) {
372 void CAudioIO::flush() throw (CAudioError) {
373 if (__mIsInit == false || IsReady() == false) {
374 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
379 AUDIO_IO_LOGD("flush");
380 mpPulseAudioClient->flush();
382 } catch (CAudioError e) {
388 CAudioInfo CAudioIO::getAudioInfo() throw (CAudioError) {
389 if (__mIsInit == false) {
390 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
396 void CAudioIO::setStreamCallback(SStreamCallback callback) throw (CAudioError) {
397 if (__mIsInit == false) {
398 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
401 mStreamCallback = callback;
404 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() throw (CAudioError) {
405 if (__mIsInit == false) {
406 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
409 return mStreamCallback;
412 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) throw (CAudioError) {
413 if (__mIsInit == false) {
414 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
417 mStateChangedCallback = callback;
420 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() throw (CAudioError) {
421 if (__mIsInit == false) {
422 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
425 return mStateChangedCallback;
428 void CAudioIO::setInterruptCallback(SInterruptCallback callback) throw (CAudioError) {
429 if (__mIsInit == false) {
430 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
433 mInterruptCallback = callback;
436 CAudioIO::SInterruptCallback CAudioIO::getInterruptCallback() throw (CAudioError) {
437 if (__mIsInit == false) {
438 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
441 return mInterruptCallback;
445 void CAudioIO::ignoreSession() throw (CAudioError) {
446 if (__mIsInit == false) {
447 THROW_ERROR_MSG(CAudioError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
453 if (mpPulseAudioClient != NULL && mpPulseAudioClient->isCorked() == false) {
454 THROW_ERROR_MSG(CAudioError::ERROR_INVALID_OPERATION, "An Operation is not permitted while started");
457 bool isSkip = mpAudioSessionHandler->isSkipSessionEvent();
458 if (isSkip == false && mpAudioSessionHandler->getId() >= 0) {
459 mpAudioSessionHandler->unregisterSound();
460 __mForceIgnore = true;
464 } catch (CAudioError e) {