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.cpp189
1 files changed, 116 insertions, 73 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7b9eda7..b147d25 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -54,7 +54,7 @@ AudioTrack::AudioTrack(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -62,7 +62,7 @@ AudioTrack::AudioTrack(
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames, 0);
}
@@ -70,7 +70,7 @@ AudioTrack::AudioTrack(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
const sp<IMemory>& sharedBuffer,
uint32_t flags,
callback_t cbf,
@@ -78,7 +78,7 @@ AudioTrack::AudioTrack(
int notificationFrames)
: mStatus(NO_INIT)
{
- mStatus = set(streamType, sampleRate, format, channelCount,
+ mStatus = set(streamType, sampleRate, format, channels,
0, flags, cbf, user, notificationFrames, sharedBuffer);
}
@@ -97,6 +97,7 @@ AudioTrack::~AudioTrack()
}
mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
+ AudioSystem::releaseOutput(getOutput());
}
}
@@ -104,7 +105,7 @@ status_t AudioTrack::set(
int streamType,
uint32_t sampleRate,
int format,
- int channelCount,
+ int channels,
int frameCount,
uint32_t flags,
callback_t cbf,
@@ -150,63 +151,84 @@ status_t AudioTrack::set(
if (format == 0) {
format = AudioSystem::PCM_16_BIT;
}
- if (channelCount == 0) {
- channelCount = 2;
+ if (channels == 0) {
+ channels = AudioSystem::CHANNEL_OUT_STEREO;
}
// validate parameters
- if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
- (format != AudioSystem::PCM_16_BIT)) {
+ if (!AudioSystem::isValidFormat(format)) {
LOGE("Invalid format");
return BAD_VALUE;
}
- if (channelCount != 1 && channelCount != 2) {
- LOGE("Invalid channel number");
+
+ // force direct flag if format is not linear PCM
+ if (!AudioSystem::isLinearPCM(format)) {
+ flags |= AudioSystem::OUTPUT_FLAG_DIRECT;
+ }
+
+ if (!AudioSystem::isOutputChannel(channels)) {
+ LOGE("Invalid channel mask");
return BAD_VALUE;
}
+ uint32_t channelCount = AudioSystem::popCount(channels);
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
+ audio_io_handle_t output = AudioSystem::getOutput((AudioSystem::stream_type)streamType,
+ sampleRate, format, channels, (AudioSystem::output_flags)flags);
- // When playing from shared buffer, playback will start even if last audioflinger
- // block is partly filled.
- if (sharedBuffer != 0 && minBufCount > 1) {
- minBufCount--;
+ if (output == 0) {
+ LOGE("Could not get audio output for stream type %d", streamType);
+ return BAD_VALUE;
}
- int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
-
- if (sharedBuffer == 0) {
- if (frameCount == 0) {
- frameCount = minFrameCount;
- }
- if (notificationFrames == 0) {
- notificationFrames = frameCount/2;
- }
- // Make sure that application is notified with sufficient margin
- // before underrun
- if (notificationFrames > frameCount/2) {
- notificationFrames = frameCount/2;
+ if (!AudioSystem::isLinearPCM(format)) {
+ if (sharedBuffer != 0) {
+ frameCount = sharedBuffer->size();
}
} else {
- // Ensure that buffer alignment matches channelcount
- if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
- LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
- return BAD_VALUE;
- }
- frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
- }
+ // Ensure that buffer depth covers at least audio hardware latency
+ uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+ if (minBufCount < 2) minBufCount = 2;
- if (frameCount < minFrameCount) {
- LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
- return BAD_VALUE;
+ int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+
+ if (sharedBuffer == 0) {
+ if (frameCount == 0) {
+ frameCount = minFrameCount;
+ }
+ if (notificationFrames == 0) {
+ notificationFrames = frameCount/2;
+ }
+ // Make sure that application is notified with sufficient margin
+ // before underrun
+ if (notificationFrames > frameCount/2) {
+ notificationFrames = frameCount/2;
+ }
+ if (frameCount < minFrameCount) {
+ LOGE("Invalid buffer size: minFrameCount %d, frameCount %d", minFrameCount, frameCount);
+ return BAD_VALUE;
+ }
+ } else {
+ // Ensure that buffer alignment matches channelcount
+ if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
+ LOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
+ return BAD_VALUE;
+ }
+ frameCount = sharedBuffer->size()/channelCount/sizeof(int16_t);
+ }
}
// create the track
status_t status;
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
- streamType, sampleRate, format, channelCount, frameCount, flags, sharedBuffer, &status);
+ streamType,
+ sampleRate,
+ format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ sharedBuffer,
+ output,
+ &status);
if (track == 0) {
LOGE("AudioFlinger could not create track, status: %d", status);
@@ -245,6 +267,7 @@ status_t AudioTrack::set(
mVolume[RIGHT] = 1.0f;
mStreamType = streamType;
mFormat = format;
+ mChannels = channels;
mChannelCount = channelCount;
mSharedBuffer = sharedBuffer;
mMuted = false;
@@ -259,6 +282,7 @@ status_t AudioTrack::set(
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
+ mFlags = flags;
return NO_ERROR;
}
@@ -297,7 +321,11 @@ uint32_t AudioTrack::frameCount() const
int AudioTrack::frameSize() const
{
- return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ return channelCount()*((format() == AudioSystem::PCM_8_BIT) ? sizeof(uint8_t) : sizeof(int16_t));
+ } else {
+ return sizeof(uint8_t);
+ }
}
sp<IMemory>& AudioTrack::sharedBuffer()
@@ -323,6 +351,7 @@ void AudioTrack::start()
}
if (android_atomic_or(1, &mActive) == 0) {
+ AudioSystem::startOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
@@ -367,6 +396,7 @@ void AudioTrack::stop()
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
if (t != 0) {
@@ -382,12 +412,12 @@ bool AudioTrack::stopped() const
void AudioTrack::flush()
{
LOGV("flush");
-
+
// clear playback marker and periodic update counter
mMarkerPosition = 0;
mMarkerReached = false;
mUpdatePeriod = 0;
-
+
if (!mActive) {
mAudioTrack->flush();
@@ -403,6 +433,7 @@ void AudioTrack::pause()
if (android_atomic_and(~1, &mActive) == 1) {
mActive = 0;
mAudioTrack->pause();
+ AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
}
}
@@ -455,7 +486,6 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
{
audio_track_cblk_t* cblk = mCblk;
-
Mutex::Autolock _l(cblk->lock);
if (loopCount == 0) {
@@ -476,7 +506,7 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
loopStart, loopEnd, mFrameCount);
return BAD_VALUE;
- }
+ }
cblk->loopStart = loopStart;
cblk->loopEnd = loopEnd;
@@ -555,7 +585,7 @@ status_t AudioTrack::setPosition(uint32_t position)
mCblk->server = position;
mCblk->forceReady = 1;
-
+
return NO_ERROR;
}
@@ -571,7 +601,7 @@ status_t AudioTrack::getPosition(uint32_t *position)
status_t AudioTrack::reload()
{
if (!stopped()) return INVALID_OPERATION;
-
+
flush();
mCblk->stepUser(mFrameCount);
@@ -579,6 +609,12 @@ status_t AudioTrack::reload()
return NO_ERROR;
}
+audio_io_handle_t AudioTrack::getOutput()
+{
+ return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
+ mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
+}
+
// -------------------------------------------------------------------------
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -608,7 +644,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
return WOULD_BLOCK;
timeout = 0;
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
- if (__builtin_expect(result!=NO_ERROR, false)) {
+ if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += waitTimeMs;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
// timing out when a loop has been set and we have already written upto loop end
@@ -616,7 +652,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
if (cblk->user < cblk->loopEnd) {
LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
"user=%08x, server=%08x", this, cblk->user, cblk->server);
- //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
+ //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
mAudioTrack->start();
cblk->lock.lock();
@@ -624,7 +660,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
cblk->waitTimeMs = 0;
}
-
+
if (--waitCount == 0) {
return TIMED_OUT;
}
@@ -636,7 +672,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
cblk->waitTimeMs = 0;
-
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -653,12 +689,16 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
"but didn't need to be locked. We recovered, but "
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
- audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
- audioBuffer->channelCount= mChannelCount;
- audioBuffer->format = AudioSystem::PCM_16_BIT;
- audioBuffer->frameCount = framesReq;
- audioBuffer->size = framesReq*mChannelCount*sizeof(int16_t);
- audioBuffer->raw = (int8_t *)cblk->buffer(u);
+ audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+ audioBuffer->channelCount = mChannelCount;
+ audioBuffer->frameCount = framesReq;
+ audioBuffer->size = framesReq * cblk->frameSize;
+ if (AudioSystem::isLinearPCM(mFormat)) {
+ audioBuffer->format = AudioSystem::PCM_16_BIT;
+ } else {
+ audioBuffer->format = mFormat;
+ }
+ audioBuffer->raw = (int8_t *)cblk->buffer(u);
active = mActive;
return active ? status_t(NO_ERROR) : status_t(STOPPED);
}
@@ -690,10 +730,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
Buffer audioBuffer;
do {
- audioBuffer.frameCount = userSize/mChannelCount;
- if (mFormat == AudioSystem::PCM_16_BIT) {
- audioBuffer.frameCount >>= 1;
- }
+ audioBuffer.frameCount = userSize/frameSize();
+
// Calling obtainBuffer() with a negative wait count causes
// an (almost) infinite wait time.
status_t err = obtainBuffer(&audioBuffer, -1);
@@ -705,6 +743,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
}
size_t toWrite;
+
if (mFormat == AudioSystem::PCM_8_BIT) {
// Divide capacity by 2 to take expansion into account
toWrite = audioBuffer.size>>1;
@@ -742,13 +781,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
if (mCblk->flowControlFlag == 0) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
if (mCblk->server == mCblk->frameCount) {
- mCbf(EVENT_BUFFER_END, mUserData, 0);
+ mCbf(EVENT_BUFFER_END, mUserData, 0);
}
mCblk->flowControlFlag = 1;
if (mSharedBuffer != 0) return false;
}
}
-
+
// Manage loop end callback
while (mLoopCount > mCblk->loopCount) {
int loopCount = -1;
@@ -767,7 +806,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
// Manage new position callback
- if(mUpdatePeriod > 0) {
+ if (mUpdatePeriod > 0) {
while (mCblk->server >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
@@ -784,10 +823,10 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
do {
audioBuffer.frameCount = frames;
-
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
- // stuck here not being able to handle timed events (position, markers, loops).
+
+ // Calling obtainBuffer() with a wait count of 1
+ // limits wait time to WAIT_PERIOD_MS. This prevents from being
+ // stuck here not being able to handle timed events (position, markers, loops).
status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
@@ -832,7 +871,11 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
audioBuffer.size = writtenSize;
- audioBuffer.frameCount = writtenSize/mChannelCount/sizeof(int16_t);
+ // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for
+ // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of
+ // 16 bit.
+ audioBuffer.frameCount = writtenSize/mCblk->frameSize;
+
frames -= audioBuffer.frameCount;
releaseBuffer(&audioBuffer);
@@ -949,7 +992,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
// we switch to normal obtainBuffer() timeout period
if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) {
bufferTimeoutMs = MAX_RUN_TIMEOUT_MS - 1;
- }
+ }
// It is possible that we receive a flush()
// while the mixer is processing a block: in this case,
// stepServer() is called After the flush() has reset u & s and
@@ -981,7 +1024,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
void* audio_track_cblk_t::buffer(uint32_t offset) const
{
- return (int16_t *)this->buffers + (offset-userBase)*this->channels;
+ return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;
}
uint32_t audio_track_cblk_t::framesAvailable()