694341a94a6367f9ec822d880697a621af0dff35
[platform/framework/native/media.git] / src / FMedia_AudioOutImpl.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 #include <pthread.h>
18 #include <FMediaCapability.h>
19 #include <FBaseSysLog.h>
20 #include "FMedia_AudioOutEvent.h"
21 #include "FMedia_AudioOutImpl.h"
22 #include "FMedia_AudioOutEventArg.h"
23 #include "FMedia_AudioManagerConvert.h"
24
25
26 #define attribute_deprecated
27
28 #ifdef __cplusplus
29 #define __STDC_CONSTANT_MACROS
30 #ifdef _STDINT_H
31 #undef _STDINT_H
32 #endif
33 #include <stdint.h>
34 #endif
35
36 extern "C"
37 {
38 #include <stdlib.h>
39 #include <libavutil/common.h>
40 #include <libswscale/swscale.h>
41 }
42
43 using namespace Tizen::Base;
44 using namespace Tizen::Base::Runtime;
45 using namespace Tizen::Base::Collection;
46
47 namespace Tizen { namespace Media
48 {
49
50 int _AudioOutImpl::instanceCount = 0;
51 int _AudioOutImpl::maxInstanceCount = 0;
52 AudioChannelType _AudioOutImpl::audioOutOptimalChannelType = AUDIO_CHANNEL_TYPE_STEREO;
53 AudioSampleType _AudioOutImpl::audioOutOptimalSampleType = AUDIO_TYPE_PCM_S16_LE;
54 int _AudioOutImpl::audioOutOptimalSampleRate = 44100;
55 int _AudioOutImpl::audioOutMinimumBufferSize = 2048;
56 int _AudioOutImpl::audioOutMaximumBufferSize = 164112;
57 std::unique_ptr<Tizen::Base::Runtime::Mutex> _AudioOutImpl::__pInstanceMutex;
58 bool _AudioOutImpl::__isInstanceMutexInitialized = false;
59
60 _AudioOutImpl::_AudioOutImpl(void)
61         : __pAudioOut(null)
62         , __pAudioOutEventListener(null)
63         , __audioOutState(AUDIOOUT_STATE_ERROR)
64         , __volume(-1)
65         , __volume256(-1)
66         , __presentSampleType(AUDIO_TYPE_NONE)
67         , __presentSampleRate(0)
68         , __audioOutHandle(null)
69         , __audioOutOptimalBufferSize(0)
70         , __stop(false)
71         , __interruptFlag(false)
72 {
73 }
74
75
76 _AudioOutImpl::~_AudioOutImpl(void)
77 {
78         if (__audioOutState < AUDIOOUT_STATE_UNPREPARED && __audioOutState >= AUDIOOUT_STATE_PREPARED)
79         {
80                 if (__audioOutState == AUDIOOUT_STATE_PLAYING )
81                 {
82                         this->Stop();
83                 }
84                 this->Reset();
85                 this->UnPrepare();
86         }
87         __pAudioOut = null;
88
89         if ((__audioOutState == AUDIOOUT_STATE_INITIALIZED ) || __audioOutState == AUDIOOUT_STATE_UNPREPARED )
90         {
91                 __pInstanceMutex->Acquire();
92                 instanceCount--;
93                 __pInstanceMutex->Release();
94         }
95 }
96
97 void
98 _AudioOutImpl::InitInstanceMutex(void)
99 {
100         result r = E_SUCCESS;
101         __pInstanceMutex.reset(new (std::nothrow) Tizen::Base::Runtime::Mutex);
102         SysTryReturn(NID_MEDIA, __pInstanceMutex.get() != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] no memory to create instance Mutex");
103         r = __pInstanceMutex->Create("FMEDIA_AUDIOOUT_N");
104         SysTryReturn(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Mutex::Create failed.");
105         __isInstanceMutexInitialized  = true;
106 }
107
108 _AudioOutImpl*
109 _AudioOutImpl::GetInstance(AudioOut* pAudioOut)
110 {
111         if (pAudioOut != null)
112         {
113                 return pAudioOut->__pAudioOutImpl;
114         }
115
116         return null;
117 }
118
119 const _AudioOutImpl*
120 _AudioOutImpl::GetInstance(const AudioOut* pAudioOut)
121 {
122         if (pAudioOut != null)
123         {
124                 return pAudioOut->__pAudioOutImpl;
125         }
126
127         return null;
128 }
129
130 result
131 _AudioOutImpl::Construct(const Tizen::Media::AudioOut* pAudioOut, Tizen::Media::IAudioOutEventListener& listener)
132 {
133         result r = E_SUCCESS;
134         __pAudioOut = const_cast <AudioOut*>(pAudioOut);
135         static pthread_once_t onceBlock = PTHREAD_ONCE_INIT;
136         if (!__isInstanceMutexInitialized)
137         {
138                 pthread_once(&onceBlock, InitInstanceMutex);
139         }
140         SysTryCatch(NID_MEDIA, __isInstanceMutexInitialized == true, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] memory allocation for Instance Mutex failed");
141
142         if (!maxInstanceCount)
143         {
144                 r = MediaCapability::GetValue(AUDIOOUT_COUNT_MAX, maxInstanceCount);
145                 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
146                 SysTryCatch(NID_MEDIA, maxInstanceCount > 0, , r, "[%s] Propagating.", GetErrorMessage(r));
147         }
148
149         SysTryCatch(NID_MEDIA, instanceCount < maxInstanceCount, r = E_RESOURCE_UNAVAILABLE, E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The number of instances exceeds the available number of instances. The current number of instance is %d", instanceCount);
150
151         //Setting up the Events
152         __pAudioOutEvent.reset(new (std::nothrow) _AudioOutEvent);
153         SysTryReturnResult(NID_MEDIA, __pAudioOutEvent.get(), E_OUT_OF_MEMORY, "Memory allocation failed.");
154         r = __pAudioOutEvent->Construct(__pAudioOut);
155         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
156         r = __pAudioOutEvent->AddListener(listener);
157         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
158
159         //BufferQueue
160         r = __bufferQueue.Construct();
161         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
162         //Buffer Sync
163         __pBufferSync.reset( new (std::nothrow) Monitor);
164         SysTryCatch(NID_MEDIA, __pBufferSync.get() != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory allocation failed.");
165         r = __pBufferSync->Construct();
166         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
167
168         __volume = 50;
169         __volume256 = (__volume << 8) / 100;
170
171         __pInstanceMutex->Acquire();
172         instanceCount++;
173         __pInstanceMutex->Release();
174
175         __audioOutState = AUDIOOUT_STATE_INITIALIZED;
176         return E_SUCCESS;
177
178 CATCH:
179         __pAudioOut = null;
180         SetLastResult(r);
181         return r;
182 }
183
184 int
185 _AudioOutImpl::GetMaxBufferSize(void)
186 {
187         result r = E_SUCCESS;
188         SysTryCatch(NID_MEDIA, __audioOutState < AUDIOOUT_STATE_UNPREPARED && __audioOutState >= AUDIOOUT_STATE_PREPARED,
189                 r = E_INVALID_STATE, E_INVALID_STATE, "[E_INVALID_STATE] The state of this instance is in an invalid state.");
190         return audioOutMaximumBufferSize;
191 CATCH:
192         SetLastResult(r);
193         return -1;
194 }
195
196 int
197 _AudioOutImpl::GetMinBufferSize(void)
198 {
199         result r = E_SUCCESS;
200         SysTryCatch(NID_MEDIA, __audioOutState < AUDIOOUT_STATE_UNPREPARED && __audioOutState >= AUDIOOUT_STATE_PREPARED,
201                 r = E_INVALID_STATE, E_INVALID_STATE, "[E_INVALID_STATE] The state of this instance is in an invalid state.");
202         return audioOutMinimumBufferSize;
203 CATCH:
204         SetLastResult(r);
205         return -1;
206 }
207
208 AudioChannelType
209 _AudioOutImpl::GetOptimizedChannelType(void)
210 {
211         return audioOutOptimalChannelType;
212 }
213
214 int
215 _AudioOutImpl::GetOptimizedSampleRate(void)
216 {
217         result r = E_SUCCESS;
218         SetLastResult(r);
219         return audioOutOptimalSampleRate;
220 }
221
222 AudioSampleType
223 _AudioOutImpl::GetOptimizedSampleType(void)
224 {
225         return audioOutOptimalSampleType;
226 }
227
228 AudioOutState
229 _AudioOutImpl::GetState(void)
230 {
231         result r = E_SUCCESS;
232         SetLastResult(r);
233         SysLog(NID_MEDIA, "The current state of this instance is %d", __audioOutState);
234         return __audioOutState;
235 }
236
237 int
238 _AudioOutImpl::GetVolume(void) const
239 {
240         result r = E_SUCCESS;
241         SysTryCatch(NID_MEDIA, __audioOutState < AUDIOOUT_STATE_UNPREPARED && __audioOutState >= AUDIOOUT_STATE_PREPARED,
242         r = E_INVALID_STATE, E_INVALID_STATE, "[E_INVALID_STATE] The state of this instance is in an invalid state.");
243         return __volume;
244 CATCH:
245         SetLastResult(r);
246         return -1;
247 }
248
249 result
250 _AudioOutImpl::SetVolume(int& volume)
251 {
252         result r = E_SUCCESS;
253         SysTryCatch(NID_MEDIA, __audioOutState < AUDIOOUT_STATE_UNPREPARED && __audioOutState >= AUDIOOUT_STATE_PREPARED,
254                 r = E_INVALID_STATE, E_INVALID_STATE, "[E_INVALID_STATE] The state of this instance is in an invalid state.");
255         __volume = volume;
256         __volume256 = (__volume << 8) / 100;
257 CATCH:
258         return r;
259
260 }
261
262 result
263 _AudioOutImpl::Prepare(AudioSampleType audioSampleType, AudioChannelType audioChannelType, int audioSampleRate)
264 {
265         result r = E_SUCCESS;
266         int ret = 0;
267
268         SysTryReturnResult(NID_MEDIA, __audioOutState == AUDIOOUT_STATE_UNPREPARED || __audioOutState == AUDIOOUT_STATE_INITIALIZED,
269                 E_INVALID_STATE, "The state of this instance is in an invalid state.");
270         SysTryReturnResult(NID_MEDIA, audioSampleType >= AUDIO_TYPE_PCM_U8 && audioSampleType < AUDIO_TYPE_PCM_S16_BE, E_UNSUPPORTED_FORMAT,
271                 "Audio sample type is not valid.");
272         SysTryReturnResult(NID_MEDIA, audioChannelType == AUDIO_CHANNEL_TYPE_MONO || audioChannelType == AUDIO_CHANNEL_TYPE_STEREO, E_INVALID_ARG,
273                 "Invalid argument is used. Audio channel type is not valid");
274         SysTryReturnResult(NID_MEDIA, audioSampleRate >= 8000 && audioSampleRate <= 48000, E_INVALID_ARG,
275                 "Invalid argument is used. Audio sample rate is not valid.");
276
277         ret = audio_out_create(audioSampleRate, _AudioManagerConvert::ConvertChannelType(audioChannelType), _AudioManagerConvert::ConvertSampleType(audioSampleType), SOUND_TYPE_MEDIA, &__audioOutHandle);
278         r = MapExceptionToResult(ret);
279         SysTryCatch(NID_MEDIA, r != E_INVALID_STATE, , r, "[%s] The device has moved to invalid state as it has run out of system resources: 0x%x", GetErrorMessage(r), ret);
280         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_create operation with error code : 0x%x", GetErrorMessage(r), ret);
281
282         ret = audio_out_set_interrupted_cb(__audioOutHandle, AudioIoInterrupted, this);
283         r = MapExceptionToResult(ret);
284         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r,
285                 "[%s] Failed to perform audio_out_set_interrupted_cb operation with error code : 0x%x", GetErrorMessage(r), ret);
286
287         ret = audio_out_get_buffer_size(__audioOutHandle, &__audioOutOptimalBufferSize);
288         if (ret == AUDIO_IO_ERROR_NONE)
289         {
290                 SysLog(NID_MEDIA, "The optimal buffer size is %d", __audioOutOptimalBufferSize);
291         }
292         else
293         {
294                 r = MapExceptionToResult(ret);
295                 SysLogException(NID_MEDIA, r, "[%s] Failed to perform audio_out_get_buffer_size operation with error code : %x", GetErrorMessage(r), ret);
296         }
297         // this is done to get better Stop time
298         __audioOutOptimalBufferSize = 1024;
299         __pFeedBuffer.reset(new (std::nothrow) ByteBuffer);
300         __pFeedBuffer->Construct(__audioOutOptimalBufferSize);
301         __presentSampleType = audioSampleType;
302         __presentSampleRate = audioSampleRate;
303
304         __audioOutState = AUDIOOUT_STATE_PREPARED;
305         return r;
306 CATCH:
307         __audioOutHandle = null;
308         return r;
309 }
310
311 result
312 _AudioOutImpl::Prepare(AudioStreamType audioStreamType, AudioSampleType audioSampleType, AudioChannelType audioChannelType, int audioSampleRate)
313 {
314         result r = E_SUCCESS;
315         int ret = 0;
316
317         SysTryReturnResult(NID_MEDIA, __audioOutState == AUDIOOUT_STATE_UNPREPARED || __audioOutState == AUDIOOUT_STATE_INITIALIZED,
318                 E_INVALID_STATE, "The state of this instance is in an invalid state.");
319         SysTryReturnResult(NID_MEDIA, audioSampleType >= AUDIO_TYPE_PCM_U8 && audioSampleType < AUDIO_TYPE_PCM_S16_BE, E_UNSUPPORTED_FORMAT,
320                 "Audio sample type is not valid.");
321         SysTryReturnResult(NID_MEDIA, audioChannelType == AUDIO_CHANNEL_TYPE_MONO || audioChannelType == AUDIO_CHANNEL_TYPE_STEREO, E_INVALID_ARG,
322                 "Invalid argument is used. Audio channel type is not valid");
323         SysTryReturnResult(NID_MEDIA, audioSampleRate >= 8000 && audioSampleRate <= 48000, E_INVALID_ARG,
324                 "Invalid argument is used. Audio sample rate is not valid.");
325
326         ret = audio_out_create(audioSampleRate, _AudioManagerConvert::ConvertChannelType(audioChannelType), _AudioManagerConvert::ConvertSampleType(audioSampleType), _AudioManagerConvert::ConvertAudioStreamType2SoundType(audioStreamType), &__audioOutHandle);
327         r = MapExceptionToResult(ret);
328         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_create operation with error code : 0x%x", GetErrorMessage(r), ret);
329
330         ret = audio_out_prepare(__audioOutHandle);
331         r = MapExceptionToResult(ret);
332         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_prepare operation with error code : 0x%x", GetErrorMessage(r), ret);
333
334         ret = audio_out_set_interrupted_cb(__audioOutHandle, AudioIoInterrupted, this);
335         r = MapExceptionToResult(ret);
336         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_set_interrupted_cb operation with error code : 0x%x", GetErrorMessage(r), ret);
337
338         ret = audio_out_get_buffer_size(__audioOutHandle, &__audioOutOptimalBufferSize);
339         if (ret == AUDIO_IO_ERROR_NONE)
340         {
341                 SysLog(NID_MEDIA, "The optimal buffer size is %d", __audioOutOptimalBufferSize);
342         }
343         else
344         {
345                 r = MapExceptionToResult(ret);
346                 SysLogException(NID_MEDIA, r, "[%s] Failed to perform audio_out_get_buffer_size operation with error code : %x", GetErrorMessage(r), ret);
347         }
348
349         __audioOutOptimalBufferSize = 1024;
350         __pFeedBuffer.reset(new (std::nothrow) ByteBuffer);
351         __pFeedBuffer->Construct(__audioOutOptimalBufferSize);
352         __presentSampleType = audioSampleType;
353         __presentSampleRate = audioSampleRate;
354
355         __audioOutState = AUDIOOUT_STATE_PREPARED;
356         return r;
357 CATCH:
358         __audioOutHandle = null;
359         return r;
360 }
361
362 result
363 _AudioOutImpl::Reset(void)
364 {
365         result r = E_SUCCESS;
366         SysTryReturnResult(NID_MEDIA, __audioOutState <AUDIOOUT_STATE_UNPREPARED && __audioOutState> AUDIOOUT_STATE_PREPARED, E_INVALID_STATE,
367                 "The state of this instance is in an invalid state. the current state is %d.", __audioOutState);
368         if (__audioOutState == AUDIOOUT_STATE_PLAYING )
369         {
370                 Stop();
371         }
372         __bufferQueue.RemoveAll();
373         __audioOutState = AUDIOOUT_STATE_PREPARED;
374         return r;
375 }
376
377 result
378 _AudioOutImpl::UnPrepare(void)
379 {
380         result r = E_SUCCESS;
381         int ret = 0;
382
383         SysTryReturnResult(NID_MEDIA, __audioOutState == AUDIOOUT_STATE_PREPARED || __audioOutState == AUDIOOUT_STATE_STOPPED, E_INVALID_STATE,
384                 "The state of this instance is in an invalid state. the current state is %d", __audioOutState);
385         __bufferQueue.RemoveAll();
386
387         ret = audio_out_unprepare(__audioOutHandle);
388         r = MapExceptionToResult(ret);
389         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_prepare operation with error code : %x", GetErrorMessage(r), ret);
390
391         SysTryCatch(NID_MEDIA, __audioOutHandle, r = E_SYSTEM, E_SYSTEM, "__audioout Handle is NULL");
392
393         ret = audio_out_unset_interrupted_cb(__audioOutHandle);
394         r = MapExceptionToResult(ret);
395         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_unset_interrupted_cb operation with error code : %x", GetErrorMessage(r), ret);
396
397         ret = audio_out_destroy(__audioOutHandle);
398         r = MapExceptionToResult(ret);
399         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Failed to perform audio_out_destroy operation with error code : %d", GetErrorMessage(r), ret);
400         __audioOutHandle = null;
401
402         __audioOutState = AUDIOOUT_STATE_UNPREPARED;
403         return r;
404 CATCH:
405         return r;
406 }
407
408 result
409 _AudioOutImpl::Start(void)
410 {
411         result r = E_SUCCESS;
412         int ret = 0;
413         SysTryReturnResult(NID_MEDIA, __audioOutState == AUDIOOUT_STATE_PREPARED || __audioOutState == AUDIOOUT_STATE_STOPPED, E_INVALID_STATE,
414                 "The state of this instance is in an invalid state.");
415
416         ret = audio_out_prepare(__audioOutHandle);
417         r = MapExceptionToResult(ret);
418         SysTryReturnResult(NID_MEDIA, r != E_DEVICE_BUSY, E_DEVICE_BUSY, "AudioOut cannot Start, higher priority task at work.");
419         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r,
420                 "[%s] Failed to perform audio_out_prepare operation with error code :  0x%x", GetErrorMessage(r), ret);
421
422         __stop = false;
423         __pWorkerThread.reset(new (std::nothrow) Thread);
424         SysTryReturnResult(NID_MEDIA, __pWorkerThread.get() != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
425         r = __pWorkerThread->Construct(*this);
426         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
427         r = __pWorkerThread->Start();
428         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
429         __audioOutState = AUDIOOUT_STATE_PLAYING;
430         return r;
431 CATCH:
432         SetLastResult(r);
433         return r;
434 }
435
436 result
437 _AudioOutImpl::Stop(void)
438 {
439         result r = E_SUCCESS;
440         SysTryReturnResult(NID_MEDIA, __audioOutState == AUDIOOUT_STATE_PLAYING, E_INVALID_STATE,
441                 "The state of this instance is in an invalid state. The current state is %d", __audioOutState);
442         if (__pWorkerThread.get())
443         {
444                 __stop = true;
445                 __pBufferSync->Notify();
446                 r = __pWorkerThread->Join();
447                 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagating.", GetErrorMessage(r));
448         }
449         else
450         {
451                 SysLog(NID_MEDIA, "Thread is null.");
452         }
453         __audioOutState = AUDIOOUT_STATE_STOPPED;
454         return r;
455 }
456
457 result
458 _AudioOutImpl::WriteBuffer(const Tizen::Base::ByteBuffer& userData)
459 {
460         result r = E_SUCCESS;
461         int size = userData.GetLimit();
462         SysTryReturnResult(NID_MEDIA, __audioOutState >= AUDIOOUT_STATE_PREPARED && __audioOutState < AUDIOOUT_STATE_UNPREPARED, E_INVALID_STATE,
463                 "The state of this instance is in an invalid state.");
464         SysTryReturnResult(NID_MEDIA, (size >= audioOutMinimumBufferSize), E_INVALID_ARG,
465                 "Invalid argument is used. The size of buffer is too small, the current size of buffer is %d. It should be between %d and %d",
466                         audioOutMinimumBufferSize, size, audioOutMaximumBufferSize);
467         SysTryReturnResult(NID_MEDIA, audioOutMaximumBufferSize >= size, E_OVERFLOW, "The size of buffer size is too big, the current size is %d. It should be between %d and %d", audioOutMinimumBufferSize, size, audioOutMaximumBufferSize);
468
469         __pBufferSync->Enter();
470         r = __bufferQueue.Enqueue(&const_cast <ByteBuffer&>(userData));
471         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Propagating.", GetErrorMessage(r));
472         __pBufferSync->Notify();
473         __pBufferSync->Exit();
474         return r;
475 CATCH:
476         __pBufferSync->Exit();
477         return r;
478 }
479
480 Tizen::Base::Object*
481 _AudioOutImpl::Run(void)
482 {
483         ByteBuffer* pBuffer = null;
484         int buffer_size = 0;
485         unsigned char* pData = NULL;
486         result r = E_SUCCESS;
487         int ret = 0;
488         bool isSuccesful = true;
489         int feedSize = 0;
490         int index = 0;
491         while (!__stop)
492         {
493                 if (isSuccesful)
494                 {
495                         __pBufferSync->Enter();
496                         if ( __bufferQueue.Peek(pBuffer) == E_UNDERFLOW)
497                         {
498                                 //wait
499                                 __pBufferSync->Wait();
500                                 if (__stop)
501                                 {
502                                         __pBufferSync->Exit();
503                                         return this;
504                                 }
505                                 __bufferQueue.Peek(pBuffer);
506                         }
507                         __pBufferSync->Exit();
508
509                         SysTryCatch(NID_MEDIA, pBuffer, r = E_INVALID_ARG, E_INVALID_ARG,
510                                 "[E_INVALID_ARG] Invalid argument is used. The buffer to write is null.");
511                         isSuccesful = false;
512                 }
513
514                 buffer_size = pBuffer->GetLimit();
515                 pData = (unsigned char*) pBuffer->GetPointer();
516                 SysTryCatch(NID_MEDIA, pData, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Invalid argument is used. The data to write is null");
517                 index = 0;
518                 while (!__stop && buffer_size)
519                 {
520                         if (buffer_size > __audioOutOptimalBufferSize)
521                         {
522                                 feedSize = __audioOutOptimalBufferSize;
523                                 buffer_size = buffer_size - __audioOutOptimalBufferSize;
524                                 SysLog(NID_MEDIA, "index - %d buffer_size - %d", index, feedSize);
525                         }
526                         else
527                         {
528                                 feedSize = buffer_size;
529                                 buffer_size = 0;
530                                 SysLog(NID_MEDIA, "index - %d buffer_size - %d", index, feedSize);
531                         }
532                         if ((__volume >= 0) && (__volume < 100))
533                         {
534                                 PreProcess(pBuffer, index, feedSize);
535                                 ret = audio_out_write(__audioOutHandle, (void*) __pFeedBuffer->GetPointer(), feedSize);
536                         }
537                         else
538                         {
539                                 pData = pData + index;
540                                 ret = audio_out_write(__audioOutHandle, (void*) pData, feedSize);
541                         }
542                         if (ret != feedSize)
543                         {
544                                 SysLog(NID_MEDIA, "The size of actual written data is %d", ret);
545                         }
546                         index = index + feedSize;
547                 }
548                 if (buffer_size == 0)
549                 {
550                         isSuccesful = true;
551                         if (!__stop)
552                         {
553                                 __pBufferSync->Enter();
554                                 __bufferQueue.Dequeue(pBuffer);
555                                 __pBufferSync->Exit();
556                                 pBuffer = NULL;
557                                 SendBufferEndReachedEvent();
558                         }
559                 }
560         }
561         return this;
562 CATCH:
563         return this;
564 }
565
566 void
567 _AudioOutImpl::AudioIoInterrupted(audio_io_interrupted_code_e code, void *pUserData)
568 {
569         SysTryReturn(NID_MEDIA, pUserData, , E_SYSTEM, "[E_SYSTEM] A system error has been occurred. The value of pUserData is null.");
570         _AudioOutImpl *pAudioOutImpl = (_AudioOutImpl *)pUserData;
571
572         switch(code)
573         {
574         case AUDIO_IO_INTERRUPTED_COMPLETED:
575                 if (pAudioOutImpl->__audioOutState == AUDIOOUT_STATE_STOPPED)
576                 {
577                         if (!(pAudioOutImpl->__interruptFlag))
578                         {
579                                 pAudioOutImpl->SendReleased();
580                         }
581                         pAudioOutImpl->__interruptFlag = false;
582                 }
583                 break;
584         case AUDIO_IO_INTERRUPTED_BY_CALL:
585                 pAudioOutImpl->__interruptFlag = true;
586                 //Intentional Fall through
587         case AUDIO_IO_INTERRUPTED_BY_EARJACK_UNPLUG:
588                 //Intentional Fall through
589         case AUDIO_IO_INTERRUPTED_BY_MEDIA:
590                 //Intentional Fall through
591         case AUDIO_IO_INTERRUPTED_BY_RESOURCE_CONFLICT:
592                 if (pAudioOutImpl->__audioOutState == AUDIOOUT_STATE_PLAYING)
593                 {
594                         pAudioOutImpl->SendAudioFocusChanged();
595                 }
596                 break;
597         case AUDIO_IO_INTERRUPTED_BY_ALARM:
598                 //Intentional Fall through
599         case AUDIO_IO_INTERRUPTED_BY_EMERGENCY:
600                 //Intentional Fall through
601         case AUDIO_IO_INTERRUPTED_BY_RESUMABLE_MEDIA:
602                 if (pAudioOutImpl->__audioOutState == AUDIOOUT_STATE_PLAYING)
603                 {
604                         pAudioOutImpl->SendInterrupted();
605                 }
606                 break;
607         default:
608                 SysLog(NID_MEDIA, "Interrupt code obtained is wrong - %d", code);
609                 break;
610         }
611 }
612
613 result
614 _AudioOutImpl::SendBufferEndReachedEvent(void)
615 {
616         result r = E_SUCCESS;
617         _AudioOutEventArg* pAudioOutEventArg = null;
618         pAudioOutEventArg = new (std::nothrow) _AudioOutEventArg;
619         SysTryReturnResult(NID_MEDIA, pAudioOutEventArg, E_OUT_OF_MEMORY, "Memory allocation failed.");
620
621         pAudioOutEventArg->SetEventType(_AUDIOOUT_EVENT_DATA_END_REACHED);
622         r = __pAudioOutEvent->FireAsync(*pAudioOutEventArg);
623         SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = GetLastResult(), r, "[%s] Propagating.", GetErrorMessage(r));
624         return r;
625 CATCH:
626         delete pAudioOutEventArg;
627         return r;
628 }
629
630 result
631 _AudioOutImpl::SendInterrupted()
632 {
633         result r = E_SUCCESS;
634         _AudioOutEventArg* pAudioOutEventArg = null;
635         pAudioOutEventArg = new (std::nothrow) _AudioOutEventArg;
636         SysTryReturnResult(NID_MEDIA, pAudioOutEventArg, E_OUT_OF_MEMORY, "Memory allocation failed.");
637         this->Stop();
638         pAudioOutEventArg->SetEventType(_AUDIOOUT_EVENT_INTERRUPTED);
639         r = __pAudioOutEvent->FireAsync(*pAudioOutEventArg);
640         SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = GetLastResult(), r, "[%s] Propagating.", GetErrorMessage(r));
641         return r;
642 CATCH:
643         delete pAudioOutEventArg;
644         return r;
645 }
646
647 result
648 _AudioOutImpl::SendAudioFocusChanged()
649 {
650         result r = E_SUCCESS;
651         _AudioOutEventArg* pAudioOutEventArg = null;
652         pAudioOutEventArg = new (std::nothrow) _AudioOutEventArg;
653         SysTryReturnResult(NID_MEDIA, pAudioOutEventArg, E_OUT_OF_MEMORY, "Memory allocation failed.");
654         this->Stop();
655         pAudioOutEventArg->SetEventType(_AUDIOOUT_EVENT_AUDIO_FOCUS_CHANGED);
656         r = __pAudioOutEvent->FireAsync(*pAudioOutEventArg);
657         SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = GetLastResult(), r, "[%s] Propagating.", GetErrorMessage(r));
658         return r;
659 CATCH:
660         delete pAudioOutEventArg;
661         return r;
662 }
663
664 result
665 _AudioOutImpl::SendReleased()
666 {
667         result r = E_SUCCESS;
668         _AudioOutEventArg* pAudioOutEventArg = null;
669         pAudioOutEventArg = new (std::nothrow) _AudioOutEventArg;
670         SysTryReturnResult(NID_MEDIA, pAudioOutEventArg, E_OUT_OF_MEMORY, "Memory allocation failed.");
671         pAudioOutEventArg->SetEventType(_AUDIOOUT_EVENT_RELEASED);
672         r = __pAudioOutEvent->FireAsync(*pAudioOutEventArg);
673         SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = GetLastResult(), r, "[%s] Propagating.", GetErrorMessage(r));
674         return r;
675 CATCH:
676         delete pAudioOutEventArg;
677         return r;
678 }
679
680 void
681 _AudioOutImpl::ScaleDownVolume(unsigned char* pDataBuffer, int bytes)
682 {
683         switch (__presentSampleType)
684         {
685         case AUDIO_TYPE_PCM_U8:
686         {
687                 unsigned char* pOutput = __pFeedBuffer->GetPointer();
688                 unsigned char* pData = pDataBuffer;
689                 int noOfSamples = bytes;
690                 for (int i = 0; i < noOfSamples; i++)
691                 {
692                         int v = (((*pData++ - 128) * __volume256 + 128) >> 8) + 128;
693                         *pOutput++ = av_clip_uint8(v);
694                 }
695         }
696         break;
697
698         case AUDIO_TYPE_PCM_S16_LE:
699         {
700                 short* pData = (short*) pDataBuffer;
701                 short* pOutput = (short*) __pFeedBuffer->GetPointer();
702                 int noOfSamples = bytes >> 1;
703                 for (int i = 0; i < noOfSamples; i++)
704                 {
705                         int v = ((*pData++) * __volume256 + 128) >> 8;
706                         *pOutput++ = av_clip_int16(v);
707                 }
708         }
709         break;
710
711         default:
712                 break;
713         }
714 }
715
716 void
717 _AudioOutImpl::PreProcess(ByteBuffer* pBuffer, int index, int size)
718 {
719         unsigned char* pDataBuffer = null;
720         if (pBuffer->GetLimit() > 0)
721         {
722                 pDataBuffer = (unsigned char*) pBuffer->GetPointer();
723                 if (!pDataBuffer)
724                 {
725                         return;
726                 }
727                 pDataBuffer = pDataBuffer + index;
728         }
729         else
730         {
731                 return;
732         }
733         if ((__volume256 < 256) && (__volume256 >= 0))
734         {
735                 ScaleDownVolume(pDataBuffer, size);
736         }
737 }
738
739 result
740 _AudioOutImpl::MapExceptionToResult(int reason)
741 {
742         //All the fall through are intentional
743         switch (reason)
744         {
745         //Successful
746         case AUDIO_IO_ERROR_NONE:
747                 return E_SUCCESS;
748                 break;
749         //Out of memory
750         case AUDIO_IO_ERROR_OUT_OF_MEMORY:
751                 return E_OUT_OF_MEMORY;
752                 break;
753         //Invalid parameter
754         case AUDIO_IO_ERROR_INVALID_PARAMETER:
755                 return E_INVALID_ARG;
756                 break;
757         //Invalid operation
758         case AUDIO_IO_ERROR_INVALID_OPERATION:
759                 return E_INVALID_OPERATION;
760                 break;
761         //Deviced not opened
762         case AUDIO_IO_ERROR_DEVICE_NOT_OPENED:
763                 return E_INVALID_STATE;
764                 break;
765         //Invalid Buffer
766         case AUDIO_IO_ERROR_INVALID_BUFFER:
767                 return E_INVALID_ARG;
768                 break;
769         //Device not Closed
770         case AUDIO_IO_ERROR_DEVICE_NOT_CLOSED:
771                 return E_INVALID_STATE;
772                 break;
773         //Sound policy error
774         case AUDIO_IO_ERROR_SOUND_POLICY:
775                 return E_DEVICE_BUSY;
776                 break;
777         default:
778                 return E_SYSTEM;
779                 break;
780         }
781 }
782
783 }}  //Tizen::Media