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