summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioService.java141
-rw-r--r--media/java/android/media/RemoteControlClient.java30
-rw-r--r--media/libmedia/AudioTrack.cpp5
-rw-r--r--media/libstagefright/AudioPlayer.cpp2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp1
-rwxr-xr-xmedia/libstagefright/CameraSource.cpp9
-rwxr-xr-xmedia/libstagefright/OMXCodec.cpp1
-rw-r--r--media/libstagefright/foundation/ALooperRoster.cpp49
-rw-r--r--media/libstagefright/foundation/AMessage.cpp25
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp32
10 files changed, 207 insertions, 88 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index a876291..a5c9053 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -81,6 +81,10 @@ public class AudioService extends IAudioService.Stub {
private static final String TAG = "AudioService";
+ /** Debug remote control client/display feature */
+ // TODO set to false before release
+ protected static final boolean DEBUG_RC = true;
+
/** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 3000;
@@ -3072,7 +3076,7 @@ public class AudioService extends IAudioService.Stub {
/**
* Update the remote control displays with the new "focused" client generation
*/
- private void setNewRcClientOnDisplays_syncRcStack(int newClientGeneration,
+ private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
ComponentName newClientEventReceiver, boolean clearing) {
// NOTE: Only one IRemoteControlDisplay supported in this implementation
if (mRcDisplay != null) {
@@ -3091,7 +3095,7 @@ public class AudioService extends IAudioService.Stub {
/**
* Update the remote control clients with the new "focused" client generation
*/
- private void setNewRcClientGenerationOnClients_syncRcStack(int newClientGeneration) {
+ private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry se = stackIterator.next();
@@ -3115,29 +3119,28 @@ public class AudioService extends IAudioService.Stub {
* @param clearing true if the new client generation value maps to a remote control update
* where the display should be cleared.
*/
- private void setNewRcClient(int newClientGeneration, ComponentName newClientEventReceiver,
- boolean clearing) {
- synchronized(mRCStack) {
- // send the new valid client generation ID to all displays
- setNewRcClientOnDisplays_syncRcStack(newClientGeneration, newClientEventReceiver,
- clearing);
- // send the new valid client generation ID to all clients
- setNewRcClientGenerationOnClients_syncRcStack(newClientGeneration);
- }
+ private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
+ ComponentName newClientEventReceiver, boolean clearing) {
+ // send the new valid client generation ID to all displays
+ setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newClientEventReceiver,
+ clearing);
+ // send the new valid client generation ID to all clients
+ setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
}
/**
* Called when processing MSG_RCDISPLAY_CLEAR event
*/
private void onRcDisplayClear() {
- // TODO remove log before release
- Log.i(TAG, "Clear remote control display");
-
- synchronized(mCurrentRcLock) {
- mCurrentRcClientGen++;
+ if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
- // synchronously update the displays and clients with the new client generation
- setNewRcClient(mCurrentRcClientGen, null /*event receiver*/, true /*clearing*/);
+ synchronized(mRCStack) {
+ synchronized(mCurrentRcLock) {
+ mCurrentRcClientGen++;
+ // synchronously update the displays and clients with the new client generation
+ setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+ null /*event receiver*/, true /*clearing*/);
+ }
}
}
@@ -3145,30 +3148,31 @@ public class AudioService extends IAudioService.Stub {
* Called when processing MSG_RCDISPLAY_UPDATE event
*/
private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
- synchronized(mCurrentRcLock) {
- if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
- // TODO remove log before release
- Log.i(TAG, "Display/update remote control ");
-
- mCurrentRcClientGen++;
-
- // synchronously update the displays and clients with the new client generation
- setNewRcClient(mCurrentRcClientGen,
- rcse.mReceiverComponent /*event receiver*/,
- false /*clearing*/);
-
- // ask the current client that it needs to send info
- try {
- mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
- flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
- } catch (RemoteException e) {
- Log.e(TAG, "Current valid remote client is dead: "+e);
- mCurrentRcClient = null;
+ synchronized(mRCStack) {
+ synchronized(mCurrentRcLock) {
+ if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
+ if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
+
+ mCurrentRcClientGen++;
+ // synchronously update the displays and clients with
+ // the new client generation
+ setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
+ rcse.mReceiverComponent /*event receiver*/,
+ false /*clearing*/);
+
+ // ask the current client that it needs to send info
+ try {
+ mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
+ flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Current valid remote client is dead: "+e);
+ mCurrentRcClient = null;
+ }
+ } else {
+ // the remote control display owner has changed between the
+ // the message to update the display was sent, and the time it
+ // gets to be processed (now)
}
- } else {
- // the remote control display owner has changed between the
- // the message to update the display was sent, and the time it
- // gets to be processed (now)
}
}
}
@@ -3372,34 +3376,45 @@ public class AudioService extends IAudioService.Stub {
* of displays if necessary.
*/
private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
+ private IBinder mCb; // To be notified of client's death
+
+ public RcDisplayDeathHandler(IBinder b) {
+ if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
+ mCb = b;
+ }
+
public void binderDied() {
synchronized(mRCStack) {
- Log.w(TAG, " RemoteControl: display died");
+ Log.w(TAG, "RemoteControl: display died");
mRcDisplay = null;
}
}
- }
-
- private void rcDisplay_stopDeathMonitor_syncRcStack() {
- if (mRcDisplay != null) {
- // we had a display before, stop monitoring its death
- IBinder b = mRcDisplay.asBinder();
+ public void unlinkToRcDisplayDeath() {
+ if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
try {
- b.unlinkToDeath(mRcDisplayDeathHandler, 0);
+ mCb.unlinkToDeath(this, 0);
} catch (java.util.NoSuchElementException e) {
- // being conservative here
- Log.e(TAG, "Error while trying to unlink display death handler " + e);
+ // not much we can do here, the display was being unregistered anyway
+ Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
e.printStackTrace();
}
}
+
+ }
+
+ private void rcDisplay_stopDeathMonitor_syncRcStack() {
+ if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
+ // we had a display before, stop monitoring its death
+ mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
+ }
}
private void rcDisplay_startDeathMonitor_syncRcStack() {
if (mRcDisplay != null) {
// new non-null display, monitor its death
IBinder b = mRcDisplay.asBinder();
- mRcDisplayDeathHandler = new RcDisplayDeathHandler();
+ mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
try {
b.linkToDeath(mRcDisplayDeathHandler, 0);
} catch (RemoteException e) {
@@ -3410,9 +3425,15 @@ public class AudioService extends IAudioService.Stub {
}
}
+ /**
+ * Register an IRemoteControlDisplay and notify all IRemoteControlClient of the new display.
+ * Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
+ * @param rcd the IRemoteControlDisplay to register. No effect if null.
+ */
public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
+ if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
synchronized(mRCStack) {
- if (mRcDisplay == rcd) {
+ if ((mRcDisplay == rcd) || (rcd == null)) {
return;
}
// if we had a display before, stop monitoring its death
@@ -3422,6 +3443,8 @@ public class AudioService extends IAudioService.Stub {
rcDisplay_startDeathMonitor_syncRcStack();
// let all the remote control clients there is a new display
+ // no need to unplug the previous because we only support one display
+ // and the clients don't track the death of the display
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = stackIterator.next();
@@ -3437,8 +3460,20 @@ public class AudioService extends IAudioService.Stub {
}
}
+ /**
+ * Unregister an IRemoteControlDisplay.
+ * Since only one IRemoteControlDisplay is supported, this has no effect if the one to
+ * unregister is not the current one.
+ * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
+ */
public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
+ if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
synchronized(mRCStack) {
+ // only one display here, so you can only unregister the current display
+ if ((rcd == null) || (rcd != mRcDisplay)) {
+ if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD");
+ return;
+ }
// if we had a display before, stop monitoring its death
rcDisplay_stopDeathMonitor_syncRcStack();
mRcDisplay = null;
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index e6331ce..2bdd3c9 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -722,20 +722,22 @@ public class RemoteControlClient
*/
private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
- if (width > maxWidth || height > maxHeight) {
- float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
- int newWidth = Math.round(scale * width);
- int newHeight = Math.round(scale * height);
- Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, bitmap.getConfig());
- Canvas canvas = new Canvas(outBitmap);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- canvas.drawBitmap(bitmap, null,
- new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
- bitmap = outBitmap;
+ if (bitmap != null) {
+ final int width = bitmap.getWidth();
+ final int height = bitmap.getHeight();
+ if (width > maxWidth || height > maxHeight) {
+ float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
+ int newWidth = Math.round(scale * width);
+ int newHeight = Math.round(scale * height);
+ Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, bitmap.getConfig());
+ Canvas canvas = new Canvas(outBitmap);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ canvas.drawBitmap(bitmap, null,
+ new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
+ bitmap = outBitmap;
+ }
}
return bitmap;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 3949c39..cecedb5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -259,6 +259,7 @@ status_t AudioTrack::set(
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
+ mFlushed = false;
mFlags = flags;
AudioSystem::acquireAudioSessionId(mSessionId);
@@ -337,6 +338,7 @@ void AudioTrack::start()
audio_track_cblk_t* cblk = mCblk;
if (mActive == 0) {
+ mFlushed = false;
mActive = 1;
mNewPosition = cblk->server + mUpdatePeriod;
cblk->lock.lock();
@@ -437,6 +439,7 @@ void AudioTrack::flush_l()
mUpdatePeriod = 0;
if (!mActive) {
+ mFlushed = true;
mAudioTrack->flush();
// Release AudioTrack callback thread in case it was waiting for new buffers
// in AudioTrack::obtainBuffer()
@@ -655,7 +658,7 @@ status_t AudioTrack::getPosition(uint32_t *position)
{
if (position == 0) return BAD_VALUE;
AutoMutex lock(mLock);
- *position = mCblk->server;
+ *position = mFlushed ? 0 : mCblk->server;
return NO_ERROR;
}
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index dd69e6b..d41ab1b 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -180,6 +180,8 @@ void AudioPlayer::pause(bool playPendingSamples) {
} else {
mAudioTrack->stop();
}
+
+ mNumFramesPlayed = 0;
} else {
if (mAudioSink.get() != NULL) {
mAudioSink->pause();
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f2673b3..bc42a42 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1318,6 +1318,7 @@ void AwesomePlayer::onRTSPSeekDone() {
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
if (mRTSPController != NULL) {
+ mSeekNotificationSent = false;
mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
return OK;
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index ac3565f..256f3ba 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -635,6 +635,12 @@ status_t CameraSource::stop() {
mStarted = false;
mFrameAvailableCondition.signal();
+ int64_t token;
+ bool isTokenValid = false;
+ if (mCamera != 0) {
+ token = IPCThreadState::self()->clearCallingIdentity();
+ isTokenValid = true;
+ }
releaseQueuedFrames();
while (!mFramesBeingEncoded.empty()) {
if (NO_ERROR !=
@@ -645,6 +651,9 @@ status_t CameraSource::stop() {
}
stopCameraRecording();
releaseCamera();
+ if (isTokenValid) {
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
if (mCollectStats) {
LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 525ee8b..7f09319 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2325,6 +2325,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
{
CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)",
data1, data2);
+ CHECK(mFilledBuffers.empty());
if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
onPortSettingsChanged(data1);
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 8aa1b15..e399f2f 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -27,7 +27,8 @@
namespace android {
ALooperRoster::ALooperRoster()
- : mNextHandlerID(1) {
+ : mNextHandlerID(1),
+ mNextReplyID(1) {
}
ALooper::handler_id ALooperRoster::registerHandler(
@@ -70,15 +71,19 @@ void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
mHandlers.removeItemsAt(index);
}
-void ALooperRoster::postMessage(
+status_t ALooperRoster::postMessage(
const sp<AMessage> &msg, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
+ return postMessage_l(msg, delayUs);
+}
+status_t ALooperRoster::postMessage_l(
+ const sp<AMessage> &msg, int64_t delayUs) {
ssize_t index = mHandlers.indexOfKey(msg->target());
if (index < 0) {
LOGW("failed to post message. Target handler not registered.");
- return;
+ return -ENOENT;
}
const HandlerInfo &info = mHandlers.valueAt(index);
@@ -91,10 +96,12 @@ void ALooperRoster::postMessage(
msg->target());
mHandlers.removeItemsAt(index);
- return;
+ return -ENOENT;
}
looper->post(msg, delayUs);
+
+ return OK;
}
void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
@@ -145,4 +152,38 @@ sp<ALooper> ALooperRoster::findLooper(ALooper::handler_id handlerID) {
return looper;
}
+status_t ALooperRoster::postAndAwaitResponse(
+ const sp<AMessage> &msg, sp<AMessage> *response) {
+ Mutex::Autolock autoLock(mLock);
+
+ uint32_t replyID = mNextReplyID++;
+
+ msg->setInt32("replyID", replyID);
+
+ status_t err = postMessage_l(msg, 0 /* delayUs */);
+
+ if (err != OK) {
+ response->clear();
+ return err;
+ }
+
+ ssize_t index;
+ while ((index = mReplies.indexOfKey(replyID)) < 0) {
+ mRepliesCondition.wait(mLock);
+ }
+
+ *response = mReplies.valueAt(index);
+ mReplies.removeItemsAt(index);
+
+ return OK;
+}
+
+void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK(mReplies.indexOfKey(replyID) < 0);
+ mReplies.add(replyID, reply);
+ mRepliesCondition.broadcast();
+}
+
} // namespace android
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index b592c3f..582bdba 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -27,6 +27,8 @@
namespace android {
+extern ALooperRoster gLooperRoster;
+
AMessage::AMessage(uint32_t what, ALooper::handler_id target)
: mWhat(what),
mTarget(target),
@@ -227,11 +229,30 @@ bool AMessage::findRect(
}
void AMessage::post(int64_t delayUs) {
- extern ALooperRoster gLooperRoster;
-
gLooperRoster.postMessage(this, delayUs);
}
+status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
+ return gLooperRoster.postAndAwaitResponse(this, response);
+}
+
+void AMessage::postReply(uint32_t replyID) {
+ gLooperRoster.postReply(replyID, this);
+}
+
+bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
+ int32_t tmp;
+ bool found = findInt32("replyID", &tmp);
+
+ if (!found) {
+ return false;
+ }
+
+ *replyID = static_cast<uint32_t>(tmp);
+
+ return true;
+}
+
sp<AMessage> AMessage::dup() const {
sp<AMessage> msg = new AMessage(mWhat, mTarget);
msg->mNumItems = mNumItems;
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 2e66a2c..ce07e32 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -136,24 +136,28 @@ void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
void AnotherPacketSource::queueDiscontinuity(
ATSParser::DiscontinuityType type,
const sp<AMessage> &extra) {
- sp<ABuffer> buffer = new ABuffer(0);
- buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
- buffer->meta()->setMessage("extra", extra);
-
Mutex::Autolock autoLock(mLock);
-#if 0
- if (type == ATSParser::DISCONTINUITY_SEEK
- || type == ATSParser::DISCONTINUITY_FORMATCHANGE) {
- // XXX Fix this: This will also clear any pending discontinuities,
- // If there's a pending DISCONTINUITY_FORMATCHANGE and the new
- // discontinuity is "just" a DISCONTINUITY_SEEK, this will effectively
- // downgrade the type of discontinuity received by the client.
+ // Leave only discontinuities in the queue.
+ List<sp<ABuffer> >::iterator it = mBuffers.begin();
+ while (it != mBuffers.end()) {
+ sp<ABuffer> oldBuffer = *it;
+
+ int32_t oldDiscontinuityType;
+ if (!oldBuffer->meta()->findInt32(
+ "discontinuity", &oldDiscontinuityType)) {
+ it = mBuffers.erase(it);
+ continue;
+ }
- mBuffers.clear();
- mEOSResult = OK;
+ ++it;
}
-#endif
+
+ mEOSResult = OK;
+
+ sp<ABuffer> buffer = new ABuffer(0);
+ buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
+ buffer->meta()->setMessage("extra", extra);
mBuffers.push_back(buffer);
mCondition.signal();