SoundPool.cpp revision 4944acb7355b3aa25748fd25945a363a69d65444
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "SoundPool" 19#include <utils/Log.h> 20 21#define USE_SHARED_MEM_BUFFER 22 23#include <media/AudioTrack.h> 24#include <media/IMediaHTTPService.h> 25#include <media/mediaplayer.h> 26#include <media/SoundPool.h> 27#include "SoundPoolThread.h" 28 29namespace android 30{ 31 32int kDefaultBufferCount = 4; 33uint32_t kMaxSampleRate = 48000; 34uint32_t kDefaultSampleRate = 44100; 35uint32_t kDefaultFrameCount = 1200; 36size_t kDefaultHeapSize = 1024 * 1024; // 1MB 37 38 39SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality) 40{ 41 ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", 42 maxChannels, streamType, srcQuality); 43 44 // check limits 45 mMaxChannels = maxChannels; 46 if (mMaxChannels < 1) { 47 mMaxChannels = 1; 48 } 49 else if (mMaxChannels > 32) { 50 mMaxChannels = 32; 51 } 52 ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels); 53 54 mQuit = false; 55 mDecodeThread = 0; 56 mStreamType = streamType; 57 mSrcQuality = srcQuality; 58 mAllocated = 0; 59 mNextSampleID = 0; 60 mNextChannelID = 0; 61 62 mCallback = 0; 63 mUserData = 0; 64 65 mChannelPool = new SoundChannel[mMaxChannels]; 66 for (int i = 0; i < mMaxChannels; ++i) { 67 mChannelPool[i].init(this); 68 mChannels.push_back(&mChannelPool[i]); 69 } 70 71 // start decode thread 72 startThreads(); 73} 74 75SoundPool::~SoundPool() 76{ 77 ALOGV("SoundPool destructor"); 78 mDecodeThread->quit(); 79 quit(); 80 81 Mutex::Autolock lock(&mLock); 82 83 mChannels.clear(); 84 if (mChannelPool) 85 delete [] mChannelPool; 86 // clean up samples 87 ALOGV("clear samples"); 88 mSamples.clear(); 89 90 if (mDecodeThread) 91 delete mDecodeThread; 92} 93 94void SoundPool::addToRestartList(SoundChannel* channel) 95{ 96 Mutex::Autolock lock(&mRestartLock); 97 if (!mQuit) { 98 mRestart.push_back(channel); 99 mCondition.signal(); 100 } 101} 102 103void SoundPool::addToStopList(SoundChannel* channel) 104{ 105 Mutex::Autolock lock(&mRestartLock); 106 if (!mQuit) { 107 mStop.push_back(channel); 108 mCondition.signal(); 109 } 110} 111 112int SoundPool::beginThread(void* arg) 113{ 114 SoundPool* p = (SoundPool*)arg; 115 return p->run(); 116} 117 118int SoundPool::run() 119{ 120 mRestartLock.lock(); 121 while (!mQuit) { 122 mCondition.wait(mRestartLock); 123 ALOGV("awake"); 124 if (mQuit) break; 125 126 while (!mStop.empty()) { 127 SoundChannel* channel; 128 ALOGV("Getting channel from stop list"); 129 List<SoundChannel* >::iterator iter = mStop.begin(); 130 channel = *iter; 131 mStop.erase(iter); 132 mRestartLock.unlock(); 133 if (channel != 0) { 134 Mutex::Autolock lock(&mLock); 135 channel->stop(); 136 } 137 mRestartLock.lock(); 138 if (mQuit) break; 139 } 140 141 while (!mRestart.empty()) { 142 SoundChannel* channel; 143 ALOGV("Getting channel from list"); 144 List<SoundChannel*>::iterator iter = mRestart.begin(); 145 channel = *iter; 146 mRestart.erase(iter); 147 mRestartLock.unlock(); 148 if (channel != 0) { 149 Mutex::Autolock lock(&mLock); 150 channel->nextEvent(); 151 } 152 mRestartLock.lock(); 153 if (mQuit) break; 154 } 155 } 156 157 mStop.clear(); 158 mRestart.clear(); 159 mCondition.signal(); 160 mRestartLock.unlock(); 161 ALOGV("goodbye"); 162 return 0; 163} 164 165void SoundPool::quit() 166{ 167 mRestartLock.lock(); 168 mQuit = true; 169 mCondition.signal(); 170 mCondition.wait(mRestartLock); 171 ALOGV("return from quit"); 172 mRestartLock.unlock(); 173} 174 175bool SoundPool::startThreads() 176{ 177 createThreadEtc(beginThread, this, "SoundPool"); 178 if (mDecodeThread == NULL) 179 mDecodeThread = new SoundPoolThread(this); 180 return mDecodeThread != NULL; 181} 182 183SoundChannel* SoundPool::findChannel(int channelID) 184{ 185 for (int i = 0; i < mMaxChannels; ++i) { 186 if (mChannelPool[i].channelID() == channelID) { 187 return &mChannelPool[i]; 188 } 189 } 190 return NULL; 191} 192 193SoundChannel* SoundPool::findNextChannel(int channelID) 194{ 195 for (int i = 0; i < mMaxChannels; ++i) { 196 if (mChannelPool[i].nextChannelID() == channelID) { 197 return &mChannelPool[i]; 198 } 199 } 200 return NULL; 201} 202 203int SoundPool::load(const char* path, int priority __unused) 204{ 205 ALOGV("load: path=%s, priority=%d", path, priority); 206 Mutex::Autolock lock(&mLock); 207 sp<Sample> sample = new Sample(++mNextSampleID, path); 208 mSamples.add(sample->sampleID(), sample); 209 doLoad(sample); 210 return sample->sampleID(); 211} 212 213int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused) 214{ 215 ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d", 216 fd, offset, length, priority); 217 Mutex::Autolock lock(&mLock); 218 sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length); 219 mSamples.add(sample->sampleID(), sample); 220 doLoad(sample); 221 return sample->sampleID(); 222} 223 224void SoundPool::doLoad(sp<Sample>& sample) 225{ 226 ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID()); 227 sample->startLoad(); 228 mDecodeThread->loadSample(sample->sampleID()); 229} 230 231bool SoundPool::unload(int sampleID) 232{ 233 ALOGV("unload: sampleID=%d", sampleID); 234 Mutex::Autolock lock(&mLock); 235 return mSamples.removeItem(sampleID); 236} 237 238int SoundPool::play(int sampleID, float leftVolume, float rightVolume, 239 int priority, int loop, float rate) 240{ 241 ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", 242 sampleID, leftVolume, rightVolume, priority, loop, rate); 243 sp<Sample> sample; 244 SoundChannel* channel; 245 int channelID; 246 247 Mutex::Autolock lock(&mLock); 248 249 if (mQuit) { 250 return 0; 251 } 252 // is sample ready? 253 sample = findSample(sampleID); 254 if ((sample == 0) || (sample->state() != Sample::READY)) { 255 ALOGW(" sample %d not READY", sampleID); 256 return 0; 257 } 258 259 dump(); 260 261 // allocate a channel 262 channel = allocateChannel_l(priority); 263 264 // no channel allocated - return 0 265 if (!channel) { 266 ALOGV("No channel allocated"); 267 return 0; 268 } 269 270 channelID = ++mNextChannelID; 271 272 ALOGV("play channel %p state = %d", channel, channel->state()); 273 channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate); 274 return channelID; 275} 276 277SoundChannel* SoundPool::allocateChannel_l(int priority) 278{ 279 List<SoundChannel*>::iterator iter; 280 SoundChannel* channel = NULL; 281 282 // allocate a channel 283 if (!mChannels.empty()) { 284 iter = mChannels.begin(); 285 if (priority >= (*iter)->priority()) { 286 channel = *iter; 287 mChannels.erase(iter); 288 ALOGV("Allocated active channel"); 289 } 290 } 291 292 // update priority and put it back in the list 293 if (channel) { 294 channel->setPriority(priority); 295 for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) { 296 if (priority < (*iter)->priority()) { 297 break; 298 } 299 } 300 mChannels.insert(iter, channel); 301 } 302 return channel; 303} 304 305// move a channel from its current position to the front of the list 306void SoundPool::moveToFront_l(SoundChannel* channel) 307{ 308 for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) { 309 if (*iter == channel) { 310 mChannels.erase(iter); 311 mChannels.push_front(channel); 312 break; 313 } 314 } 315} 316 317void SoundPool::pause(int channelID) 318{ 319 ALOGV("pause(%d)", channelID); 320 Mutex::Autolock lock(&mLock); 321 SoundChannel* channel = findChannel(channelID); 322 if (channel) { 323 channel->pause(); 324 } 325} 326 327void SoundPool::autoPause() 328{ 329 ALOGV("autoPause()"); 330 Mutex::Autolock lock(&mLock); 331 for (int i = 0; i < mMaxChannels; ++i) { 332 SoundChannel* channel = &mChannelPool[i]; 333 channel->autoPause(); 334 } 335} 336 337void SoundPool::resume(int channelID) 338{ 339 ALOGV("resume(%d)", channelID); 340 Mutex::Autolock lock(&mLock); 341 SoundChannel* channel = findChannel(channelID); 342 if (channel) { 343 channel->resume(); 344 } 345} 346 347void SoundPool::autoResume() 348{ 349 ALOGV("autoResume()"); 350 Mutex::Autolock lock(&mLock); 351 for (int i = 0; i < mMaxChannels; ++i) { 352 SoundChannel* channel = &mChannelPool[i]; 353 channel->autoResume(); 354 } 355} 356 357void SoundPool::stop(int channelID) 358{ 359 ALOGV("stop(%d)", channelID); 360 Mutex::Autolock lock(&mLock); 361 SoundChannel* channel = findChannel(channelID); 362 if (channel) { 363 channel->stop(); 364 } else { 365 channel = findNextChannel(channelID); 366 if (channel) 367 channel->clearNextEvent(); 368 } 369} 370 371void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume) 372{ 373 Mutex::Autolock lock(&mLock); 374 SoundChannel* channel = findChannel(channelID); 375 if (channel) { 376 channel->setVolume(leftVolume, rightVolume); 377 } 378} 379 380void SoundPool::setPriority(int channelID, int priority) 381{ 382 ALOGV("setPriority(%d, %d)", channelID, priority); 383 Mutex::Autolock lock(&mLock); 384 SoundChannel* channel = findChannel(channelID); 385 if (channel) { 386 channel->setPriority(priority); 387 } 388} 389 390void SoundPool::setLoop(int channelID, int loop) 391{ 392 ALOGV("setLoop(%d, %d)", channelID, loop); 393 Mutex::Autolock lock(&mLock); 394 SoundChannel* channel = findChannel(channelID); 395 if (channel) { 396 channel->setLoop(loop); 397 } 398} 399 400void SoundPool::setRate(int channelID, float rate) 401{ 402 ALOGV("setRate(%d, %f)", channelID, rate); 403 Mutex::Autolock lock(&mLock); 404 SoundChannel* channel = findChannel(channelID); 405 if (channel) { 406 channel->setRate(rate); 407 } 408} 409 410// call with lock held 411void SoundPool::done_l(SoundChannel* channel) 412{ 413 ALOGV("done_l(%d)", channel->channelID()); 414 // if "stolen", play next event 415 if (channel->nextChannelID() != 0) { 416 ALOGV("add to restart list"); 417 addToRestartList(channel); 418 } 419 420 // return to idle state 421 else { 422 ALOGV("move to front"); 423 moveToFront_l(channel); 424 } 425} 426 427void SoundPool::setCallback(SoundPoolCallback* callback, void* user) 428{ 429 Mutex::Autolock lock(&mCallbackLock); 430 mCallback = callback; 431 mUserData = user; 432} 433 434void SoundPool::notify(SoundPoolEvent event) 435{ 436 Mutex::Autolock lock(&mCallbackLock); 437 if (mCallback != NULL) { 438 mCallback(event, this, mUserData); 439 } 440} 441 442void SoundPool::dump() 443{ 444 for (int i = 0; i < mMaxChannels; ++i) { 445 mChannelPool[i].dump(); 446 } 447} 448 449 450Sample::Sample(int sampleID, const char* url) 451{ 452 init(); 453 mSampleID = sampleID; 454 mUrl = strdup(url); 455 ALOGV("create sampleID=%d, url=%s", mSampleID, mUrl); 456} 457 458Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length) 459{ 460 init(); 461 mSampleID = sampleID; 462 mFd = dup(fd); 463 mOffset = offset; 464 mLength = length; 465 ALOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset); 466} 467 468void Sample::init() 469{ 470 mSize = 0; 471 mRefCount = 0; 472 mSampleID = 0; 473 mState = UNLOADED; 474 mFd = -1; 475 mOffset = 0; 476 mLength = 0; 477 mUrl = 0; 478} 479 480Sample::~Sample() 481{ 482 ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd); 483 if (mFd > 0) { 484 ALOGV("close(%d)", mFd); 485 ::close(mFd); 486 } 487 free(mUrl); 488} 489 490status_t Sample::doLoad() 491{ 492 uint32_t sampleRate; 493 int numChannels; 494 audio_format_t format; 495 status_t status; 496 mHeap = new MemoryHeapBase(kDefaultHeapSize); 497 498 ALOGV("Start decode"); 499 if (mUrl) { 500 status = MediaPlayer::decode( 501 NULL /* httpService */, 502 mUrl, 503 &sampleRate, 504 &numChannels, 505 &format, 506 mHeap, 507 &mSize); 508 } else { 509 status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format, 510 mHeap, &mSize); 511 ALOGV("close(%d)", mFd); 512 ::close(mFd); 513 mFd = -1; 514 } 515 if (status != NO_ERROR) { 516 ALOGE("Unable to load sample: %s", mUrl); 517 goto error; 518 } 519 ALOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d", 520 mHeap->getBase(), mSize, sampleRate, numChannels); 521 522 if (sampleRate > kMaxSampleRate) { 523 ALOGE("Sample rate (%u) out of range", sampleRate); 524 status = BAD_VALUE; 525 goto error; 526 } 527 528 if ((numChannels < 1) || (numChannels > 2)) { 529 ALOGE("Sample channel count (%d) out of range", numChannels); 530 status = BAD_VALUE; 531 goto error; 532 } 533 534 mData = new MemoryBase(mHeap, 0, mSize); 535 mSampleRate = sampleRate; 536 mNumChannels = numChannels; 537 mFormat = format; 538 mState = READY; 539 return NO_ERROR; 540 541error: 542 mHeap.clear(); 543 return status; 544} 545 546 547void SoundChannel::init(SoundPool* soundPool) 548{ 549 mSoundPool = soundPool; 550} 551 552// call with sound pool lock held 553void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume, 554 float rightVolume, int priority, int loop, float rate) 555{ 556 sp<AudioTrack> oldTrack; 557 sp<AudioTrack> newTrack; 558 status_t status; 559 560 { // scope for the lock 561 Mutex::Autolock lock(&mLock); 562 563 ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f," 564 " priority=%d, loop=%d, rate=%f", 565 this, sample->sampleID(), nextChannelID, leftVolume, rightVolume, 566 priority, loop, rate); 567 568 // if not idle, this voice is being stolen 569 if (mState != IDLE) { 570 ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID); 571 mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); 572 stop_l(); 573 return; 574 } 575 576 // initialize track 577 size_t afFrameCount; 578 uint32_t afSampleRate; 579 audio_stream_type_t streamType = mSoundPool->streamType(); 580 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { 581 afFrameCount = kDefaultFrameCount; 582 } 583 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { 584 afSampleRate = kDefaultSampleRate; 585 } 586 int numChannels = sample->numChannels(); 587 uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5); 588 uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate; 589 uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount; 590 uint32_t frameCount = 0; 591 592 if (loop) { 593 frameCount = sample->size()/numChannels/ 594 ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); 595 } 596 597#ifndef USE_SHARED_MEM_BUFFER 598 // Ensure minimum audio buffer size in case of short looped sample 599 if(frameCount < totalFrames) { 600 frameCount = totalFrames; 601 } 602#endif 603 604 // mToggle toggles each time a track is started on a given channel. 605 // The toggle is concatenated with the SoundChannel address and passed to AudioTrack 606 // as callback user data. This enables the detection of callbacks received from the old 607 // audio track while the new one is being started and avoids processing them with 608 // wrong audio audio buffer size (mAudioBufferSize) 609 unsigned long toggle = mToggle ^ 1; 610 void *userData = (void *)((unsigned long)this | toggle); 611 audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels); 612 613 // do not create a new audio track if current track is compatible with sample parameters 614#ifdef USE_SHARED_MEM_BUFFER 615 newTrack = new AudioTrack(streamType, sampleRate, sample->format(), 616 channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData); 617#else 618 newTrack = new AudioTrack(streamType, sampleRate, sample->format(), 619 channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData, 620 bufferFrames); 621#endif 622 oldTrack = mAudioTrack; 623 status = newTrack->initCheck(); 624 if (status != NO_ERROR) { 625 ALOGE("Error creating AudioTrack"); 626 goto exit; 627 } 628 ALOGV("setVolume %p", newTrack.get()); 629 newTrack->setVolume(leftVolume, rightVolume); 630 newTrack->setLoop(0, frameCount, loop); 631 632 // From now on, AudioTrack callbacks received with previous toggle value will be ignored. 633 mToggle = toggle; 634 mAudioTrack = newTrack; 635 mPos = 0; 636 mSample = sample; 637 mChannelID = nextChannelID; 638 mPriority = priority; 639 mLoop = loop; 640 mLeftVolume = leftVolume; 641 mRightVolume = rightVolume; 642 mNumChannels = numChannels; 643 mRate = rate; 644 clearNextEvent(); 645 mState = PLAYING; 646 mAudioTrack->start(); 647 mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize(); 648 } 649 650exit: 651 ALOGV("delete oldTrack %p", oldTrack.get()); 652 if (status != NO_ERROR) { 653 mAudioTrack.clear(); 654 } 655} 656 657void SoundChannel::nextEvent() 658{ 659 sp<Sample> sample; 660 int nextChannelID; 661 float leftVolume; 662 float rightVolume; 663 int priority; 664 int loop; 665 float rate; 666 667 // check for valid event 668 { 669 Mutex::Autolock lock(&mLock); 670 nextChannelID = mNextEvent.channelID(); 671 if (nextChannelID == 0) { 672 ALOGV("stolen channel has no event"); 673 return; 674 } 675 676 sample = mNextEvent.sample(); 677 leftVolume = mNextEvent.leftVolume(); 678 rightVolume = mNextEvent.rightVolume(); 679 priority = mNextEvent.priority(); 680 loop = mNextEvent.loop(); 681 rate = mNextEvent.rate(); 682 } 683 684 ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID); 685 play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate); 686} 687 688void SoundChannel::callback(int event, void* user, void *info) 689{ 690 SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1)); 691 692 channel->process(event, info, (unsigned long)user & 1); 693} 694 695void SoundChannel::process(int event, void *info, unsigned long toggle) 696{ 697 //ALOGV("process(%d)", mChannelID); 698 699 Mutex::Autolock lock(&mLock); 700 701 AudioTrack::Buffer* b = NULL; 702 if (event == AudioTrack::EVENT_MORE_DATA) { 703 b = static_cast<AudioTrack::Buffer *>(info); 704 } 705 706 if (mToggle != toggle) { 707 ALOGV("process wrong toggle %p channel %d", this, mChannelID); 708 if (b != NULL) { 709 b->size = 0; 710 } 711 return; 712 } 713 714 sp<Sample> sample = mSample; 715 716// ALOGV("SoundChannel::process event %d", event); 717 718 if (event == AudioTrack::EVENT_MORE_DATA) { 719 720 // check for stop state 721 if (b->size == 0) return; 722 723 if (mState == IDLE) { 724 b->size = 0; 725 return; 726 } 727 728 if (sample != 0) { 729 // fill buffer 730 uint8_t* q = (uint8_t*) b->i8; 731 size_t count = 0; 732 733 if (mPos < (int)sample->size()) { 734 uint8_t* p = sample->data() + mPos; 735 count = sample->size() - mPos; 736 if (count > b->size) { 737 count = b->size; 738 } 739 memcpy(q, p, count); 740// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, 741// count); 742 } else if (mPos < mAudioBufferSize) { 743 count = mAudioBufferSize - mPos; 744 if (count > b->size) { 745 count = b->size; 746 } 747 memset(q, 0, count); 748// ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count); 749 } 750 751 mPos += count; 752 b->size = count; 753 //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]); 754 } 755 } else if (event == AudioTrack::EVENT_UNDERRUN || event == AudioTrack::EVENT_BUFFER_END || 756 event == AudioTrack::EVENT_NEW_IAUDIOTRACK) { 757 ALOGV("process %p channel %d event %s", 758 this, mChannelID, (event == AudioTrack::EVENT_UNDERRUN) ? "UNDERRUN" : 759 (event == AudioTrack::EVENT_BUFFER_END) ? "BUFFER_END" : "NEW_IAUDIOTRACK"); 760 mSoundPool->addToStopList(this); 761 } else if (event == AudioTrack::EVENT_LOOP_END) { 762 ALOGV("End loop %p channel %d", this, mChannelID); 763 } else { 764 ALOGW("SoundChannel::process unexpected event %d", event); 765 } 766} 767 768 769// call with lock held 770bool SoundChannel::doStop_l() 771{ 772 if (mState != IDLE) { 773 setVolume_l(0, 0); 774 ALOGV("stop"); 775 mAudioTrack->stop(); 776 mSample.clear(); 777 mState = IDLE; 778 mPriority = IDLE_PRIORITY; 779 return true; 780 } 781 return false; 782} 783 784// call with lock held and sound pool lock held 785void SoundChannel::stop_l() 786{ 787 if (doStop_l()) { 788 mSoundPool->done_l(this); 789 } 790} 791 792// call with sound pool lock held 793void SoundChannel::stop() 794{ 795 bool stopped; 796 { 797 Mutex::Autolock lock(&mLock); 798 stopped = doStop_l(); 799 } 800 801 if (stopped) { 802 mSoundPool->done_l(this); 803 } 804} 805 806//FIXME: Pause is a little broken right now 807void SoundChannel::pause() 808{ 809 Mutex::Autolock lock(&mLock); 810 if (mState == PLAYING) { 811 ALOGV("pause track"); 812 mState = PAUSED; 813 mAudioTrack->pause(); 814 } 815} 816 817void SoundChannel::autoPause() 818{ 819 Mutex::Autolock lock(&mLock); 820 if (mState == PLAYING) { 821 ALOGV("pause track"); 822 mState = PAUSED; 823 mAutoPaused = true; 824 mAudioTrack->pause(); 825 } 826} 827 828void SoundChannel::resume() 829{ 830 Mutex::Autolock lock(&mLock); 831 if (mState == PAUSED) { 832 ALOGV("resume track"); 833 mState = PLAYING; 834 mAutoPaused = false; 835 mAudioTrack->start(); 836 } 837} 838 839void SoundChannel::autoResume() 840{ 841 Mutex::Autolock lock(&mLock); 842 if (mAutoPaused && (mState == PAUSED)) { 843 ALOGV("resume track"); 844 mState = PLAYING; 845 mAutoPaused = false; 846 mAudioTrack->start(); 847 } 848} 849 850void SoundChannel::setRate(float rate) 851{ 852 Mutex::Autolock lock(&mLock); 853 if (mAudioTrack != NULL && mSample != 0) { 854 uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5); 855 mAudioTrack->setSampleRate(sampleRate); 856 mRate = rate; 857 } 858} 859 860// call with lock held 861void SoundChannel::setVolume_l(float leftVolume, float rightVolume) 862{ 863 mLeftVolume = leftVolume; 864 mRightVolume = rightVolume; 865 if (mAudioTrack != NULL) 866 mAudioTrack->setVolume(leftVolume, rightVolume); 867} 868 869void SoundChannel::setVolume(float leftVolume, float rightVolume) 870{ 871 Mutex::Autolock lock(&mLock); 872 setVolume_l(leftVolume, rightVolume); 873} 874 875void SoundChannel::setLoop(int loop) 876{ 877 Mutex::Autolock lock(&mLock); 878 if (mAudioTrack != NULL && mSample != 0) { 879 uint32_t loopEnd = mSample->size()/mNumChannels/ 880 ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)); 881 mAudioTrack->setLoop(0, loopEnd, loop); 882 mLoop = loop; 883 } 884} 885 886SoundChannel::~SoundChannel() 887{ 888 ALOGV("SoundChannel destructor %p", this); 889 { 890 Mutex::Autolock lock(&mLock); 891 clearNextEvent(); 892 doStop_l(); 893 } 894 // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack 895 // callback thread to exit which may need to execute process() and acquire the mLock. 896 mAudioTrack.clear(); 897} 898 899void SoundChannel::dump() 900{ 901 ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d", 902 mState, mChannelID, mNumChannels, mPos, mPriority, mLoop); 903} 904 905void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume, 906 float rightVolume, int priority, int loop, float rate) 907{ 908 mSample = sample; 909 mChannelID = channelID; 910 mLeftVolume = leftVolume; 911 mRightVolume = rightVolume; 912 mPriority = priority; 913 mLoop = loop; 914 mRate =rate; 915} 916 917} // end namespace android 918