summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioRecord.h2
-rw-r--r--include/media/AudioTrack.h2
-rw-r--r--include/media/ToneGenerator.h2
-rw-r--r--include/private/media/AudioTrackShared.h9
-rw-r--r--media/libmedia/AudioRecord.cpp46
-rw-r--r--media/libmedia/AudioTrack.cpp82
6 files changed, 89 insertions, 54 deletions
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 71744be..dd585c9 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -275,7 +275,7 @@ public:
STOPPED = 1
};
- status_t obtainBuffer(Buffer* audioBuffer, bool blocking);
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
void releaseBuffer(Buffer* audioBuffer);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index f382451..fd62daa 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -358,7 +358,7 @@ public:
STOPPED = 1
};
- status_t obtainBuffer(Buffer* audioBuffer, bool blocking);
+ status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
void releaseBuffer(Buffer* audioBuffer);
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 0ddfb8e..0cfdeec 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -134,7 +134,7 @@ private:
Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
float mVolume; // Volume applied to audio track
int mStreamType; // Audio stream used for output
- int mProcessSize; // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
+ unsigned int mProcessSize; // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
bool initAudioTrack();
static void audioCallback(int event, void* user, void *info);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 72ed281..1991aa7 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -28,6 +28,11 @@ namespace android {
#define MAX_SAMPLE_RATE 65535
#define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
+// Maximum cumulated timeout milliseconds before restarting audioflinger thread
+#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
+#define MAX_RUN_TIMEOUT_MS 1000
+#define WAIT_PERIOD_MS 10
+
struct audio_track_cblk_t
{
@@ -55,9 +60,11 @@ struct audio_track_cblk_t
int16_t flowControlFlag; // underrun (out) or overrrun (in) indication
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
uint8_t forceReady;
+ uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
+ uint16_t waitTimeMs; // Cumulated wait time
// Padding ensuring that data buffer starts on a cache line boundary (32 bytes).
// See AudioFlinger::TrackBase constructor
- int32_t Padding[4];
+ int32_t Padding[3];
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index bbb9548..3d39181 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -245,6 +245,8 @@ status_t AudioRecord::start()
if (android_atomic_or(1, &mActive) == 0) {
mNewPosition = mCblk->user + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
if (t != 0) {
t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -342,7 +344,7 @@ status_t AudioRecord::getPosition(uint32_t *position)
// -------------------------------------------------------------------------
-status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
int active;
int timeout = 0;
@@ -362,14 +364,21 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
active = mActive;
if (UNLIKELY(!active))
return NO_MORE_BUFFERS;
- if (UNLIKELY(!blocking))
+ if (UNLIKELY(!waitCount))
return WOULD_BLOCK;
timeout = 0;
- result = cblk->cv.waitRelative(cblk->lock, seconds(1));
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
if (__builtin_expect(result!=NO_ERROR, false)) {
- LOGW( "obtainBuffer timed out (is the CPU pegged?) "
- "user=%08x, server=%08x", cblk->user, cblk->server);
- timeout = 1;
+ cblk->waitTimeMs += WAIT_PERIOD_MS;
+ if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) "
+ "user=%08x, server=%08x", cblk->user, cblk->server);
+ timeout = 1;
+ cblk->waitTimeMs = 0;
+ }
+ if (--waitCount == 0) {
+ return TIMED_OUT;
+ }
}
// read the server count again
start_loop_here:
@@ -382,6 +391,8 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
"but didn't need to be locked. We recovered, but "
"this shouldn't happen (user=%08x, server=%08x)", cblk->user, cblk->server);
+ cblk->waitTimeMs = 0;
+
if (framesReq > framesReady) {
framesReq = framesReady;
}
@@ -430,7 +441,9 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
audioBuffer.frameCount = userSize/mChannelCount/sizeof(int16_t);
- status_t err = obtainBuffer(&audioBuffer, true);
+ // Calling obtainBuffer() with a negative wait count causes
+ // an (almost) infinite wait time.
+ status_t err = obtainBuffer(&audioBuffer, -1);
if (err < 0) {
// out of buffers, return #bytes written
if (err == status_t(NO_MORE_BUFFERS))
@@ -457,7 +470,7 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
{
Buffer audioBuffer;
uint32_t frames = mRemainingFrames;
- size_t readSize = 0;
+ size_t readSize;
// Manage marker callback
if (mMarkerPosition > 0) {
@@ -477,17 +490,19 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
do {
audioBuffer.frameCount = frames;
- status_t err = obtainBuffer(&audioBuffer, false);
+ // 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).
+ status_t err = obtainBuffer(&audioBuffer, 1);
if (err < NO_ERROR) {
- if (err != WOULD_BLOCK) {
+ if (err != TIMED_OUT) {
LOGE("Error obtaining an audio buffer, giving up.");
return false;
}
+ break;
}
if (err == status_t(STOPPED)) return false;
- if (audioBuffer.size == 0) break;
-
size_t reqSize = audioBuffer.size;
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
readSize = audioBuffer.size;
@@ -514,13 +529,6 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
}
}
- // If no data was read, it is likely that obtainBuffer() did
- // not find available data in PCM buffer: we release the processor for
- // a few millisecond before polling again for available data.
- if (readSize == 0) {
- usleep(5000);
- }
-
if (frames == 0) {
mRemainingFrames = mNotificationFrames;
} else {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ce65312..f9f8568 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -330,6 +330,8 @@ void AudioTrack::start()
if (android_atomic_or(1, &mActive) == 0) {
mNewPosition = mCblk->server + mUpdatePeriod;
+ mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+ mCblk->waitTimeMs = 0;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -572,7 +574,7 @@ status_t AudioTrack::reload()
// -------------------------------------------------------------------------
-status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
int active;
int timeout = 0;
@@ -594,15 +596,23 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
LOGV("Not active and NO_MORE_BUFFERS");
return NO_MORE_BUFFERS;
}
- if (UNLIKELY(!blocking))
+ if (UNLIKELY(!waitCount))
return WOULD_BLOCK;
timeout = 0;
- result = cblk->cv.waitRelative(cblk->lock, seconds(1));
- if (__builtin_expect(result!=NO_ERROR, false)) {
- LOGW( "obtainBuffer timed out (is the CPU pegged?) "
- "user=%08x, server=%08x", cblk->user, cblk->server);
- mAudioTrack->start(); // FIXME: Wake up audioflinger
- timeout = 1;
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(WAIT_PERIOD_MS));
+ if (__builtin_expect(result!=NO_ERROR, false)) {
+ cblk->waitTimeMs += WAIT_PERIOD_MS;
+ if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) "
+ "user=%08x, server=%08x", cblk->user, cblk->server);
+ mAudioTrack->start(); // FIXME: Wake up audioflinger
+ timeout = 1;
+ cblk->waitTimeMs = 0;
+ }
+ ;
+ if (--waitCount == 0) {
+ return TIMED_OUT;
+ }
}
// read the server count again
start_loop_here:
@@ -610,6 +620,8 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
}
}
+ cblk->waitTimeMs = 0;
+
if (framesReq > framesAvail) {
framesReq = framesAvail;
}
@@ -667,8 +679,9 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
if (mFormat == AudioSystem::PCM_16_BIT) {
audioBuffer.frameCount >>= 1;
}
-
- status_t err = obtainBuffer(&audioBuffer, true);
+ // Calling obtainBuffer() with a negative wait count causes
+ // an (almost) infinite wait time.
+ status_t err = obtainBuffer(&audioBuffer, -1);
if (err < 0) {
// out of buffers, return #bytes written
if (err == status_t(NO_MORE_BUFFERS))
@@ -706,7 +719,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
{
Buffer audioBuffer;
uint32_t frames;
- size_t writtenSize = 0;
+ size_t writtenSize;
// Manage underrun callback
if (mActive && (mCblk->framesReady() == 0)) {
@@ -756,18 +769,20 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
do {
audioBuffer.frameCount = frames;
-
- status_t err = obtainBuffer(&audioBuffer, false);
+
+ // 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 != WOULD_BLOCK) {
+ if (err != TIMED_OUT) {
LOGE("Error obtaining an audio buffer, giving up.");
return false;
}
+ break;
}
if (err == status_t(STOPPED)) return false;
- if (audioBuffer.size == 0) break;
-
// 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
@@ -802,13 +817,6 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
}
while (frames);
- // If no data was written, it is likely that obtainBuffer() did
- // not find room in PCM buffer: we release the processor for
- // a few millisecond before polling again for available room.
- if (writtenSize == 0) {
- usleep(5000);
- }
-
if (frames == 0) {
mRemainingFrames = mNotificationFrames;
} else {
@@ -872,7 +880,12 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)
u += frameCount;
// Ensure that user is never ahead of server for AudioRecord
- if (!out && u > this->server) {
+ if (out) {
+ // If stepServer() has been called once, switch to normal obtainBuffer() timeout period
+ if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {
+ bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ }
+ } else if (u > this->server) {
LOGW("stepServer occured after track reset");
u = this->server;
}
@@ -909,13 +922,20 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount)
uint32_t s = this->server;
s += frameCount;
- // 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
- // we have s > u
- if (out && s > this->user) {
- LOGW("stepServer occured after track reset");
- s = this->user;
+ if (out) {
+ // Mark that we have read the first buffer so that next time stepUser() is called
+ // 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
+ // we have s > u
+ if (s > this->user) {
+ LOGW("stepServer occured after track reset");
+ s = this->user;
+ }
}
if (s >= loopEnd) {