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