blob: 1e2d6ce2bd627af620cba56009e5d0e89e6d12e1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Eric Laurent45fce582009-07-22 11:12:31 -070021//#define USE_SHARED_MEM_BUFFER
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
23// XXX needed for timing latency
24#include <utils/Timers.h>
25
26#include <sys/resource.h>
27#include <media/AudioTrack.h>
28#include <media/mediaplayer.h>
29
30#include "SoundPool.h"
31#include "SoundPoolThread.h"
32
33namespace android
34{
35
36int kDefaultBufferCount = 4;
37uint32_t kMaxSampleRate = 48000;
38uint32_t kDefaultSampleRate = 44100;
39uint32_t kDefaultFrameCount = 1200;
40
Dave Sparksc0e3ddf2009-12-07 12:36:20 -080041SoundPool::SoundPool(int maxChannels, int streamType, int srcQuality)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042{
43 LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
44 maxChannels, streamType, srcQuality);
45
Dave Sparks3c8704b2009-05-29 19:12:11 -070046 // check limits
47 mMaxChannels = maxChannels;
48 if (mMaxChannels < 1) {
49 mMaxChannels = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 }
Dave Sparks3c8704b2009-05-29 19:12:11 -070051 else if (mMaxChannels > 32) {
52 mMaxChannels = 32;
53 }
54 LOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
56 mQuit = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 mDecodeThread = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 mStreamType = streamType;
59 mSrcQuality = srcQuality;
60 mAllocated = 0;
61 mNextSampleID = 0;
62 mNextChannelID = 0;
63
Dave Sparksf6e43bf2009-12-08 08:10:42 -080064 mCallback = 0;
65 mUserData = 0;
66
Dave Sparks3c8704b2009-05-29 19:12:11 -070067 mChannelPool = new SoundChannel[mMaxChannels];
68 for (int i = 0; i < mMaxChannels; ++i) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 mChannelPool[i].init(this);
70 mChannels.push_back(&mChannelPool[i]);
71 }
72
73 // start decode thread
74 startThreads();
75}
76
77SoundPool::~SoundPool()
78{
79 LOGV("SoundPool destructor");
80 mDecodeThread->quit();
81 quit();
82
83 Mutex::Autolock lock(&mLock);
Eric Laurenta60e2122010-12-28 16:49:07 -080084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 mChannels.clear();
86 if (mChannelPool)
87 delete [] mChannelPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 // clean up samples
89 LOGV("clear samples");
90 mSamples.clear();
91
92 if (mDecodeThread)
93 delete mDecodeThread;
94}
95
96void SoundPool::addToRestartList(SoundChannel* channel)
97{
Eric Laurentfd8c0e12009-07-31 06:29:13 -070098 Mutex::Autolock lock(&mRestartLock);
Eric Laurenta60e2122010-12-28 16:49:07 -080099 if (!mQuit) {
100 mRestart.push_back(channel);
101 mCondition.signal();
102 }
103}
104
105void SoundPool::addToStopList(SoundChannel* channel)
106{
107 Mutex::Autolock lock(&mRestartLock);
108 if (!mQuit) {
109 mStop.push_back(channel);
110 mCondition.signal();
111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112}
113
114int SoundPool::beginThread(void* arg)
115{
116 SoundPool* p = (SoundPool*)arg;
117 return p->run();
118}
119
120int SoundPool::run()
121{
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700122 mRestartLock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 while (!mQuit) {
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700124 mCondition.wait(mRestartLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 LOGV("awake");
126 if (mQuit) break;
127
Eric Laurenta60e2122010-12-28 16:49:07 -0800128 while (!mStop.empty()) {
129 SoundChannel* channel;
130 LOGV("Getting channel from stop list");
131 List<SoundChannel* >::iterator iter = mStop.begin();
132 channel = *iter;
133 mStop.erase(iter);
134 mRestartLock.unlock();
135 if (channel != 0) {
136 Mutex::Autolock lock(&mLock);
137 channel->stop();
138 }
139 mRestartLock.lock();
140 if (mQuit) break;
141 }
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 while (!mRestart.empty()) {
144 SoundChannel* channel;
145 LOGV("Getting channel from list");
146 List<SoundChannel*>::iterator iter = mRestart.begin();
147 channel = *iter;
148 mRestart.erase(iter);
Eric Laurenta60e2122010-12-28 16:49:07 -0800149 mRestartLock.unlock();
150 if (channel != 0) {
151 Mutex::Autolock lock(&mLock);
152 channel->nextEvent();
153 }
154 mRestartLock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 if (mQuit) break;
156 }
157 }
158
Eric Laurenta60e2122010-12-28 16:49:07 -0800159 mStop.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 mRestart.clear();
161 mCondition.signal();
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700162 mRestartLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 LOGV("goodbye");
164 return 0;
165}
166
167void SoundPool::quit()
168{
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700169 mRestartLock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 mQuit = true;
171 mCondition.signal();
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700172 mCondition.wait(mRestartLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 LOGV("return from quit");
Eric Laurentfd8c0e12009-07-31 06:29:13 -0700174 mRestartLock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175}
176
177bool SoundPool::startThreads()
178{
Steve Howard09468db2010-03-11 13:51:52 -0800179 createThreadEtc(beginThread, this, "SoundPool");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 if (mDecodeThread == NULL)
181 mDecodeThread = new SoundPoolThread(this);
182 return mDecodeThread != NULL;
183}
184
185SoundChannel* SoundPool::findChannel(int channelID)
186{
187 for (int i = 0; i < mMaxChannels; ++i) {
188 if (mChannelPool[i].channelID() == channelID) {
189 return &mChannelPool[i];
190 }
191 }
192 return NULL;
193}
194
195SoundChannel* SoundPool::findNextChannel(int channelID)
196{
197 for (int i = 0; i < mMaxChannels; ++i) {
198 if (mChannelPool[i].nextChannelID() == channelID) {
199 return &mChannelPool[i];
200 }
201 }
202 return NULL;
203}
204
205int SoundPool::load(const char* path, int priority)
206{
207 LOGV("load: path=%s, priority=%d", path, priority);
208 Mutex::Autolock lock(&mLock);
209 sp<Sample> sample = new Sample(++mNextSampleID, path);
210 mSamples.add(sample->sampleID(), sample);
211 doLoad(sample);
212 return sample->sampleID();
213}
214
215int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
216{
217 LOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
218 fd, offset, length, priority);
219 Mutex::Autolock lock(&mLock);
220 sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
221 mSamples.add(sample->sampleID(), sample);
222 doLoad(sample);
223 return sample->sampleID();
224}
225
226void SoundPool::doLoad(sp<Sample>& sample)
227{
228 LOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
229 sample->startLoad();
230 mDecodeThread->loadSample(sample->sampleID());
231}
232
233bool SoundPool::unload(int sampleID)
234{
235 LOGV("unload: sampleID=%d", sampleID);
236 Mutex::Autolock lock(&mLock);
237 return mSamples.removeItem(sampleID);
238}
239
240int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
241 int priority, int loop, float rate)
242{
Eric Laurenta60e2122010-12-28 16:49:07 -0800243 LOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 sampleID, leftVolume, rightVolume, priority, loop, rate);
245 sp<Sample> sample;
246 SoundChannel* channel;
247 int channelID;
248
Eric Laurenta60e2122010-12-28 16:49:07 -0800249 Mutex::Autolock lock(&mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
Eric Laurenta60e2122010-12-28 16:49:07 -0800251 if (mQuit) {
252 return 0;
253 }
254 // is sample ready?
255 sample = findSample(sampleID);
256 if ((sample == 0) || (sample->state() != Sample::READY)) {
257 LOGW(" sample %d not READY", sampleID);
258 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 }
260
Eric Laurenta60e2122010-12-28 16:49:07 -0800261 dump();
262
263 // allocate a channel
264 channel = allocateChannel_l(priority);
265
266 // no channel allocated - return 0
267 if (!channel) {
268 LOGV("No channel allocated");
269 return 0;
270 }
271
272 channelID = ++mNextChannelID;
273
274 LOGV("play channel %p state = %d", channel, channel->state());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
276 return channelID;
277}
278
Eric Laurenta60e2122010-12-28 16:49:07 -0800279SoundChannel* SoundPool::allocateChannel_l(int priority)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280{
281 List<SoundChannel*>::iterator iter;
282 SoundChannel* channel = NULL;
283
284 // allocate a channel
285 if (!mChannels.empty()) {
286 iter = mChannels.begin();
287 if (priority >= (*iter)->priority()) {
288 channel = *iter;
289 mChannels.erase(iter);
290 LOGV("Allocated active channel");
291 }
292 }
293
294 // update priority and put it back in the list
295 if (channel) {
296 channel->setPriority(priority);
297 for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
298 if (priority < (*iter)->priority()) {
299 break;
300 }
301 }
302 mChannels.insert(iter, channel);
303 }
304 return channel;
305}
306
307// move a channel from its current position to the front of the list
Eric Laurenta60e2122010-12-28 16:49:07 -0800308void SoundPool::moveToFront_l(SoundChannel* channel)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309{
310 for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
311 if (*iter == channel) {
312 mChannels.erase(iter);
313 mChannels.push_front(channel);
314 break;
315 }
316 }
317}
318
319void SoundPool::pause(int channelID)
320{
321 LOGV("pause(%d)", channelID);
322 Mutex::Autolock lock(&mLock);
323 SoundChannel* channel = findChannel(channelID);
324 if (channel) {
325 channel->pause();
326 }
327}
328
Dave Sparksf992cbb2010-02-09 13:00:09 -0800329void SoundPool::autoPause()
330{
Dave Sparks7bef5a52010-02-17 09:09:24 -0800331 LOGV("autoPause()");
Dave Sparksf992cbb2010-02-09 13:00:09 -0800332 Mutex::Autolock lock(&mLock);
333 for (int i = 0; i < mMaxChannels; ++i) {
334 SoundChannel* channel = &mChannelPool[i];
335 channel->autoPause();
336 }
337}
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339void SoundPool::resume(int channelID)
340{
341 LOGV("resume(%d)", channelID);
342 Mutex::Autolock lock(&mLock);
343 SoundChannel* channel = findChannel(channelID);
344 if (channel) {
345 channel->resume();
346 }
347}
348
Dave Sparksf992cbb2010-02-09 13:00:09 -0800349void SoundPool::autoResume()
350{
Dave Sparks7bef5a52010-02-17 09:09:24 -0800351 LOGV("autoResume()");
Dave Sparksf992cbb2010-02-09 13:00:09 -0800352 Mutex::Autolock lock(&mLock);
353 for (int i = 0; i < mMaxChannels; ++i) {
354 SoundChannel* channel = &mChannelPool[i];
355 channel->autoResume();
356 }
357}
358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359void SoundPool::stop(int channelID)
360{
361 LOGV("stop(%d)", channelID);
362 Mutex::Autolock lock(&mLock);
363 SoundChannel* channel = findChannel(channelID);
364 if (channel) {
365 channel->stop();
366 } else {
367 channel = findNextChannel(channelID);
368 if (channel)
369 channel->clearNextEvent();
370 }
371}
372
373void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
374{
375 Mutex::Autolock lock(&mLock);
376 SoundChannel* channel = findChannel(channelID);
377 if (channel) {
378 channel->setVolume(leftVolume, rightVolume);
379 }
380}
381
382void SoundPool::setPriority(int channelID, int priority)
383{
384 LOGV("setPriority(%d, %d)", channelID, priority);
385 Mutex::Autolock lock(&mLock);
386 SoundChannel* channel = findChannel(channelID);
387 if (channel) {
388 channel->setPriority(priority);
389 }
390}
391
392void SoundPool::setLoop(int channelID, int loop)
393{
394 LOGV("setLoop(%d, %d)", channelID, loop);
395 Mutex::Autolock lock(&mLock);
396 SoundChannel* channel = findChannel(channelID);
397 if (channel) {
398 channel->setLoop(loop);
399 }
400}
401
402void SoundPool::setRate(int channelID, float rate)
403{
404 LOGV("setRate(%d, %f)", channelID, rate);
405 Mutex::Autolock lock(&mLock);
406 SoundChannel* channel = findChannel(channelID);
407 if (channel) {
408 channel->setRate(rate);
409 }
410}
411
412// call with lock held
Eric Laurenta60e2122010-12-28 16:49:07 -0800413void SoundPool::done_l(SoundChannel* channel)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414{
Eric Laurenta60e2122010-12-28 16:49:07 -0800415 LOGV("done_l(%d)", channel->channelID());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 // if "stolen", play next event
417 if (channel->nextChannelID() != 0) {
418 LOGV("add to restart list");
419 addToRestartList(channel);
420 }
421
422 // return to idle state
423 else {
424 LOGV("move to front");
Eric Laurenta60e2122010-12-28 16:49:07 -0800425 moveToFront_l(channel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
427}
428
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800429void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
430{
431 Mutex::Autolock lock(&mCallbackLock);
432 mCallback = callback;
433 mUserData = user;
434}
435
436void SoundPool::notify(SoundPoolEvent event)
437{
438 Mutex::Autolock lock(&mCallbackLock);
439 if (mCallback != NULL) {
440 mCallback(event, this, mUserData);
441 }
442}
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444void SoundPool::dump()
445{
446 for (int i = 0; i < mMaxChannels; ++i) {
447 mChannelPool[i].dump();
448 }
449}
450
451
452Sample::Sample(int sampleID, const char* url)
453{
454 init();
455 mSampleID = sampleID;
456 mUrl = strdup(url);
457 LOGV("create sampleID=%d, url=%s", mSampleID, mUrl);
458}
459
460Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
461{
462 init();
463 mSampleID = sampleID;
464 mFd = dup(fd);
465 mOffset = offset;
466 mLength = length;
467 LOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset);
468}
469
470void Sample::init()
471{
472 mData = 0;
473 mSize = 0;
474 mRefCount = 0;
475 mSampleID = 0;
476 mState = UNLOADED;
477 mFd = -1;
478 mOffset = 0;
479 mLength = 0;
480 mUrl = 0;
481}
482
483Sample::~Sample()
484{
485 LOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
486 if (mFd > 0) {
487 LOGV("close(%d)", mFd);
488 ::close(mFd);
489 }
490 mData.clear();
491 delete mUrl;
492}
493
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800494status_t Sample::doLoad()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495{
496 uint32_t sampleRate;
497 int numChannels;
498 int format;
499 sp<IMemory> p;
500 LOGV("Start decode");
501 if (mUrl) {
502 p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format);
503 } else {
504 p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format);
505 LOGV("close(%d)", mFd);
506 ::close(mFd);
507 mFd = -1;
508 }
509 if (p == 0) {
510 LOGE("Unable to load sample: %s", mUrl);
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800511 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 }
513 LOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d",
514 p->pointer(), p->size(), sampleRate, numChannels);
515
516 if (sampleRate > kMaxSampleRate) {
517 LOGE("Sample rate (%u) out of range", sampleRate);
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800518 return - 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 }
520
521 if ((numChannels < 1) || (numChannels > 2)) {
522 LOGE("Sample channel count (%d) out of range", numChannels);
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800523 return - 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 }
525
526 //_dumpBuffer(p->pointer(), p->size());
527 uint8_t* q = static_cast<uint8_t*>(p->pointer()) + p->size() - 10;
528 //_dumpBuffer(q, 10, 10, false);
529
530 mData = p;
531 mSize = p->size();
532 mSampleRate = sampleRate;
533 mNumChannels = numChannels;
534 mFormat = format;
535 mState = READY;
Dave Sparksf6e43bf2009-12-08 08:10:42 -0800536 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537}
538
539
540void SoundChannel::init(SoundPool* soundPool)
541{
542 mSoundPool = soundPool;
543}
544
Eric Laurenta60e2122010-12-28 16:49:07 -0800545// call with sound pool lock held
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
547 float rightVolume, int priority, int loop, float rate)
548{
549 AudioTrack* oldTrack;
Eric Laurenta60e2122010-12-28 16:49:07 -0800550 AudioTrack* newTrack;
551 status_t status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552
Eric Laurenta60e2122010-12-28 16:49:07 -0800553 { // scope for the lock
554 Mutex::Autolock lock(&mLock);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555
Eric Laurenta60e2122010-12-28 16:49:07 -0800556 LOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
557 " priority=%d, loop=%d, rate=%f",
558 this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
559 priority, loop, rate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560
Eric Laurenta60e2122010-12-28 16:49:07 -0800561 // if not idle, this voice is being stolen
562 if (mState != IDLE) {
563 LOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
564 mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
565 stop_l();
566 return;
567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568
Eric Laurenta60e2122010-12-28 16:49:07 -0800569 // initialize track
570 int afFrameCount;
571 int afSampleRate;
572 int streamType = mSoundPool->streamType();
573 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
574 afFrameCount = kDefaultFrameCount;
575 }
576 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
577 afSampleRate = kDefaultSampleRate;
578 }
579 int numChannels = sample->numChannels();
580 uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
581 uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
582 uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
583 uint32_t frameCount = 0;
584
585 if (loop) {
586 frameCount = sample->size()/numChannels/
587 ((sample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589
Eric Laurent9648e4b2009-05-07 03:14:31 -0700590#ifndef USE_SHARED_MEM_BUFFER
Eric Laurenta60e2122010-12-28 16:49:07 -0800591 // Ensure minimum audio buffer size in case of short looped sample
592 if(frameCount < totalFrames) {
593 frameCount = totalFrames;
594 }
Eric Laurent9648e4b2009-05-07 03:14:31 -0700595#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
Eric Laurenta60e2122010-12-28 16:49:07 -0800597 // mToggle toggles each time a track is started on a given channel.
598 // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
599 // as callback user data. This enables the detection of callbacks received from the old
600 // audio track while the new one is being started and avoids processing them with
601 // wrong audio audio buffer size (mAudioBufferSize)
602 unsigned long toggle = mToggle ^ 1;
603 void *userData = (void *)((unsigned long)this | toggle);
604 uint32_t channels = (numChannels == 2) ?
605 AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO;
Dave Sparks66d28ce2009-12-14 21:12:05 -0800606
Eric Laurenta60e2122010-12-28 16:49:07 -0800607 // do not create a new audio track if current track is compatible with sample parameters
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608#ifdef USE_SHARED_MEM_BUFFER
Eric Laurenta60e2122010-12-28 16:49:07 -0800609 newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
610 channels, sample->getIMemory(), 0, callback, userData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611#else
Eric Laurenta60e2122010-12-28 16:49:07 -0800612 newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
613 channels, frameCount, 0, callback, userData, bufferFrames);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614#endif
Eric Laurenta60e2122010-12-28 16:49:07 -0800615 oldTrack = mAudioTrack;
616 status = newTrack->initCheck();
617 if (status != NO_ERROR) {
618 LOGE("Error creating AudioTrack");
619 goto exit;
620 }
621 LOGV("setVolume %p", newTrack);
622 newTrack->setVolume(leftVolume, rightVolume);
623 newTrack->setLoop(0, frameCount, loop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
626 mToggle = toggle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 mAudioTrack = newTrack;
628 mPos = 0;
629 mSample = sample;
630 mChannelID = nextChannelID;
631 mPriority = priority;
632 mLoop = loop;
633 mLeftVolume = leftVolume;
634 mRightVolume = rightVolume;
635 mNumChannels = numChannels;
636 mRate = rate;
637 clearNextEvent();
638 mState = PLAYING;
639 mAudioTrack->start();
640 mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
641 }
642
Eric Laurenta60e2122010-12-28 16:49:07 -0800643exit:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 LOGV("delete oldTrack %p", oldTrack);
645 delete oldTrack;
Eric Laurenta60e2122010-12-28 16:49:07 -0800646 if (status != NO_ERROR) {
647 delete newTrack;
648 mAudioTrack = NULL;
649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650}
651
652void SoundChannel::nextEvent()
653{
654 sp<Sample> sample;
655 int nextChannelID;
656 float leftVolume;
657 float rightVolume;
658 int priority;
659 int loop;
660 float rate;
661
662 // check for valid event
663 {
664 Mutex::Autolock lock(&mLock);
665 nextChannelID = mNextEvent.channelID();
666 if (nextChannelID == 0) {
667 LOGV("stolen channel has no event");
668 return;
669 }
670
671 sample = mNextEvent.sample();
672 leftVolume = mNextEvent.leftVolume();
673 rightVolume = mNextEvent.rightVolume();
674 priority = mNextEvent.priority();
675 loop = mNextEvent.loop();
676 rate = mNextEvent.rate();
677 }
678
679 LOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
680 play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
681}
682
683void SoundChannel::callback(int event, void* user, void *info)
684{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
686
Eric Laurenta60e2122010-12-28 16:49:07 -0800687 channel->process(event, info, (unsigned long)user & 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688}
689
Eric Laurenta60e2122010-12-28 16:49:07 -0800690void SoundChannel::process(int event, void *info, unsigned long toggle)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691{
692 //LOGV("process(%d)", mChannelID);
Eric Laurenta60e2122010-12-28 16:49:07 -0800693
694 Mutex::Autolock lock(&mLock);
695
696 AudioTrack::Buffer* b = NULL;
697 if (event == AudioTrack::EVENT_MORE_DATA) {
698 b = static_cast<AudioTrack::Buffer *>(info);
699 }
700
701 if (mToggle != toggle) {
702 LOGV("process wrong toggle %p channel %d", this, mChannelID);
703 if (b != NULL) {
704 b->size = 0;
705 }
706 return;
707 }
708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 sp<Sample> sample = mSample;
710
711// LOGV("SoundChannel::process event %d", event);
712
713 if (event == AudioTrack::EVENT_MORE_DATA) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714
715 // check for stop state
716 if (b->size == 0) return;
717
Eric Laurenta60e2122010-12-28 16:49:07 -0800718 if (mState == IDLE) {
719 b->size = 0;
720 return;
721 }
722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 if (sample != 0) {
724 // fill buffer
725 uint8_t* q = (uint8_t*) b->i8;
726 size_t count = 0;
727
728 if (mPos < (int)sample->size()) {
729 uint8_t* p = sample->data() + mPos;
730 count = sample->size() - mPos;
731 if (count > b->size) {
732 count = b->size;
733 }
734 memcpy(q, p, count);
Eric Laurenta60e2122010-12-28 16:49:07 -0800735// LOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 } else if (mPos < mAudioBufferSize) {
737 count = mAudioBufferSize - mPos;
738 if (count > b->size) {
739 count = b->size;
740 }
741 memset(q, 0, count);
Eric Laurenta60e2122010-12-28 16:49:07 -0800742// LOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
744
745 mPos += count;
746 b->size = count;
747 //LOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
748 }
749 } else if (event == AudioTrack::EVENT_UNDERRUN) {
Eric Laurenta60e2122010-12-28 16:49:07 -0800750 LOGV("process %p channel %d EVENT_UNDERRUN", this, mChannelID);
751 mSoundPool->addToStopList(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 } else if (event == AudioTrack::EVENT_LOOP_END) {
Eric Laurenta60e2122010-12-28 16:49:07 -0800753 LOGV("End loop %p channel %d count %d", this, mChannelID, *(int *)info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 }
755}
756
757
758// call with lock held
Eric Laurenta60e2122010-12-28 16:49:07 -0800759bool SoundChannel::doStop_l()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760{
761 if (mState != IDLE) {
762 setVolume_l(0, 0);
763 LOGV("stop");
764 mAudioTrack->stop();
765 mSample.clear();
766 mState = IDLE;
767 mPriority = IDLE_PRIORITY;
Eric Laurenta60e2122010-12-28 16:49:07 -0800768 return true;
769 }
770 return false;
771}
772
773// call with lock held and sound pool lock held
774void SoundChannel::stop_l()
775{
776 if (doStop_l()) {
777 mSoundPool->done_l(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 }
779}
780
Eric Laurenta60e2122010-12-28 16:49:07 -0800781// call with sound pool lock held
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782void SoundChannel::stop()
783{
Eric Laurenta60e2122010-12-28 16:49:07 -0800784 bool stopped;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 {
786 Mutex::Autolock lock(&mLock);
Eric Laurenta60e2122010-12-28 16:49:07 -0800787 stopped = doStop_l();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 }
Eric Laurenta60e2122010-12-28 16:49:07 -0800789
790 if (stopped) {
791 mSoundPool->done_l(this);
792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793}
794
795//FIXME: Pause is a little broken right now
796void SoundChannel::pause()
797{
798 Mutex::Autolock lock(&mLock);
799 if (mState == PLAYING) {
800 LOGV("pause track");
801 mState = PAUSED;
802 mAudioTrack->pause();
803 }
804}
805
Dave Sparksf992cbb2010-02-09 13:00:09 -0800806void SoundChannel::autoPause()
807{
808 Mutex::Autolock lock(&mLock);
809 if (mState == PLAYING) {
810 LOGV("pause track");
811 mState = PAUSED;
812 mAutoPaused = true;
813 mAudioTrack->pause();
814 }
815}
816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817void SoundChannel::resume()
818{
819 Mutex::Autolock lock(&mLock);
820 if (mState == PAUSED) {
821 LOGV("resume track");
822 mState = PLAYING;
Dave Sparksf992cbb2010-02-09 13:00:09 -0800823 mAutoPaused = false;
824 mAudioTrack->start();
825 }
826}
827
828void SoundChannel::autoResume()
829{
830 Mutex::Autolock lock(&mLock);
831 if (mAutoPaused && (mState == PAUSED)) {
832 LOGV("resume track");
833 mState = PLAYING;
834 mAutoPaused = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 mAudioTrack->start();
836 }
837}
838
839void SoundChannel::setRate(float rate)
840{
841 Mutex::Autolock lock(&mLock);
842 if (mAudioTrack != 0 && mSample.get() != 0) {
843 uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
844 mAudioTrack->setSampleRate(sampleRate);
845 mRate = rate;
846 }
847}
848
849// call with lock held
850void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
851{
852 mLeftVolume = leftVolume;
853 mRightVolume = rightVolume;
854 if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume);
855}
856
857void SoundChannel::setVolume(float leftVolume, float rightVolume)
858{
859 Mutex::Autolock lock(&mLock);
860 setVolume_l(leftVolume, rightVolume);
861}
862
863void SoundChannel::setLoop(int loop)
864{
865 Mutex::Autolock lock(&mLock);
866 if (mAudioTrack != 0 && mSample.get() != 0) {
Eric Laurenta60e2122010-12-28 16:49:07 -0800867 uint32_t loopEnd = mSample->size()/mNumChannels/
868 ((mSample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
869 mAudioTrack->setLoop(0, loopEnd, loop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 mLoop = loop;
871 }
872}
873
874SoundChannel::~SoundChannel()
875{
Eric Laurenta60e2122010-12-28 16:49:07 -0800876 LOGV("SoundChannel destructor %p", this);
877 {
878 Mutex::Autolock lock(&mLock);
879 clearNextEvent();
880 doStop_l();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 }
Eric Laurenta60e2122010-12-28 16:49:07 -0800882 // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
883 // callback thread to exit which may need to execute process() and acquire the mLock.
884 delete mAudioTrack;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885}
886
887void SoundChannel::dump()
888{
889 LOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
890 mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
891}
892
893void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
894 float rightVolume, int priority, int loop, float rate)
895{
Eric Laurenta60e2122010-12-28 16:49:07 -0800896 mSample = sample;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 mChannelID = channelID;
898 mLeftVolume = leftVolume;
899 mRightVolume = rightVolume;
900 mPriority = priority;
901 mLoop = loop;
902 mRate =rate;
903}
904
905} // end namespace android