Merge "Make sure we restore our input buffer to its original state if we want to revisit it."
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 80d2d72..70f79c6 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -38,7 +38,7 @@
// ----------------------------------------------------------------------------
-class AudioRecord
+class AudioRecord : virtual public RefBase
{
public:
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4906bd3..98b1f3e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -138,7 +138,7 @@
* frameCount: Minimum size of track PCM buffer in frames. This defines the
* latency of the track. The actual size selected by the AudioTrack could be
* larger if the requested size is not compatible with current audio HAL
- * latency.
+ * latency. Zero means to use a default value.
* flags: See comments on audio_output_flags_t in <system/audio.h>.
* cbf: Callback function. If not null, this function is called periodically
* to request new PCM data.
@@ -460,12 +460,24 @@
{
public:
AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
+
+ // Do not call Thread::requestExitAndWait() without first calling requestExit().
+ // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
+ virtual void requestExit();
+
+ void pause(); // suspend thread from execution at next loop boundary
+ void resume(); // allow thread to execute, if not requested to exit
+
private:
friend class AudioTrack;
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
AudioTrack& mReceiver;
+ ~AudioTrackThread();
+ Mutex mMyLock; // Thread::mLock is private
+ Condition mMyCond; // Thread::mThreadExitedCondition is private
+ bool mPaused; // whether thread is currently paused
};
// body of AudioTrackThread::threadLoop()
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 04ac3ee..86e228b 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -65,6 +65,7 @@
track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ pid_t tid, // -1 means unused, otherwise must be valid non-0
int *sessionId,
status_t *status) = 0;
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index c486c6b..ebc03ea 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -35,10 +35,9 @@
DECLARE_META_INTERFACE(AudioRecord);
/* After it's created the track is not active. Call start() to
- * make it active. If set, the callback will start being called.
- * tid identifies the client callback thread, or 0 if not needed.
+ * make it active.
*/
- virtual status_t start(pid_t tid, int event, int triggerSession) = 0;
+ virtual status_t start(int event, int triggerSession) = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 577b095..9e0e389 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -39,10 +39,9 @@
virtual sp<IMemory> getCblk() const = 0;
/* After it's created the track is not active. Call start() to
- * make it active. If set, the callback will start being called.
- * tid identifies the client callback thread, or 0 if not needed.
+ * make it active.
*/
- virtual status_t start(pid_t tid) = 0;
+ virtual status_t start() = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 9a8f4b0..a70fe8c 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -63,6 +63,9 @@
// when the channel mask isn't known, use the channel count to derive a mask in AudioSink::open()
#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
+// duration below which we do not allow deep audio buffering
+#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
+
// callback mechanism for passing messages to MediaPlayer object
typedef void (*notify_callback_f)(void* cookie,
int msg, int ext1, int ext2, const Parcel *obj);
@@ -98,7 +101,8 @@
audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
AudioCallback cb = NULL,
- void *cookie = NULL) = 0;
+ void *cookie = NULL,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
virtual void start() = 0;
virtual ssize_t write(const void* buffer, size_t size) = 0;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 70c47ae..9e8e4bb 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -37,6 +37,7 @@
};
AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
+ bool allowDeepBuffering = false,
AwesomePlayer *audioObserver = NULL);
virtual ~AudioPlayer();
@@ -95,6 +96,8 @@
MediaBuffer *mFirstBuffer;
sp<MediaPlayerBase::AudioSink> mAudioSink;
+ bool mAllowDeepBuffering; // allow audio deep audio buffers. Helps with low power audio
+ // playback but implies high latency
AwesomePlayer *mObserver;
static void AudioCallback(int event, void *user, void *info);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index af2db93..469f5ff 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -53,6 +53,7 @@
#define CBLK_RESTORED_MSK 0x0040
#define CBLK_RESTORED_ON 0x0040 // track has been restored after invalidation
#define CBLK_RESTORED_OFF 0x0040 // by AudioFlinger
+#define CBLK_FAST 0x0080 // AudioFlinger successfully created a fast track
// Important: do not add any virtual methods, including ~
struct audio_track_cblk_t
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index c9cff81..fc9fb49 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -392,7 +392,7 @@
status_t VideoEditorPlayer::VeAudioOutput::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie) {
+ AudioCallback cb, void *cookie, audio_output_flags_t flags) {
mCallback = cb;
mCallbackCookie = cookie;
@@ -442,7 +442,7 @@
format,
channelMask,
frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
+ flags,
CallbackWrapper,
this);
} else {
@@ -451,7 +451,8 @@
sampleRate,
format,
channelMask,
- frameCount);
+ frameCount,
+ flags);
}
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index 350b384..2ab4eef 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -52,7 +52,7 @@
virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie);
+ AudioCallback cb, void *cookie, audio_output_flags_t flags);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1fdc536..950f5c6 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -321,8 +321,8 @@
cblk->lock.lock();
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- ALOGV("mAudioRecord->start(tid=%d)", tid);
- ret = mAudioRecord->start(tid, event, triggerSession);
+ ALOGV("mAudioRecord->start()");
+ ret = mAudioRecord->start(event, triggerSession);
cblk->lock.lock();
if (ret == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -542,7 +542,7 @@
"user=%08x, server=%08x", cblk->user, cblk->server);
cblk->lock.unlock();
// callback thread or sync event hasn't changed
- result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0);
+ result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -781,7 +781,7 @@
mFrameCount, getInput_l());
if (result == NO_ERROR) {
// callback thread or sync event hasn't changed
- result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0);
+ result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
}
if (result != NO_ERROR) {
mActive = false;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 092b516..9d338f3 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -73,6 +73,8 @@
*frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
afFrameCount * minBufCount * sampleRate / afSampleRate;
+ ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d",
+ *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
return NO_ERROR;
}
@@ -159,6 +161,7 @@
// Otherwise the callback thread will never exit.
stop();
if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
@@ -223,8 +226,13 @@
// force direct flag if format is not linear PCM
if (!audio_is_linear_pcm(format)) {
flags = (audio_output_flags_t)
+ // FIXME why can't we allow direct AND fast?
((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
}
+ // only allow deep buffering for music stream type
+ if (streamType != AUDIO_STREAM_MUSIC) {
+ flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ }
if (!audio_is_output_channel(channelMask)) {
ALOGE("Invalid channel mask");
@@ -251,6 +259,11 @@
mAuxEffectId = 0;
mCbf = cbf;
+ if (cbf != NULL) {
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+ }
+
// create the IAudioTrack
status_t status = createTrack_l(streamType,
sampleRate,
@@ -262,13 +275,13 @@
output);
if (status != NO_ERROR) {
+ if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExit();
+ mAudioTrackThread.clear();
+ }
return status;
}
- if (cbf != NULL) {
- mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
- }
-
mStatus = NO_ERROR;
mStreamType = streamType;
@@ -345,14 +358,6 @@
status_t status = NO_ERROR;
ALOGV("start %p", this);
- if (t != 0) {
- if (t->exitPending()) {
- if (t->requestExitAndWait() == WOULD_BLOCK) {
- ALOGE("AudioTrack::start called from thread");
- return;
- }
- }
- }
AutoMutex lock(mLock);
// acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
@@ -369,26 +374,19 @@
cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
cblk->waitTimeMs = 0;
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
- pid_t tid;
if (t != 0) {
- t->run("AudioTrack", ANDROID_PRIORITY_AUDIO);
- tid = t->getTid(); // pid_t is unknown until run()
- ALOGV("getTid=%d", tid);
- if (tid == -1) {
- tid = 0;
- }
+ t->resume();
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
- tid = 0; // not gettid()
}
ALOGV("start %p before lock cblk %p", this, mCblk);
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- ALOGV("mAudioTrack->start(tid=%d)", tid);
- status = mAudioTrack->start(tid);
+ ALOGV("mAudioTrack->start()");
+ status = mAudioTrack->start();
cblk->lock.lock();
if (status == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -402,7 +400,7 @@
ALOGV("start() failed");
mActive = false;
if (t != 0) {
- t->requestExit();
+ t->pause();
} else {
setpriority(PRIO_PROCESS, 0, mPreviousPriority);
androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
@@ -435,7 +433,7 @@
flush_l();
}
if (t != 0) {
- t->requestExit();
+ t->pause();
} else {
setpriority(PRIO_PROCESS, 0, mPreviousPriority);
androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup);
@@ -767,7 +765,7 @@
(sharedBuffer != 0) ||
// use case 2: callback handler
(mCbf != NULL))) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
}
ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency);
@@ -783,6 +781,13 @@
if (minBufCount < 2) minBufCount = 2;
int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+ ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d"
+ ", afLatency=%d",
+ minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
+#define MIN_FRAME_COUNT_FAST 128 // FIXME hard-coded
+ if ((flags & AUDIO_OUTPUT_FLAG_FAST) && (minFrameCount > MIN_FRAME_COUNT_FAST)) {
+ minFrameCount = MIN_FRAME_COUNT_FAST;
+ }
if (sharedBuffer == 0) {
if (frameCount == 0) {
@@ -796,7 +801,7 @@
if (mNotificationFramesAct > (uint32_t)frameCount/2) {
mNotificationFramesAct = frameCount/2;
}
- if (frameCount < minFrameCount && !(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+ if (frameCount < minFrameCount) {
// not ALOGW because it happens all the time when playing key clicks over A2DP
ALOGV("Minimum buffer size corrected from %d to %d",
frameCount, minFrameCount);
@@ -817,8 +822,13 @@
if (mIsTimed) {
trackFlags |= IAudioFlinger::TRACK_TIMED;
}
+
+ pid_t tid = -1;
if (flags & AUDIO_OUTPUT_FLAG_FAST) {
trackFlags |= IAudioFlinger::TRACK_FAST;
+ if (mAudioTrackThread != 0) {
+ tid = mAudioTrackThread->getTid();
+ }
}
sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
@@ -830,6 +840,7 @@
trackFlags,
sharedBuffer,
output,
+ tid,
&mSessionId,
&status);
@@ -845,7 +856,15 @@
mAudioTrack = track;
mCblkMemory = cblk;
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
- android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags);
+ // old has the previous value of mCblk->flags before the "or" operation
+ int32_t old = android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags);
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (old & CBLK_FAST) {
+ ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", mCblk->frameCount);
+ } else {
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", mCblk->frameCount);
+ }
+ }
if (sharedBuffer == 0) {
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
} else {
@@ -922,7 +941,7 @@
"user=%08x, server=%08x", this, cblk->user, cblk->server);
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
- result = mAudioTrack->start(0); // callback thread hasn't changed
+ result = mAudioTrack->start();
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -954,7 +973,7 @@
if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
ALOGW("obtainBuffer() track %p disabled, restarting", this);
- mAudioTrack->start(0); // callback thread hasn't changed
+ mAudioTrack->start();
}
cblk->waitTimeMs = 0;
@@ -1092,7 +1111,7 @@
if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
- mAudioTrack->start(0);
+ mAudioTrack->start();
}
return mAudioTrack->queueTimedBuffer(buffer, pts);
@@ -1297,7 +1316,7 @@
}
}
if (mActive) {
- result = mAudioTrack->start(0); // callback thread hasn't changed
+ result = mAudioTrack->start();
ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
}
if (fromStart && result == NO_ERROR) {
@@ -1365,12 +1384,24 @@
// =========================================================================
AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver)
+ : Thread(bCanCallJava), mReceiver(receiver), mPaused(true)
+{
+}
+
+AudioTrack::AudioTrackThread::~AudioTrackThread()
{
}
bool AudioTrack::AudioTrackThread::threadLoop()
{
+ {
+ AutoMutex _l(mMyLock);
+ if (mPaused) {
+ mMyCond.wait(mMyLock);
+ // caller will check for exitPending()
+ return true;
+ }
+ }
return mReceiver.processAudioBuffer(this);
}
@@ -1383,6 +1414,28 @@
{
}
+void AudioTrack::AudioTrackThread::requestExit()
+{
+ // must be in this order to avoid a race condition
+ Thread::requestExit();
+ mMyCond.signal();
+}
+
+void AudioTrack::AudioTrackThread::pause()
+{
+ AutoMutex _l(mMyLock);
+ mPaused = true;
+}
+
+void AudioTrack::AudioTrackThread::resume()
+{
+ AutoMutex _l(mMyLock);
+ if (mPaused) {
+ mPaused = false;
+ mMyCond.signal();
+ }
+}
+
// =========================================================================
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 2b5126f..e8dd438 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -91,6 +91,7 @@
track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ pid_t tid,
int *sessionId,
status_t *status)
{
@@ -106,6 +107,7 @@
data.writeInt32((int32_t) flags);
data.writeStrongBinder(sharedBuffer->asBinder());
data.writeInt32((int32_t) output);
+ data.writeInt32((int32_t) tid);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
@@ -701,11 +703,12 @@
track_flags_t flags = (track_flags_t) data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+ pid_t tid = (pid_t) data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
(audio_stream_type_t) streamType, sampleRate, format,
- channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+ channelCount, bufferCount, flags, buffer, output, tid, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 58c6d38..57a80a9 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,11 +42,10 @@
{
}
- virtual status_t start(pid_t tid, int event, int triggerSession)
+ virtual status_t start(int event, int triggerSession)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
- data.writeInt32(tid);
data.writeInt32(event);
data.writeInt32(triggerSession);
status_t status = remote()->transact(START, data, &reply);
@@ -93,10 +92,9 @@
} break;
case START: {
CHECK_INTERFACE(IAudioRecord, data, reply);
- pid_t tid = (pid_t) data.readInt32();
int event = data.readInt32();
int triggerSession = data.readInt32();
- reply->writeInt32(start(tid, event, triggerSession));
+ reply->writeInt32(start(event, triggerSession));
return NO_ERROR;
} break;
case STOP: {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 09f31a7..867d1a5 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -61,11 +61,10 @@
return cblk;
}
- virtual status_t start(pid_t tid)
+ virtual status_t start()
{
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
- data.writeInt32(tid);
status_t status = remote()->transact(START, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
@@ -180,7 +179,7 @@
} break;
case START: {
CHECK_INTERFACE(IAudioTrack, data, reply);
- reply->writeInt32(start(data.readInt32()));
+ reply->writeInt32(start());
return NO_ERROR;
} break;
case STOP: {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 7254599..bfdf250 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1412,7 +1412,8 @@
mCallbackCookie(NULL),
mCallbackData(NULL),
mBytesWritten(0),
- mSessionId(sessionId) {
+ mSessionId(sessionId),
+ mFlags(AUDIO_OUTPUT_FLAG_NONE) {
ALOGV("AudioOutput(%d)", sessionId);
mTrack = 0;
mRecycledTrack = 0;
@@ -1506,7 +1507,8 @@
status_t MediaPlayerService::AudioOutput::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie)
+ AudioCallback cb, void *cookie,
+ audio_output_flags_t flags)
{
mCallback = cb;
mCallbackCookie = cookie;
@@ -1521,7 +1523,7 @@
format, bufferCount, mSessionId);
int afSampleRate;
int afFrameCount;
- int frameCount;
+ uint32_t frameCount;
if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
return NO_INIT;
@@ -1539,6 +1541,7 @@
return NO_INIT;
}
}
+
if (mRecycledTrack) {
// check if the existing track can be reused as-is, or if a new track needs to be created.
@@ -1553,6 +1556,9 @@
(mRecycledTrack->frameCount() != frameCount)) {
ALOGV("samplerate, channelcount or framecount differ");
reuse = false;
+ } if (flags != mFlags) {
+ ALOGV("output flags differ");
+ reuse = false;
}
if (reuse) {
ALOGV("chaining to next output");
@@ -1587,7 +1593,7 @@
format,
channelMask,
frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
+ flags,
CallbackWrapper,
mCallbackData,
0, // notification frames
@@ -1599,7 +1605,7 @@
format,
channelMask,
frameCount,
- AUDIO_OUTPUT_FLAG_NONE,
+ flags,
NULL,
NULL,
0,
@@ -1616,6 +1622,7 @@
t->setVolume(mLeftVolume, mRightVolume);
mSampleRateHz = sampleRate;
+ mFlags = flags;
mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
uint32_t pos;
if (t->getPosition(&pos) == OK) {
@@ -1891,7 +1898,7 @@
status_t MediaPlayerService::AudioCache::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie)
+ AudioCallback cb, void *cookie, audio_output_flags_t flags)
{
ALOGV("open(%u, %d, 0x%x, %d, %d)", sampleRate, channelCount, channelMask, format, bufferCount);
if (mHeap->getHeapID() < 0) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 2a8cfd2..95b1b05 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -91,7 +91,8 @@
virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie);
+ AudioCallback cb, void *cookie,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
@@ -135,6 +136,7 @@
int mAuxEffectId;
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
+ audio_output_flags_t mFlags;
// CallbackData is what is passed to the AudioTrack as the "user" data.
// We need to be able to target this to a different Output on the fly,
@@ -190,7 +192,8 @@
virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount = 1,
- AudioCallback cb = NULL, void *cookie = NULL);
+ AudioCallback cb = NULL, void *cookie = NULL,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 11cea3b..f1467c4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -390,12 +390,30 @@
sampleRate, numChannels);
mAudioSink->close();
+
+ audio_output_flags_t flags;
+ int64_t durationUs;
+ // FIXME: we should handle the case where the video decoder is created after
+ // we receive the format change indication. Current code will just make that
+ // we select deep buffer with video which should not be a problem as it should
+ // not prevent from keeping A/V sync.
+ if (mVideoDecoder == NULL &&
+ mSource->getDuration(&durationUs) == OK &&
+ durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
+ flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ } else {
+ flags = AUDIO_OUTPUT_FLAG_NONE;
+ }
+
CHECK_EQ(mAudioSink->open(
sampleRate,
numChannels,
CHANNEL_MASK_USE_CHANNEL_ORDER,
AUDIO_FORMAT_PCM_16_BIT,
- 8 /* bufferCount */),
+ 8 /* bufferCount */,
+ NULL,
+ NULL,
+ flags),
(status_t)OK);
mAudioSink->start();
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 468fe2c..2e0b013 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -33,6 +33,7 @@
AudioPlayer::AudioPlayer(
const sp<MediaPlayerBase::AudioSink> &audioSink,
+ bool allowDeepBuffering,
AwesomePlayer *observer)
: mAudioTrack(NULL),
mInputBuffer(NULL),
@@ -50,6 +51,7 @@
mFirstBufferResult(OK),
mFirstBuffer(NULL),
mAudioSink(audioSink),
+ mAllowDeepBuffering(allowDeepBuffering),
mObserver(observer) {
}
@@ -120,10 +122,15 @@
}
if (mAudioSink.get() != NULL) {
+
status_t err = mAudioSink->open(
mSampleRate, numChannels, channelMask, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
- &AudioPlayer::AudioSinkCallback, this);
+ &AudioPlayer::AudioSinkCallback,
+ this,
+ (mAllowDeepBuffering ?
+ AUDIO_OUTPUT_FLAG_DEEP_BUFFER :
+ AUDIO_OUTPUT_FLAG_NONE));
if (err != OK) {
if (mFirstBuffer != NULL) {
mFirstBuffer->release();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b67476b..b15cb67 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -870,7 +870,18 @@
if (mAudioSource != NULL) {
if (mAudioPlayer == NULL) {
if (mAudioSink != NULL) {
- mAudioPlayer = new AudioPlayer(mAudioSink, this);
+ bool allowDeepBuffering;
+ int64_t cachedDurationUs;
+ bool eos;
+ if (mVideoSource == NULL && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US ||
+ getCachedDuration_l(&cachedDurationUs, &eos) &&
+ cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US)) {
+ allowDeepBuffering = true;
+ } else {
+ allowDeepBuffering = false;
+ }
+
+ mAudioPlayer = new AudioPlayer(mAudioSink, allowDeepBuffering, this);
mAudioPlayer->setSource(mAudioSource);
mTimeSource = mAudioPlayer;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 4667649..7202b8b 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -68,4 +68,6 @@
LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
+LOCAL_CFLAGS += -UHAVE_REQUEST_PRIORITY
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bce30d7..865051f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -401,6 +401,7 @@
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ pid_t tid,
int *sessionId,
status_t *status)
{
@@ -458,9 +459,8 @@
}
ALOGV("createTrack() lSessionId: %d", lSessionId);
- bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
track = thread->createTrack_l(client, streamType, sampleRate, format,
- channelMask, frameCount, sharedBuffer, lSessionId, flags, &lStatus);
+ channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus);
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
@@ -1569,6 +1569,7 @@
const sp<IMemory>& sharedBuffer,
int sessionId,
IAudioFlinger::track_flags_t flags,
+ pid_t tid,
status_t *status)
{
sp<Track> track;
@@ -1589,7 +1590,7 @@
) ||
// use case 2: callback handler and small power-of-2 frame count
(
- // unfortunately we can't verify that there's a callback until start()
+ (tid != -1) &&
// FIXME supported frame counts should not be hard-coded
(
(frameCount == 128) ||
@@ -1678,6 +1679,20 @@
chain->incTrackCnt();
}
}
+
+#ifdef HAVE_REQUEST_PRIORITY
+ if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
+ // so ask activity manager to do this on our behalf
+ int err = requestPriority(callingPid, tid, 1);
+ if (err != 0) {
+ ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+ 1, callingPid, tid, err);
+ }
+ }
+#endif
+
lStatus = NO_ERROR;
Exit:
@@ -3681,20 +3696,11 @@
return false;
}
-status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid,
- AudioSystem::sync_event_t event,
+status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event,
int triggerSession)
{
status_t status = NO_ERROR;
- ALOGV("start(%d), calling pid %d session %d tid %d",
- mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
- // check for use case 2 with missing callback
- if (isFastTrack() && (mSharedBuffer == 0) && (tid == 0)) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
- mFlags &= ~IAudioFlinger::TRACK_FAST;
- // FIXME the track must be invalidated and moved to another thread or
- // attached directly to the normal mixer now
- }
+
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -4467,14 +4473,13 @@
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid,
- AudioSystem::sync_event_t event,
+status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event,
int triggerSession)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
- return recordThread->start(this, tid, event, triggerSession);
+ return recordThread->start(this, event, triggerSession);
} else {
return BAD_VALUE;
}
@@ -4541,11 +4546,10 @@
clearBufferQueue();
}
-status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid,
- AudioSystem::sync_event_t event,
+status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event,
int triggerSession)
{
- status_t status = Track::start(tid, event, triggerSession);
+ status_t status = Track::start(event, triggerSession);
if (status != NO_ERROR) {
return status;
}
@@ -4575,7 +4579,7 @@
uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
if (!mActive && frames != 0) {
- start(0);
+ start();
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
MixerThread *mixerThread = (MixerThread *)thread.get();
@@ -4834,8 +4838,8 @@
return mTrack->getCblk();
}
-status_t AudioFlinger::TrackHandle::start(pid_t tid) {
- return mTrack->start(tid);
+status_t AudioFlinger::TrackHandle::start() {
+ return mTrack->start();
}
void AudioFlinger::TrackHandle::stop() {
@@ -4988,9 +4992,9 @@
return mRecordTrack->getCblk();
}
-status_t AudioFlinger::RecordHandle::start(pid_t tid, int event, int triggerSession) {
+status_t AudioFlinger::RecordHandle::start(int event, int triggerSession) {
ALOGV("RecordHandle::start()");
- return mRecordTrack->start(tid, (AudioSystem::sync_event_t)event, triggerSession);
+ return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
}
void AudioFlinger::RecordHandle::stop() {
@@ -5291,9 +5295,10 @@
}
status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack,
- pid_t tid, AudioSystem::sync_event_t event,
+ AudioSystem::sync_event_t event,
int triggerSession)
{
+ // FIXME use tid here
ALOGV("RecordThread::start tid=%d, event %d, triggerSession %d", tid, event, triggerSession);
sp<ThreadBase> strongMe = this;
status_t status = NO_ERROR;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b1c5554..6b18945 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -91,6 +91,7 @@
IAudioFlinger::track_flags_t flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
+ pid_t tid,
int *sessionId,
status_t *status);
@@ -376,8 +377,7 @@
int sessionId);
virtual ~TrackBase();
- virtual status_t start(pid_t tid,
- AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+ virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0) = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const { return mCblkMemory; }
@@ -669,8 +669,7 @@
virtual ~Track();
void dump(char* buffer, size_t size);
- virtual status_t start(pid_t tid,
- AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+ virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0);
virtual void stop();
void pause();
@@ -855,8 +854,7 @@
int frameCount);
virtual ~OutputTrack();
- virtual status_t start(pid_t tid,
- AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+ virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0);
virtual void stop();
bool write(int16_t* data, uint32_t frames);
@@ -933,6 +931,7 @@
const sp<IMemory>& sharedBuffer,
int sessionId,
IAudioFlinger::track_flags_t flags,
+ pid_t tid,
status_t *status);
AudioStreamOut* getOutput() const;
@@ -1188,7 +1187,7 @@
TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start(pid_t tid);
+ virtual status_t start();
virtual void stop();
virtual void flush();
virtual void mute(bool);
@@ -1227,8 +1226,7 @@
int sessionId);
virtual ~RecordTrack();
- virtual status_t start(pid_t tid,
- AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
+ virtual status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
int triggerSession = 0);
virtual void stop();
@@ -1276,7 +1274,7 @@
int sessionId,
status_t *status);
- status_t start(RecordTrack* recordTrack, pid_t tid,
+ status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
int triggerSession);
void stop(RecordTrack* recordTrack);
@@ -1335,7 +1333,7 @@
RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start(pid_t tid, int event, int triggerSession);
+ virtual status_t start(int event, int triggerSession);
virtual void stop();
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);