Merge "Shorten thread names"
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index f269e80..fac3a8c 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -396,7 +396,7 @@
for (size_t i = 0; i < mStateByTrackIndex.size(); ++i) {
CodecState *state = &mStateByTrackIndex.editValueAt(i);
- CHECK_EQ(state->mCodec->stop(), (status_t)OK);
+ CHECK_EQ(state->mCodec->release(), (status_t)OK);
}
mStartTimeRealUs = -1ll;
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index b850190..fbf800c 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -295,7 +295,7 @@
for (size_t i = 0; i < stateByTrack.size(); ++i) {
CodecState *state = &stateByTrack.editValueAt(i);
- CHECK_EQ((status_t)OK, state->mCodec->stop());
+ CHECK_EQ((status_t)OK, state->mCodec->release());
}
return 0;
diff --git a/drm/drmserver/main_drmserver.cpp b/drm/drmserver/main_drmserver.cpp
index e61b269..434d561 100644
--- a/drm/drmserver/main_drmserver.cpp
+++ b/drm/drmserver/main_drmserver.cpp
@@ -17,15 +17,10 @@
#define LOG_TAG "drmserver"
//#define LOG_NDEBUG 0
-#include <sys/types.h>
-#include <unistd.h>
-#include <grp.h>
-
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
-#include <private/android_filesystem_config.h>
#include <DrmManagerService.h>
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 437a89c..b0c581a 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -225,7 +225,7 @@
/* get sample rate for this record track
*/
- uint32_t getSampleRate();
+ uint32_t getSampleRate() const;
/* Sets marker position. When record reaches the number of frames specified,
* a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
@@ -242,7 +242,7 @@
* - INVALID_OPERATION: the AudioRecord has no callback installed.
*/
status_t setMarkerPosition(uint32_t marker);
- status_t getMarkerPosition(uint32_t *marker);
+ status_t getMarkerPosition(uint32_t *marker) const;
/* Sets position update period. Every time the number of frames specified has been recorded,
@@ -261,7 +261,7 @@
* - INVALID_OPERATION: the AudioRecord has no callback installed.
*/
status_t setPositionUpdatePeriod(uint32_t updatePeriod);
- status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
+ status_t getPositionUpdatePeriod(uint32_t *updatePeriod) const;
/* Gets record head position. The position is the total number of frames
@@ -275,7 +275,7 @@
* - NO_ERROR: successful operation
* - BAD_VALUE: position is NULL
*/
- status_t getPosition(uint32_t *position);
+ status_t getPosition(uint32_t *position) const;
/* returns a handle on the audio input used by this AudioRecord.
*
@@ -285,7 +285,7 @@
* Returned value:
* handle on audio hardware input
*/
- audio_io_handle_t getInput();
+ audio_io_handle_t getInput() const;
/* returns the audio session ID associated to this AudioRecord.
*
@@ -295,7 +295,7 @@
* Returned value:
* AudioRecord session ID.
*/
- int getSessionId();
+ int getSessionId() const;
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
@@ -326,7 +326,7 @@
* Such loss typically occurs when the user space process is blocked longer than the capacity of audio driver buffers.
* Unit: the number of input audio frames
*/
- unsigned int getInputFramesLost();
+ unsigned int getInputFramesLost() const;
private:
/* copying audio tracks is not allowed */
@@ -360,7 +360,7 @@
sp<IMemory> mCblkMemory;
sp<ClientRecordThread> mClientRecordThread;
status_t mReadyToRun;
- Mutex mLock;
+ mutable Mutex mLock;
Condition mCondition;
uint32_t mFrameCount;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 70799a6..6735aff 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -49,7 +49,7 @@
void initiateSetup(const sp<AMessage> &msg);
void signalFlush();
void signalResume();
- void initiateShutdown();
+ void initiateShutdown(bool keepComponentAllocated = false);
void initiateAllocateComponent(const sp<AMessage> &msg);
void initiateConfigureComponent(const sp<AMessage> &msg);
@@ -61,6 +61,7 @@
private:
struct BaseState;
struct UninitializedState;
+ struct LoadedState;
struct LoadedToIdleState;
struct IdleToExecutingState;
struct ExecutingState;
@@ -107,6 +108,7 @@
sp<AMessage> mNotify;
sp<UninitializedState> mUninitializedState;
+ sp<LoadedState> mLoadedState;
sp<LoadedToIdleState> mLoadedToIdleState;
sp<IdleToExecutingState> mIdleToExecutingState;
sp<ExecutingState> mExecutingState;
@@ -131,6 +133,12 @@
bool mSentFormat;
bool mIsEncoder;
+ bool mShutdownInProgress;
+
+ // If "mKeepComponentAllocated" we only transition back to Loaded state
+ // and do not release the component instance.
+ bool mKeepComponentAllocated;
+
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffer(OMX_U32 portIndex, size_t i);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 8c11c9c..72ac56a 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -53,8 +53,15 @@
uint32_t flags);
status_t start();
+
+ // Returns to a state in which the component remains allocated but
+ // unconfigured.
status_t stop();
+ // Client MUST call release before releasing final reference to this
+ // object.
+ status_t release();
+
status_t flush();
status_t queueInputBuffer(
@@ -97,6 +104,7 @@
STARTED,
FLUSHING,
STOPPING,
+ RELEASING,
};
enum {
@@ -109,6 +117,7 @@
kWhatConfigure = 'conf',
kWhatStart = 'strt',
kWhatStop = 'stop',
+ kWhatRelease = 'rele',
kWhatDequeueInputBuffer = 'deqI',
kWhatQueueInputBuffer = 'queI',
kWhatDequeueOutputBuffer = 'deqO',
diff --git a/media/libstagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
similarity index 100%
rename from media/libstagefright/timedtext/TimedTextDriver.h
rename to include/media/stagefright/timedtext/TimedTextDriver.h
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index dd73a8e..943f3af 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -386,7 +386,7 @@
return !mActive;
}
-uint32_t AudioRecord::getSampleRate()
+uint32_t AudioRecord::getSampleRate() const
{
AutoMutex lock(mLock);
return mCblk->sampleRate;
@@ -402,7 +402,7 @@
return NO_ERROR;
}
-status_t AudioRecord::getMarkerPosition(uint32_t *marker)
+status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
{
if (marker == NULL) return BAD_VALUE;
@@ -423,7 +423,7 @@
return NO_ERROR;
}
-status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
+status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) const
{
if (updatePeriod == NULL) return BAD_VALUE;
@@ -432,7 +432,7 @@
return NO_ERROR;
}
-status_t AudioRecord::getPosition(uint32_t *position)
+status_t AudioRecord::getPosition(uint32_t *position) const
{
if (position == NULL) return BAD_VALUE;
@@ -442,7 +442,7 @@
return NO_ERROR;
}
-unsigned int AudioRecord::getInputFramesLost()
+unsigned int AudioRecord::getInputFramesLost() const
{
if (mActive)
return AudioSystem::getInputFramesLost(mInput);
@@ -597,7 +597,7 @@
mCblk->stepUser(audioBuffer->frameCount);
}
-audio_io_handle_t AudioRecord::getInput()
+audio_io_handle_t AudioRecord::getInput() const
{
AutoMutex lock(mLock);
return mInput;
@@ -615,7 +615,7 @@
return mInput;
}
-int AudioRecord::getSessionId()
+int AudioRecord::getSessionId() const
{
return mSessionId;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 85bd7ba..9a9d094 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -165,18 +165,36 @@
protected:
virtual bool onMessageReceived(const sp<AMessage> &msg);
+ virtual void stateEntered();
private:
void onSetup(const sp<AMessage> &msg);
- void onAllocateComponent(const sp<AMessage> &msg);
- void onConfigureComponent(const sp<AMessage> &msg);
- void onStart();
+ bool onAllocateComponent(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
};
////////////////////////////////////////////////////////////////////////////////
+struct ACodec::LoadedState : public ACodec::BaseState {
+ LoadedState(ACodec *codec);
+
+protected:
+ virtual bool onMessageReceived(const sp<AMessage> &msg);
+ virtual void stateEntered();
+
+private:
+ friend struct ACodec::UninitializedState;
+
+ bool onConfigureComponent(const sp<AMessage> &msg);
+ void onStart();
+ void onShutdown(bool keepComponentAllocated);
+
+ DISALLOW_EVIL_CONSTRUCTORS(LoadedState);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
struct ACodec::LoadedToIdleState : public ACodec::BaseState {
LoadedToIdleState(ACodec *codec);
@@ -312,8 +330,10 @@
ACodec::ACodec()
: mNode(NULL),
mSentFormat(false),
- mIsEncoder(false) {
+ mIsEncoder(false),
+ mShutdownInProgress(false) {
mUninitializedState = new UninitializedState(this);
+ mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
mIdleToExecutingState = new IdleToExecutingState(this);
mExecutingState = new ExecutingState(this);
@@ -369,8 +389,10 @@
(new AMessage(kWhatResume, id()))->post();
}
-void ACodec::initiateShutdown() {
- (new AMessage(kWhatShutdown, id()))->post();
+void ACodec::initiateShutdown(bool keepComponentAllocated) {
+ sp<AMessage> msg = new AMessage(kWhatShutdown, id());
+ msg->setInt32("keepComponentAllocated", keepComponentAllocated);
+ msg->post();
}
status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
@@ -2492,6 +2514,10 @@
: BaseState(codec) {
}
+void ACodec::UninitializedState::stateEntered() {
+ ALOGV("Now uninitialized");
+}
+
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
@@ -2511,22 +2537,13 @@
break;
}
- case ACodec::kWhatConfigureComponent:
- {
- onConfigureComponent(msg);
- handled = true;
- break;
- }
-
- case ACodec::kWhatStart:
- {
- onStart();
- handled = true;
- break;
- }
-
case ACodec::kWhatShutdown:
{
+ int32_t keepComponentAllocated;
+ CHECK(msg->findInt32(
+ "keepComponentAllocated", &keepComponentAllocated));
+ CHECK(!keepComponentAllocated);
+
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", ACodec::kWhatShutdownCompleted);
notify->post();
@@ -2554,22 +2571,16 @@
void ACodec::UninitializedState::onSetup(
const sp<AMessage> &msg) {
- onAllocateComponent(msg);
- onConfigureComponent(msg);
- onStart();
+ if (onAllocateComponent(msg)
+ && mCodec->mLoadedState->onConfigureComponent(msg)) {
+ mCodec->mLoadedState->onStart();
+ }
}
-void ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
+bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
ALOGV("onAllocateComponent");
- if (mCodec->mNode != NULL) {
- CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
-
- mCodec->mNativeWindow.clear();
- mCodec->mNode = NULL;
- mCodec->mOMX.clear();
- mCodec->mComponentName.clear();
- }
+ CHECK(mCodec->mNode == NULL);
OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);
@@ -2628,7 +2639,7 @@
}
mCodec->signalError(OMX_ErrorComponentNotFound);
- return;
+ return false;
}
sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id());
@@ -2649,9 +2660,96 @@
notify->setString("componentName", mCodec->mComponentName.c_str());
notify->post();
}
+
+ mCodec->changeState(mCodec->mLoadedState);
+
+ return true;
}
-void ACodec::UninitializedState::onConfigureComponent(
+////////////////////////////////////////////////////////////////////////////////
+
+ACodec::LoadedState::LoadedState(ACodec *codec)
+ : BaseState(codec) {
+}
+
+void ACodec::LoadedState::stateEntered() {
+ ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
+
+ if (mCodec->mShutdownInProgress) {
+ bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
+
+ mCodec->mShutdownInProgress = false;
+ mCodec->mKeepComponentAllocated = false;
+
+ onShutdown(keepComponentAllocated);
+ }
+}
+
+void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) {
+ if (!keepComponentAllocated) {
+ CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
+
+ mCodec->mNativeWindow.clear();
+ mCodec->mNode = NULL;
+ mCodec->mOMX.clear();
+ mCodec->mComponentName.clear();
+
+ mCodec->changeState(mCodec->mUninitializedState);
+ }
+
+ sp<AMessage> notify = mCodec->mNotify->dup();
+ notify->setInt32("what", ACodec::kWhatShutdownCompleted);
+ notify->post();
+}
+
+bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {
+ bool handled = false;
+
+ switch (msg->what()) {
+ case ACodec::kWhatConfigureComponent:
+ {
+ onConfigureComponent(msg);
+ handled = true;
+ break;
+ }
+
+ case ACodec::kWhatStart:
+ {
+ onStart();
+ handled = true;
+ break;
+ }
+
+ case ACodec::kWhatShutdown:
+ {
+ int32_t keepComponentAllocated;
+ CHECK(msg->findInt32(
+ "keepComponentAllocated", &keepComponentAllocated));
+
+ onShutdown(keepComponentAllocated);
+
+ handled = true;
+ break;
+ }
+
+ case ACodec::kWhatFlush:
+ {
+ sp<AMessage> notify = mCodec->mNotify->dup();
+ notify->setInt32("what", ACodec::kWhatFlushCompleted);
+ notify->post();
+
+ handled = true;
+ break;
+ }
+
+ default:
+ return BaseState::onMessageReceived(msg);
+ }
+
+ return handled;
+}
+
+bool ACodec::LoadedState::onConfigureComponent(
const sp<AMessage> &msg) {
ALOGV("onConfigureComponent");
@@ -2664,7 +2762,7 @@
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, err);
- return;
+ return false;
}
sp<RefBase> obj;
@@ -2682,9 +2780,11 @@
notify->setInt32("what", ACodec::kWhatComponentConfigured);
notify->post();
}
+
+ return true;
}
-void ACodec::UninitializedState::onStart() {
+void ACodec::LoadedState::onStart() {
ALOGV("onStart");
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -2873,6 +2973,13 @@
switch (msg->what()) {
case kWhatShutdown:
{
+ int32_t keepComponentAllocated;
+ CHECK(msg->findInt32(
+ "keepComponentAllocated", &keepComponentAllocated));
+
+ mCodec->mShutdownInProgress = true;
+ mCodec->mKeepComponentAllocated = keepComponentAllocated;
+
mActive = false;
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -3210,20 +3317,7 @@
CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet);
CHECK_EQ(data2, (OMX_U32)OMX_StateLoaded);
- ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str());
-
- CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK);
-
- mCodec->mNativeWindow.clear();
- mCodec->mNode = NULL;
- mCodec->mOMX.clear();
- mCodec->mComponentName.clear();
-
- mCodec->changeState(mCodec->mUninitializedState);
-
- sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", ACodec::kWhatShutdownCompleted);
- notify->post();
+ mCodec->changeState(mCodec->mLoadedState);
return true;
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index cfb1e29..95bcada 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -58,6 +58,7 @@
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/include/media/stagefright/openmax \
+ $(TOP)/frameworks/base/include/media/stagefright/timedtext \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
$(TOP)/external/openssl/include \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8cfb8d3..b21e86a 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -30,13 +30,12 @@
#include "include/MPEG2TSExtractor.h"
#include "include/WVMExtractor.h"
-#include "timedtext/TimedTextDriver.h"
-
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/timedtext/TimedTextDriver.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e14b1c4..a9e7f36 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -164,6 +164,13 @@
return PostAndAwaitResponse(msg, &response);
}
+status_t MediaCodec::release() {
+ sp<AMessage> msg = new AMessage(kWhatRelease, id());
+
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+
status_t MediaCodec::queueInputBuffer(
size_t index,
size_t offset,
@@ -422,6 +429,7 @@
}
case STOPPING:
+ case RELEASING:
{
// Ignore the error, assuming we'll still get
// the shutdown complete notification.
@@ -577,7 +585,9 @@
{
/* size_t index = */updateBuffers(kPortIndexInput, msg);
- if (mState == FLUSHING || mState == STOPPING) {
+ if (mState == FLUSHING
+ || mState == STOPPING
+ || mState == RELEASING) {
returnBuffersToCodecOnPort(kPortIndexInput);
break;
}
@@ -596,7 +606,9 @@
{
/* size_t index = */updateBuffers(kPortIndexOutput, msg);
- if (mState == FLUSHING || mState == STOPPING) {
+ if (mState == FLUSHING
+ || mState == STOPPING
+ || mState == RELEASING) {
returnBuffersToCodecOnPort(kPortIndexOutput);
break;
}
@@ -628,8 +640,12 @@
case ACodec::kWhatShutdownCompleted:
{
- CHECK_EQ(mState, STOPPING);
- setState(UNINITIALIZED);
+ if (mState == STOPPING) {
+ setState(INITIALIZED);
+ } else {
+ CHECK_EQ(mState, RELEASING);
+ setState(UNINITIALIZED);
+ }
(new AMessage)->postReply(mReplyID);
break;
@@ -767,6 +783,28 @@
mReplyID = replyID;
setState(STOPPING);
+ mCodec->initiateShutdown(true /* keepComponentAllocated */);
+ returnBuffersToCodec();
+ break;
+ }
+
+ case kWhatRelease:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ if (mState != INITIALIZED
+ && mState != CONFIGURED && mState != STARTED) {
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", INVALID_OPERATION);
+
+ response->postReply(replyID);
+ break;
+ }
+
+ mReplyID = replyID;
+ setState(RELEASING);
+
mCodec->initiateShutdown();
returnBuffersToCodec();
break;
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index dde2066..d2d5f7b 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -12,6 +12,7 @@
LOCAL_CFLAGS += -Wno-multichar
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
+ $(TOP)/frameworks/base/include/media/stagefright/timedtext \
$(TOP)/frameworks/base/media/libstagefright
LOCAL_MODULE:= libstagefright_timedtext
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 9ec9415..c70870e 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -27,8 +27,7 @@
#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-
-#include "TimedTextDriver.h"
+#include <media/stagefright/timedtext/TimedTextDriver.h>
#include "TextDescriptions.h"
#include "TimedTextPlayer.h"
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index bf7cbf6..bda7b46 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -20,12 +20,12 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/timedtext/TimedTextDriver.h>
#include <media/stagefright/MediaErrors.h>
#include <media/MediaPlayerInterface.h>
#include "TimedTextPlayer.h"
-#include "TimedTextDriver.h"
#include "TimedTextSource.h"
namespace android {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b7ddbb5..8f7b35c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1993,9 +1993,12 @@
bool AudioFlinger::MixerThread::threadLoop()
{
+ // DirectOutputThread has single trackToRemove instead of Vector
Vector< sp<Track> > tracksToRemove;
+ // DirectOutputThread has activeTrack here
nsecs_t standbyTime = systemTime();
size_t mixBufferSize = mFrameCount * mFrameSize;
+
// FIXME: Relaxed timing because of a certain device that can't meet latency
// Should be reduced to 2x after the vendor fixes the driver issue
// increase threshold again due to low power audio mode. The way this warning threshold is
@@ -2003,18 +2006,26 @@
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 15;
nsecs_t lastWarning = 0;
bool longStandbyExit = false;
+
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
+
uint32_t sleepTimeShift = 0;
- Vector< sp<EffectChain> > effectChains;
CpuStats cpuStats;
+ // DirectOutputThread has shorter standbyDelay
+
acquireWakeLock();
while (!exitPending())
{
cpuStats.sample();
+
+ // DirectOutputThread has rampVolume, leftVol, rightVol
+
+ Vector< sp<EffectChain> > effectChains;
+
processConfigEvents();
mixer_state mixerStatus = MIXER_IDLE;
@@ -2024,28 +2035,29 @@
if (checkForNewParameters_l()) {
mixBufferSize = mFrameCount * mFrameSize;
+
// FIXME: Relaxed timing because of a certain device that can't meet latency
// Should be reduced to 2x after the vendor fixes the driver issue
// increase threshold again due to low power audio mode. The way this warning
// threshold is calculated and its usefulness should be reconsidered anyway.
maxPeriod = seconds(mFrameCount) / mSampleRate * 15;
+
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
+ // DirectOutputThread updates standbyDelay also
}
- const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
// put audio hardware into standby after short delay
- if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
- mSuspended)) {
+ if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
+ mSuspended > 0)) {
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended);
+ ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
}
- if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
// we're about to wait, flush the binder command buffer
IPCThreadState::self()->flushCommands();
@@ -2068,7 +2080,7 @@
}
}
- mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+ mixerStatus = prepareTracks_l(&tracksToRemove);
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
@@ -2130,12 +2142,15 @@
// TODO add standby time extension fct of effect tail
}
- if (mSuspended) {
+ if (mSuspended > 0) {
sleepTime = suspendSleepTimeUs();
}
// only process effects if we're going to write
if (sleepTime == 0) {
+
+ // DirectOutputThread adds applyVolume here
+
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
@@ -2146,14 +2161,16 @@
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {
+ // FIXME Only in MixerThread, and rewrite to reduce number of system calls
mLastWriteTime = systemTime();
mInWrite = true;
mBytesWritten += mixBufferSize;
-
int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
mNumWrites++;
mInWrite = false;
+
+ // Only in MixerThread: start of write blocked detection
nsecs_t now = systemTime();
nsecs_t delta = now - mLastWriteTime;
if (!mStandby && delta > maxPeriod) {
@@ -2167,12 +2184,14 @@
longStandbyExit = true;
}
}
+ // end of write blocked detection
+
mStandby = false;
} else {
usleep(sleepTime);
}
- // finally let go of all our tracks, without the lock held
+ // finally let go of removed track(s), without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove.clear();
@@ -2180,8 +2199,12 @@
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains.clear();
+
+ // FIXME Note that the above .clear() is no longer necessary since effectChains
+ // is now local to this block, but will keep it for now (at least until merge done).
}
+ // put output stream into standby mode
if (!mStandby) {
mOutput->stream->common.standby(&mOutput->stream->common);
}
@@ -2194,12 +2217,12 @@
// prepareTracks_l() must be called with ThreadBase::mLock held
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
- const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
+ Vector< sp<Track> > *tracksToRemove)
{
mixer_state mixerStatus = MIXER_IDLE;
// find out which tracks need to be processed
- size_t count = activeTracks.size();
+ size_t count = mActiveTracks.size();
size_t mixedTracks = 0;
size_t tracksWithEffect = 0;
@@ -2219,7 +2242,7 @@
}
for (size_t i=0 ; i<count ; i++) {
- sp<Track> t = activeTracks[i].promote();
+ sp<Track> t = mActiveTracks[i].promote();
if (t == 0) continue;
// this const just means the local variable doesn't change
@@ -2706,13 +2729,20 @@
bool AudioFlinger::DirectOutputThread::threadLoop()
{
+ // MixerThread has Vector instead of single trackToRemove
sp<Track> trackToRemove;
- sp<Track> activeTrack;
+
nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount*mFrameSize;
+ size_t mixBufferSize = mFrameCount * mFrameSize;
+
+ // MixerThread has relaxed timing: maxPeriod, lastWarning, longStandbyExit
+
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
+
+ // MixerThread has sleepTimeShift and cpuStats
+
// use shorter standby delay as on normal output to release
// hardware resources as soon as possible
nsecs_t standbyDelay = microseconds(activeSleepTime*2);
@@ -2721,20 +2751,30 @@
while (!exitPending())
{
+ // MixerThread has cpuStats.sample()
+
bool rampVolume;
uint16_t leftVol;
uint16_t rightVol;
+
Vector< sp<EffectChain> > effectChains;
processConfigEvents();
+ // MixerThread does not have activeTrack here
+ sp<Track> activeTrack;
+
mixer_state mixerStatus = MIXER_IDLE;
{ // scope for the mLock
Mutex::Autolock _l(mLock);
if (checkForNewParameters_l()) {
- mixBufferSize = mFrameCount*mFrameSize;
+ mixBufferSize = mFrameCount * mFrameSize;
+
+ // different calculations here
+ standbyDelay = microseconds(activeSleepTime*2);
+
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
standbyDelay = microseconds(activeSleepTime*2);
@@ -2742,10 +2782,9 @@
// put audio hardware into standby after short delay
if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
- mSuspended)) {
- // wait until we have something to do...
+ mSuspended > 0)) {
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended);
+ ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
mOutput->stream->common.standby(&mOutput->stream->common);
mStandby = true;
mBytesWritten = 0;
@@ -2758,19 +2797,27 @@
if (exitPending()) break;
releaseWakeLock_l();
+ // wait until we have something to do...
ALOGV("Thread %p type %d TID %d going to sleep", this, mType, gettid());
mWaitWorkCV.wait(mLock);
ALOGV("Thread %p type %d TID %d waking up", this, mType, gettid());
acquireWakeLock_l();
+ // MixerThread has "mPrevMixerStatus = MIXER_IDLE"
checkSilentMode_l();
+ // MixerThread has different standbyDelay
standbyTime = systemTime() + standbyDelay;
sleepTime = idleSleepTime;
+ // MixerThread has "sleepTimeShift = 0"
continue;
}
}
+ // MixerThread has "mixerStatus = prepareTracks_l(...)"
+
+ // equivalent to MixerThread's lockEffectChains_l, but without the lock
+ // FIXME - is it OK to omit the lock here?
effectChains = mEffectChains;
// find out which tracks need to be processed
@@ -2901,6 +2948,7 @@
lockEffectChains_l(effectChains);
}
+ // For DirectOutputThread, this test is equivalent to "activeTrack != 0"
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
AudioBufferProvider::Buffer buffer;
size_t frameCount = mFrameCount;
@@ -2933,15 +2981,18 @@
}
}
- if (mSuspended) {
+ if (mSuspended > 0) {
sleepTime = suspendSleepTimeUs();
}
// only process effects if we're going to write
if (sleepTime == 0) {
+
+ // MixerThread does not have applyVolume
if (mixerStatus == MIXER_TRACKS_READY) {
applyVolume(leftVol, rightVol, rampVolume);
}
+
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
}
@@ -2959,12 +3010,15 @@
if (bytesWritten < 0) mBytesWritten -= mixBufferSize;
mNumWrites++;
mInWrite = false;
+
+ // MixerThread has write blocked detection here
+
mStandby = false;
} else {
usleep(sleepTime);
}
- // finally let go of removed track, without the lock held
+ // finally let go of removed track(s), without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
trackToRemove.clear();
@@ -2973,8 +3027,12 @@
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains.clear();
+
+ // FIXME Note that the above .clear() is no longer necessary since effectChains
+ // is now local to this block, but will keep it for now (at least until merge done).
}
+ // put output stream into standby mode
if (!mStandby) {
mOutput->stream->common.standby(&mOutput->stream->common);
}
@@ -3099,18 +3157,24 @@
{
Vector< sp<Track> > tracksToRemove;
nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount*mFrameSize;
+ size_t mixBufferSize = mFrameCount * mFrameSize;
+
+ // Only in DuplicatingThread
SortedVector< sp<OutputTrack> > outputTracks;
uint32_t writeFrames = 0;
+
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
- Vector< sp<EffectChain> > effectChains;
acquireWakeLock();
while (!exitPending())
{
+ // MixerThread has cpuStats.sample
+
+ Vector< sp<EffectChain> > effectChains;
+
processConfigEvents();
mixer_state mixerStatus = MIXER_IDLE;
@@ -3119,22 +3183,25 @@
Mutex::Autolock _l(mLock);
if (checkForNewParameters_l()) {
- mixBufferSize = mFrameCount*mFrameSize;
+ mixBufferSize = mFrameCount * mFrameSize;
+
+ // Only in DuplicatingThread
updateWaitTime();
+
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
}
- const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
-
+ // Only in DuplicatingThread
for (size_t i = 0; i < mOutputTracks.size(); i++) {
outputTracks.add(mOutputTracks[i]);
}
// put audio hardware into standby after short delay
- if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
- mSuspended)) {
+ if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
+ mSuspended > 0)) {
if (!mStandby) {
+ // DuplicatingThread implements standby by stopping all tracks
for (size_t i = 0; i < outputTracks.size(); i++) {
outputTracks[i]->stop();
}
@@ -3142,7 +3209,7 @@
mBytesWritten = 0;
}
- if (!activeTracks.size() && mConfigEvents.isEmpty()) {
+ if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
// we're about to wait, flush the binder command buffer
IPCThreadState::self()->flushCommands();
outputTracks.clear();
@@ -3156,15 +3223,17 @@
ALOGV("Thread %p type %d TID %d waking up", this, mType, gettid());
acquireWakeLock_l();
+ // MixerThread has "mPrevMixerStatus = MIXER_IDLE"
checkSilentMode_l();
standbyTime = systemTime() + mStandbyTimeInNsecs;
sleepTime = idleSleepTime;
+ // MixerThread has sleepTimeShift
continue;
}
}
- mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
+ mixerStatus = prepareTracks_l(&tracksToRemove);
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
@@ -3172,6 +3241,7 @@
lockEffectChains_l(effectChains);
}
+ // Duplicating Thread is completely different here
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
if (outputsReady(outputTracks)) {
@@ -3201,7 +3271,7 @@
}
}
- if (mSuspended) {
+ if (mSuspended > 0) {
sleepTime = suspendSleepTimeUs();
}
@@ -3223,11 +3293,14 @@
}
mStandby = false;
mBytesWritten += mixBufferSize;
+
+ // MixerThread has write blocked detection here
+
} else {
usleep(sleepTime);
}
- // finally let go of all our tracks, without the lock held
+ // finally let go of removed track(s), without the lock held
// since we can't guarantee the destructors won't acquire that
// same lock.
tracksToRemove.clear();
@@ -3236,8 +3309,14 @@
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
effectChains.clear();
+
+ // FIXME Note that the above .clear() is no longer necessary since effectChains
+ // is now local to this block, but will keep it for now (at least until merge done).
}
+ // MixerThread and DirectOutpuThread have standby here,
+ // but for DuplicatingThread this is handled by the outputTracks
+
releaseWakeLock();
ALOGV("Thread %p type %d exiting", this, mType);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 457bd98..bdaf97c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -455,9 +455,10 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
// remove an effect chain from the chain list (mEffectChains)
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain) = 0;
- // lock mall effect chains Mutexes. Must be called before releasing the
+ // lock all effect chains Mutexes. Must be called before releasing the
// ThreadBase mutex before processing the mixer and effects. This guarantees the
// integrity of the chains during the process.
+ // Also sets the parameter 'effectChains' to current value of mEffectChains.
void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains);
// unlock effect chains after process
void unlockEffectChains(const Vector<sp<EffectChain> >& effectChains);
@@ -575,9 +576,11 @@
public:
enum mixer_state {
- MIXER_IDLE,
- MIXER_TRACKS_ENABLED,
- MIXER_TRACKS_READY
+ MIXER_IDLE, // no active tracks
+ MIXER_TRACKS_ENABLED, // at least one active track, but no track has any data ready
+ MIXER_TRACKS_READY // at least one active track, and at least one track has data
+ // standby mode does not have an enum value
+ // suspend by audio policy manager is orthogonal to mixer state
};
// playback track
@@ -821,8 +824,8 @@
virtual audio_stream_t* stream();
void suspend() { mSuspended++; }
- void restore() { if (mSuspended) mSuspended--; }
- bool isSuspended() const { return (mSuspended != 0); }
+ void restore() { if (mSuspended > 0) mSuspended--; }
+ bool isSuspended() const { return (mSuspended > 0); }
virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged_l(int event, int param = 0);
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
@@ -843,7 +846,7 @@
protected:
int16_t* mMixBuffer;
- int mSuspended;
+ uint32_t mSuspended; // suspend count, > 0 means suspended
int mBytesWritten;
private:
// mMasterMute is in both PlaybackThread and in AudioFlinger. When a
@@ -913,8 +916,11 @@
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
protected:
- mixer_state prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
- Vector< sp<Track> > *tracksToRemove);
+ // prepareTracks_l reads and writes mActiveTracks, and also returns the
+ // pending set of tracks to remove via Vector 'tracksToRemove'. The caller is
+ // responsible for clearing or destroying this Vector later on, when it
+ // is safe to do so. That will drop the final ref count and destroy the tracks.
+ mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
virtual uint32_t idleSleepTimeUs();