blob: 890786e6d1dfab866c02f3a1be687c664f59803b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/extlibs/pv/android/AudioTrack.cpp
2**
3** Copyright 2007, 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
19//#define LOG_NDEBUG 0
20#define LOG_TAG "AudioTrack"
21
22#include <stdint.h>
23#include <sys/types.h>
24#include <limits.h>
25
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>
Mathias Agopian07952722009-05-19 19:08:10 -070035#include <binder/Parcel.h>
36#include <binder/IPCThreadState.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037#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 {
Chia-chi Yehbd240c22010-06-16 06:33:13 +080044// ---------------------------------------------------------------------------
45
46// static
47status_t AudioTrack::getMinFrameCount(
48 int* frameCount,
49 int streamType,
50 uint32_t sampleRate)
51{
52 int afSampleRate;
53 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
54 return NO_INIT;
55 }
56 int afFrameCount;
57 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
58 return NO_INIT;
59 }
60 uint32_t afLatency;
61 if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
62 return NO_INIT;
63 }
64
65 // Ensure that buffer depth covers at least audio hardware latency
66 uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
67 if (minBufCount < 2) minBufCount = 2;
68
69 *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
70 afFrameCount * minBufCount * sampleRate / afSampleRate;
71 return NO_ERROR;
72}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073
74// ---------------------------------------------------------------------------
75
76AudioTrack::AudioTrack()
77 : mStatus(NO_INIT)
78{
79}
80
81AudioTrack::AudioTrack(
82 int streamType,
83 uint32_t sampleRate,
84 int format,
Eric Laurenta553c252009-07-17 12:17:14 -070085 int channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 int frameCount,
87 uint32_t flags,
88 callback_t cbf,
89 void* user,
Eric Laurent65b65452010-06-01 23:49:17 -070090 int notificationFrames,
91 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 : mStatus(NO_INIT)
93{
Eric Laurenta553c252009-07-17 12:17:14 -070094 mStatus = set(streamType, sampleRate, format, channels,
Eric Laurent619346f2010-06-21 09:27:30 -070095 frameCount, flags, cbf, user, notificationFrames,
96 0, false, sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097}
98
99AudioTrack::AudioTrack(
100 int streamType,
101 uint32_t sampleRate,
102 int format,
Eric Laurenta553c252009-07-17 12:17:14 -0700103 int channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 const sp<IMemory>& sharedBuffer,
105 uint32_t flags,
106 callback_t cbf,
107 void* user,
Eric Laurent65b65452010-06-01 23:49:17 -0700108 int notificationFrames,
109 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 : mStatus(NO_INIT)
111{
Eric Laurenta553c252009-07-17 12:17:14 -0700112 mStatus = set(streamType, sampleRate, format, channels,
Eric Laurent619346f2010-06-21 09:27:30 -0700113 0, flags, cbf, user, notificationFrames,
114 sharedBuffer, false, sessionId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115}
116
117AudioTrack::~AudioTrack()
118{
119 LOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
120
121 if (mStatus == NO_ERROR) {
122 // Make sure that callback function exits in the case where
123 // it is looping on buffer full condition in obtainBuffer().
124 // Otherwise the callback thread will never exit.
125 stop();
126 if (mAudioTrackThread != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 mAudioTrackThread->requestExitAndWait();
128 mAudioTrackThread.clear();
129 }
130 mAudioTrack.clear();
131 IPCThreadState::self()->flushCommands();
132 }
133}
134
135status_t AudioTrack::set(
136 int streamType,
137 uint32_t sampleRate,
138 int format,
Eric Laurenta553c252009-07-17 12:17:14 -0700139 int channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 int frameCount,
141 uint32_t flags,
142 callback_t cbf,
143 void* user,
144 int notificationFrames,
145 const sp<IMemory>& sharedBuffer,
Eric Laurent65b65452010-06-01 23:49:17 -0700146 bool threadCanCallJava,
147 int sessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148{
149
150 LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
151
Eric Laurentef028272009-04-21 07:56:33 -0700152 if (mAudioTrack != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 LOGE("Track already in use");
154 return INVALID_OPERATION;
155 }
156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 int afSampleRate;
158 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
159 return NO_INIT;
160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 uint32_t afLatency;
162 if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
163 return NO_INIT;
164 }
165
166 // handle default values first.
167 if (streamType == AudioSystem::DEFAULT) {
168 streamType = AudioSystem::MUSIC;
169 }
170 if (sampleRate == 0) {
171 sampleRate = afSampleRate;
172 }
173 // these below should probably come from the audioFlinger too...
174 if (format == 0) {
175 format = AudioSystem::PCM_16_BIT;
176 }
Eric Laurenta553c252009-07-17 12:17:14 -0700177 if (channels == 0) {
178 channels = AudioSystem::CHANNEL_OUT_STEREO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
180
181 // validate parameters
Eric Laurenta553c252009-07-17 12:17:14 -0700182 if (!AudioSystem::isValidFormat(format)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 LOGE("Invalid format");
184 return BAD_VALUE;
185 }
Eric Laurenta553c252009-07-17 12:17:14 -0700186
187 // force direct flag if format is not linear PCM
188 if (!AudioSystem::isLinearPCM(format)) {
189 flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
190 }
191
192 if (!AudioSystem::isOutputChannel(channels)) {
193 LOGE("Invalid channel mask");
194 return BAD_VALUE;
195 }
196 uint32_t channelCount = AudioSystem::popCount(channels);
197
198 audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
199 sampleRate, format, channels, (AudioSystem::output_flags)flags);
200
201 if (output == 0) {
202 LOGE("Could not get audio output for stream type %d", streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 return BAD_VALUE;
204 }
205
Eric Laurentbda74692009-11-04 08:27:26 -0800206 mVolume[LEFT] = 1.0f;
207 mVolume[RIGHT] = 1.0f;
Eric Laurent65b65452010-06-01 23:49:17 -0700208 mSendLevel = 0;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700209 mFrameCount = frameCount;
210 mNotificationFramesReq = notificationFrames;
Eric Laurent65b65452010-06-01 23:49:17 -0700211 mSessionId = sessionId;
Eric Laurent7070b362010-07-16 07:43:46 -0700212 mAuxEffectId = 0;
Eric Laurent65b65452010-06-01 23:49:17 -0700213
Eric Laurentbda74692009-11-04 08:27:26 -0800214 // create the IAudioTrack
215 status_t status = createTrack(streamType, sampleRate, format, channelCount,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700216 frameCount, flags, sharedBuffer, output, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
Eric Laurentbda74692009-11-04 08:27:26 -0800218 if (status != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 return status;
220 }
Eric Laurentbda74692009-11-04 08:27:26 -0800221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 if (cbf != 0) {
223 mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
224 if (mAudioTrackThread == 0) {
225 LOGE("Could not create callback thread");
226 return NO_INIT;
227 }
228 }
229
230 mStatus = NO_ERROR;
231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 mStreamType = streamType;
233 mFormat = format;
Eric Laurenta553c252009-07-17 12:17:14 -0700234 mChannels = channels;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 mChannelCount = channelCount;
236 mSharedBuffer = sharedBuffer;
237 mMuted = false;
238 mActive = 0;
239 mCbf = cbf;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 mUserData = user;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 mLoopCount = 0;
242 mMarkerPosition = 0;
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700243 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 mNewPosition = 0;
245 mUpdatePeriod = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700246 mFlags = flags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 return NO_ERROR;
249}
250
251status_t AudioTrack::initCheck() const
252{
253 return mStatus;
254}
255
256// -------------------------------------------------------------------------
257
258uint32_t AudioTrack::latency() const
259{
260 return mLatency;
261}
262
263int AudioTrack::streamType() const
264{
265 return mStreamType;
266}
267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268int AudioTrack::format() const
269{
270 return mFormat;
271}
272
273int AudioTrack::channelCount() const
274{
275 return mChannelCount;
276}
277
278uint32_t AudioTrack::frameCount() const
279{
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700280 return mCblk->frameCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281}
282
283int AudioTrack::frameSize() const
284{
Eric Laurenta553c252009-07-17 12:17:14 -0700285 if (AudioSystem::isLinearPCM(mFormat)) {
286 return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
287 } else {
288 return sizeof(uint8_t);
289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290}
291
292sp<IMemory>& AudioTrack::sharedBuffer()
293{
294 return mSharedBuffer;
295}
296
297// -------------------------------------------------------------------------
298
299void AudioTrack::start()
300{
301 sp<AudioTrackThread> t = mAudioTrackThread;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700302 status_t status;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 LOGV("start %p", this);
305 if (t != 0) {
306 if (t->exitPending()) {
307 if (t->requestExitAndWait() == WOULD_BLOCK) {
308 LOGE("AudioTrack::start called from thread");
309 return;
310 }
311 }
312 t->mLock.lock();
313 }
314
315 if (android_atomic_or(1, &mActive) == 0) {
Eric Laurent059b4be2009-11-09 23:32:22 -0800316 mNewPosition = mCblk->server + mUpdatePeriod;
317 mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
318 mCblk->waitTimeMs = 0;
319 if (t != 0) {
320 t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
321 } else {
322 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
323 }
324
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700325 if (mCblk->flags & CBLK_INVALID_MSK) {
326 LOGW("start() track %p invalidated, creating a new one", this);
327 // no need to clear the invalid flag as this cblk will not be used anymore
328 // force new track creation
329 status = DEAD_OBJECT;
330 } else {
331 status = mAudioTrack->start();
332 }
Eric Laurentbda74692009-11-04 08:27:26 -0800333 if (status == DEAD_OBJECT) {
334 LOGV("start() dead IAudioTrack: creating a new one");
335 status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700336 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
Eric Laurent49f02be2009-11-19 09:00:56 -0800337 if (status == NO_ERROR) {
338 status = mAudioTrack->start();
339 if (status == NO_ERROR) {
340 mNewPosition = mCblk->server + mUpdatePeriod;
341 }
342 }
Eric Laurent059b4be2009-11-09 23:32:22 -0800343 }
344 if (status != NO_ERROR) {
Eric Laurentbda74692009-11-04 08:27:26 -0800345 LOGV("start() failed");
346 android_atomic_and(~1, &mActive);
Eric Laurent059b4be2009-11-09 23:32:22 -0800347 if (t != 0) {
348 t->requestExit();
349 } else {
350 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
351 }
Eric Laurentbda74692009-11-04 08:27:26 -0800352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 }
354
355 if (t != 0) {
356 t->mLock.unlock();
357 }
358}
359
360void AudioTrack::stop()
361{
362 sp<AudioTrackThread> t = mAudioTrackThread;
363
364 LOGV("stop %p", this);
365 if (t != 0) {
366 t->mLock.lock();
367 }
368
369 if (android_atomic_and(~1, &mActive) == 1) {
Eric Laurentef028272009-04-21 07:56:33 -0700370 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 mAudioTrack->stop();
372 // Cancel loops (If we are in the middle of a loop, playback
373 // would not stop until loopCount reaches 0).
374 setLoop(0, 0, 0);
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700375 // the playback head position will reset to 0, so if a marker is set, we need
376 // to activate it again
377 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 // Force flush if a shared buffer is used otherwise audioflinger
379 // will not stop before end of buffer is reached.
380 if (mSharedBuffer != 0) {
381 flush();
382 }
383 if (t != 0) {
384 t->requestExit();
385 } else {
386 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
387 }
388 }
389
390 if (t != 0) {
391 t->mLock.unlock();
392 }
393}
394
395bool AudioTrack::stopped() const
396{
397 return !mActive;
398}
399
400void AudioTrack::flush()
401{
402 LOGV("flush");
Eric Laurenta553c252009-07-17 12:17:14 -0700403
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700404 // clear playback marker and periodic update counter
405 mMarkerPosition = 0;
406 mMarkerReached = false;
407 mUpdatePeriod = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409
410 if (!mActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 mAudioTrack->flush();
412 // Release AudioTrack callback thread in case it was waiting for new buffers
413 // in AudioTrack::obtainBuffer()
414 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 }
416}
417
418void AudioTrack::pause()
419{
420 LOGV("pause");
421 if (android_atomic_and(~1, &mActive) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 mAudioTrack->pause();
423 }
424}
425
426void AudioTrack::mute(bool e)
427{
428 mAudioTrack->mute(e);
429 mMuted = e;
430}
431
432bool AudioTrack::muted() const
433{
434 return mMuted;
435}
436
Eric Laurent65b65452010-06-01 23:49:17 -0700437status_t AudioTrack::setVolume(float left, float right)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438{
Eric Laurent65b65452010-06-01 23:49:17 -0700439 if (left > 1.0f || right > 1.0f) {
440 return BAD_VALUE;
441 }
442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 mVolume[LEFT] = left;
444 mVolume[RIGHT] = right;
445
446 // write must be atomic
Eric Laurent65b65452010-06-01 23:49:17 -0700447 mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
448
449 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450}
451
452void AudioTrack::getVolume(float* left, float* right)
453{
Eric Laurent65b65452010-06-01 23:49:17 -0700454 if (left != NULL) {
455 *left = mVolume[LEFT];
456 }
457 if (right != NULL) {
458 *right = mVolume[RIGHT];
459 }
460}
461
Eric Laurent7070b362010-07-16 07:43:46 -0700462status_t AudioTrack::setAuxEffectSendLevel(float level)
Eric Laurent65b65452010-06-01 23:49:17 -0700463{
Eric Laurent7070b362010-07-16 07:43:46 -0700464 LOGV("setAuxEffectSendLevel(%f)", level);
Eric Laurent65b65452010-06-01 23:49:17 -0700465 if (level > 1.0f) {
466 return BAD_VALUE;
467 }
468
469 mSendLevel = level;
470
471 mCblk->sendLevel = uint16_t(level * 0x1000);
472
473 return NO_ERROR;
474}
475
Eric Laurent7070b362010-07-16 07:43:46 -0700476void AudioTrack::getAuxEffectSendLevel(float* level)
Eric Laurent65b65452010-06-01 23:49:17 -0700477{
478 if (level != NULL) {
479 *level = mSendLevel;
480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481}
482
Eric Laurent88e209d2009-07-07 07:10:45 -0700483status_t AudioTrack::setSampleRate(int rate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484{
485 int afSamplingRate;
486
487 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
Eric Laurent88e209d2009-07-07 07:10:45 -0700488 return NO_INIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 // Resampler implementation limits input sampling rate to 2 x output sampling rate.
Eric Laurent88e209d2009-07-07 07:10:45 -0700491 if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492
Eric Laurent88e209d2009-07-07 07:10:45 -0700493 mCblk->sampleRate = rate;
494 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495}
496
497uint32_t AudioTrack::getSampleRate()
498{
Eric Laurent88e209d2009-07-07 07:10:45 -0700499 return mCblk->sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500}
501
502status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
503{
504 audio_track_cblk_t* cblk = mCblk;
505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 Mutex::Autolock _l(cblk->lock);
507
508 if (loopCount == 0) {
509 cblk->loopStart = UINT_MAX;
510 cblk->loopEnd = UINT_MAX;
511 cblk->loopCount = 0;
512 mLoopCount = 0;
513 return NO_ERROR;
514 }
515
516 if (loopStart >= loopEnd ||
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700517 loopEnd - loopStart > cblk->frameCount) {
518 LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 return BAD_VALUE;
520 }
521
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700522 if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700524 loopStart, loopEnd, cblk->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 return BAD_VALUE;
Eric Laurenta553c252009-07-17 12:17:14 -0700526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527
528 cblk->loopStart = loopStart;
529 cblk->loopEnd = loopEnd;
530 cblk->loopCount = loopCount;
531 mLoopCount = loopCount;
532
533 return NO_ERROR;
534}
535
536status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
537{
538 if (loopStart != 0) {
539 *loopStart = mCblk->loopStart;
540 }
541 if (loopEnd != 0) {
542 *loopEnd = mCblk->loopEnd;
543 }
544 if (loopCount != 0) {
545 if (mCblk->loopCount < 0) {
546 *loopCount = -1;
547 } else {
548 *loopCount = mCblk->loopCount;
549 }
550 }
551
552 return NO_ERROR;
553}
554
555status_t AudioTrack::setMarkerPosition(uint32_t marker)
556{
557 if (mCbf == 0) return INVALID_OPERATION;
558
559 mMarkerPosition = marker;
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700560 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561
562 return NO_ERROR;
563}
564
565status_t AudioTrack::getMarkerPosition(uint32_t *marker)
566{
567 if (marker == 0) return BAD_VALUE;
568
569 *marker = mMarkerPosition;
570
571 return NO_ERROR;
572}
573
574status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
575{
576 if (mCbf == 0) return INVALID_OPERATION;
577
578 uint32_t curPosition;
579 getPosition(&curPosition);
580 mNewPosition = curPosition + updatePeriod;
581 mUpdatePeriod = updatePeriod;
582
583 return NO_ERROR;
584}
585
586status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
587{
588 if (updatePeriod == 0) return BAD_VALUE;
589
590 *updatePeriod = mUpdatePeriod;
591
592 return NO_ERROR;
593}
594
595status_t AudioTrack::setPosition(uint32_t position)
596{
597 Mutex::Autolock _l(mCblk->lock);
598
599 if (!stopped()) return INVALID_OPERATION;
600
601 if (position > mCblk->user) return BAD_VALUE;
602
603 mCblk->server = position;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700604 mCblk->flags |= CBLK_FORCEREADY_ON;
Eric Laurenta553c252009-07-17 12:17:14 -0700605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 return NO_ERROR;
607}
608
609status_t AudioTrack::getPosition(uint32_t *position)
610{
611 if (position == 0) return BAD_VALUE;
612
613 *position = mCblk->server;
614
615 return NO_ERROR;
616}
617
618status_t AudioTrack::reload()
619{
620 if (!stopped()) return INVALID_OPERATION;
Eric Laurenta553c252009-07-17 12:17:14 -0700621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 flush();
623
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700624 mCblk->stepUser(mCblk->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625
626 return NO_ERROR;
627}
628
Eric Laurenta553c252009-07-17 12:17:14 -0700629audio_io_handle_t AudioTrack::getOutput()
630{
631 return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
632 mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
633}
634
Eric Laurent65b65452010-06-01 23:49:17 -0700635int AudioTrack::getSessionId()
636{
637 return mSessionId;
638}
639
640status_t AudioTrack::attachAuxEffect(int effectId)
641{
Eric Laurent7070b362010-07-16 07:43:46 -0700642 LOGV("attachAuxEffect(%d)", effectId);
643 status_t status = mAudioTrack->attachAuxEffect(effectId);
644 if (status == NO_ERROR) {
645 mAuxEffectId = effectId;
646 }
647 return status;
Eric Laurent65b65452010-06-01 23:49:17 -0700648}
649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650// -------------------------------------------------------------------------
651
Eric Laurentbda74692009-11-04 08:27:26 -0800652status_t AudioTrack::createTrack(
653 int streamType,
654 uint32_t sampleRate,
655 int format,
656 int channelCount,
657 int frameCount,
658 uint32_t flags,
659 const sp<IMemory>& sharedBuffer,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700660 audio_io_handle_t output,
661 bool enforceFrameCount)
Eric Laurentbda74692009-11-04 08:27:26 -0800662{
663 status_t status;
664 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
665 if (audioFlinger == 0) {
666 LOGE("Could not get audioflinger");
667 return NO_INIT;
668 }
669
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700670 int afSampleRate;
671 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
672 return NO_INIT;
673 }
674 int afFrameCount;
675 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
676 return NO_INIT;
677 }
678 uint32_t afLatency;
679 if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
680 return NO_INIT;
681 }
682
683 mNotificationFramesAct = mNotificationFramesReq;
684 if (!AudioSystem::isLinearPCM(format)) {
685 if (sharedBuffer != 0) {
686 frameCount = sharedBuffer->size();
687 }
688 } else {
689 // Ensure that buffer depth covers at least audio hardware latency
690 uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
691 if (minBufCount < 2) minBufCount = 2;
692
693 int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
694
695 if (sharedBuffer == 0) {
696 if (frameCount == 0) {
697 frameCount = minFrameCount;
698 }
699 if (mNotificationFramesAct == 0) {
700 mNotificationFramesAct = frameCount/2;
701 }
702 // Make sure that application is notified with sufficient margin
703 // before underrun
704 if (mNotificationFramesAct > (uint32_t)frameCount/2) {
705 mNotificationFramesAct = frameCount/2;
706 }
707 if (frameCount < minFrameCount) {
708 if (enforceFrameCount) {
709 LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
710 return BAD_VALUE;
711 } else {
712 frameCount = minFrameCount;
713 }
714 }
715 } else {
716 // Ensure that buffer alignment matches channelcount
717 if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
718 LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
719 return BAD_VALUE;
720 }
721 frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
722 }
723 }
724
Eric Laurentbda74692009-11-04 08:27:26 -0800725 sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
726 streamType,
727 sampleRate,
728 format,
729 channelCount,
730 frameCount,
731 ((uint16_t)flags) << 16,
732 sharedBuffer,
733 output,
Eric Laurent65b65452010-06-01 23:49:17 -0700734 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800735 &status);
736
737 if (track == 0) {
738 LOGE("AudioFlinger could not create track, status: %d", status);
739 return status;
740 }
741 sp<IMemory> cblk = track->getCblk();
742 if (cblk == 0) {
743 LOGE("Could not get control block");
744 return NO_INIT;
745 }
746 mAudioTrack.clear();
747 mAudioTrack = track;
748 mCblkMemory.clear();
749 mCblkMemory = cblk;
750 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700751 mCblk->flags |= CBLK_DIRECTION_OUT;
Eric Laurentbda74692009-11-04 08:27:26 -0800752 if (sharedBuffer == 0) {
753 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
754 } else {
755 mCblk->buffers = sharedBuffer->pointer();
756 // Force buffer full condition as data is already present in shared memory
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700757 mCblk->stepUser(mCblk->frameCount);
Eric Laurentbda74692009-11-04 08:27:26 -0800758 }
759
Eric Laurent65b65452010-06-01 23:49:17 -0700760 mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
761 mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
Eric Laurent7070b362010-07-16 07:43:46 -0700762 mAudioTrack->attachAuxEffect(mAuxEffectId);
Eric Laurent49f02be2009-11-19 09:00:56 -0800763 mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
764 mCblk->waitTimeMs = 0;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700765 mRemainingFrames = mNotificationFramesAct;
766 mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate;
Eric Laurentbda74692009-11-04 08:27:26 -0800767 return NO_ERROR;
768}
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
771{
772 int active;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 status_t result;
774 audio_track_cblk_t* cblk = mCblk;
775 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700776 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777
778 audioBuffer->frameCount = 0;
779 audioBuffer->size = 0;
780
781 uint32_t framesAvail = cblk->framesAvailable();
782
783 if (framesAvail == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800784 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 goto start_loop_here;
786 while (framesAvail == 0) {
787 active = mActive;
788 if (UNLIKELY(!active)) {
789 LOGV("Not active and NO_MORE_BUFFERS");
Eric Laurentbda74692009-11-04 08:27:26 -0800790 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 return NO_MORE_BUFFERS;
792 }
Eric Laurentbda74692009-11-04 08:27:26 -0800793 if (UNLIKELY(!waitCount)) {
794 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800796 }
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700797 if (!(cblk->flags & CBLK_INVALID_MSK)) {
798 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
799 }
800 if (cblk->flags & CBLK_INVALID_MSK) {
801 LOGW("obtainBuffer() track %p invalidated, creating a new one", this);
802 // no need to clear the invalid flag as this cblk will not be used anymore
803 cblk->lock.unlock();
804 goto create_new_track;
805 }
Eric Laurenta553c252009-07-17 12:17:14 -0700806 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700807 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
809 // timing out when a loop has been set and we have already written upto loop end
810 // is a normal condition: no need to wake AudioFlinger up.
811 if (cblk->user < cblk->loopEnd) {
812 LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
813 "user=%08x, server=%08x", this, cblk->user, cblk->server);
Eric Laurenta553c252009-07-17 12:17:14 -0700814 //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 cblk->lock.unlock();
Eric Laurentbda74692009-11-04 08:27:26 -0800816 result = mAudioTrack->start();
817 if (result == DEAD_OBJECT) {
818 LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700819create_new_track:
Eric Laurentbda74692009-11-04 08:27:26 -0800820 result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700821 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
Eric Laurentbda74692009-11-04 08:27:26 -0800822 if (result == NO_ERROR) {
823 cblk = mCblk;
824 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
Eric Laurent49f02be2009-11-19 09:00:56 -0800825 mAudioTrack->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800826 }
827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
830 cblk->waitTimeMs = 0;
831 }
Eric Laurenta553c252009-07-17 12:17:14 -0700832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800834 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 return TIMED_OUT;
836 }
837 }
838 // read the server count again
839 start_loop_here:
840 framesAvail = cblk->framesAvailable_l();
841 }
Eric Laurentbda74692009-11-04 08:27:26 -0800842 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844
845 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 if (framesReq > framesAvail) {
848 framesReq = framesAvail;
849 }
850
851 uint32_t u = cblk->user;
852 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
853
854 if (u + framesReq > bufferEnd) {
855 framesReq = bufferEnd - u;
856 }
857
Eric Laurenta553c252009-07-17 12:17:14 -0700858 audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
859 audioBuffer->channelCount = mChannelCount;
860 audioBuffer->frameCount = framesReq;
861 audioBuffer->size = framesReq * cblk->frameSize;
862 if (AudioSystem::isLinearPCM(mFormat)) {
863 audioBuffer->format = AudioSystem::PCM_16_BIT;
864 } else {
865 audioBuffer->format = mFormat;
866 }
867 audioBuffer->raw = (int8_t *)cblk->buffer(u);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 active = mActive;
869 return active ? status_t(NO_ERROR) : status_t(STOPPED);
870}
871
872void AudioTrack::releaseBuffer(Buffer* audioBuffer)
873{
874 audio_track_cblk_t* cblk = mCblk;
875 cblk->stepUser(audioBuffer->frameCount);
876}
877
878// -------------------------------------------------------------------------
879
880ssize_t AudioTrack::write(const void* buffer, size_t userSize)
881{
882
883 if (mSharedBuffer != 0) return INVALID_OPERATION;
884
885 if (ssize_t(userSize) < 0) {
886 // sanity-check. user is most-likely passing an error code.
887 LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
888 buffer, userSize, userSize);
889 return BAD_VALUE;
890 }
891
892 LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
893
894 ssize_t written = 0;
895 const int8_t *src = (const int8_t *)buffer;
896 Buffer audioBuffer;
897
898 do {
Eric Laurenta553c252009-07-17 12:17:14 -0700899 audioBuffer.frameCount = userSize/frameSize();
900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 // Calling obtainBuffer() with a negative wait count causes
902 // an (almost) infinite wait time.
903 status_t err = obtainBuffer(&audioBuffer, -1);
904 if (err < 0) {
905 // out of buffers, return #bytes written
906 if (err == status_t(NO_MORE_BUFFERS))
907 break;
908 return ssize_t(err);
909 }
910
911 size_t toWrite;
Eric Laurenta553c252009-07-17 12:17:14 -0700912
Eric Laurent28ad42b2009-08-04 10:42:26 -0700913 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 // Divide capacity by 2 to take expansion into account
915 toWrite = audioBuffer.size>>1;
916 // 8 to 16 bit conversion
917 int count = toWrite;
918 int16_t *dst = (int16_t *)(audioBuffer.i8);
919 while(count--) {
920 *dst++ = (int16_t)(*src++^0x80) << 8;
921 }
Eric Laurent28ad42b2009-08-04 10:42:26 -0700922 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 toWrite = audioBuffer.size;
924 memcpy(audioBuffer.i8, src, toWrite);
925 src += toWrite;
926 }
927 userSize -= toWrite;
928 written += toWrite;
929
930 releaseBuffer(&audioBuffer);
931 } while (userSize);
932
933 return written;
934}
935
936// -------------------------------------------------------------------------
937
938bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
939{
940 Buffer audioBuffer;
941 uint32_t frames;
942 size_t writtenSize;
943
944 // Manage underrun callback
945 if (mActive && (mCblk->framesReady() == 0)) {
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700946 LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
947 if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 mCbf(EVENT_UNDERRUN, mUserData, 0);
949 if (mCblk->server == mCblk->frameCount) {
Eric Laurenta553c252009-07-17 12:17:14 -0700950 mCbf(EVENT_BUFFER_END, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 }
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700952 mCblk->flags |= CBLK_UNDERRUN_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 if (mSharedBuffer != 0) return false;
954 }
955 }
Eric Laurenta553c252009-07-17 12:17:14 -0700956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 // Manage loop end callback
958 while (mLoopCount > mCblk->loopCount) {
959 int loopCount = -1;
960 mLoopCount--;
961 if (mLoopCount >= 0) loopCount = mLoopCount;
962
963 mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
964 }
965
966 // Manage marker callback
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700967 if (!mMarkerReached && (mMarkerPosition > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 if (mCblk->server >= mMarkerPosition) {
969 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700970 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 }
972 }
973
974 // Manage new position callback
Eric Laurenta553c252009-07-17 12:17:14 -0700975 if (mUpdatePeriod > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 while (mCblk->server >= mNewPosition) {
977 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
978 mNewPosition += mUpdatePeriod;
979 }
980 }
981
982 // If Shared buffer is used, no data is requested from client.
983 if (mSharedBuffer != 0) {
984 frames = 0;
985 } else {
986 frames = mRemainingFrames;
987 }
988
989 do {
990
991 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -0700992
993 // Calling obtainBuffer() with a wait count of 1
994 // limits wait time to WAIT_PERIOD_MS. This prevents from being
995 // stuck here not being able to handle timed events (position, markers, loops).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 status_t err = obtainBuffer(&audioBuffer, 1);
997 if (err < NO_ERROR) {
998 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -0700999 LOGE_IF(err != status_t(NO_MORE_BUFFERS), "Error obtaining an audio buffer, giving up.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 return false;
1001 }
1002 break;
1003 }
1004 if (err == status_t(STOPPED)) return false;
1005
1006 // Divide buffer size by 2 to take into account the expansion
1007 // due to 8 to 16 bit conversion: the callback must fill only half
1008 // of the destination buffer
Eric Laurent28ad42b2009-08-04 10:42:26 -07001009 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 audioBuffer.size >>= 1;
1011 }
1012
1013 size_t reqSize = audioBuffer.size;
1014 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
1015 writtenSize = audioBuffer.size;
1016
1017 // Sanity check on returned size
The Android Open Source Project4df24232009-03-05 14:34:35 -08001018 if (ssize_t(writtenSize) <= 0) {
1019 // The callback is done filling buffers
1020 // Keep this thread going to handle timed events and
1021 // still try to get more data in intervals of WAIT_PERIOD_MS
1022 // but don't just loop and block the CPU, so wait
1023 usleep(WAIT_PERIOD_MS*1000);
1024 break;
1025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 if (writtenSize > reqSize) writtenSize = reqSize;
1027
Eric Laurent28ad42b2009-08-04 10:42:26 -07001028 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 // 8 to 16 bit conversion
1030 const int8_t *src = audioBuffer.i8 + writtenSize-1;
1031 int count = writtenSize;
1032 int16_t *dst = audioBuffer.i16 + writtenSize-1;
1033 while(count--) {
1034 *dst-- = (int16_t)(*src--^0x80) << 8;
1035 }
1036 writtenSize <<= 1;
1037 }
1038
1039 audioBuffer.size = writtenSize;
Eric Laurenta553c252009-07-17 12:17:14 -07001040 // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
1041 // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of
1042 // 16 bit.
1043 audioBuffer.frameCount = writtenSize/mCblk->frameSize;
1044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 frames -= audioBuffer.frameCount;
1046
1047 releaseBuffer(&audioBuffer);
1048 }
1049 while (frames);
1050
1051 if (frames == 0) {
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001052 mRemainingFrames = mNotificationFramesAct;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 } else {
1054 mRemainingFrames = frames;
1055 }
1056 return true;
1057}
1058
1059status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
1060{
1061
1062 const size_t SIZE = 256;
1063 char buffer[SIZE];
1064 String8 result;
1065
1066 result.append(" AudioTrack::dump\n");
1067 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
1068 result.append(buffer);
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001069 snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mCblk->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 result.append(buffer);
Eric Laurent88e209d2009-07-07 07:10:45 -07001071 snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 result.append(buffer);
1073 snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
1074 result.append(buffer);
1075 ::write(fd, result.string(), result.size());
1076 return NO_ERROR;
1077}
1078
1079// =========================================================================
1080
1081AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
1082 : Thread(bCanCallJava), mReceiver(receiver)
1083{
1084}
1085
1086bool AudioTrack::AudioTrackThread::threadLoop()
1087{
1088 return mReceiver.processAudioBuffer(this);
1089}
1090
1091status_t AudioTrack::AudioTrackThread::readyToRun()
1092{
1093 return NO_ERROR;
1094}
1095
1096void AudioTrack::AudioTrackThread::onFirstRef()
1097{
1098}
1099
1100// =========================================================================
1101
1102audio_track_cblk_t::audio_track_cblk_t()
Mathias Agopiana729f972010-03-19 16:14:13 -07001103 : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
1104 userBase(0), serverBase(0), buffers(0), frameCount(0),
1105 loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
Eric Laurent65b65452010-06-01 23:49:17 -07001106 flags(0), sendLevel(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107{
1108}
1109
1110uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
1111{
1112 uint32_t u = this->user;
1113
1114 u += frameCount;
1115 // Ensure that user is never ahead of server for AudioRecord
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001116 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
1118 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
1119 bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
1120 }
1121 } else if (u > this->server) {
1122 LOGW("stepServer occured after track reset");
1123 u = this->server;
1124 }
1125
1126 if (u >= userBase + this->frameCount) {
1127 userBase += this->frameCount;
1128 }
1129
1130 this->user = u;
1131
1132 // Clear flow control error condition as new data has been written/read to/from buffer.
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001133 flags &= ~CBLK_UNDERRUN_MSK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134
1135 return u;
1136}
1137
1138bool audio_track_cblk_t::stepServer(uint32_t frameCount)
1139{
1140 // the code below simulates lock-with-timeout
1141 // we MUST do this to protect the AudioFlinger server
1142 // as this lock is shared with the client.
1143 status_t err;
1144
1145 err = lock.tryLock();
1146 if (err == -EBUSY) { // just wait a bit
1147 usleep(1000);
1148 err = lock.tryLock();
1149 }
1150 if (err != NO_ERROR) {
1151 // probably, the client just died.
1152 return false;
1153 }
1154
1155 uint32_t s = this->server;
1156
1157 s += frameCount;
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001158 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 // Mark that we have read the first buffer so that next time stepUser() is called
1160 // we switch to normal obtainBuffer() timeout period
1161 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
Eric Laurentbda74692009-11-04 08:27:26 -08001162 bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1;
Eric Laurenta553c252009-07-17 12:17:14 -07001163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 // It is possible that we receive a flush()
1165 // while the mixer is processing a block: in this case,
1166 // stepServer() is called After the flush() has reset u & s and
1167 // we have s > u
1168 if (s > this->user) {
1169 LOGW("stepServer occured after track reset");
1170 s = this->user;
1171 }
1172 }
1173
1174 if (s >= loopEnd) {
1175 LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
1176 s = loopStart;
1177 if (--loopCount == 0) {
1178 loopEnd = UINT_MAX;
1179 loopStart = UINT_MAX;
1180 }
1181 }
1182 if (s >= serverBase + this->frameCount) {
1183 serverBase += this->frameCount;
1184 }
1185
1186 this->server = s;
1187
1188 cv.signal();
1189 lock.unlock();
1190 return true;
1191}
1192
1193void* audio_track_cblk_t::buffer(uint32_t offset) const
1194{
Eric Laurenta553c252009-07-17 12:17:14 -07001195 return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196}
1197
1198uint32_t audio_track_cblk_t::framesAvailable()
1199{
1200 Mutex::Autolock _l(lock);
1201 return framesAvailable_l();
1202}
1203
1204uint32_t audio_track_cblk_t::framesAvailable_l()
1205{
1206 uint32_t u = this->user;
1207 uint32_t s = this->server;
1208
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001209 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 uint32_t limit = (s < loopStart) ? s : loopStart;
1211 return limit + frameCount - u;
1212 } else {
1213 return frameCount + u - s;
1214 }
1215}
1216
1217uint32_t audio_track_cblk_t::framesReady()
1218{
1219 uint32_t u = this->user;
1220 uint32_t s = this->server;
1221
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001222 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 if (u < loopEnd) {
1224 return u - s;
1225 } else {
1226 Mutex::Autolock _l(lock);
1227 if (loopCount >= 0) {
1228 return (loopEnd - loopStart)*loopCount + u - s;
1229 } else {
1230 return UINT_MAX;
1231 }
1232 }
1233 } else {
1234 return s - u;
1235 }
1236}
1237
1238// -------------------------------------------------------------------------
1239
1240}; // namespace android
1241