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