diff --git a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer/ext/vp9/VpxPlaybackTest.java b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer/ext/vp9/VpxPlaybackTest.java index 32a3fa1e7d..18c80be063 100644 --- a/extensions/vp9/src/androidTest/java/com/google/android/exoplayer/ext/vp9/VpxPlaybackTest.java +++ b/extensions/vp9/src/androidTest/java/com/google/android/exoplayer/ext/vp9/VpxPlaybackTest.java @@ -104,8 +104,9 @@ public class VpxPlaybackTest extends InstrumentationTestCase { false), new DefaultAllocator(BUFFER_SEGMENT_SIZE), BUFFER_SEGMENT_SIZE * BUFFER_SEGMENT_COUNT, new Extractor[] {new MatroskaExtractor()}); - player.sendMessage(videoRenderer, LibvpxVideoTrackRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER, - new VpxVideoSurfaceView(context)); + player.sendMessages(new ExoPlayer.ExoPlayerMessage(videoRenderer, + LibvpxVideoTrackRenderer.MSG_SET_OUTPUT_BUFFER_RENDERER, + new VpxVideoSurfaceView(context))); player.setSource(sampleSource); player.setPlayWhenReady(true); Looper.loop(); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java index 0b05b1db6a..51e707c634 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/LibvpxVideoTrackRenderer.java @@ -41,10 +41,10 @@ public final class LibvpxVideoTrackRenderer extends TrackRenderer { /** * The type of a message that can be passed to an instance of this class via - * {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object + * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object * should be the target {@link VpxOutputBufferRenderer}, or null. */ - public static final int MSG_SET_OUTPUT_BUFFER_RENDERER = 2; + public static final int MSG_SET_OUTPUT_BUFFER_RENDERER = C.MSG_CUSTOM_BASE; /** * The number of input buffers and the number of output buffers. The track renderer may limit the diff --git a/library/src/main/java/com/google/android/exoplayer/C.java b/library/src/main/java/com/google/android/exoplayer/C.java index d0cc66aecd..c4e7b67b00 100644 --- a/library/src/main/java/com/google/android/exoplayer/C.java +++ b/library/src/main/java/com/google/android/exoplayer/C.java @@ -231,25 +231,30 @@ public interface C { /** * The type of a message that can be passed to a video {@link TrackRenderer} via - * {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object + * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object * should be the target {@link Surface}, or null. */ int MSG_SET_SURFACE = 1; /** * The type of a message that can be passed to an audio {@link TrackRenderer} via - * {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object + * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object * should be a {@link Float} with 0 being silence and 1 being unity gain. */ int MSG_SET_VOLUME = 2; /** * The type of a message that can be passed to an audio {@link TrackRenderer} via - * {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object + * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object * should be a {@link android.media.PlaybackParams}, which will be used to configure the * underlying {@link android.media.AudioTrack}. The message object should not be modified by the * caller after it has been passed */ int MSG_SET_PLAYBACK_PARAMS = 3; + /** + * A minimum value for custom {@link TrackRenderer} message types. + */ + int MSG_CUSTOM_BASE = 10000; + } diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java index b9a1f3eddc..f975a0db39 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java @@ -132,8 +132,8 @@ public interface ExoPlayer { /** * A component of an {@link ExoPlayer} that can receive messages on the playback thread. *

- * Messages can be delivered to a component via {@link ExoPlayer#sendMessage} and - * {@link ExoPlayer#blockingSendMessage}. + * Messages can be delivered to a component via {@link ExoPlayer#sendMessages} and + * {@link ExoPlayer#blockingSendMessages}. */ interface ExoPlayerComponent { @@ -148,6 +148,28 @@ public interface ExoPlayer { } + /** + * Defines a message and a target {@link ExoPlayerComponent} to receive it. + */ + final class ExoPlayerMessage { + + public final ExoPlayerComponent target; + public final int messageType; + public final Object message; + + /** + * @param target The target of the message. + * @param messageType An integer identifying the type of message. + * @param message The message object. + */ + public ExoPlayerMessage(ExoPlayerComponent target, int messageType, Object message) { + this.target = target; + this.messageType = messageType; + this.message = message; + } + + } + /** * The player does not have a source to load, so it is neither buffering nor ready to play. */ @@ -256,25 +278,21 @@ public interface ExoPlayer { void release(); /** - * Sends a message to a specified component. The message is delivered to the component on the - * playback thread. If the component throws a {@link ExoPlaybackException}, then it is - * propagated out of the player as an error. + * Sends messages to their target components. The messages are delivered on the playback thread. + * If a component throws an {@link ExoPlaybackException} then it is propagated out of the player + * as an error. * - * @param target The target to which the message should be delivered. - * @param messageType An integer that can be used to identify the type of the message. - * @param message The message object. + * @param messages The messages to be sent. */ - void sendMessage(ExoPlayerComponent target, int messageType, Object message); + void sendMessages(ExoPlayerMessage... messages); /** - * Blocking variant of {@link #sendMessage(ExoPlayerComponent, int, Object)} that does not return - * until after the message has been delivered. + * Variant of {@link #sendMessages(ExoPlayerMessage...)} that blocks until after the messages have + * been delivered. * - * @param target The target to which the message should be delivered. - * @param messageType An integer that can be used to identify the type of the message. - * @param message The message object. + * @param messages The messages to be sent. */ - void blockingSendMessage(ExoPlayerComponent target, int messageType, Object message); + void blockingSendMessages(ExoPlayerMessage... messages); /** * Gets the duration of the track in milliseconds. diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java index f4c0013f1b..f8b2e486fe 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java @@ -129,13 +129,13 @@ import java.util.concurrent.CopyOnWriteArraySet; } @Override - public void sendMessage(ExoPlayerComponent target, int messageType, Object message) { - internalPlayer.sendMessage(target, messageType, message); + public void sendMessages(ExoPlayerMessage... messages) { + internalPlayer.sendMessages(messages); } @Override - public void blockingSendMessage(ExoPlayerComponent target, int messageType, Object message) { - internalPlayer.blockingSendMessage(target, messageType, message); + public void blockingSendMessages(ExoPlayerMessage... messages) { + internalPlayer.blockingSendMessages(messages); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index 45baca488b..04635ec41f 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -15,7 +15,7 @@ */ package com.google.android.exoplayer; -import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent; +import com.google.android.exoplayer.ExoPlayer.ExoPlayerMessage; import com.google.android.exoplayer.TrackSelector.InvalidationListener; import com.google.android.exoplayer.util.PriorityHandlerThread; import com.google.android.exoplayer.util.TraceUtil; @@ -154,19 +154,22 @@ import java.util.concurrent.atomic.AtomicInteger; handler.sendEmptyMessage(MSG_STOP); } - public void sendMessage(ExoPlayerComponent target, int messageType, Object message) { + public void sendMessages(ExoPlayerMessage... messages) { + if (released) { + Log.w(TAG, "Ignoring messages sent after release."); + return; + } customMessagesSent++; - handler.obtainMessage(MSG_CUSTOM, messageType, 0, Pair.create(target, message)).sendToTarget(); + handler.obtainMessage(MSG_CUSTOM, messages).sendToTarget(); } - public synchronized void blockingSendMessage(ExoPlayerComponent target, int messageType, - Object message) { + public synchronized void blockingSendMessages(ExoPlayerMessage... messages) { if (released) { - Log.w(TAG, "Sent message(" + messageType + ") after release. Message ignored."); + Log.w(TAG, "Ignoring messages sent after release."); return; } int messageNumber = customMessagesSent++; - handler.obtainMessage(MSG_CUSTOM, messageType, 0, Pair.create(target, message)).sendToTarget(); + handler.obtainMessage(MSG_CUSTOM, messages).sendToTarget(); while (customMessagesProcessed <= messageNumber) { try { wait(); @@ -225,7 +228,7 @@ import java.util.concurrent.atomic.AtomicInteger; return true; } case MSG_CUSTOM: { - sendMessageInternal(msg.arg1, msg.obj); + sendMessagesInternal((ExoPlayerMessage[]) msg.obj); return true; } case MSG_TRACK_SELECTION_INVALIDATED: { @@ -517,12 +520,11 @@ import java.util.concurrent.atomic.AtomicInteger; } } - private void sendMessageInternal(int what, Object obj) - throws ExoPlaybackException { + private void sendMessagesInternal(ExoPlayerMessage[] messages) throws ExoPlaybackException { try { - @SuppressWarnings("unchecked") - Pair targetAndMessage = (Pair) obj; - targetAndMessage.first.handleMessage(what, targetAndMessage.second); + for (ExoPlayerMessage message : messages) { + message.target.handleMessage(message.messageType, message.message); + } if (preparedSource) { // The message may have caused something to change that now requires us to do work. handler.sendEmptyMessage(MSG_DO_SOME_WORK); diff --git a/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java index e09e2fd282..05ff27cba1 100644 --- a/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java @@ -89,6 +89,8 @@ public final class SimpleExoPlayer implements ExoPlayer { private final TrackRenderer[] renderers; private final ComponentListener componentListener; private final Handler mainHandler; + private final int videoRendererCount; + private final int audioRendererCount; private Format videoFormat; private Format audioFormat; @@ -115,6 +117,22 @@ public final class SimpleExoPlayer implements ExoPlayer { buildRenderers(context, drmSessionManager, renderersList); renderers = renderersList.toArray(new TrackRenderer[renderersList.size()]); + // Obtain counts of video and audio renderers. + int videoRendererCount = 0; + int audioRendererCount = 0; + for (TrackRenderer renderer : renderers) { + switch (renderer.getTrackType()) { + case C.TRACK_TYPE_VIDEO: + videoRendererCount++; + break; + case C.TRACK_TYPE_AUDIO: + audioRendererCount++; + break; + } + } + this.videoRendererCount = videoRendererCount; + this.audioRendererCount = audioRendererCount; + // Build the player and associated objects. player = new ExoPlayerImpl(renderers, trackSelector, minBufferMs, minRebufferMs); } @@ -145,16 +163,19 @@ public final class SimpleExoPlayer implements ExoPlayer { * @param surface The {@link Surface}. */ public void setSurface(Surface surface) { + ExoPlayerMessage[] messages = new ExoPlayerMessage[videoRendererCount]; + int count = 0; for (TrackRenderer renderer : renderers) { if (renderer.getTrackType() == C.TRACK_TYPE_VIDEO) { - if (surface == null) { - // Block to ensure that the surface is not accessed after the method returns. - player.blockingSendMessage(renderer, C.MSG_SET_SURFACE, null); - } else { - player.sendMessage(renderer, C.MSG_SET_SURFACE, surface); - } + messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_SURFACE, surface); } } + if (surface == null) { + // Block to ensure that the surface is not accessed after the method returns. + player.blockingSendMessages(messages); + } else { + player.sendMessages(messages); + } } /** @@ -163,11 +184,14 @@ public final class SimpleExoPlayer implements ExoPlayer { * @param volume The volume. */ public void setVolume(float volume) { + ExoPlayerMessage[] messages = new ExoPlayerMessage[audioRendererCount]; + int count = 0; for (TrackRenderer renderer : renderers) { if (renderer.getTrackType() == C.TRACK_TYPE_AUDIO) { - player.sendMessage(renderer, C.MSG_SET_VOLUME, volume); + messages[count++] = new ExoPlayerMessage(renderer, C.MSG_SET_VOLUME, volume); } } + player.sendMessages(messages); } /** @@ -296,13 +320,13 @@ public final class SimpleExoPlayer implements ExoPlayer { } @Override - public void sendMessage(ExoPlayerComponent target, int messageType, Object message) { - player.sendMessage(target, messageType, message); + public void sendMessages(ExoPlayerMessage... messages) { + player.sendMessages(messages); } @Override - public void blockingSendMessage(ExoPlayerComponent target, int messageType, Object message) { - player.blockingSendMessage(target, messageType, message); + public void blockingSendMessages(ExoPlayerMessage... messages) { + player.blockingSendMessages(messages); } @Override