3 ** Copyright 2008, The Android Open Source Project
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
9 ** http://www.apache.org/licenses/LICENSE-2.0
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.
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "AudioOutput"
20 #include <utils/Log.h>
22 #include "android_audio_output.h"
24 #include <sys/prctl.h>
25 #include <sys/resource.h>
26 #include <utils/threads.h>
27 #include <media/AudioTrack.h>
29 using namespace android;
31 // TODO: dynamic buffer count based on sample rate and # channels
32 static const int kNumOutputBuffers = 4;
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
39 / Packet Video Audio MIO component
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
48 OSCL_EXPORT_REF AndroidAudioOutput::AndroidAudioOutput() :
49 AndroidAudioMIO("AndroidAudioOutput"),
50 iExitAudioThread(false),
51 iReturnBuffers(false),
55 iClockTimeOfWriting_ns = 0;
56 iInputFrameSizeInBytes = 0;
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);
68 // locks to access the queues by this mio and by the audio output thread
69 iOSSRequestQueueLock.Create();
70 iOSSRequestQueue.reserve(iWriteResponseQueue.capacity());
72 // create active timing object
73 OsclMemAllocator alloc;
74 OsclAny*ptr = alloc.allocate(sizeof(AndroidAudioMIOActiveTimingSupport));
77 iActiveTiming = new(ptr)AndroidAudioMIOActiveTimingSupport(kMaxClockDriftInMsecs, kMaxClockCorrection);
78 iActiveTiming->setThreadSemaphore(iAudioThreadSem);
82 OSCL_EXPORT_REF AndroidAudioOutput::~AndroidAudioOutput()
86 // make sure output thread has exited
87 RequestAndWaitForThreadExit();
89 // cleanup active timing object
92 iActiveTiming->~AndroidAudioMIOActiveTimingSupport();
93 OsclMemAllocator alloc;
94 alloc.deallocate(iActiveTiming);
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;
107 iOSSRequestQueueLock.Close();
110 PVMFCommandId AndroidAudioOutput::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext)
112 LOGV("QueryInterface in");
113 // check for active timing extension
114 if (iActiveTiming && (aUuid == PvmiClockExtensionInterfaceUuid))
116 PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, iActiveTiming);
117 aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface);
118 return QueueCmdResponse(PVMFSuccess, aContext);
121 // pass to base class
122 else return AndroidAudioMIO::QueryInterface(aUuid, aInterfacePtr, aContext);
125 PVMFCommandId AndroidAudioOutput::Stop(const OsclAny* aContext)
127 LOGV("AndroidAudioOutput Stop (%p)", aContext);
128 // return all buffer by writecomplete
130 return AndroidAudioMIO::Stop(aContext);
133 PVMFCommandId AndroidAudioOutput::Reset(const OsclAny* aContext)
135 LOGV("AndroidAudioOutput Reset (%p)", aContext);
136 // return all buffer by writecomplete
138 // request output thread to exit
139 RequestAndWaitForThreadExit();
140 return AndroidAudioMIO::Reset(aContext);
143 void AndroidAudioOutput::cancelCommand(PVMFCommandId command_id)
145 LOGV("cancelCommand (%u) RequestQ size %d", command_id, iOSSRequestQueue.size());
146 iOSSRequestQueueLock.Lock();
147 for (uint32 i = 0; i < iOSSRequestQueue.size(); i++)
149 if (iOSSRequestQueue[i].iCmdId == command_id)
151 iDataQueued -= iOSSRequestQueue[i].iDataLen;
153 iPeer->writeComplete(PVMFSuccess, iOSSRequestQueue[i].iCmdId, (OsclAny*)iOSSRequestQueue[i].iContext);
154 iOSSRequestQueue.erase(&iOSSRequestQueue[i]);
158 iOSSRequestQueueLock.Unlock();
159 LOGV("cancelCommand data queued = %u", iDataQueued);
161 ProcessWriteResponseQueue();
164 void AndroidAudioOutput::returnAllBuffers()
166 LOGV("returnAllBuffers RequestQ size %d", iOSSRequestQueue.size());
167 iOSSRequestQueueLock.Lock();
168 while (iOSSRequestQueue.size())
170 iDataQueued -= iOSSRequestQueue[0].iDataLen;
172 iPeer->writeComplete(PVMFSuccess, iOSSRequestQueue[0].iCmdId, (OsclAny*)iOSSRequestQueue[0].iContext);
173 iOSSRequestQueue.erase(&iOSSRequestQueue[0]);
175 iOSSRequestQueueLock.Unlock();
176 LOGV("returnAllBuffers data queued = %u", iDataQueued);
177 if (iAudioThreadSem && iAudioThreadCreatedAndMIOConfigured)
179 LOGV("signal thread to return buffers");
180 iReturnBuffers = true;
181 iAudioThreadSem->Signal();
182 while (iAudioThreadReturnSem->Wait() != OsclProcStatus::SUCCESS_ERROR)
184 LOGV("return buffers signal completed");
189 PVMFCommandId AndroidAudioOutput::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext)
191 LOGV("DiscardData timestamp(%u) RequestQ size %d", aTimestamp, iOSSRequestQueue.size());
195 LOGV("Force clock update");
196 iActiveTiming->ForceClockUpdate();
200 PVMFCommandId audcmdid;
201 const OsclAny* context;
202 PVMFTimestamp timestamp;
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--)
212 if (iOSSRequestQueue[i].iTimestamp < aTimestamp)
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]);
222 WriteResponse resp(PVMFSuccess, audcmdid, context, timestamp);
223 iWriteResponseQueueLock.Lock();
224 iWriteResponseQueue.push_back(resp);
225 iWriteResponseQueueLock.Unlock();
228 LOGV("DiscardData data queued = %u, setting flush pending", iDataQueued);
229 iFlushPending = true;
231 iOSSRequestQueueLock.Unlock();
236 return AndroidAudioMIO::DiscardData(aTimestamp, aContext);
239 void AndroidAudioOutput::RequestAndWaitForThreadExit()
241 LOGV("RequestAndWaitForThreadExit In");
242 if (iAudioThreadSem && iAudioThreadCreatedAndMIOConfigured)
244 LOGV("signal thread for exit");
245 iExitAudioThread = true;
246 iAudioThreadSem->Signal();
247 while (iAudioThreadTermSem->Wait() != OsclProcStatus::SUCCESS_ERROR)
249 LOGV("thread term signal received");
250 iAudioThreadCreatedAndMIOConfigured = false;
254 void AndroidAudioOutput::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
255 int num_elements, PvmiKvp * & aRet_kvp)
257 LOGV("AndroidAudioOutput setParametersSync In");
258 AndroidAudioMIO::setParametersSync(aSession, aParameters, num_elements, aRet_kvp);
260 // initialize thread when we have enough information
261 if (iAudioSamplingRateValid && iAudioNumChannelsValid && iAudioFormat != PVMF_MIME_FORMAT_UNKNOWN)
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);
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)
274 if (OsclProcStatus::SUCCESS_ERROR == ret)
276 iAudioThreadCreatedAndMIOConfigured = true;
279 LOGV("event PVMFMIOConfigurationComplete to peer");
280 iObserver->ReportInfoEvent(PVMFMIOConfigurationComplete);
285 iAudioThreadCreatedAndMIOConfigured = false;
288 LOGE("event PVMFErrResourceConfiguration to peer");
289 iObserver->ReportErrorEvent(PVMFErrResourceConfiguration);
293 LOGV("AndroidAudioOutput setParametersSync out");
296 void AndroidAudioOutput::Run()
298 // if running, update clock
299 if ((iState == STATE_MIO_STARTED) && iInputFrameSizeInBytes)
301 uint32 msecsQueued = iDataQueued / iInputFrameSizeInBytes * iActiveTiming->msecsPerFrame();
302 LOGV("%u msecs of data queued, %u bytes of data queued", msecsQueued, iDataQueued);
303 iActiveTiming->UpdateClock();
305 AndroidAudioMIO::Run();
308 void AndroidAudioOutput::writeAudioBuffer(uint8* aData, uint32 aDataLen, PVMFCommandId cmdId, OsclAny* aContext, PVMFTimestamp aTimestamp)
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;
317 // wake up the audio output thread to process this buffer only if clock has started running
318 if (iActiveTiming->clockState() == PVMFMediaClock::RUNNING)
320 LOGV("clock is ticking signal thread for data");
321 iAudioThreadSem->Signal();
323 iOSSRequestQueueLock.Unlock();
326 //------------------------------------------------------------------------
331 #define LOG_TAG "audiothread"
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)
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);
346 int AndroidAudioOutput::audout_thread_func()
348 enum { IDLE, STOPPED, STARTED, PAUSED } state = IDLE;
349 int64_t lastClock = 0;
351 // LOGD("audout_thread_func");
353 #if defined(HAVE_SCHED_SETSCHEDULER) && defined(HAVE_GETTID)
354 setpriority(PRIO_PROCESS, gettid(), ANDROID_PRIORITY_AUDIO);
357 if (iAudioNumChannelsValid == false || iAudioSamplingRateValid == false || iAudioFormat == PVMF_MIME_FORMAT_UNKNOWN)
359 LOGE("channel count or sample rate is invalid");
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;
370 iAudioThreadCreatedAndMIOConfigured = false;
371 LOGE("Error creating AudioTrack");
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());
381 // initialize active timing
382 iActiveTiming->setFrameRate(msecsPerFrame);
383 iActiveTiming->setDriverLatency(latency);
385 iAudioThreadCreatedSem->Signal();
386 // this must be set after iActiveTiming->setFrameRate to prevent race
387 // condition in Run()
388 iInputFrameSizeInBytes = outputFrameSizeInBytes;
391 uint32 bytesAvailInBuffer = 0;
396 PVMFCommandId cmdid = 0;
397 const OsclAny* context = 0;
398 PVMFTimestamp timestamp = 0;
400 // wait for signal from MIO thread
401 LOGV("wait for signal");
402 iAudioThreadSem->Wait();
403 LOGV("ready to work");
407 // if paused, stop the output track
408 switch (iActiveTiming->clockState())
410 case PVMFMediaClock::RUNNING:
412 if (state != STARTED)
418 iFlushPending = false;
419 bytesAvailInBuffer = 0;
420 iClockTimeOfWriting_ns = 0;
421 // discard partial buffer and send response to MIO
424 LOGV("discard partial buffer and send response to MIO");
425 sendResponse(cmdid, context, timestamp);
430 if (iDataQueued || len)
438 LOGV("clock running and no data queued - don't start track");
443 LOGV("audio sink already in started state");
446 case PVMFMediaClock::STOPPED:
447 LOGV("clock has been stopped...");
448 case PVMFMediaClock::PAUSED:
449 if (state == STARTED)
455 if (!iExitAudioThread && !iReturnBuffers)
458 iAudioThreadSem->Wait();
465 // if out of data, check the request queue
468 //LOGV("no playable data, Request Q size %d",iOSSRequestQueue.size());
469 iOSSRequestQueueLock.Lock();
470 bool empty = iOSSRequestQueue.empty();
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;
479 iOSSRequestQueue.erase(&iOSSRequestQueue[0]);
480 LOGV("receive buffer (%d), timestamp = %u data queued = %u", cmdid, timestamp, iDataQueued);
482 iOSSRequestQueueLock.Unlock();
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)
488 LOGV("queue is empty, wait for more work");
489 iAudioThreadSem->Wait();
492 // empty buffer means "End-Of-Stream" - send response to MIO
498 if (!iExitAudioThread)
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)
505 interval_nanosec = now - iClockTimeOfWriting_ns;
507 else //when timevalue wraps
509 interval_nanosec = 0;
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)
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");
521 else // interval is greater than latency so no need of sleep
523 LOGV(" No time to sleep :( send response to engine anyways");
525 iClockTimeOfWriting_ns = 0;
526 sendResponse(cmdid, context, timestamp);
533 LOGV("Return buffers from the audio thread");
534 if (len) sendResponse(cmdid, context, timestamp);
535 iReturnBuffers = false;
538 iAudioThreadReturnSem->Signal();
541 // check for exit signal
542 if (iExitAudioThread)
544 LOGV("exit received");
545 if (len) sendResponse(cmdid, context, timestamp);
550 if (len && (state == STARTED) && !iExitAudioThread)
553 // always align to AudioFlinger buffer boundary
554 if (bytesAvailInBuffer == 0)
555 bytesAvailInBuffer = mAudioSink->bufferSize();
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)
562 LOGE("Error writing audio data");
563 iAudioThreadSem->Wait();
565 data += bytesWritten;
567 iClockTimeOfWriting_ns = systemTime(SYSTEM_TIME_MONOTONIC);
571 bytesAvailInBuffer -= bytesWritten;
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
579 LOGV("done with the data cmdid %d, context %p, timestamp %d ", cmdid, context, timestamp);
580 sendResponse(cmdid, context, timestamp);
586 LOGV("stop and delete track");
588 iClockTimeOfWriting_ns = 0;
590 // LOGD("audout_thread_func exit");
591 iAudioThreadTermSem->Signal();