diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/AudioService.java | 141 | ||||
-rw-r--r-- | media/java/android/media/RemoteControlClient.java | 30 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 5 | ||||
-rw-r--r-- | media/libstagefright/AudioPlayer.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 1 | ||||
-rwxr-xr-x | media/libstagefright/CameraSource.cpp | 9 | ||||
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 1 | ||||
-rw-r--r-- | media/libstagefright/foundation/ALooperRoster.cpp | 49 | ||||
-rw-r--r-- | media/libstagefright/foundation/AMessage.cpp | 25 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/AnotherPacketSource.cpp | 32 |
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(); |