AudioRecord.cpp revision 99ffda877980468a9ae31e013cd10fb3645df1b0
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 "AudioRecord" 20 21#include <stdint.h> 22#include <sys/types.h> 23 24#include <sched.h> 25#include <sys/resource.h> 26 27#include <private/media/AudioTrackShared.h> 28 29#include <media/AudioSystem.h> 30#include <media/AudioRecord.h> 31 32#include <utils/IServiceManager.h> 33#include <utils/Log.h> 34#include <utils/MemoryDealer.h> 35#include <utils/Parcel.h> 36#include <utils/IPCThreadState.h> 37#include <utils/Timers.h> 38#include <cutils/atomic.h> 39 40#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) 41#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) 42 43namespace android { 44 45// --------------------------------------------------------------------------- 46 47AudioRecord::AudioRecord() 48 : mStatus(NO_INIT) 49{ 50} 51 52AudioRecord::AudioRecord( 53 int streamType, 54 uint32_t sampleRate, 55 int format, 56 int channelCount, 57 int frameCount, 58 uint32_t flags, 59 callback_t cbf, 60 void* user, 61 int notificationFrames) 62 : mStatus(NO_INIT) 63{ 64 mStatus = set(streamType, sampleRate, format, channelCount, 65 frameCount, flags, cbf, user, notificationFrames); 66} 67 68AudioRecord::~AudioRecord() 69{ 70 if (mStatus == NO_ERROR) { 71 // Make sure that callback function exits in the case where 72 // it is looping on buffer empty condition in obtainBuffer(). 73 // Otherwise the callback thread will never exit. 74 stop(); 75 if (mClientRecordThread != 0) { 76 mCblk->cv.signal(); 77 mClientRecordThread->requestExitAndWait(); 78 mClientRecordThread.clear(); 79 } 80 mAudioRecord.clear(); 81 IPCThreadState::self()->flushCommands(); 82 } 83} 84 85status_t AudioRecord::set( 86 int streamType, 87 uint32_t sampleRate, 88 int format, 89 int channelCount, 90 int frameCount, 91 uint32_t flags, 92 callback_t cbf, 93 void* user, 94 int notificationFrames, 95 bool threadCanCallJava) 96{ 97 98 LOGV("set(): sampleRate %d, channelCount %d, frameCount %d",sampleRate, channelCount, frameCount); 99 if (mAudioFlinger != 0) { 100 return INVALID_OPERATION; 101 } 102 103 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); 104 if (audioFlinger == 0) { 105 return NO_INIT; 106 } 107 108 if (streamType == DEFAULT_INPUT) { 109 streamType = MIC_INPUT; 110 } 111 112 if (sampleRate == 0) { 113 sampleRate = DEFAULT_SAMPLE_RATE; 114 } 115 // these below should probably come from the audioFlinger too... 116 if (format == 0) { 117 format = AudioSystem::PCM_16_BIT; 118 } 119 if (channelCount == 0) { 120 channelCount = 1; 121 } 122 123 // validate parameters 124 if (format != AudioSystem::PCM_16_BIT) { 125 return BAD_VALUE; 126 } 127 if (channelCount != 1 && channelCount != 2) { 128 return BAD_VALUE; 129 } 130 131 // validate framecount 132 size_t inputBuffSizeInBytes = -1; 133 if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes) 134 != NO_ERROR) { 135 LOGE("AudioSystem could not query the input buffer size."); 136 return NO_INIT; 137 } 138 if (inputBuffSizeInBytes == 0) { 139 LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d", 140 sampleRate, channelCount, format); 141 return BAD_VALUE; 142 } 143 int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); 144 145 // We use 2* size of input buffer for ping pong use of record buffer. 146 int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes; 147 LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); 148 149 if (frameCount == 0) { 150 frameCount = minFrameCount; 151 } else if (frameCount < minFrameCount) { 152 return BAD_VALUE; 153 } 154 155 if (notificationFrames == 0) { 156 notificationFrames = frameCount/2; 157 } 158 159 // open record channel 160 status_t status; 161 sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType, 162 sampleRate, format, 163 channelCount, 164 frameCount, 165 ((uint16_t)flags) << 16, 166 &status); 167 if (record == 0) { 168 LOGE("AudioFlinger could not create record track, status: %d", status); 169 return status; 170 } 171 sp<IMemory> cblk = record->getCblk(); 172 if (cblk == 0) { 173 return NO_INIT; 174 } 175 if (cbf != 0) { 176 mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava); 177 if (mClientRecordThread == 0) { 178 return NO_INIT; 179 } 180 } 181 182 mStatus = NO_ERROR; 183 184 mAudioFlinger = audioFlinger; 185 mAudioRecord = record; 186 mCblkMemory = cblk; 187 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); 188 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); 189 mCblk->out = 0; 190 mSampleRate = sampleRate; 191 mFormat = format; 192 // Update buffer size in case it has been limited by AudioFlinger during track creation 193 mFrameCount = mCblk->frameCount; 194 mChannelCount = channelCount; 195 mActive = 0; 196 mCbf = cbf; 197 mNotificationFrames = notificationFrames; 198 mRemainingFrames = notificationFrames; 199 mUserData = user; 200 // TODO: add audio hardware input latency here 201 mLatency = (1000*mFrameCount) / mSampleRate; 202 mMarkerPosition = 0; 203 mNewPosition = 0; 204 mUpdatePeriod = 0; 205 206 return NO_ERROR; 207} 208 209status_t AudioRecord::initCheck() const 210{ 211 return mStatus; 212} 213 214// ------------------------------------------------------------------------- 215 216uint32_t AudioRecord::latency() const 217{ 218 return mLatency; 219} 220 221uint32_t AudioRecord::sampleRate() const 222{ 223 return mSampleRate; 224} 225 226int AudioRecord::format() const 227{ 228 return mFormat; 229} 230 231int AudioRecord::channelCount() const 232{ 233 return mChannelCount; 234} 235 236uint32_t AudioRecord::frameCount() const 237{ 238 return mFrameCount; 239} 240 241int AudioRecord::frameSize() const 242{ 243 return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t)); 244} 245 246// ------------------------------------------------------------------------- 247 248status_t AudioRecord::start() 249{ 250 status_t ret = NO_ERROR; 251 sp<ClientRecordThread> t = mClientRecordThread; 252 253 LOGV("start"); 254 255 if (t != 0) { 256 if (t->exitPending()) { 257 if (t->requestExitAndWait() == WOULD_BLOCK) { 258 LOGE("AudioRecord::start called from thread"); 259 return WOULD_BLOCK; 260 } 261 } 262 t->mLock.lock(); 263 } 264 265 if (android_atomic_or(1, &mActive) == 0) { 266 mNewPosition = mCblk->user + mUpdatePeriod; 267 mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; 268 mCblk->waitTimeMs = 0; 269 if (t != 0) { 270 t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT); 271 } else { 272 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); 273 } 274 ret = mAudioRecord->start(); 275 } 276 277 if (t != 0) { 278 t->mLock.unlock(); 279 } 280 281 return ret; 282} 283 284status_t AudioRecord::stop() 285{ 286 sp<ClientRecordThread> t = mClientRecordThread; 287 288 LOGV("stop"); 289 290 if (t != 0) { 291 t->mLock.lock(); 292 } 293 294 if (android_atomic_and(~1, &mActive) == 1) { 295 mAudioRecord->stop(); 296 if (t != 0) { 297 t->requestExit(); 298 } else { 299 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); 300 } 301 } 302 303 if (t != 0) { 304 t->mLock.unlock(); 305 } 306 307 return NO_ERROR; 308} 309 310bool AudioRecord::stopped() const 311{ 312 return !mActive; 313} 314 315status_t AudioRecord::setMarkerPosition(uint32_t marker) 316{ 317 if (mCbf == 0) return INVALID_OPERATION; 318 319 mMarkerPosition = marker; 320 321 return NO_ERROR; 322} 323 324status_t AudioRecord::getMarkerPosition(uint32_t *marker) 325{ 326 if (marker == 0) return BAD_VALUE; 327 328 *marker = mMarkerPosition; 329 330 return NO_ERROR; 331} 332 333status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod) 334{ 335 if (mCbf == 0) return INVALID_OPERATION; 336 337 uint32_t curPosition; 338 getPosition(&curPosition); 339 mNewPosition = curPosition + updatePeriod; 340 mUpdatePeriod = updatePeriod; 341 342 return NO_ERROR; 343} 344 345status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) 346{ 347 if (updatePeriod == 0) return BAD_VALUE; 348 349 *updatePeriod = mUpdatePeriod; 350 351 return NO_ERROR; 352} 353 354status_t AudioRecord::getPosition(uint32_t *position) 355{ 356 if (position == 0) return BAD_VALUE; 357 358 *position = mCblk->user; 359 360 return NO_ERROR; 361} 362 363 364// ------------------------------------------------------------------------- 365 366status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) 367{ 368 int active; 369 int timeout = 0; 370 status_t result; 371 audio_track_cblk_t* cblk = mCblk; 372 uint32_t framesReq = audioBuffer->frameCount; 373 374 audioBuffer->frameCount = 0; 375 audioBuffer->size = 0; 376 377 uint32_t framesReady = cblk->framesReady(); 378 379 if (framesReady == 0) { 380 Mutex::Autolock _l(cblk->lock); 381 goto start_loop_here; 382 while (framesReady == 0) { 383 active = mActive; 384 if (UNLIKELY(!active)) 385 return NO_MORE_BUFFERS; 386 if (UNLIKELY(!waitCount)) 387 return WOULD_BLOCK; 388 timeout = 0; 389 result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS)); 390 if (__builtin_expect(result!=NO_ERROR, false)) { 391 cblk->waitTimeMs += WAIT_PERIOD_MS; 392 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { 393 LOGW( "obtainBuffer timed out (is the CPU pegged?) " 394 "user=%08x, server=%08x", cblk->user, cblk->server); 395 timeout = 1; 396 cblk->waitTimeMs = 0; 397 } 398 if (--waitCount == 0) { 399 return TIMED_OUT; 400 } 401 } 402 // read the server count again 403 start_loop_here: 404 framesReady = cblk->framesReady(); 405 } 406 } 407 408 LOGW_IF(timeout, 409 "*** SERIOUS WARNING *** obtainBuffer() timed out " 410 "but didn't need to be locked. We recovered, but " 411 "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server); 412 413 cblk->waitTimeMs = 0; 414 415 if (framesReq > framesReady) { 416 framesReq = framesReady; 417 } 418 419 uint32_t u = cblk->user; 420 uint32_t bufferEnd = cblk->userBase + cblk->frameCount; 421 422 if (u + framesReq > bufferEnd) { 423 framesReq = bufferEnd - u; 424 } 425 426 audioBuffer->flags = 0; 427 audioBuffer->channelCount= mChannelCount; 428 audioBuffer->format = mFormat; 429 audioBuffer->frameCount = framesReq; 430 audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t); 431 audioBuffer->raw = (int8_t*)cblk->buffer(u); 432 active = mActive; 433 return active ? status_t(NO_ERROR) : status_t(STOPPED); 434} 435 436void AudioRecord::releaseBuffer(Buffer* audioBuffer) 437{ 438 audio_track_cblk_t* cblk = mCblk; 439 cblk->stepUser(audioBuffer->frameCount); 440} 441 442// ------------------------------------------------------------------------- 443 444ssize_t AudioRecord::read(void* buffer, size_t userSize) 445{ 446 ssize_t read = 0; 447 Buffer audioBuffer; 448 int8_t *dst = static_cast<int8_t*>(buffer); 449 450 if (ssize_t(userSize) < 0) { 451 // sanity-check. user is most-likely passing an error code. 452 LOGE("AudioRecord::read(buffer=%p, size=%u (%d)", 453 buffer, userSize, userSize); 454 return BAD_VALUE; 455 } 456 457 LOGV("read size: %d", userSize); 458 459 do { 460 461 audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t); 462 463 // Calling obtainBuffer() with a negative wait count causes 464 // an (almost) infinite wait time. 465 status_t err = obtainBuffer(&audioBuffer, -1); 466 if (err < 0) { 467 // out of buffers, return #bytes written 468 if (err == status_t(NO_MORE_BUFFERS)) 469 break; 470 return ssize_t(err); 471 } 472 473 size_t bytesRead = audioBuffer.size; 474 memcpy(dst, audioBuffer.i8, bytesRead); 475 476 dst += bytesRead; 477 userSize -= bytesRead; 478 read += bytesRead; 479 480 releaseBuffer(&audioBuffer); 481 } while (userSize); 482 483 return read; 484} 485 486// ------------------------------------------------------------------------- 487 488bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) 489{ 490 Buffer audioBuffer; 491 uint32_t frames = mRemainingFrames; 492 size_t readSize; 493 494 // Manage marker callback 495 if (mMarkerPosition > 0) { 496 if (mCblk->user >= mMarkerPosition) { 497 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition); 498 mMarkerPosition = 0; 499 } 500 } 501 502 // Manage new position callback 503 if (mUpdatePeriod > 0) { 504 while (mCblk->user >= mNewPosition) { 505 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition); 506 mNewPosition += mUpdatePeriod; 507 } 508 } 509 510 do { 511 audioBuffer.frameCount = frames; 512 // Calling obtainBuffer() with a wait count of 1 513 // limits wait time to WAIT_PERIOD_MS. This prevents from being 514 // stuck here not being able to handle timed events (position, markers). 515 status_t err = obtainBuffer(&audioBuffer, 1); 516 if (err < NO_ERROR) { 517 if (err != TIMED_OUT) { 518 LOGE("Error obtaining an audio buffer, giving up."); 519 return false; 520 } 521 break; 522 } 523 if (err == status_t(STOPPED)) return false; 524 525 size_t reqSize = audioBuffer.size; 526 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer); 527 readSize = audioBuffer.size; 528 529 // Sanity check on returned size 530 if (ssize_t(readSize) <= 0) break; 531 if (readSize > reqSize) readSize = reqSize; 532 533 audioBuffer.size = readSize; 534 audioBuffer.frameCount = readSize/mChannelCount/sizeof(int16_t); 535 frames -= audioBuffer.frameCount; 536 537 releaseBuffer(&audioBuffer); 538 539 } while (frames); 540 541 542 // Manage overrun callback 543 if (mActive && (mCblk->framesAvailable_l() == 0)) { 544 LOGV("Overrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag); 545 if (mCblk->flowControlFlag == 0) { 546 mCbf(EVENT_OVERRUN, mUserData, 0); 547 mCblk->flowControlFlag = 1; 548 } 549 } 550 551 if (frames == 0) { 552 mRemainingFrames = mNotificationFrames; 553 } else { 554 mRemainingFrames = frames; 555 } 556 return true; 557} 558 559// ========================================================================= 560 561AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava) 562 : Thread(bCanCallJava), mReceiver(receiver) 563{ 564} 565 566bool AudioRecord::ClientRecordThread::threadLoop() 567{ 568 return mReceiver.processAudioBuffer(this); 569} 570 571// ------------------------------------------------------------------------- 572 573}; // namespace android 574 575