OSDN Git Service

RIO-8910: Fix for MP3 parser returning incorrect value for bitrate key
[android-x86/external-opencore.git] / android / android_audio_output.cpp
1 /*
2 **
3 ** Copyright 2008, The Android Open Source Project
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
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "AudioOutput"
20 #include <utils/Log.h>
21
22 #include "android_audio_output.h"
23
24 #include <sys/prctl.h>
25 #include <sys/resource.h>
26 #include <utils/threads.h>
27 #include <media/AudioTrack.h>
28
29 using namespace android;
30
31 // TODO: dynamic buffer count based on sample rate and # channels
32 static const int kNumOutputBuffers = 4;
33
34 // maximum allowed clock drift before correction
35 static const int32 kMaxClockDriftInMsecs = 25;    // should be tight enough for reasonable sync
36 static const int32 kMaxClockCorrection = 100;     // maximum clock correction per update
37
38 /*
39 / Packet Video Audio MIO component
40 /
41 / This implementation routes audio to AudioFlinger. Audio buffers are
42 / enqueued in a message queue to a separate audio output thread. Once
43 / the buffers have been successfully written, they are returned through
44 / another message queue to the MIO and from there back to the engine.
45 / This separation is necessary because most of the PV API is not
46 / thread-safe.
47 */
48 OSCL_EXPORT_REF AndroidAudioOutput::AndroidAudioOutput() :
49         AndroidAudioMIO("AndroidAudioOutput"),
50         iExitAudioThread(false),
51         iReturnBuffers(false),
52         iActiveTiming(NULL)
53 {
54     LOGV("constructor");
55     iClockTimeOfWriting_ns = 0;
56     iInputFrameSizeInBytes = 0;
57
58     // semaphore used to communicate between this  mio and the audio output thread
59     iAudioThreadSem = new OsclSemaphore();
60     iAudioThreadSem->Create(0);
61     iAudioThreadTermSem = new OsclSemaphore();
62     iAudioThreadTermSem->Create(0);
63     iAudioThreadReturnSem = new OsclSemaphore();
64     iAudioThreadReturnSem->Create(0);
65     iAudioThreadCreatedSem = new OsclSemaphore();
66     iAudioThreadCreatedSem->Create(0);
67
68     // locks to access the queues by this mio and by the audio output thread
69     iOSSRequestQueueLock.Create();
70     iOSSRequestQueue.reserve(iWriteResponseQueue.capacity());
71
72     // create active timing object
73     OsclMemAllocator alloc;
74     OsclAny*ptr = alloc.allocate(sizeof(AndroidAudioMIOActiveTimingSupport));
75     if (ptr)
76     {
77         iActiveTiming = new(ptr)AndroidAudioMIOActiveTimingSupport(kMaxClockDriftInMsecs, kMaxClockCorrection);
78         iActiveTiming->setThreadSemaphore(iAudioThreadSem);
79     }
80 }
81
82 OSCL_EXPORT_REF AndroidAudioOutput::~AndroidAudioOutput()
83 {
84     LOGV("destructor");
85
86     // make sure output thread has exited
87     RequestAndWaitForThreadExit();
88
89     // cleanup active timing object
90     if (iActiveTiming)
91     {
92         iActiveTiming->~AndroidAudioMIOActiveTimingSupport();
93         OsclMemAllocator alloc;
94         alloc.deallocate(iActiveTiming);
95     }
96
97     // clean up some thread interface objects
98     iAudioThreadSem->Close();
99     delete iAudioThreadSem;
100     iAudioThreadTermSem->Close();
101     delete iAudioThreadTermSem;
102     iAudioThreadReturnSem->Close();
103     delete iAudioThreadReturnSem;
104     iAudioThreadCreatedSem->Close();
105     delete iAudioThreadCreatedSem;
106
107     iOSSRequestQueueLock.Close();
108 }
109
110 PVMFCommandId AndroidAudioOutput::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext)
111 {
112     LOGV("QueryInterface in");
113     // check for active timing extension
114     if (iActiveTiming && (aUuid == PvmiClockExtensionInterfaceUuid))
115     {
116         PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, iActiveTiming);
117         aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface);
118         return QueueCmdResponse(PVMFSuccess, aContext);
119     }
120
121     // pass to base class
122     else return AndroidAudioMIO::QueryInterface(aUuid, aInterfacePtr, aContext);
123 }
124
125 PVMFCommandId AndroidAudioOutput::Stop(const OsclAny* aContext)
126 {
127     LOGV("AndroidAudioOutput Stop (%p)", aContext);
128     // return all buffer by writecomplete
129     returnAllBuffers();
130     return AndroidAudioMIO::Stop(aContext);
131 }
132
133 PVMFCommandId AndroidAudioOutput::Reset(const OsclAny* aContext)
134 {
135     LOGV("AndroidAudioOutput Reset (%p)", aContext);
136     // return all buffer by writecomplete
137     returnAllBuffers();
138     // request output thread to exit
139     RequestAndWaitForThreadExit();
140     return AndroidAudioMIO::Reset(aContext);
141 }
142
143 void AndroidAudioOutput::cancelCommand(PVMFCommandId command_id)
144 {
145     LOGV("cancelCommand (%u) RequestQ size %d", command_id, iOSSRequestQueue.size());
146     iOSSRequestQueueLock.Lock();
147     for (uint32 i = 0; i < iOSSRequestQueue.size(); i++)
148     {
149         if (iOSSRequestQueue[i].iCmdId == command_id)
150         {
151             iDataQueued -= iOSSRequestQueue[i].iDataLen;
152             if (iPeer)
153                 iPeer->writeComplete(PVMFSuccess, iOSSRequestQueue[i].iCmdId, (OsclAny*)iOSSRequestQueue[i].iContext);
154             iOSSRequestQueue.erase(&iOSSRequestQueue[i]);
155             break;
156         }
157     }
158     iOSSRequestQueueLock.Unlock();
159     LOGV("cancelCommand data queued = %u", iDataQueued);
160
161     ProcessWriteResponseQueue();
162 }
163
164 void AndroidAudioOutput::returnAllBuffers()
165 {
166     LOGV("returnAllBuffers RequestQ size %d", iOSSRequestQueue.size());
167     iOSSRequestQueueLock.Lock();
168     while (iOSSRequestQueue.size())
169     {
170         iDataQueued -= iOSSRequestQueue[0].iDataLen;
171         if (iPeer)
172             iPeer->writeComplete(PVMFSuccess, iOSSRequestQueue[0].iCmdId, (OsclAny*)iOSSRequestQueue[0].iContext);
173         iOSSRequestQueue.erase(&iOSSRequestQueue[0]);
174     }
175     iOSSRequestQueueLock.Unlock();
176     LOGV("returnAllBuffers data queued = %u", iDataQueued);
177     if (iAudioThreadSem && iAudioThreadCreatedAndMIOConfigured)
178     {
179         LOGV("signal thread to return buffers");
180         iReturnBuffers = true;
181         iAudioThreadSem->Signal();
182         while (iAudioThreadReturnSem->Wait() != OsclProcStatus::SUCCESS_ERROR)
183             ;
184         LOGV("return buffers signal completed");
185     }
186 }
187
188
189 PVMFCommandId AndroidAudioOutput::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext)
190 {
191     LOGV("DiscardData timestamp(%u) RequestQ size %d", aTimestamp, iOSSRequestQueue.size());
192
193     if (iActiveTiming)
194     {
195         LOGV("Force clock update");
196         iActiveTiming->ForceClockUpdate();
197     }
198
199     bool sched = false;
200     PVMFCommandId audcmdid;
201     const OsclAny* context;
202     PVMFTimestamp timestamp;
203
204     // the OSSRequest queue should be drained
205     // all the buffers in them should be returned to the engine
206     // writeComplete cannot be called from here
207     // thus the best way is to queue the buffers onto the write response queue
208     // and then call RunIfNotReady
209     iOSSRequestQueueLock.Lock();
210     for (int32 i = (iOSSRequestQueue.size() - 1); i >= 0; i--)
211     {
212         if (iOSSRequestQueue[i].iTimestamp < aTimestamp)
213         {
214             audcmdid = iOSSRequestQueue[i].iCmdId;
215             context = iOSSRequestQueue[i].iContext;
216             timestamp = iOSSRequestQueue[i].iTimestamp;
217             iDataQueued -= iOSSRequestQueue[i].iDataLen;
218             LOGV("discard buffer (%d) context(%p) timestamp(%u) Datalen(%d)", audcmdid, context, timestamp, iOSSRequestQueue[i].iDataLen);
219             iOSSRequestQueue.erase(&iOSSRequestQueue[i]);
220             sched = true;
221
222             WriteResponse resp(PVMFSuccess, audcmdid, context, timestamp);
223             iWriteResponseQueueLock.Lock();
224             iWriteResponseQueue.push_back(resp);
225             iWriteResponseQueueLock.Unlock();
226         }
227     }
228     LOGV("DiscardData data queued = %u, setting flush pending", iDataQueued);
229     iFlushPending = true;
230
231     iOSSRequestQueueLock.Unlock();
232
233     if (sched)
234         RunIfNotReady();
235
236     return AndroidAudioMIO::DiscardData(aTimestamp, aContext);
237 }
238
239 void AndroidAudioOutput::RequestAndWaitForThreadExit()
240 {
241     LOGV("RequestAndWaitForThreadExit In");
242     if (iAudioThreadSem && iAudioThreadCreatedAndMIOConfigured)
243     {
244         LOGV("signal thread for exit");
245         iExitAudioThread = true;
246         iAudioThreadSem->Signal();
247         while (iAudioThreadTermSem->Wait() != OsclProcStatus::SUCCESS_ERROR)
248             ;
249         LOGV("thread term signal received");
250         iAudioThreadCreatedAndMIOConfigured = false;
251     }
252 }
253
254 void AndroidAudioOutput::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
255         int num_elements, PvmiKvp * & aRet_kvp)
256 {
257     LOGV("AndroidAudioOutput setParametersSync In");
258     AndroidAudioMIO::setParametersSync(aSession, aParameters, num_elements, aRet_kvp);
259
260     // initialize thread when we have enough information
261     if (iAudioSamplingRateValid && iAudioNumChannelsValid && iAudioFormat != PVMF_MIME_FORMAT_UNKNOWN)
262     {
263         LOGV("start audio thread");
264         OsclThread AudioOutput_Thread;
265         iExitAudioThread = false;
266         iReturnBuffers = false;
267         OsclProcStatus::eOsclProcError ret = AudioOutput_Thread.Create((TOsclThreadFuncPtr)start_audout_thread_func,
268                                              0, (TOsclThreadFuncArg)this, Start_on_creation);
269
270         //Don't signal the MIO node that the configuration is complete until the driver latency has been set
271         while (iAudioThreadCreatedSem->Wait() != OsclProcStatus::SUCCESS_ERROR)
272             ;
273
274         if (OsclProcStatus::SUCCESS_ERROR == ret)
275         {
276             iAudioThreadCreatedAndMIOConfigured = true;
277             if (iObserver)
278             {
279                 LOGV("event PVMFMIOConfigurationComplete to peer");
280                 iObserver->ReportInfoEvent(PVMFMIOConfigurationComplete);
281             }
282         }
283         else
284         {
285             iAudioThreadCreatedAndMIOConfigured = false;
286             if (iObserver)
287             {
288                 LOGE("event PVMFErrResourceConfiguration to peer");
289                 iObserver->ReportErrorEvent(PVMFErrResourceConfiguration);
290             }
291         }
292     }
293     LOGV("AndroidAudioOutput setParametersSync out");
294 }
295
296 void AndroidAudioOutput::Run()
297 {
298     // if running, update clock
299     if ((iState == STATE_MIO_STARTED) && iInputFrameSizeInBytes)
300     {
301         uint32 msecsQueued = iDataQueued / iInputFrameSizeInBytes * iActiveTiming->msecsPerFrame();
302         LOGV("%u msecs of data queued, %u bytes of data queued", msecsQueued, iDataQueued);
303         iActiveTiming->UpdateClock();
304     }
305     AndroidAudioMIO::Run();
306 }
307
308 void AndroidAudioOutput::writeAudioBuffer(uint8* aData, uint32 aDataLen, PVMFCommandId cmdId, OsclAny* aContext, PVMFTimestamp aTimestamp)
309 {
310     // queue up buffer and signal audio thread to process it
311     LOGV("writeAudioBuffer :: DataLen(%d), cmdId(%d), Context(%p), Timestamp (%d)", aDataLen, cmdId, aContext, aTimestamp);
312     OSSRequest req(aData, aDataLen, cmdId, aContext, aTimestamp);
313     iOSSRequestQueueLock.Lock();
314     iOSSRequestQueue.push_back(req);
315     iDataQueued += aDataLen;
316
317     // wake up the audio output thread to process this buffer only if clock has started running
318     if (iActiveTiming->clockState() == PVMFMediaClock::RUNNING)
319     {
320         LOGV("clock is ticking signal thread for data");
321         iAudioThreadSem->Signal();
322     }
323     iOSSRequestQueueLock.Unlock();
324 }
325
326 //------------------------------------------------------------------------
327 // audio thread
328 //
329
330 #undef LOG_TAG
331 #define LOG_TAG "audiothread"
332
333 // this is the audio output thread
334 // used to send data to the linux audio output device
335 // communicates with the audio MIO via a semaphore, a request queue and a response queue
336 /*static*/ int AndroidAudioOutput::start_audout_thread_func(TOsclThreadFuncArg arg)
337 {
338     LOGV("start_audout_thread_func in");
339     AndroidAudioOutput *obj = (AndroidAudioOutput *)arg;
340     prctl(PR_SET_NAME, (unsigned long) "audio out", 0, 0, 0);
341     int err = obj->audout_thread_func();
342     LOGV("start_audout_thread_func out return code %d", err);
343     return err;
344 }
345
346 int AndroidAudioOutput::audout_thread_func()
347 {
348     enum { IDLE, STOPPED, STARTED, PAUSED } state = IDLE;
349     int64_t lastClock = 0;
350
351     // LOGD("audout_thread_func");
352
353 #if defined(HAVE_SCHED_SETSCHEDULER) && defined(HAVE_GETTID)
354     setpriority(PRIO_PROCESS, gettid(), ANDROID_PRIORITY_AUDIO);
355 #endif
356
357     if (iAudioNumChannelsValid == false || iAudioSamplingRateValid == false || iAudioFormat == PVMF_MIME_FORMAT_UNKNOWN)
358     {
359         LOGE("channel count or sample rate is invalid");
360         return -1;
361     }
362
363     LOGV("Creating AudioTrack object: rate=%d, channels=%d, buffers=%d", iAudioSamplingRate, iAudioNumChannels, kNumOutputBuffers);
364     status_t ret = mAudioSink->open(iAudioSamplingRate, iAudioNumChannels, ((iAudioFormat == PVMF_MIME_PCM8) ? AudioSystem::PCM_8_BIT : AudioSystem::PCM_16_BIT), kNumOutputBuffers);
365     iAudioSamplingRateValid = false; // purpose of these flags is over here, reset these for next validation recording.
366     iAudioNumChannelsValid  = false;
367     iAudioFormat = PVMF_MIME_FORMAT_UNKNOWN;
368     if (ret != 0)
369     {
370         iAudioThreadCreatedAndMIOConfigured = false;
371         LOGE("Error creating AudioTrack");
372         return -1;
373     }
374
375     // calculate timing data
376     int outputFrameSizeInBytes = mAudioSink->frameSize();
377     float msecsPerFrame = mAudioSink->msecsPerFrame();
378     uint32 latency = mAudioSink->latency();
379     LOGV("driver latency(%u),outputFrameSizeInBytes(%d),msecsPerFrame(%f),frame count(%d)", latency, outputFrameSizeInBytes, msecsPerFrame, mAudioSink->frameCount());
380
381     // initialize active timing
382     iActiveTiming->setFrameRate(msecsPerFrame);
383     iActiveTiming->setDriverLatency(latency);
384
385     iAudioThreadCreatedSem->Signal();
386     // this must be set after iActiveTiming->setFrameRate to prevent race
387     // condition in Run()
388     iInputFrameSizeInBytes = outputFrameSizeInBytes;
389
390     // buffer management
391     uint32 bytesAvailInBuffer = 0;
392     uint32 bytesToWrite;
393     uint32 bytesWritten;
394     uint8* data = 0;
395     uint32 len = 0;
396     PVMFCommandId cmdid = 0;
397     const OsclAny* context = 0;
398     PVMFTimestamp timestamp = 0;
399
400     // wait for signal from MIO thread
401     LOGV("wait for signal");
402     iAudioThreadSem->Wait();
403     LOGV("ready to work");
404
405     while (1)
406     {
407         // if paused, stop the output track
408         switch (iActiveTiming->clockState())
409         {
410             case PVMFMediaClock::RUNNING:
411                 // start output
412                 if (state != STARTED)
413                 {
414                     if (iFlushPending)
415                     {
416                         LOGV("flush");
417                         mAudioSink->flush();
418                         iFlushPending = false;
419                         bytesAvailInBuffer = 0;
420                         iClockTimeOfWriting_ns = 0;
421                         // discard partial buffer and send response to MIO
422                         if (data && len)
423                         {
424                             LOGV("discard partial buffer and send response to MIO");
425                             sendResponse(cmdid, context, timestamp);
426                             data = 0;
427                             len = 0;
428                         }
429                     }
430                     if (iDataQueued || len)
431                     {
432                         LOGV("start");
433                         mAudioSink->start();
434                         state = STARTED;
435                     }
436                     else
437                     {
438                         LOGV("clock running and no data queued - don't start track");
439                     }
440                 }
441                 else
442                 {
443                     LOGV("audio sink already in started state");
444                 }
445                 break;
446             case PVMFMediaClock::STOPPED:
447                 LOGV("clock has been stopped...");
448             case PVMFMediaClock::PAUSED:
449                 if (state == STARTED)
450                 {
451                     LOGV("pause");
452                     mAudioSink->pause();
453                 }
454                 state = PAUSED;
455                 if (!iExitAudioThread && !iReturnBuffers)
456                 {
457                     LOGV("wait");
458                     iAudioThreadSem->Wait();
459                     LOGV("awake");
460                 }
461                 break;
462             default:
463                 break;
464         }
465         // if out of data, check the request queue
466         if (len == 0)
467         {
468             //LOGV("no playable data, Request Q size %d",iOSSRequestQueue.size());
469             iOSSRequestQueueLock.Lock();
470             bool empty = iOSSRequestQueue.empty();
471             if (!empty)
472             {
473                 data = iOSSRequestQueue[0].iData;
474                 len = iOSSRequestQueue[0].iDataLen;
475                 cmdid = iOSSRequestQueue[0].iCmdId;
476                 context = iOSSRequestQueue[0].iContext;
477                 timestamp = iOSSRequestQueue[0].iTimestamp;
478                 iDataQueued -= len;
479                 iOSSRequestQueue.erase(&iOSSRequestQueue[0]);
480                 LOGV("receive buffer (%d), timestamp = %u data queued = %u", cmdid, timestamp, iDataQueued);
481             }
482             iOSSRequestQueueLock.Unlock();
483
484             // if queue is empty, wait for more work
485             // FIXME: Why do end up here so many times when stopping?
486             if (empty && !iExitAudioThread && !iReturnBuffers)
487             {
488                 LOGV("queue is empty, wait for more work");
489                 iAudioThreadSem->Wait();
490             }
491
492             // empty buffer means "End-Of-Stream" - send response to MIO
493             else if (len == 0)
494             {
495                 LOGV("EOS");
496                 state = STOPPED;
497                 mAudioSink->stop();
498                 if (!iExitAudioThread)
499                 {
500                     nsecs_t interval_nanosec = 0; // Interval between last writetime and EOS processing time in nanosec
501                     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
502                     LOGV("now = %lld ,iClockTimeOfWriting_ns = %lld", now, iClockTimeOfWriting_ns);
503                     if (now >= iClockTimeOfWriting_ns)
504                     {
505                         interval_nanosec = now - iClockTimeOfWriting_ns;
506                     }
507                     else  //when timevalue wraps
508                     {
509                         interval_nanosec = 0;
510                     }
511                     LOGV(" I am early,going for sleep for latency = %u millsec, interval_nanosec = %lld", latency, interval_nanosec);
512                     struct timespec requested_time_delay, remaining;
513                     requested_time_delay.tv_sec = latency / 1000;
514                     nsecs_t latency_nanosec = (latency % 1000) * 1000 * 1000;
515                     if (interval_nanosec < latency_nanosec)
516                     {
517                         requested_time_delay.tv_nsec = latency_nanosec - interval_nanosec;
518                         nanosleep(&requested_time_delay, &remaining);
519                         LOGV(" Wow, what a great siesta....send response to engine");
520                     }
521                     else // interval is greater than latency so no need of sleep
522                     {
523                         LOGV(" No time to sleep :( send response to engine anyways");
524                     }
525                     iClockTimeOfWriting_ns = 0;
526                     sendResponse(cmdid, context, timestamp);
527                 }
528             }
529         }
530
531         if (iReturnBuffers)
532         {
533             LOGV("Return buffers from the audio thread");
534             if (len) sendResponse(cmdid, context, timestamp);
535             iReturnBuffers = false;
536             data = 0;
537             len = 0;
538             iAudioThreadReturnSem->Signal();
539         }
540
541         // check for exit signal
542         if (iExitAudioThread)
543         {
544             LOGV("exit received");
545             if (len) sendResponse(cmdid, context, timestamp);
546             break;
547         }
548
549         // data to output?
550         if (len && (state == STARTED) && !iExitAudioThread)
551         {
552
553             // always align to AudioFlinger buffer boundary
554             if (bytesAvailInBuffer == 0)
555                 bytesAvailInBuffer = mAudioSink->bufferSize();
556
557             bytesToWrite = bytesAvailInBuffer > len ? len : bytesAvailInBuffer;
558             //LOGV("16 bit :: cmdid = %d, len = %u, bytesAvailInBuffer = %u, bytesToWrite = %u", cmdid, len, bytesAvailInBuffer, bytesToWrite);
559             bytesWritten = mAudioSink->write(data, bytesToWrite);
560             if (bytesWritten != bytesToWrite)
561             {
562                 LOGE("Error writing audio data");
563                 iAudioThreadSem->Wait();
564             }
565             data += bytesWritten;
566             len -= bytesWritten;
567             iClockTimeOfWriting_ns = systemTime(SYSTEM_TIME_MONOTONIC);
568
569
570             // count bytes sent
571             bytesAvailInBuffer -= bytesWritten;
572
573             // update frame count for latency calculation
574             iActiveTiming->incFrameCount(bytesWritten / outputFrameSizeInBytes);
575             //LOGV("outputFrameSizeInBytes = %u,bytesWritten = %u,bytesAvailInBuffer = %u", outputFrameSizeInBytes,bytesWritten,bytesAvailInBuffer);
576             // if done with buffer - send response to MIO
577             if (data && !len)
578             {
579                 LOGV("done with the data cmdid %d, context %p, timestamp %d ", cmdid, context, timestamp);
580                 sendResponse(cmdid, context, timestamp);
581                 data = 0;
582             }
583         }
584     } // while loop
585
586     LOGV("stop and delete track");
587     mAudioSink->stop();
588     iClockTimeOfWriting_ns = 0;
589
590     // LOGD("audout_thread_func exit");
591     iAudioThreadTermSem->Signal();
592
593     return 0;
594 }
595