Allow delivery to multiple messages in a single message.

Where multiple messages are required to be sent in order
to perform a player reconfiguration, it will usually be
desirable to process all messages in a single "transaction"
(i.e. without any rendering happening when only some of
the messages have been applied).
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=123228334
This commit is contained in:
olly 2016-05-25 10:36:34 -07:00 committed by Oliver Woodman
parent ff7819e86a
commit 10329eb111
7 changed files with 100 additions and 50 deletions

View File

@ -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();

View File

@ -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

View File

@ -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;
}

View File

@ -132,8 +132,8 @@ public interface ExoPlayer {
/**
* A component of an {@link ExoPlayer} that can receive messages on the playback thread.
* <p>
* 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.

View File

@ -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

View File

@ -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 <T> void sendMessageInternal(int what, Object obj)
throws ExoPlaybackException {
private void sendMessagesInternal(ExoPlayerMessage[] messages) throws ExoPlaybackException {
try {
@SuppressWarnings("unchecked")
Pair<ExoPlayerComponent, Object> targetAndMessage = (Pair<ExoPlayerComponent, Object>) 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);

View File

@ -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,15 +163,18 @@ 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) {
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.blockingSendMessage(renderer, C.MSG_SET_SURFACE, null);
player.blockingSendMessages(messages);
} else {
player.sendMessage(renderer, C.MSG_SET_SURFACE, surface);
}
}
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