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