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