e8b6ab7c4cc41f712d42070e4025c9f318674265
[platform/core/api/audio-io.git] / src / cpp / CAudioIO.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18 #include <mm.h>
19 #include <pthread.h>
20 #include <assert.h>
21 #include "CAudioIODef.h"
22 #include <sound_manager_internal.h>
23
24 using namespace std;
25 using namespace tizen_media_audio;
26
27
28 /**
29  * class CAudioIO
30  */
31 CAudioIO::CAudioIO() :
32     mpPulseAudioClient(NULL),
33     __mMutex(PTHREAD_MUTEX_INITIALIZER),
34     __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
35     __mCond(PTHREAD_COND_INITIALIZER),
36     __mIsInit(false) {
37     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
38     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
39     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
40     mByPolicy = false;
41 }
42
43 CAudioIO::CAudioIO(CAudioInfo& audioInfo) :
44     mpPulseAudioClient(NULL),
45     __mMutex(PTHREAD_MUTEX_INITIALIZER),
46     __mCondMutex(PTHREAD_MUTEX_INITIALIZER),
47     __mCond(PTHREAD_COND_INITIALIZER),
48     __mIsInit(false) {
49     mAudioInfo = audioInfo;
50     mDirection = CAudioInfo::EAudioDirection::AUDIO_DIRECTION_MAX;
51     mState = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
52     mStatePrev = CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE;
53     mByPolicy = false;
54 }
55
56 CAudioIO::~CAudioIO() {
57 }
58
59 void CAudioIO::setInit(bool flag) {
60     __mIsInit = flag;
61 }
62
63 bool CAudioIO::isInit() {
64     return __mIsInit;
65 }
66
67 bool CAudioIO::IsReady() {
68     return ((mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_RUNNING ||
69              mState == CAudioInfo::EAudioIOState::AUDIO_IO_STATE_PAUSED)? true : false);
70 }
71
72 void CAudioIO::internalLock() {
73     if (__mIsInit == false)
74         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
75
76     if (pthread_mutex_lock(&__mMutex) != 0)
77         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
78
79 #ifdef _AUDIO_IO_DEBUG_TIMING_
80     AUDIO_IO_LOGD(COLOR_RED "%p LOCKED" COLOR_END, &__mMutex);
81 #endif
82 }
83
84 void CAudioIO::internalUnlock() {
85     if (__mIsInit == false)
86         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
87
88     if (pthread_mutex_unlock(&__mMutex) != 0)
89         THROW_ERROR_MSG(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Failed pthread_mutex_lock()");
90
91 #ifdef _AUDIO_IO_DEBUG_TIMING_
92     AUDIO_IO_LOGD(COLOR_GREEN "%p UNLOCKED" COLOR_END, &__mMutex);
93 #endif
94 }
95
96 void CAudioIO::internalWait() {
97     if (__mIsInit == false)
98         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
99
100 #ifdef _AUDIO_IO_DEBUG_TIMING_
101     AUDIO_IO_LOGD(COLOR_RED "WAIT" COLOR_END);
102 #endif
103
104     pthread_mutex_lock(&__mCondMutex);
105     pthread_cond_wait(&__mCond, &__mCondMutex);
106     pthread_mutex_unlock(&__mCondMutex);
107 }
108
109 void CAudioIO::internalSignal() {
110     if (__mIsInit == false)
111         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
112
113 #ifdef _AUDIO_IO_DEBUG_TIMING_
114     AUDIO_IO_LOGD(COLOR_GREEN "SIGNAL" COLOR_END);
115 #endif
116
117     pthread_mutex_lock(&__mCondMutex);
118     pthread_cond_signal(&__mCond);
119     pthread_mutex_unlock(&__mCondMutex);
120 }
121
122 void CAudioIO::initialize() {
123     if (__mIsInit == true)
124         return;
125
126     AUDIO_IO_LOGD("initialize");
127
128     int ret = pthread_mutex_init(&__mMutex, NULL);
129     if (ret != 0)
130         THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_mutex_init()");
131
132     ret = pthread_cond_init(&__mCond, NULL);
133     if (ret != 0)
134         THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pthread_cond_init()");
135
136     __mIsInit = true;
137 }
138
139 void CAudioIO::finalize() {
140     if (__mIsInit == false)
141         return;
142
143     AUDIO_IO_LOGD("finalize");
144
145     bool error_occured = false;
146     int ret = pthread_mutex_destroy(&__mMutex);
147     if (ret != 0) {
148         AUDIO_IO_LOGE("Failed pthread_mutex_destroy(%p) errno:%d", &__mMutex, ret);
149         error_occured = true;
150     }
151
152     ret = pthread_mutex_destroy(&__mCondMutex);
153     if (ret != 0) {
154         AUDIO_IO_LOGE("Failed cond pthread_mutex_destroy(%p) errno:%d", &__mCondMutex, ret);
155         error_occured = true;
156     }
157
158     ret = pthread_cond_destroy(&__mCond);
159     if (ret != 0) {
160         AUDIO_IO_LOGE("Failed pthread_cond_destroy(%p) errno:%d", &__mCond, ret);
161         error_occured = true;
162     }
163
164     if (error_occured)
165         THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "Finalize Failed");
166
167     __mIsInit = false;
168 }
169
170 void CAudioIO::onStream(CPulseAudioClient* pClient, size_t length) {
171     assert(__mIsInit == true);
172     assert(pClient != NULL);
173     assert(length > 0);
174
175 #ifdef _AUDIO_IO_DEBUG_TIMING_
176     AUDIO_IO_LOGD("mStreamCallback.onStream(%p), pClient(%p), length(%zu)", mStreamCallback.onStream, pClient, length);
177 #endif
178
179     if (mStreamCallback.onStream != NULL)
180         mStreamCallback.onStream(length, mStreamCallback.mUserData);
181 }
182
183 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state, bool byPolicy) {
184     assert(__mIsInit == true);
185     assert(state >= CAudioInfo::EAudioIOState::AUDIO_IO_STATE_NONE && state < CAudioInfo::EAudioIOState::AUDIO_IO_STATE_MAX);
186
187     mStatePrev = mState;
188     mState = state;
189     mByPolicy = byPolicy;
190
191     if (mState == mStatePrev)
192         return;
193
194     const char* state_string[] = { "NONE", "IDLE", "RUNNING", "PAUSED" };
195
196     AUDIO_IO_LOGD("previous(%s,%d) ===> current(%s,%d), by_policy(%d)",
197                   state_string[static_cast<int>(mStatePrev)],
198                   static_cast<int>(mStatePrev),
199                   state_string[static_cast<int>(mState)],
200                   static_cast<int>(mState),
201                   mByPolicy);
202
203     if (mStateChangedCallback.onStateChanged != NULL)
204         mStateChangedCallback.onStateChanged(mState, mStatePrev, mByPolicy, mStateChangedCallback.mUserData);
205 }
206
207 void CAudioIO::onStateChanged(CAudioInfo::EAudioIOState state) {
208     onStateChanged(state, false);
209 }
210
211 CAudioInfo::EAudioIOState CAudioIO::getState() {
212     return mState;
213 }
214
215 void CAudioIO::prepare() {
216     if (__mIsInit == false)
217         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
218 }
219
220 void CAudioIO::unprepare() {
221     if (__mIsInit == false)
222         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
223 }
224
225 void CAudioIO::pause() {
226     if (__mIsInit == false || IsReady() == false)
227         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
228
229     try {
230         internalLock();
231         AUDIO_IO_LOGD("pause");
232         mpPulseAudioClient->cork(true);
233         internalUnlock();
234     } catch (CAudioError& e) {
235         internalUnlock();
236         throw;
237     }
238 }
239
240 void CAudioIO::resume() {
241     if (__mIsInit == false || IsReady() == false)
242         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
243
244     try {
245         internalLock();
246         AUDIO_IO_LOGD("resume");
247         mpPulseAudioClient->cork(false);
248         internalUnlock();
249     } catch (CAudioError& e) {
250         internalUnlock();
251         throw;
252     }
253 }
254
255 void CAudioIO::drain() {
256     if (__mIsInit == false || IsReady() == false)
257         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
258
259     try {
260         if (mpPulseAudioClient->isInThread()) {
261             mpPulseAudioClient->drain();
262         } else {
263             internalLock();
264             mpPulseAudioClient->drain();
265             internalUnlock();
266         }
267     } catch (CAudioError& e) {
268         if (!mpPulseAudioClient->isInThread())
269             internalUnlock();
270         throw;
271     }
272 }
273
274 void CAudioIO::flush() {
275     if (__mIsInit == false || IsReady() == false)
276         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Did not initialize or prepare CAudioIO");
277
278     try {
279         if (mpPulseAudioClient->isInThread()) {
280             mpPulseAudioClient->flush();
281         } else {
282             internalLock();
283             mpPulseAudioClient->flush();
284             internalUnlock();
285         }
286     } catch (CAudioError& e) {
287         if (!mpPulseAudioClient->isInThread())
288             internalUnlock();
289         throw;
290     }
291 }
292
293 CAudioInfo& CAudioIO::getAudioInfo() {
294     if (__mIsInit == false)
295         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
296
297     return mAudioInfo;
298 }
299
300 void CAudioIO::setStreamCallback(SStreamCallback callback) {
301     if (__mIsInit == false)
302         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
303
304     mStreamCallback = callback;
305 }
306
307 CAudioIO::SStreamCallback CAudioIO::getStreamCallback() {
308     if (__mIsInit == false)
309         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
310
311     return mStreamCallback;
312 }
313
314 void CAudioIO::setStateChangedCallback(SStateChangedCallback callback) {
315     if (__mIsInit == false)
316         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
317
318     mStateChangedCallback = callback;
319 }
320
321 CAudioIO::SStateChangedCallback CAudioIO::getStateChangedCallback() {
322     if (__mIsInit == false)
323         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
324
325     return mStateChangedCallback;
326 }
327
328 void CAudioIO::setStreamInfo(sound_stream_info_h stream_info) {
329     if (stream_info == NULL)
330         THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_ARGUMENT, "stream_info is NULL");
331
332     if (__mIsInit == false)
333         THROW_ERROR_MSG(CAudioError::EError::ERROR_NOT_INITIALIZED, "Doesn't initialize CAudioIO");
334
335     try {
336         if (mState != CAudioInfo::EAudioIOState::AUDIO_IO_STATE_IDLE)
337             THROW_ERROR_MSG(CAudioError::EError::ERROR_INVALID_STATE, "it is not permitted while started");
338
339         int errorCode = SOUND_MANAGER_ERROR_NONE;
340         CAudioInfo::EAudioType audioType = CAudioInfo::EAudioType::AUDIO_IN_TYPE_MEDIA;
341         char *type = NULL;
342         int index = -1;
343         bool avail = false;
344
345         if ((errorCode = sound_manager_is_available_stream_information(stream_info, NATIVE_API_AUDIO_IO, &avail)) != SOUND_MANAGER_ERROR_NONE)
346             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info is invalid [ret:%d]", errorCode);
347         if (!avail)
348             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_NOT_SUPPORTED_TYPE, "Input stream is not supported");
349
350         if ((errorCode = sound_manager_get_type_from_stream_information(stream_info, &type)) != SOUND_MANAGER_ERROR_NONE)
351             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->stream_type is invalid [ret:%d]", errorCode);
352         if (mDirection == CAudioInfo::EAudioDirection::AUDIO_DIRECTION_IN)
353             getAudioInfo().convertInputStreamType2AudioType(type, &audioType);
354         else
355             getAudioInfo().convertOutputStreamType2AudioType(type, &audioType);
356         getAudioInfo().setAudioType(audioType);
357
358         if ((errorCode = sound_manager_get_index_from_stream_information(stream_info, &index)) != SOUND_MANAGER_ERROR_NONE)
359             THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INVALID_ARGUMENT, "Parameter stream_info->index is invalid [ret:%d]", errorCode);
360         getAudioInfo().setAudioIndex(index);
361
362     } catch (CAudioError& e) {
363         throw;
364     }
365 }