blob: d4f2e5a473134770bda665eec3d7c7331a1d5cea [file] [log] [blame]
The Android Open Source Project2729ea92008-10-21 07:00:00 -07001/* //device/extlibs/pv/android/AudioTrack.cpp
2**
3** Copyright 2007, The Android Open Source Project
4**
The Android Open Source Project7b5eb022008-12-17 18:05:43 -08005** 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
The Android Open Source Project2729ea92008-10-21 07:00:00 -07008**
The Android Open Source Project7b5eb022008-12-17 18:05:43 -08009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project2729ea92008-10-21 07:00:00 -070010**
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080011** 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
The Android Open Source Project2729ea92008-10-21 07:00:00 -070015** limitations under the License.
16*/
17
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "AudioTrack"
21
22#include <stdint.h>
23#include <sys/types.h>
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080024#include <limits.h>
The Android Open Source Project2729ea92008-10-21 07:00:00 -070025
26#include <sched.h>
27#include <sys/resource.h>
28
29#include <private/media/AudioTrackShared.h>
30
31#include <media/AudioSystem.h>
32#include <media/AudioTrack.h>
33
34#include <utils/Log.h>
35#include <utils/MemoryDealer.h>
36#include <utils/Parcel.h>
37#include <utils/IPCThreadState.h>
38#include <utils/Timers.h>
39#include <cutils/atomic.h>
40
41#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
42#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
43
44namespace android {
45
46// ---------------------------------------------------------------------------
47
The Android Open Source Project2729ea92008-10-21 07:00:00 -070048AudioTrack::AudioTrack()
49 : mStatus(NO_INIT)
50{
51}
52
53AudioTrack::AudioTrack(
54 int streamType,
55 uint32_t sampleRate,
56 int format,
57 int channelCount,
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080058 int frameCount,
The Android Open Source Project2729ea92008-10-21 07:00:00 -070059 uint32_t flags,
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080060 callback_t cbf,
61 void* user,
62 int notificationFrames)
The Android Open Source Project2729ea92008-10-21 07:00:00 -070063 : mStatus(NO_INIT)
64{
65 mStatus = set(streamType, sampleRate, format, channelCount,
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080066 frameCount, flags, cbf, user, notificationFrames, 0);
67}
68
69AudioTrack::AudioTrack(
70 int streamType,
71 uint32_t sampleRate,
72 int format,
73 int channelCount,
74 const sp<IMemory>& sharedBuffer,
75 uint32_t flags,
76 callback_t cbf,
77 void* user,
78 int notificationFrames)
79 : mStatus(NO_INIT)
80{
81 mStatus = set(streamType, sampleRate, format, channelCount,
82 0, flags, cbf, user, notificationFrames, sharedBuffer);
The Android Open Source Project2729ea92008-10-21 07:00:00 -070083}
84
85AudioTrack::~AudioTrack()
86{
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080087 LOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
88
The Android Open Source Project2729ea92008-10-21 07:00:00 -070089 if (mStatus == NO_ERROR) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080090 // Make sure that callback function exits in the case where
91 // it is looping on buffer full condition in obtainBuffer().
92 // Otherwise the callback thread will never exit.
93 stop();
The Android Open Source Project2729ea92008-10-21 07:00:00 -070094 if (mAudioTrackThread != 0) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080095 mCblk->cv.signal();
The Android Open Source Project2729ea92008-10-21 07:00:00 -070096 mAudioTrackThread->requestExitAndWait();
97 mAudioTrackThread.clear();
98 }
99 mAudioTrack.clear();
100 IPCThreadState::self()->flushCommands();
101 }
102}
103
104status_t AudioTrack::set(
105 int streamType,
106 uint32_t sampleRate,
107 int format,
108 int channelCount,
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800109 int frameCount,
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700110 uint32_t flags,
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800111 callback_t cbf,
112 void* user,
113 int notificationFrames,
114 const sp<IMemory>& sharedBuffer,
115 bool threadCanCallJava)
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700116{
117
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800118 LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
119
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700120 if (mAudioFlinger != 0) {
121 LOGE("Track already in use");
122 return INVALID_OPERATION;
123 }
124
125 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
126 if (audioFlinger == 0) {
127 LOGE("Could not get audioflinger");
128 return NO_INIT;
129 }
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800130 int afSampleRate;
131 if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
132 return NO_INIT;
133 }
134 int afFrameCount;
135 if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
136 return NO_INIT;
137 }
138 uint32_t afLatency;
139 if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
140 return NO_INIT;
141 }
142
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700143
144 // handle default values first.
145 if (streamType == DEFAULT) {
146 streamType = MUSIC;
147 }
148 if (sampleRate == 0) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800149 sampleRate = afSampleRate;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700150 }
151 // these below should probably come from the audioFlinger too...
152 if (format == 0) {
153 format = AudioSystem::PCM_16_BIT;
154 }
155 if (channelCount == 0) {
156 channelCount = 2;
157 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700158
159 // validate parameters
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800160 if (((format != AudioSystem::PCM_8_BIT) || mSharedBuffer != 0) &&
161 (format != AudioSystem::PCM_16_BIT)) {
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700162 LOGE("Invalid format");
163 return BAD_VALUE;
164 }
165 if (channelCount != 1 && channelCount != 2) {
166 LOGE("Invalid channel number");
167 return BAD_VALUE;
168 }
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800169
170 // Ensure that buffer depth covers at least audio hardware latency
171 uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
172 // When playing from shared buffer, playback will start even if last audioflinger
173 // block is partly filled.
174 if (sharedBuffer != 0 && minBufCount > 1) {
175 minBufCount--;
176 }
177
178 int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
179
180 if (sharedBuffer == 0) {
181 if (frameCount == 0) {
182 frameCount = minFrameCount;
183 }
184 if (notificationFrames == 0) {
185 notificationFrames = frameCount/2;
186 }
187 // Make sure that application is notified with sufficient margin
188 // before underrun
189 if (notificationFrames > frameCount/2) {
190 notificationFrames = frameCount/2;
191 }
192 } else {
193 // Ensure that buffer alignment matches channelcount
194 if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
195 LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
196 return BAD_VALUE;
197 }
198 frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
199 }
200
201 if (frameCount < minFrameCount) {
202 LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
203 return BAD_VALUE;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700204 }
205
206 // create the track
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800207 status_t status;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700208 sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800209 streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
210
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700211 if (track == 0) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800212 LOGE("AudioFlinger could not create track, status: %d", status);
213 return status;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700214 }
215 sp<IMemory> cblk = track->getCblk();
216 if (cblk == 0) {
217 LOGE("Could not get control block");
218 return NO_INIT;
219 }
220 if (cbf != 0) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800221 mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700222 if (mAudioTrackThread == 0) {
223 LOGE("Could not create callback thread");
224 return NO_INIT;
225 }
226 }
227
228 mStatus = NO_ERROR;
229
230 mAudioFlinger = audioFlinger;
231 mAudioTrack = track;
232 mCblkMemory = cblk;
233 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800234 if (sharedBuffer == 0) {
235 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
236 } else {
237 mCblk->buffers = sharedBuffer->pointer();
238 }
239 mCblk->out = 1;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700240 mCblk->volume[0] = mCblk->volume[1] = 0x1000;
241 mVolume[LEFT] = 1.0f;
242 mVolume[RIGHT] = 1.0f;
243 mSampleRate = sampleRate;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700244 mStreamType = streamType;
245 mFormat = format;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800246 // Update buffer size in case it has been limited by AudioFlinger during track creation
247 mFrameCount = mCblk->frameCount;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700248 mChannelCount = channelCount;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800249 mSharedBuffer = sharedBuffer;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700250 mMuted = false;
251 mActive = 0;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700252 mCbf = cbf;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800253 mNotificationFrames = notificationFrames;
254 mRemainingFrames = notificationFrames;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700255 mUserData = user;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800256 mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
257 mLoopCount = 0;
258 mMarkerPosition = 0;
259 mNewPosition = 0;
260 mUpdatePeriod = 0;
261
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700262 return NO_ERROR;
263}
264
265status_t AudioTrack::initCheck() const
266{
267 return mStatus;
268}
269
270// -------------------------------------------------------------------------
271
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800272uint32_t AudioTrack::latency() const
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700273{
274 return mLatency;
275}
276
277int AudioTrack::streamType() const
278{
279 return mStreamType;
280}
281
282uint32_t AudioTrack::sampleRate() const
283{
284 return mSampleRate;
285}
286
287int AudioTrack::format() const
288{
289 return mFormat;
290}
291
292int AudioTrack::channelCount() const
293{
294 return mChannelCount;
295}
296
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800297uint32_t AudioTrack::frameCount() const
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700298{
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800299 return mFrameCount;
300}
301
302int AudioTrack::frameSize() const
303{
304 return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
305}
306
307sp<IMemory>& AudioTrack::sharedBuffer()
308{
309 return mSharedBuffer;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700310}
311
312// -------------------------------------------------------------------------
313
314void AudioTrack::start()
315{
316 sp<AudioTrackThread> t = mAudioTrackThread;
317
318 LOGV("start");
319 if (t != 0) {
320 if (t->exitPending()) {
321 if (t->requestExitAndWait() == WOULD_BLOCK) {
322 LOGE("AudioTrack::start called from thread");
323 return;
324 }
325 }
326 t->mLock.lock();
327 }
328
329 if (android_atomic_or(1, &mActive) == 0) {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800330 if (mSharedBuffer != 0) {
331 // Force buffer full condition as data is already present in shared memory
332 mCblk->user = mFrameCount;
333 mCblk->flowControlFlag = 0;
334 }
335 mNewPosition = mCblk->server + mUpdatePeriod;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700336 if (t != 0) {
337 t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
338 } else {
339 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
340 }
341 mAudioTrack->start();
342 }
343
344 if (t != 0) {
345 t->mLock.unlock();
346 }
347}
348
349void AudioTrack::stop()
350{
351 sp<AudioTrackThread> t = mAudioTrackThread;
352
353 LOGV("stop");
354 if (t != 0) {
355 t->mLock.lock();
356 }
357
358 if (android_atomic_and(~1, &mActive) == 1) {
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700359 mAudioTrack->stop();
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800360 // Cancel loops (If we are in the middle of a loop, playback
361 // would not stop until loopCount reaches 0).
362 setLoop(0, 0, 0);
363 // Force flush if a shared buffer is used otherwise audioflinger
364 // will not stop before end of buffer is reached.
365 if (mSharedBuffer != 0) {
366 flush();
367 }
368 if (t != 0) {
369 t->requestExit();
370 } else {
371 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
372 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700373 }
374
375 if (t != 0) {
376 t->mLock.unlock();
377 }
378}
379
380bool AudioTrack::stopped() const
381{
382 return !mActive;
383}
384
385void AudioTrack::flush()
386{
387 LOGV("flush");
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800388
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700389 if (!mActive) {
390 mCblk->lock.lock();
391 mAudioTrack->flush();
392 // Release AudioTrack callback thread in case it was waiting for new buffers
393 // in AudioTrack::obtainBuffer()
394 mCblk->cv.signal();
395 mCblk->lock.unlock();
396 }
397}
398
399void AudioTrack::pause()
400{
401 LOGV("pause");
402 if (android_atomic_and(~1, &mActive) == 1) {
403 mActive = 0;
404 mAudioTrack->pause();
405 }
406}
407
408void AudioTrack::mute(bool e)
409{
410 mAudioTrack->mute(e);
411 mMuted = e;
412}
413
414bool AudioTrack::muted() const
415{
416 return mMuted;
417}
418
419void AudioTrack::setVolume(float left, float right)
420{
421 mVolume[LEFT] = left;
422 mVolume[RIGHT] = right;
423
424 // write must be atomic
425 mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
426}
427
428void AudioTrack::getVolume(float* left, float* right)
429{
430 *left = mVolume[LEFT];
431 *right = mVolume[RIGHT];
432}
433
434void AudioTrack::setSampleRate(int rate)
435{
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800436 int afSamplingRate;
437
438 if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
439 return;
440 }
441 // Resampler implementation limits input sampling rate to 2 x output sampling rate.
442 if (rate > afSamplingRate*2) rate = afSamplingRate*2;
443
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700444 if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800445
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700446 mCblk->sampleRate = rate;
447}
448
449uint32_t AudioTrack::getSampleRate()
450{
451 return uint32_t(mCblk->sampleRate);
452}
453
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800454status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
455{
456 audio_track_cblk_t* cblk = mCblk;
457
458
459 Mutex::Autolock _l(cblk->lock);
460
461 if (loopCount == 0) {
462 cblk->loopStart = UINT_MAX;
463 cblk->loopEnd = UINT_MAX;
464 cblk->loopCount = 0;
465 mLoopCount = 0;
466 return NO_ERROR;
467 }
468
469 if (loopStart >= loopEnd ||
470 loopStart < cblk->user ||
471 loopEnd - loopStart > mFrameCount) {
472 LOGW("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
473 return BAD_VALUE;
474 }
475 // TODO handle shared buffer here: limit loop end to framecount
476
477 cblk->loopStart = loopStart;
478 cblk->loopEnd = loopEnd;
479 cblk->loopCount = loopCount;
480 mLoopCount = loopCount;
481
482 return NO_ERROR;
483}
484
485status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
486{
487 if (loopStart != 0) {
488 *loopStart = mCblk->loopStart;
489 }
490 if (loopEnd != 0) {
491 *loopEnd = mCblk->loopEnd;
492 }
493 if (loopCount != 0) {
494 if (mCblk->loopCount < 0) {
495 *loopCount = -1;
496 } else {
497 *loopCount = mCblk->loopCount;
498 }
499 }
500
501 return NO_ERROR;
502}
503
504status_t AudioTrack::setMarkerPosition(uint32_t marker)
505{
506 if (mCbf == 0) return INVALID_OPERATION;
507
508 mMarkerPosition = marker;
509
510 return NO_ERROR;
511}
512
513status_t AudioTrack::getMarkerPosition(uint32_t *marker)
514{
515 if (marker == 0) return BAD_VALUE;
516
517 *marker = mMarkerPosition;
518
519 return NO_ERROR;
520}
521
522status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
523{
524 if (mCbf == 0) return INVALID_OPERATION;
525
526 uint32_t curPosition;
527 getPosition(&curPosition);
528 mNewPosition = curPosition + updatePeriod;
529 mUpdatePeriod = updatePeriod;
530
531 return NO_ERROR;
532}
533
534status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
535{
536 if (updatePeriod == 0) return BAD_VALUE;
537
538 *updatePeriod = mUpdatePeriod;
539
540 return NO_ERROR;
541}
542
543status_t AudioTrack::setPosition(uint32_t position)
544{
545 Mutex::Autolock _l(mCblk->lock);
546
547 if (!stopped()) return INVALID_OPERATION;
548
549 if (position > mCblk->user) return BAD_VALUE;
550
551 mCblk->server = position;
552 mCblk->forceReady = 1;
553
554 return NO_ERROR;
555}
556
557status_t AudioTrack::getPosition(uint32_t *position)
558{
559 if (position == 0) return BAD_VALUE;
560
561 *position = mCblk->server;
562
563 return NO_ERROR;
564}
565
566status_t AudioTrack::reload()
567{
568 if (!stopped()) return INVALID_OPERATION;
569
570 flush();
571
572 mCblk->stepUser(mFrameCount);
573
574 return NO_ERROR;
575}
576
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700577// -------------------------------------------------------------------------
578
579status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
580{
581 int active;
582 int timeout = 0;
583 status_t result;
584 audio_track_cblk_t* cblk = mCblk;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800585 uint32_t framesReq = audioBuffer->frameCount;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700586
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800587 audioBuffer->frameCount = 0;
588 audioBuffer->size = 0;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700589
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800590 uint32_t framesAvail = cblk->framesAvailable();
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700591
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800592 if (framesAvail == 0) {
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700593 Mutex::Autolock _l(cblk->lock);
594 goto start_loop_here;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800595 while (framesAvail == 0) {
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700596 active = mActive;
597 if (UNLIKELY(!active)) {
598 LOGV("Not active and NO_MORE_BUFFERS");
599 return NO_MORE_BUFFERS;
600 }
601 if (UNLIKELY(!blocking))
602 return WOULD_BLOCK;
603 timeout = 0;
604 result = cblk->cv.waitRelative(cblk->lock, seconds(1));
605 if (__builtin_expect(result!=NO_ERROR, false)) {
606 LOGW( "obtainBuffer timed out (is the CPU pegged?) "
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800607 "user=%08x, server=%08x", cblk->user, cblk->server);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700608 mAudioTrack->start(); // FIXME: Wake up audioflinger
609 timeout = 1;
610 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700611 // read the server count again
612 start_loop_here:
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800613 framesAvail = cblk->framesAvailable_l();
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700614 }
615 }
616
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800617 if (framesReq > framesAvail) {
618 framesReq = framesAvail;
619 }
620
621 uint32_t u = cblk->user;
622 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
623
624 if (u + framesReq > bufferEnd) {
625 framesReq = bufferEnd - u;
626 }
627
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700628 LOGW_IF(timeout,
629 "*** SERIOUS WARNING *** obtainBuffer() timed out "
630 "but didn't need to be locked. We recovered, but "
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800631 "this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700632
633 audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
634 audioBuffer->channelCount= mChannelCount;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800635 audioBuffer->format = AudioSystem::PCM_16_BIT;
636 audioBuffer->frameCount = framesReq;
637 audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
638 audioBuffer->raw = (int8_t *)cblk->buffer(u);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700639 active = mActive;
640 return active ? status_t(NO_ERROR) : status_t(STOPPED);
641}
642
643void AudioTrack::releaseBuffer(Buffer* audioBuffer)
644{
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700645 audio_track_cblk_t* cblk = mCblk;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800646 cblk->stepUser(audioBuffer->frameCount);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700647}
648
649// -------------------------------------------------------------------------
650
651ssize_t AudioTrack::write(const void* buffer, size_t userSize)
652{
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800653
654 if (mSharedBuffer != 0) return INVALID_OPERATION;
655
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700656 if (ssize_t(userSize) < 0) {
657 // sanity-check. user is most-likely passing an error code.
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800658 LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700659 buffer, userSize, userSize);
660 return BAD_VALUE;
661 }
662
663 LOGV("write %d bytes, mActive=%d", userSize, mActive);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800664
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700665 ssize_t written = 0;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800666 const int8_t *src = (const int8_t *)buffer;
667 Buffer audioBuffer;
668
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700669 do {
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800670 audioBuffer.frameCount = userSize/mChannelCount;
671 if (mFormat == AudioSystem::PCM_16_BIT) {
672 audioBuffer.frameCount >>= 1;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700673 }
674
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800675 status_t err = obtainBuffer(&audioBuffer, true);
676 if (err < 0) {
677 // out of buffers, return #bytes written
678 if (err == status_t(NO_MORE_BUFFERS))
679 break;
680 return ssize_t(err);
681 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700682
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800683 size_t toWrite;
684 if (mFormat == AudioSystem::PCM_8_BIT) {
685 // Divide capacity by 2 to take expansion into account
686 toWrite = audioBuffer.size>>1;
687 // 8 to 16 bit conversion
688 int count = toWrite;
689 int16_t *dst = (int16_t *)(audioBuffer.i8);
690 while(count--) {
691 *dst++ = (int16_t)(*src++^0x80) << 8;
692 }
693 }else {
694 toWrite = audioBuffer.size;
695 memcpy(audioBuffer.i8, src, toWrite);
696 src += toWrite;
697 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700698 userSize -= toWrite;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700699 written += toWrite;
700
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800701 releaseBuffer(&audioBuffer);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700702 } while (userSize);
703
704 return written;
705}
706
707// -------------------------------------------------------------------------
708
709bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
710{
711 Buffer audioBuffer;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800712 uint32_t frames;
713 size_t writtenSize = 0;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700714
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800715 // Manage underrun callback
716 if (mActive && (mCblk->framesReady() == 0)) {
717 LOGV("Underrun user: %x, server: %x, flowControlFlag %d", mCblk->user, mCblk->server, mCblk->flowControlFlag);
718 if (mCblk->flowControlFlag == 0) {
719 mCbf(EVENT_UNDERRUN, mUserData, 0);
720 if (mCblk->server == mCblk->frameCount) {
721 mCbf(EVENT_BUFFER_END, mUserData, 0);
722 }
723 mCblk->flowControlFlag = 1;
724 if (mSharedBuffer != 0) return false;
725 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700726 }
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800727
728 // Manage loop end callback
729 while (mLoopCount > mCblk->loopCount) {
730 int loopCount = -1;
731 mLoopCount--;
732 if (mLoopCount >= 0) loopCount = mLoopCount;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700733
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800734 mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
735 }
736
737 // Manage marker callback
738 if(mMarkerPosition > 0) {
739 if (mCblk->server >= mMarkerPosition) {
740 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
741 mMarkerPosition = 0;
742 }
743 }
744
745 // Manage new position callback
746 if(mUpdatePeriod > 0) {
747 while (mCblk->server >= mNewPosition) {
748 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
749 mNewPosition += mUpdatePeriod;
750 }
751 }
752
753 // If Shared buffer is used, no data is requested from client.
754 if (mSharedBuffer != 0) {
755 frames = 0;
756 } else {
757 frames = mRemainingFrames;
758 }
759
760 do {
761
762 audioBuffer.frameCount = frames;
763
764 status_t err = obtainBuffer(&audioBuffer, false);
765 if (err < NO_ERROR) {
766 if (err != WOULD_BLOCK) {
767 LOGE("Error obtaining an audio buffer, giving up.");
768 return false;
769 }
770 }
771 if (err == status_t(STOPPED)) return false;
772
773 if (audioBuffer.size == 0) break;
774
775 // Divide buffer size by 2 to take into account the expansion
776 // due to 8 to 16 bit conversion: the callback must fill only half
777 // of the destination buffer
778 if (mFormat == AudioSystem::PCM_8_BIT) {
779 audioBuffer.size >>= 1;
780 }
781
782 size_t reqSize = audioBuffer.size;
783 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
784 writtenSize = audioBuffer.size;
785
786 // Sanity check on returned size
787 if (ssize_t(writtenSize) <= 0) break;
788 if (writtenSize > reqSize) writtenSize = reqSize;
789
790 if (mFormat == AudioSystem::PCM_8_BIT) {
791 // 8 to 16 bit conversion
792 const int8_t *src = audioBuffer.i8 + writtenSize-1;
793 int count = writtenSize;
794 int16_t *dst = audioBuffer.i16 + writtenSize-1;
795 while(count--) {
796 *dst-- = (int16_t)(*src--^0x80) << 8;
797 }
798 writtenSize <<= 1;
799 }
800
801 audioBuffer.size = writtenSize;
802 audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
803 frames -= audioBuffer.frameCount;
804
805 releaseBuffer(&audioBuffer);
806 }
807 while (frames);
808
809 // If no data was written, it is likely that obtainBuffer() did
810 // not find room in PCM buffer: we release the processor for
811 // a few millisecond before polling again for available room.
812 if (writtenSize == 0) {
813 usleep(5000);
814 }
815
816 if (frames == 0) {
817 mRemainingFrames = mNotificationFrames;
818 } else {
819 mRemainingFrames = frames;
820 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700821 return true;
822}
823
824status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
825{
826
827 const size_t SIZE = 256;
828 char buffer[SIZE];
829 String8 result;
830
831 result.append(" AudioTrack::dump\n");
832 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
833 result.append(buffer);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800834 snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700835 result.append(buffer);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800836 snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700837 result.append(buffer);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800838 snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700839 result.append(buffer);
840 ::write(fd, result.string(), result.size());
841 return NO_ERROR;
842}
843
844// =========================================================================
845
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800846AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
847 : Thread(bCanCallJava), mReceiver(receiver)
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700848{
849}
850
851bool AudioTrack::AudioTrackThread::threadLoop()
852{
853 return mReceiver.processAudioBuffer(this);
854}
855
856status_t AudioTrack::AudioTrackThread::readyToRun()
857{
858 return NO_ERROR;
859}
860
861void AudioTrack::AudioTrackThread::onFirstRef()
862{
863}
864
865// =========================================================================
866
867audio_track_cblk_t::audio_track_cblk_t()
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800868 : user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
869 loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flowControlFlag(1), forceReady(0)
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700870{
871}
872
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800873uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700874{
875 uint32_t u = this->user;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800876
877 u += frameCount;
878 // Ensure that user is never ahead of server for AudioRecord
879 if (!out && u > this->server) {
880 LOGW("stepServer occured after track reset");
881 u = this->server;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700882 }
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800883
884 if (u >= userBase + this->frameCount) {
885 userBase += this->frameCount;
886 }
887
888 this->user = u;
889
890 // Clear flow control error condition as new data has been written/read to/from buffer.
891 flowControlFlag = 0;
892
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700893 return u;
894}
895
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800896bool audio_track_cblk_t::stepServer(uint32_t frameCount)
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700897{
898 // the code below simulates lock-with-timeout
899 // we MUST do this to protect the AudioFlinger server
900 // as this lock is shared with the client.
901 status_t err;
902
903 err = lock.tryLock();
904 if (err == -EBUSY) { // just wait a bit
905 usleep(1000);
906 err = lock.tryLock();
907 }
908 if (err != NO_ERROR) {
909 // probably, the client just died.
910 return false;
911 }
912
913 uint32_t s = this->server;
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700914
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800915 s += frameCount;
916 // It is possible that we receive a flush()
917 // while the mixer is processing a block: in this case,
918 // stepServer() is called After the flush() has reset u & s and
919 // we have s > u
920 if (out && s > this->user) {
921 LOGW("stepServer occured after track reset");
922 s = this->user;
923 }
924
925 if (s >= loopEnd) {
926 LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
927 s = loopStart;
928 if (--loopCount == 0) {
929 loopEnd = UINT_MAX;
930 loopStart = UINT_MAX;
931 }
932 }
933 if (s >= serverBase + this->frameCount) {
934 serverBase += this->frameCount;
935 }
936
937 this->server = s;
938
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700939 cv.signal();
940 lock.unlock();
941 return true;
942}
943
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800944void* audio_track_cblk_t::buffer(uint32_t offset) const
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700945{
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800946 return (int16_t *)this->buffers + (offset-userBase)*this->channels;
947}
948
949uint32_t audio_track_cblk_t::framesAvailable()
950{
951 Mutex::Autolock _l(lock);
952 return framesAvailable_l();
953}
954
955uint32_t audio_track_cblk_t::framesAvailable_l()
956{
957 uint32_t u = this->user;
958 uint32_t s = this->server;
959
960 if (out) {
961 if (u < loopEnd) {
962 return s + frameCount - u;
963 } else {
964 uint32_t limit = (s < loopStart) ? s : loopStart;
965 return limit + frameCount - u;
966 }
967 } else {
968 return frameCount + u - s;
969 }
970}
971
972uint32_t audio_track_cblk_t::framesReady()
973{
974 uint32_t u = this->user;
975 uint32_t s = this->server;
976
977 if (out) {
978 if (u < loopEnd) {
979 return u - s;
980 } else {
981 Mutex::Autolock _l(lock);
982 if (loopCount >= 0) {
983 return (loopEnd - loopStart)*loopCount + u - s;
984 } else {
985 return UINT_MAX;
986 }
987 }
988 } else {
989 return s - u;
990 }
The Android Open Source Project2729ea92008-10-21 07:00:00 -0700991}
992
993// -------------------------------------------------------------------------
994
995}; // namespace android
996