summaryrefslogtreecommitdiffstats
path: root/media/libmedia/AudioTrack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmedia/AudioTrack.cpp')
-rw-r--r--media/libmedia/AudioTrack.cpp157
1 files changed, 98 insertions, 59 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 8d8f67b..7520ed9 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -35,6 +35,12 @@
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <utils/Timers.h>
+#include <utils/Atomic.h>
+
+#include <cutils/bitops.h>
+
+#include <system/audio.h>
+#include <hardware/audio_policy.h>
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
@@ -164,39 +170,41 @@ status_t AudioTrack::set(
}
// handle default values first.
- if (streamType == AudioSystem::DEFAULT) {
- streamType = AudioSystem::MUSIC;
+ if (streamType == AUDIO_STREAM_DEFAULT) {
+ streamType = AUDIO_STREAM_MUSIC;
}
if (sampleRate == 0) {
sampleRate = afSampleRate;
}
// these below should probably come from the audioFlinger too...
if (format == 0) {
- format = AudioSystem::PCM_16_BIT;
+ format = AUDIO_FORMAT_PCM_16_BIT;
}
if (channels == 0) {
- channels = AudioSystem::CHANNEL_OUT_STEREO;
+ channels = AUDIO_CHANNEL_OUT_STEREO;
}
// validate parameters
- if (!AudioSystem::isValidFormat(format)) {
+ if (!audio_is_valid_format(format)) {
LOGE("Invalid format");
return BAD_VALUE;
}
// force direct flag if format is not linear PCM
- if (!AudioSystem::isLinearPCM(format)) {
- flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
+ if (!audio_is_linear_pcm(format)) {
+ flags |= AUDIO_POLICY_OUTPUT_FLAG_DIRECT;
}
- if (!AudioSystem::isOutputChannel(channels)) {
+ if (!audio_is_output_channel(channels)) {
LOGE("Invalid channel mask");
return BAD_VALUE;
}
- uint32_t channelCount = AudioSystem::popCount(channels);
+ uint32_t channelCount = popcount(channels);
- audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
- sampleRate, format, channels, (AudioSystem::output_flags)flags);
+ audio_io_handle_t output = AudioSystem::getOutput(
+ (audio_stream_type_t)streamType,
+ sampleRate,format, channels,
+ (audio_policy_output_flags_t)flags);
if (output == 0) {
LOGE("Could not get audio output for stream type %d", streamType);
@@ -289,8 +297,8 @@ uint32_t AudioTrack::frameCount() const
int AudioTrack::frameSize() const
{
- if (AudioSystem::isLinearPCM(mFormat)) {
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (audio_is_linear_pcm(mFormat)) {
+ return channelCount()*((format() == AUDIO_FORMAT_PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
} else {
return sizeof(uint8_t);
}
@@ -329,9 +337,10 @@ void AudioTrack::start()
if (mActive == 0) {
mActive = 1;
mNewPosition = cblk->server + mUpdatePeriod;
+ cblk->lock.lock();
cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
cblk->waitTimeMs = 0;
- cblk->flags &= ~CBLK_DISABLED_ON;
+ android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -339,13 +348,12 @@ void AudioTrack::start()
}
LOGV("start %p before lock cblk %p", this, mCblk);
- cblk->lock.lock();
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
status = mAudioTrack->start();
cblk->lock.lock();
if (status == DEAD_OBJECT) {
- cblk->flags |= CBLK_INVALID_MSK;
+ android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
}
}
if (cblk->flags & CBLK_INVALID_MSK) {
@@ -546,12 +554,13 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou
}
if (loopStart >= loopEnd ||
- loopEnd - loopStart > cblk->frameCount) {
+ loopEnd - loopStart > cblk->frameCount ||
+ cblk->server > loopStart) {
LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
return BAD_VALUE;
}
- if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
+ if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
loopStart, loopEnd, cblk->frameCount);
return BAD_VALUE;
@@ -635,7 +644,7 @@ status_t AudioTrack::setPosition(uint32_t position)
if (position > mCblk->user) return BAD_VALUE;
mCblk->server = position;
- mCblk->flags |= CBLK_FORCEREADY_ON;
+ android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags);
return NO_ERROR;
}
@@ -671,8 +680,8 @@ audio_io_handle_t AudioTrack::getOutput()
// must be called with mLock held
audio_io_handle_t AudioTrack::getOutput_l()
{
- return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
- mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
+ return AudioSystem::getOutput((audio_stream_type_t)mStreamType,
+ mCblk->sampleRate, mFormat, mChannels, (audio_policy_output_flags_t)mFlags);
}
int AudioTrack::getSessionId()
@@ -725,7 +734,7 @@ status_t AudioTrack::createTrack_l(
}
mNotificationFramesAct = mNotificationFramesReq;
- if (!AudioSystem::isLinearPCM(format)) {
+ if (!audio_is_linear_pcm(format)) {
if (sharedBuffer != 0) {
frameCount = sharedBuffer->size();
}
@@ -792,7 +801,7 @@ status_t AudioTrack::createTrack_l(
mCblkMemory.clear();
mCblkMemory = cblk;
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
- mCblk->flags |= CBLK_DIRECTION_OUT;
+ android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags);
if (sharedBuffer == 0) {
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
} else {
@@ -825,6 +834,12 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
uint32_t framesAvail = cblk->framesAvailable();
+ cblk->lock.lock();
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ goto create_new_track;
+ }
+ cblk->lock.unlock();
+
if (framesAvail == 0) {
cblk->lock.lock();
goto start_loop_here;
@@ -866,7 +881,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
result = mAudioTrack->start();
cblk->lock.lock();
if (result == DEAD_OBJECT) {
- cblk->flags |= CBLK_INVALID_MSK;
+ android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
create_new_track:
result = restoreTrack_l(cblk, false);
}
@@ -893,7 +908,7 @@ create_new_track:
// restart track if it was disabled by audioflinger due to previous underrun
if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
- cblk->flags &= ~CBLK_DISABLED_ON;
+ android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
LOGW("obtainBuffer() track %p disabled, restarting", this);
mAudioTrack->start();
}
@@ -915,8 +930,8 @@ create_new_track:
audioBuffer->channelCount = mChannelCount;
audioBuffer->frameCount = framesReq;
audioBuffer->size = framesReq * cblk->frameSize;
- if (AudioSystem::isLinearPCM(mFormat)) {
- audioBuffer->format = AudioSystem::PCM_16_BIT;
+ if (audio_is_linear_pcm(mFormat)) {
+ audioBuffer->format = AUDIO_FORMAT_PCM_16_BIT;
} else {
audioBuffer->format = mFormat;
}
@@ -957,9 +972,10 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
ssize_t written = 0;
const int8_t *src = (const int8_t *)buffer;
Buffer audioBuffer;
+ size_t frameSz = (size_t)frameSize();
do {
- audioBuffer.frameCount = userSize/frameSize();
+ audioBuffer.frameCount = userSize/frameSz;
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
@@ -973,7 +989,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
size_t toWrite;
- if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
+ if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
// Divide capacity by 2 to take expansion into account
toWrite = audioBuffer.size>>1;
// 8 to 16 bit conversion
@@ -991,7 +1007,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
written += toWrite;
releaseBuffer(&audioBuffer);
- } while (userSize);
+ } while (userSize >= frameSz);
return written;
}
@@ -1013,14 +1029,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
mLock.unlock();
// Manage underrun callback
- if (mActive && (cblk->framesReady() == 0)) {
+ if (mActive && (cblk->framesAvailable() == cblk->frameCount)) {
LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
- if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+ if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
if (cblk->server == cblk->frameCount) {
mCbf(EVENT_BUFFER_END, mUserData, 0);
}
- cblk->flags |= CBLK_UNDERRUN_ON;
if (mSharedBuffer != 0) return false;
}
}
@@ -1077,7 +1092,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
// Divide buffer size by 2 to take into account the expansion
// due to 8 to 16 bit conversion: the callback must fill only half
// of the destination buffer
- if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
+ if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
audioBuffer.size >>= 1;
}
@@ -1096,7 +1111,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
if (writtenSize > reqSize) writtenSize = reqSize;
- if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {
+ if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
// 8 to 16 bit conversion
const int8_t *src = audioBuffer.i8 + writtenSize-1;
int count = writtenSize;
@@ -1134,11 +1149,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
{
status_t result;
- if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+ if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
LOGW("dead IAudioTrack, creating a new one from %s",
fromStart ? "start()" : "obtainBuffer()");
- cblk->flags |= CBLK_RESTORING_ON;
// signal old cblk condition so that other threads waiting for available buffers stop
// waiting now
cblk->cv.broadcast();
@@ -1158,10 +1172,20 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
false);
if (result == NO_ERROR) {
+ // restore write index and set other indexes to reflect empty buffer status
+ mCblk->user = cblk->user;
+ mCblk->server = cblk->user;
+ mCblk->userBase = cblk->user;
+ mCblk->serverBase = cblk->user;
+ // restore loop: this is not guaranteed to succeed if new frame count is not
+ // compatible with loop length
+ setLoop_l(cblk->loopStart, cblk->loopEnd, cblk->loopCount);
if (!fromStart) {
mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
}
- result = mAudioTrack->start();
+ if (mActive) {
+ result = mAudioTrack->start();
+ }
if (fromStart && result == NO_ERROR) {
mNewPosition = mCblk->server + mUpdatePeriod;
}
@@ -1171,10 +1195,8 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
}
// signal old cblk condition for other threads waiting for restore completion
- cblk->lock.lock();
- cblk->flags |= CBLK_RESTORED_MSK;
+ android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
cblk->cv.broadcast();
- cblk->lock.unlock();
} else {
if (!(cblk->flags & CBLK_RESTORED_MSK)) {
LOGW("dead IAudioTrack, waiting for a new one");
@@ -1248,11 +1270,12 @@ void AudioTrack::AudioTrackThread::onFirstRef()
// =========================================================================
+
audio_track_cblk_t::audio_track_cblk_t()
: lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
userBase(0), serverBase(0), buffers(0), frameCount(0),
loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
- flags(0), sendLevel(0)
+ sendLevel(0), flags(0)
{
}
@@ -1279,25 +1302,17 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
this->user = u;
// Clear flow control error condition as new data has been written/read to/from buffer.
- flags &= ~CBLK_UNDERRUN_MSK;
+ if (flags & CBLK_UNDERRUN_MSK) {
+ android_atomic_and(~CBLK_UNDERRUN_MSK, &flags);
+ }
return u;
}
bool audio_track_cblk_t::stepServer(uint32_t frameCount)
{
- // the code below simulates lock-with-timeout
- // we MUST do this to protect the AudioFlinger server
- // as this lock is shared with the client.
- status_t err;
-
- err = lock.tryLock();
- if (err == -EBUSY) { // just wait a bit
- usleep(1000);
- err = lock.tryLock();
- }
- if (err != NO_ERROR) {
- // probably, the client just died.
+ if (!tryLock()) {
+ LOGW("stepServer() could not lock cblk");
return false;
}
@@ -1374,18 +1389,42 @@ uint32_t audio_track_cblk_t::framesReady()
if (u < loopEnd) {
return u - s;
} else {
- Mutex::Autolock _l(lock);
+ // do not block on mutex shared with client on AudioFlinger side
+ if (!tryLock()) {
+ LOGW("framesReady() could not lock cblk");
+ return 0;
+ }
+ uint32_t frames = UINT_MAX;
if (loopCount >= 0) {
- return (loopEnd - loopStart)*loopCount + u - s;
- } else {
- return UINT_MAX;
+ frames = (loopEnd - loopStart)*loopCount + u - s;
}
+ lock.unlock();
+ return frames;
}
} else {
return s - u;
}
}
+bool audio_track_cblk_t::tryLock()
+{
+ // the code below simulates lock-with-timeout
+ // we MUST do this to protect the AudioFlinger server
+ // as this lock is shared with the client.
+ status_t err;
+
+ err = lock.tryLock();
+ if (err == -EBUSY) { // just wait a bit
+ usleep(1000);
+ err = lock.tryLock();
+ }
+ if (err != NO_ERROR) {
+ // probably, the client just died.
+ return false;
+ }
+ return true;
+}
+
// -------------------------------------------------------------------------
}; // namespace android