blob: 587c8fff23750dd5ea75a179ea2323cf5c6eb416 [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;
Eric Laurent4712baa2010-09-30 16:12:31 -0700319 mCblk->flags &= ~CBLK_DISABLED_ON;
Eric Laurent059b4be2009-11-09 23:32:22 -0800320 if (t != 0) {
321 t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
322 } else {
323 setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
324 }
325
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700326 if (mCblk->flags & CBLK_INVALID_MSK) {
327 LOGW("start() track %p invalidated, creating a new one", this);
328 // no need to clear the invalid flag as this cblk will not be used anymore
329 // force new track creation
330 status = DEAD_OBJECT;
331 } else {
332 status = mAudioTrack->start();
333 }
Eric Laurentbda74692009-11-04 08:27:26 -0800334 if (status == DEAD_OBJECT) {
335 LOGV("start() dead IAudioTrack: creating a new one");
336 status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700337 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
Eric Laurent49f02be2009-11-19 09:00:56 -0800338 if (status == NO_ERROR) {
339 status = mAudioTrack->start();
340 if (status == NO_ERROR) {
341 mNewPosition = mCblk->server + mUpdatePeriod;
342 }
343 }
Eric Laurent059b4be2009-11-09 23:32:22 -0800344 }
345 if (status != NO_ERROR) {
Eric Laurentbda74692009-11-04 08:27:26 -0800346 LOGV("start() failed");
347 android_atomic_and(~1, &mActive);
Eric Laurent059b4be2009-11-09 23:32:22 -0800348 if (t != 0) {
349 t->requestExit();
350 } else {
351 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
352 }
Eric Laurentbda74692009-11-04 08:27:26 -0800353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 }
355
356 if (t != 0) {
357 t->mLock.unlock();
358 }
359}
360
361void AudioTrack::stop()
362{
363 sp<AudioTrackThread> t = mAudioTrackThread;
364
365 LOGV("stop %p", this);
366 if (t != 0) {
367 t->mLock.lock();
368 }
369
370 if (android_atomic_and(~1, &mActive) == 1) {
Eric Laurentef028272009-04-21 07:56:33 -0700371 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 mAudioTrack->stop();
373 // Cancel loops (If we are in the middle of a loop, playback
374 // would not stop until loopCount reaches 0).
375 setLoop(0, 0, 0);
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700376 // the playback head position will reset to 0, so if a marker is set, we need
377 // to activate it again
378 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 // Force flush if a shared buffer is used otherwise audioflinger
380 // will not stop before end of buffer is reached.
381 if (mSharedBuffer != 0) {
382 flush();
383 }
384 if (t != 0) {
385 t->requestExit();
386 } else {
387 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
388 }
389 }
390
391 if (t != 0) {
392 t->mLock.unlock();
393 }
394}
395
396bool AudioTrack::stopped() const
397{
398 return !mActive;
399}
400
401void AudioTrack::flush()
402{
403 LOGV("flush");
Eric Laurenta553c252009-07-17 12:17:14 -0700404
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700405 // clear playback marker and periodic update counter
406 mMarkerPosition = 0;
407 mMarkerReached = false;
408 mUpdatePeriod = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410
411 if (!mActive) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 mAudioTrack->flush();
413 // Release AudioTrack callback thread in case it was waiting for new buffers
414 // in AudioTrack::obtainBuffer()
415 mCblk->cv.signal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417}
418
419void AudioTrack::pause()
420{
421 LOGV("pause");
422 if (android_atomic_and(~1, &mActive) == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 mAudioTrack->pause();
424 }
425}
426
427void AudioTrack::mute(bool e)
428{
429 mAudioTrack->mute(e);
430 mMuted = e;
431}
432
433bool AudioTrack::muted() const
434{
435 return mMuted;
436}
437
Eric Laurent65b65452010-06-01 23:49:17 -0700438status_t AudioTrack::setVolume(float left, float right)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439{
Eric Laurent65b65452010-06-01 23:49:17 -0700440 if (left > 1.0f || right > 1.0f) {
441 return BAD_VALUE;
442 }
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 mVolume[LEFT] = left;
445 mVolume[RIGHT] = right;
446
447 // write must be atomic
Eric Laurent65b65452010-06-01 23:49:17 -0700448 mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
449
450 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451}
452
453void AudioTrack::getVolume(float* left, float* right)
454{
Eric Laurent65b65452010-06-01 23:49:17 -0700455 if (left != NULL) {
456 *left = mVolume[LEFT];
457 }
458 if (right != NULL) {
459 *right = mVolume[RIGHT];
460 }
461}
462
Eric Laurent7070b362010-07-16 07:43:46 -0700463status_t AudioTrack::setAuxEffectSendLevel(float level)
Eric Laurent65b65452010-06-01 23:49:17 -0700464{
Eric Laurent7070b362010-07-16 07:43:46 -0700465 LOGV("setAuxEffectSendLevel(%f)", level);
Eric Laurent65b65452010-06-01 23:49:17 -0700466 if (level > 1.0f) {
467 return BAD_VALUE;
468 }
469
470 mSendLevel = level;
471
472 mCblk->sendLevel = uint16_t(level * 0x1000);
473
474 return NO_ERROR;
475}
476
Eric Laurent7070b362010-07-16 07:43:46 -0700477void AudioTrack::getAuxEffectSendLevel(float* level)
Eric Laurent65b65452010-06-01 23:49:17 -0700478{
479 if (level != NULL) {
480 *level = mSendLevel;
481 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482}
483
Eric Laurent88e209d2009-07-07 07:10:45 -0700484status_t AudioTrack::setSampleRate(int rate)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485{
486 int afSamplingRate;
487
488 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
Eric Laurent88e209d2009-07-07 07:10:45 -0700489 return NO_INIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 }
491 // Resampler implementation limits input sampling rate to 2 x output sampling rate.
Eric Laurent88e209d2009-07-07 07:10:45 -0700492 if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493
Eric Laurent88e209d2009-07-07 07:10:45 -0700494 mCblk->sampleRate = rate;
495 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496}
497
498uint32_t AudioTrack::getSampleRate()
499{
Eric Laurent88e209d2009-07-07 07:10:45 -0700500 return mCblk->sampleRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501}
502
503status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
504{
505 audio_track_cblk_t* cblk = mCblk;
506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 Mutex::Autolock _l(cblk->lock);
508
509 if (loopCount == 0) {
510 cblk->loopStart = UINT_MAX;
511 cblk->loopEnd = UINT_MAX;
512 cblk->loopCount = 0;
513 mLoopCount = 0;
514 return NO_ERROR;
515 }
516
517 if (loopStart >= loopEnd ||
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700518 loopEnd - loopStart > cblk->frameCount) {
519 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 -0800520 return BAD_VALUE;
521 }
522
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700523 if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700525 loopStart, loopEnd, cblk->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 return BAD_VALUE;
Eric Laurenta553c252009-07-17 12:17:14 -0700527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528
529 cblk->loopStart = loopStart;
530 cblk->loopEnd = loopEnd;
531 cblk->loopCount = loopCount;
532 mLoopCount = loopCount;
533
534 return NO_ERROR;
535}
536
537status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
538{
539 if (loopStart != 0) {
540 *loopStart = mCblk->loopStart;
541 }
542 if (loopEnd != 0) {
543 *loopEnd = mCblk->loopEnd;
544 }
545 if (loopCount != 0) {
546 if (mCblk->loopCount < 0) {
547 *loopCount = -1;
548 } else {
549 *loopCount = mCblk->loopCount;
550 }
551 }
552
553 return NO_ERROR;
554}
555
556status_t AudioTrack::setMarkerPosition(uint32_t marker)
557{
558 if (mCbf == 0) return INVALID_OPERATION;
559
560 mMarkerPosition = marker;
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700561 mMarkerReached = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562
563 return NO_ERROR;
564}
565
566status_t AudioTrack::getMarkerPosition(uint32_t *marker)
567{
568 if (marker == 0) return BAD_VALUE;
569
570 *marker = mMarkerPosition;
571
572 return NO_ERROR;
573}
574
575status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
576{
577 if (mCbf == 0) return INVALID_OPERATION;
578
579 uint32_t curPosition;
580 getPosition(&curPosition);
581 mNewPosition = curPosition + updatePeriod;
582 mUpdatePeriod = updatePeriod;
583
584 return NO_ERROR;
585}
586
587status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
588{
589 if (updatePeriod == 0) return BAD_VALUE;
590
591 *updatePeriod = mUpdatePeriod;
592
593 return NO_ERROR;
594}
595
596status_t AudioTrack::setPosition(uint32_t position)
597{
598 Mutex::Autolock _l(mCblk->lock);
599
600 if (!stopped()) return INVALID_OPERATION;
601
602 if (position > mCblk->user) return BAD_VALUE;
603
604 mCblk->server = position;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700605 mCblk->flags |= CBLK_FORCEREADY_ON;
Eric Laurenta553c252009-07-17 12:17:14 -0700606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 return NO_ERROR;
608}
609
610status_t AudioTrack::getPosition(uint32_t *position)
611{
612 if (position == 0) return BAD_VALUE;
613
614 *position = mCblk->server;
615
616 return NO_ERROR;
617}
618
619status_t AudioTrack::reload()
620{
621 if (!stopped()) return INVALID_OPERATION;
Eric Laurenta553c252009-07-17 12:17:14 -0700622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 flush();
624
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700625 mCblk->stepUser(mCblk->frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626
627 return NO_ERROR;
628}
629
Eric Laurenta553c252009-07-17 12:17:14 -0700630audio_io_handle_t AudioTrack::getOutput()
631{
632 return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
633 mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
634}
635
Eric Laurent65b65452010-06-01 23:49:17 -0700636int AudioTrack::getSessionId()
637{
638 return mSessionId;
639}
640
641status_t AudioTrack::attachAuxEffect(int effectId)
642{
Eric Laurent7070b362010-07-16 07:43:46 -0700643 LOGV("attachAuxEffect(%d)", effectId);
644 status_t status = mAudioTrack->attachAuxEffect(effectId);
645 if (status == NO_ERROR) {
646 mAuxEffectId = effectId;
647 }
648 return status;
Eric Laurent65b65452010-06-01 23:49:17 -0700649}
650
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651// -------------------------------------------------------------------------
652
Eric Laurentbda74692009-11-04 08:27:26 -0800653status_t AudioTrack::createTrack(
654 int streamType,
655 uint32_t sampleRate,
656 int format,
657 int channelCount,
658 int frameCount,
659 uint32_t flags,
660 const sp<IMemory>& sharedBuffer,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700661 audio_io_handle_t output,
662 bool enforceFrameCount)
Eric Laurentbda74692009-11-04 08:27:26 -0800663{
664 status_t status;
665 const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
666 if (audioFlinger == 0) {
667 LOGE("Could not get audioflinger");
668 return NO_INIT;
669 }
670
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700671 int afSampleRate;
672 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
673 return NO_INIT;
674 }
675 int afFrameCount;
676 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
677 return NO_INIT;
678 }
679 uint32_t afLatency;
680 if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
681 return NO_INIT;
682 }
683
684 mNotificationFramesAct = mNotificationFramesReq;
685 if (!AudioSystem::isLinearPCM(format)) {
686 if (sharedBuffer != 0) {
687 frameCount = sharedBuffer->size();
688 }
689 } else {
690 // Ensure that buffer depth covers at least audio hardware latency
691 uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
692 if (minBufCount < 2) minBufCount = 2;
693
694 int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
695
696 if (sharedBuffer == 0) {
697 if (frameCount == 0) {
698 frameCount = minFrameCount;
699 }
700 if (mNotificationFramesAct == 0) {
701 mNotificationFramesAct = frameCount/2;
702 }
703 // Make sure that application is notified with sufficient margin
704 // before underrun
705 if (mNotificationFramesAct > (uint32_t)frameCount/2) {
706 mNotificationFramesAct = frameCount/2;
707 }
708 if (frameCount < minFrameCount) {
709 if (enforceFrameCount) {
710 LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
711 return BAD_VALUE;
712 } else {
713 frameCount = minFrameCount;
714 }
715 }
716 } else {
717 // Ensure that buffer alignment matches channelcount
718 if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
719 LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
720 return BAD_VALUE;
721 }
722 frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
723 }
724 }
725
Eric Laurentbda74692009-11-04 08:27:26 -0800726 sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
727 streamType,
728 sampleRate,
729 format,
730 channelCount,
731 frameCount,
732 ((uint16_t)flags) << 16,
733 sharedBuffer,
734 output,
Eric Laurent65b65452010-06-01 23:49:17 -0700735 &mSessionId,
Eric Laurentbda74692009-11-04 08:27:26 -0800736 &status);
737
738 if (track == 0) {
739 LOGE("AudioFlinger could not create track, status: %d", status);
740 return status;
741 }
742 sp<IMemory> cblk = track->getCblk();
743 if (cblk == 0) {
744 LOGE("Could not get control block");
745 return NO_INIT;
746 }
747 mAudioTrack.clear();
748 mAudioTrack = track;
749 mCblkMemory.clear();
750 mCblkMemory = cblk;
751 mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700752 mCblk->flags |= CBLK_DIRECTION_OUT;
Eric Laurentbda74692009-11-04 08:27:26 -0800753 if (sharedBuffer == 0) {
754 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
755 } else {
756 mCblk->buffers = sharedBuffer->pointer();
757 // Force buffer full condition as data is already present in shared memory
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700758 mCblk->stepUser(mCblk->frameCount);
Eric Laurentbda74692009-11-04 08:27:26 -0800759 }
760
Eric Laurent65b65452010-06-01 23:49:17 -0700761 mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
762 mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
Eric Laurent7070b362010-07-16 07:43:46 -0700763 mAudioTrack->attachAuxEffect(mAuxEffectId);
Eric Laurent49f02be2009-11-19 09:00:56 -0800764 mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
765 mCblk->waitTimeMs = 0;
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700766 mRemainingFrames = mNotificationFramesAct;
767 mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate;
Eric Laurentbda74692009-11-04 08:27:26 -0800768 return NO_ERROR;
769}
770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
772{
773 int active;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 status_t result;
775 audio_track_cblk_t* cblk = mCblk;
776 uint32_t framesReq = audioBuffer->frameCount;
Eric Laurentef028272009-04-21 07:56:33 -0700777 uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778
779 audioBuffer->frameCount = 0;
780 audioBuffer->size = 0;
781
782 uint32_t framesAvail = cblk->framesAvailable();
783
784 if (framesAvail == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800785 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 goto start_loop_here;
787 while (framesAvail == 0) {
788 active = mActive;
789 if (UNLIKELY(!active)) {
790 LOGV("Not active and NO_MORE_BUFFERS");
Eric Laurentbda74692009-11-04 08:27:26 -0800791 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 return NO_MORE_BUFFERS;
793 }
Eric Laurentbda74692009-11-04 08:27:26 -0800794 if (UNLIKELY(!waitCount)) {
795 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 return WOULD_BLOCK;
Eric Laurentbda74692009-11-04 08:27:26 -0800797 }
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700798 if (!(cblk->flags & CBLK_INVALID_MSK)) {
799 result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
800 }
801 if (cblk->flags & CBLK_INVALID_MSK) {
802 LOGW("obtainBuffer() track %p invalidated, creating a new one", this);
803 // no need to clear the invalid flag as this cblk will not be used anymore
804 cblk->lock.unlock();
805 goto create_new_track;
806 }
Eric Laurenta553c252009-07-17 12:17:14 -0700807 if (__builtin_expect(result!=NO_ERROR, false)) {
Eric Laurentef028272009-04-21 07:56:33 -0700808 cblk->waitTimeMs += waitTimeMs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
810 // timing out when a loop has been set and we have already written upto loop end
811 // is a normal condition: no need to wake AudioFlinger up.
812 if (cblk->user < cblk->loopEnd) {
813 LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
814 "user=%08x, server=%08x", this, cblk->user, cblk->server);
Eric Laurenta553c252009-07-17 12:17:14 -0700815 //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 cblk->lock.unlock();
Eric Laurentbda74692009-11-04 08:27:26 -0800817 result = mAudioTrack->start();
818 if (result == DEAD_OBJECT) {
819 LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700820create_new_track:
Eric Laurentbda74692009-11-04 08:27:26 -0800821 result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700822 mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
Eric Laurentbda74692009-11-04 08:27:26 -0800823 if (result == NO_ERROR) {
824 cblk = mCblk;
825 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
Eric Laurent49f02be2009-11-19 09:00:56 -0800826 mAudioTrack->start();
Eric Laurentbda74692009-11-04 08:27:26 -0800827 }
828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 cblk->lock.lock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831 cblk->waitTimeMs = 0;
832 }
Eric Laurenta553c252009-07-17 12:17:14 -0700833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 if (--waitCount == 0) {
Eric Laurentbda74692009-11-04 08:27:26 -0800835 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 return TIMED_OUT;
837 }
838 }
839 // read the server count again
840 start_loop_here:
841 framesAvail = cblk->framesAvailable_l();
842 }
Eric Laurentbda74692009-11-04 08:27:26 -0800843 cblk->lock.unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 }
845
Eric Laurent4712baa2010-09-30 16:12:31 -0700846 // restart track if it was disabled by audioflinger due to previous underrun
847 if (cblk->flags & CBLK_DISABLED_MSK) {
848 cblk->flags &= ~CBLK_DISABLED_ON;
849 LOGW("obtainBuffer() track %p disabled, restarting", this);
850 mAudioTrack->start();
851 }
852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 cblk->waitTimeMs = 0;
Eric Laurenta553c252009-07-17 12:17:14 -0700854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 if (framesReq > framesAvail) {
856 framesReq = framesAvail;
857 }
858
859 uint32_t u = cblk->user;
860 uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
861
862 if (u + framesReq > bufferEnd) {
863 framesReq = bufferEnd - u;
864 }
865
Eric Laurenta553c252009-07-17 12:17:14 -0700866 audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
867 audioBuffer->channelCount = mChannelCount;
868 audioBuffer->frameCount = framesReq;
869 audioBuffer->size = framesReq * cblk->frameSize;
870 if (AudioSystem::isLinearPCM(mFormat)) {
871 audioBuffer->format = AudioSystem::PCM_16_BIT;
872 } else {
873 audioBuffer->format = mFormat;
874 }
875 audioBuffer->raw = (int8_t *)cblk->buffer(u);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 active = mActive;
877 return active ? status_t(NO_ERROR) : status_t(STOPPED);
878}
879
880void AudioTrack::releaseBuffer(Buffer* audioBuffer)
881{
882 audio_track_cblk_t* cblk = mCblk;
883 cblk->stepUser(audioBuffer->frameCount);
884}
885
886// -------------------------------------------------------------------------
887
888ssize_t AudioTrack::write(const void* buffer, size_t userSize)
889{
890
891 if (mSharedBuffer != 0) return INVALID_OPERATION;
892
893 if (ssize_t(userSize) < 0) {
894 // sanity-check. user is most-likely passing an error code.
895 LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
896 buffer, userSize, userSize);
897 return BAD_VALUE;
898 }
899
900 LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
901
902 ssize_t written = 0;
903 const int8_t *src = (const int8_t *)buffer;
904 Buffer audioBuffer;
905
906 do {
Eric Laurenta553c252009-07-17 12:17:14 -0700907 audioBuffer.frameCount = userSize/frameSize();
908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 // Calling obtainBuffer() with a negative wait count causes
910 // an (almost) infinite wait time.
911 status_t err = obtainBuffer(&audioBuffer, -1);
912 if (err < 0) {
913 // out of buffers, return #bytes written
914 if (err == status_t(NO_MORE_BUFFERS))
915 break;
916 return ssize_t(err);
917 }
918
919 size_t toWrite;
Eric Laurenta553c252009-07-17 12:17:14 -0700920
Eric Laurent28ad42b2009-08-04 10:42:26 -0700921 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 // Divide capacity by 2 to take expansion into account
923 toWrite = audioBuffer.size>>1;
924 // 8 to 16 bit conversion
925 int count = toWrite;
926 int16_t *dst = (int16_t *)(audioBuffer.i8);
927 while(count--) {
928 *dst++ = (int16_t)(*src++^0x80) << 8;
929 }
Eric Laurent28ad42b2009-08-04 10:42:26 -0700930 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 toWrite = audioBuffer.size;
932 memcpy(audioBuffer.i8, src, toWrite);
933 src += toWrite;
934 }
935 userSize -= toWrite;
936 written += toWrite;
937
938 releaseBuffer(&audioBuffer);
939 } while (userSize);
940
941 return written;
942}
943
944// -------------------------------------------------------------------------
945
946bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
947{
948 Buffer audioBuffer;
949 uint32_t frames;
950 size_t writtenSize;
951
952 // Manage underrun callback
953 if (mActive && (mCblk->framesReady() == 0)) {
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700954 LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
955 if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 mCbf(EVENT_UNDERRUN, mUserData, 0);
957 if (mCblk->server == mCblk->frameCount) {
Eric Laurenta553c252009-07-17 12:17:14 -0700958 mCbf(EVENT_BUFFER_END, mUserData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
Eric Laurenteb8f850d2010-05-14 03:26:45 -0700960 mCblk->flags |= CBLK_UNDERRUN_ON;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 if (mSharedBuffer != 0) return false;
962 }
963 }
Eric Laurenta553c252009-07-17 12:17:14 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 // Manage loop end callback
966 while (mLoopCount > mCblk->loopCount) {
967 int loopCount = -1;
968 mLoopCount--;
969 if (mLoopCount >= 0) loopCount = mLoopCount;
970
971 mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);
972 }
973
974 // Manage marker callback
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700975 if (!mMarkerReached && (mMarkerPosition > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 if (mCblk->server >= mMarkerPosition) {
977 mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
Jean-Michel Trivi4a5c1a72009-03-24 18:11:07 -0700978 mMarkerReached = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
980 }
981
982 // Manage new position callback
Eric Laurenta553c252009-07-17 12:17:14 -0700983 if (mUpdatePeriod > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 while (mCblk->server >= mNewPosition) {
985 mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
986 mNewPosition += mUpdatePeriod;
987 }
988 }
989
990 // If Shared buffer is used, no data is requested from client.
991 if (mSharedBuffer != 0) {
992 frames = 0;
993 } else {
994 frames = mRemainingFrames;
995 }
996
997 do {
998
999 audioBuffer.frameCount = frames;
Eric Laurenta553c252009-07-17 12:17:14 -07001000
1001 // Calling obtainBuffer() with a wait count of 1
1002 // limits wait time to WAIT_PERIOD_MS. This prevents from being
1003 // stuck here not being able to handle timed events (position, markers, loops).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 status_t err = obtainBuffer(&audioBuffer, 1);
1005 if (err < NO_ERROR) {
1006 if (err != TIMED_OUT) {
Eric Laurentef028272009-04-21 07:56:33 -07001007 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 -08001008 return false;
1009 }
1010 break;
1011 }
1012 if (err == status_t(STOPPED)) return false;
1013
1014 // Divide buffer size by 2 to take into account the expansion
1015 // due to 8 to 16 bit conversion: the callback must fill only half
1016 // of the destination buffer
Eric Laurent28ad42b2009-08-04 10:42:26 -07001017 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 audioBuffer.size >>= 1;
1019 }
1020
1021 size_t reqSize = audioBuffer.size;
1022 mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
1023 writtenSize = audioBuffer.size;
1024
1025 // Sanity check on returned size
The Android Open Source Project4df24232009-03-05 14:34:35 -08001026 if (ssize_t(writtenSize) <= 0) {
1027 // The callback is done filling buffers
1028 // Keep this thread going to handle timed events and
1029 // still try to get more data in intervals of WAIT_PERIOD_MS
1030 // but don't just loop and block the CPU, so wait
1031 usleep(WAIT_PERIOD_MS*1000);
1032 break;
1033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 if (writtenSize > reqSize) writtenSize = reqSize;
1035
Eric Laurent28ad42b2009-08-04 10:42:26 -07001036 if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 // 8 to 16 bit conversion
1038 const int8_t *src = audioBuffer.i8 + writtenSize-1;
1039 int count = writtenSize;
1040 int16_t *dst = audioBuffer.i16 + writtenSize-1;
1041 while(count--) {
1042 *dst-- = (int16_t)(*src--^0x80) << 8;
1043 }
1044 writtenSize <<= 1;
1045 }
1046
1047 audioBuffer.size = writtenSize;
Eric Laurenta553c252009-07-17 12:17:14 -07001048 // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
1049 // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of
1050 // 16 bit.
1051 audioBuffer.frameCount = writtenSize/mCblk->frameSize;
1052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 frames -= audioBuffer.frameCount;
1054
1055 releaseBuffer(&audioBuffer);
1056 }
1057 while (frames);
1058
1059 if (frames == 0) {
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001060 mRemainingFrames = mNotificationFramesAct;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 } else {
1062 mRemainingFrames = frames;
1063 }
1064 return true;
1065}
1066
1067status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
1068{
1069
1070 const size_t SIZE = 256;
1071 char buffer[SIZE];
1072 String8 result;
1073
1074 result.append(" AudioTrack::dump\n");
1075 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
1076 result.append(buffer);
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001077 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 -08001078 result.append(buffer);
Eric Laurent88e209d2009-07-07 07:10:45 -07001079 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 -08001080 result.append(buffer);
1081 snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
1082 result.append(buffer);
1083 ::write(fd, result.string(), result.size());
1084 return NO_ERROR;
1085}
1086
1087// =========================================================================
1088
1089AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
1090 : Thread(bCanCallJava), mReceiver(receiver)
1091{
1092}
1093
1094bool AudioTrack::AudioTrackThread::threadLoop()
1095{
1096 return mReceiver.processAudioBuffer(this);
1097}
1098
1099status_t AudioTrack::AudioTrackThread::readyToRun()
1100{
1101 return NO_ERROR;
1102}
1103
1104void AudioTrack::AudioTrackThread::onFirstRef()
1105{
1106}
1107
1108// =========================================================================
1109
1110audio_track_cblk_t::audio_track_cblk_t()
Mathias Agopiana729f972010-03-19 16:14:13 -07001111 : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
1112 userBase(0), serverBase(0), buffers(0), frameCount(0),
1113 loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
Eric Laurent65b65452010-06-01 23:49:17 -07001114 flags(0), sendLevel(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115{
1116}
1117
1118uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
1119{
1120 uint32_t u = this->user;
1121
1122 u += frameCount;
1123 // Ensure that user is never ahead of server for AudioRecord
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001124 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
1126 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
1127 bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
1128 }
1129 } else if (u > this->server) {
1130 LOGW("stepServer occured after track reset");
1131 u = this->server;
1132 }
1133
1134 if (u >= userBase + this->frameCount) {
1135 userBase += this->frameCount;
1136 }
1137
1138 this->user = u;
1139
1140 // Clear flow control error condition as new data has been written/read to/from buffer.
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001141 flags &= ~CBLK_UNDERRUN_MSK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142
1143 return u;
1144}
1145
1146bool audio_track_cblk_t::stepServer(uint32_t frameCount)
1147{
1148 // the code below simulates lock-with-timeout
1149 // we MUST do this to protect the AudioFlinger server
1150 // as this lock is shared with the client.
1151 status_t err;
1152
1153 err = lock.tryLock();
1154 if (err == -EBUSY) { // just wait a bit
1155 usleep(1000);
1156 err = lock.tryLock();
1157 }
1158 if (err != NO_ERROR) {
1159 // probably, the client just died.
1160 return false;
1161 }
1162
1163 uint32_t s = this->server;
1164
1165 s += frameCount;
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001166 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 // Mark that we have read the first buffer so that next time stepUser() is called
1168 // we switch to normal obtainBuffer() timeout period
1169 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
Eric Laurentbda74692009-11-04 08:27:26 -08001170 bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1;
Eric Laurenta553c252009-07-17 12:17:14 -07001171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 // It is possible that we receive a flush()
1173 // while the mixer is processing a block: in this case,
1174 // stepServer() is called After the flush() has reset u & s and
1175 // we have s > u
1176 if (s > this->user) {
1177 LOGW("stepServer occured after track reset");
1178 s = this->user;
1179 }
1180 }
1181
1182 if (s >= loopEnd) {
1183 LOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd);
1184 s = loopStart;
1185 if (--loopCount == 0) {
1186 loopEnd = UINT_MAX;
1187 loopStart = UINT_MAX;
1188 }
1189 }
1190 if (s >= serverBase + this->frameCount) {
1191 serverBase += this->frameCount;
1192 }
1193
1194 this->server = s;
1195
1196 cv.signal();
1197 lock.unlock();
1198 return true;
1199}
1200
1201void* audio_track_cblk_t::buffer(uint32_t offset) const
1202{
Eric Laurenta553c252009-07-17 12:17:14 -07001203 return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204}
1205
1206uint32_t audio_track_cblk_t::framesAvailable()
1207{
1208 Mutex::Autolock _l(lock);
1209 return framesAvailable_l();
1210}
1211
1212uint32_t audio_track_cblk_t::framesAvailable_l()
1213{
1214 uint32_t u = this->user;
1215 uint32_t s = this->server;
1216
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001217 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 uint32_t limit = (s < loopStart) ? s : loopStart;
1219 return limit + frameCount - u;
1220 } else {
1221 return frameCount + u - s;
1222 }
1223}
1224
1225uint32_t audio_track_cblk_t::framesReady()
1226{
1227 uint32_t u = this->user;
1228 uint32_t s = this->server;
1229
Eric Laurenteb8f850d2010-05-14 03:26:45 -07001230 if (flags & CBLK_DIRECTION_MSK) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 if (u < loopEnd) {
1232 return u - s;
1233 } else {
1234 Mutex::Autolock _l(lock);
1235 if (loopCount >= 0) {
1236 return (loopEnd - loopStart)*loopCount + u - s;
1237 } else {
1238 return UINT_MAX;
1239 }
1240 }
1241 } else {
1242 return s - u;
1243 }
1244}
1245
1246// -------------------------------------------------------------------------
1247
1248}; // namespace android
1249