-
Notifications
You must be signed in to change notification settings - Fork 28
Exo-player two facade and forwarders #23
Exo-player two facade and forwarders #23
Conversation
|
||
import java.io.IOException; | ||
|
||
abstract class ExoPlayerEventForwarder implements ExoPlayerForwarder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤢 we implemented all events on this one forwarder. We now have dedicated forwarders and a generic forwarder
that has the specific forwarders as collaborators.
@@ -13,74 +22,93 @@ | |||
import com.novoda.noplayer.VideoContainer; | |||
import com.novoda.noplayer.VideoDuration; | |||
import com.novoda.noplayer.VideoPosition; | |||
import com.novoda.noplayer.exoplayer.forwarder.ExoPlayerForwarder; | |||
import com.novoda.noplayer.player.PlayerInformation; | |||
|
|||
import java.util.Collections; | |||
import java.util.List; | |||
|
|||
public class ExoPlayerTwoImpl extends PlayerListenersHolder implements Player { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Facade became a wrapper during our refactorings so quite a few of the calls here are just inlines.
|
||
import java.io.IOException; | ||
|
||
class BitrateForwarder implements AdaptiveMediaSourceEventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer extending from the abstract ExoPlayerEventForwarder
, instead, we map directly from the ExoPlayer
events to the no-player
events.
|
||
@Override | ||
public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat, int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs, long mediaEndTimeMs, long elapsedRealtimeMs) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These TODOs
were hidden in the abstract ExoPlayerEventForwarder
class, not anymore! We should figure out what to do with these!
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | ||
import com.novoda.noplayer.listeners.BufferStateListeners; | ||
|
||
class BufferStateForwarder implements ExoPlayer.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, not extending from the abstract ExoPlayerEventForwarder
instead implementing the interface from ExoPlayer
that we care about.
|
||
@Override | ||
public void onTimelineChanged(Timeline timeline, Object manifest) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, we need to figure out how we should map these from ExoPlayer
to no-player
|
||
import java.util.HashMap; | ||
|
||
class EventInfoForwarder implements ExoPlayer.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
import java.util.List; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
class ExoPlayerExtractorMediaSourceListener implements ExtractorMediaSource.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
import com.novoda.noplayer.listeners.PreparedListeners; | ||
import com.novoda.noplayer.listeners.VideoSizeChangedListeners; | ||
|
||
public class ExoPlayerForwarder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our generic forwarder that contains all of the events
that we are interested in from ExoPlayer
.
import java.util.List; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
class ExoPlayerVideoRendererEventListener implements VideoRendererEventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
import java.io.IOException; | ||
import java.util.HashMap; | ||
|
||
class ExtractorInfoForwarder implements ExtractorMediaSource.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid huge classes we have an InfoForwarder
for each of the ExoPlayer
interfaces that we are interested in monitoring.
import com.google.android.exoplayer2.upstream.DataSpec; | ||
import com.novoda.noplayer.listeners.InfoListeners; | ||
|
||
import java.io.IOException; | ||
import java.util.HashMap; | ||
|
||
class InfoForwarder extends ExoPlayerEventForwarder { | ||
class MediaSourceInfoForwarder implements AdaptiveMediaSourceEventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
import com.novoda.noplayer.Player; | ||
import com.novoda.noplayer.exoplayer.playererror.MediaSourceError; | ||
import com.novoda.noplayer.listeners.ErrorListeners; | ||
|
||
import java.io.IOException; | ||
|
||
class OnErrorForwarder extends ExoPlayerEventForwarder { | ||
class MediaSourceOnErrorForwarder implements ExtractorMediaSource.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | ||
import com.novoda.noplayer.listeners.CompletionListeners; | ||
|
||
class OnCompletionForwarder implements ExoPlayer.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
|
||
@Override | ||
public void onTimelineChanged(Timeline timeline, Object manifest) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, we need to figure out the mapping from ExoPlayer
to no-player
for these additional events.
import com.novoda.noplayer.PlayerState; | ||
import com.novoda.noplayer.listeners.PreparedListeners; | ||
|
||
class OnPrepareForwarder implements ExoPlayer.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
|
||
@Override | ||
public void onTimelineChanged(Timeline timeline, Object manifest) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once again, again. We need to figure out the mapping between ExoPlayer
and no-player
for these additional events 😄
import com.novoda.noplayer.Player; | ||
import com.novoda.noplayer.listeners.ErrorListeners; | ||
|
||
class PlayerOnErrorForwarder implements ExoPlayer.EventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
|
||
@Override | ||
public void onTimelineChanged(Timeline timeline, Object manifest) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AND AGAIN! 😄 🎉 We need to figure out the mapping between exoplayer
and no-player
.
|
||
import java.util.HashMap; | ||
|
||
class VideoRendererInfoForwarder implements VideoRendererEventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are many info forwarders and each implements a single interface from ExoPlayer
and are added to the generic forwarder
.
import com.google.android.exoplayer2.video.VideoRendererEventListener; | ||
import com.novoda.noplayer.listeners.VideoSizeChangedListeners; | ||
|
||
class VideoSizeChangedForwarder implements VideoRendererEventListener { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as others above. We no longer extend from ExoPlayerEventForwarder
but instead implement the interface we care about directly from ExoPlayer
.
|
||
@Override | ||
public void onVideoEnabled(DecoderCounters counters) { | ||
//TODO should we send ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OOOOoooo more! We need to figure out the mapping between ExoPlayer
and no-player
.
@@ -10,6 +10,8 @@ | |||
|
|||
private final Set<Player.PreparedListener> listeners = new CopyOnWriteArraySet<>(); | |||
|
|||
private boolean hasPrepared = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We moved the state up a level because it made more sense here than in each of the individual listeners.
@@ -30,7 +30,7 @@ protected void onCreate(Bundle savedInstanceState) { | |||
@Override | |||
protected void onStart() { | |||
super.onStart(); | |||
player = new PlayerFactory(this, PrioritisedPlayers.prioritiseMediaPlayer()).create(); | |||
player = new PlayerFactory(this, PrioritisedPlayers.prioritiseExoPlayer()).create(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷♂️ because we are working on ExoPlayer
👅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave a TODO maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, we should have this exposed in the UI really.
private ExoPlayerTwoImpl(SimpleExoPlayer exoPlayer, MediaSourceFactory mediaSourceFactory, ExoPlayerForwarder exoPlayerForwarder) { | ||
this.exoPlayer = exoPlayer; | ||
this.mediaSourceFactory = mediaSourceFactory; | ||
forwarder = exoPlayerForwarder; | ||
Heart.Heartbeat<Player> onHeartbeat = new Heart.Heartbeat<>(getHeartbeatCallbacks(), this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any chance we can move these inits to params so that we only pass in heart
instead? I know this is pre-existig but we try avoiding work in ctors usually and this seems a good time to do it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have done this in a follow-up branch that we are waiting to open 😆 but yes we should try and move all of these out of the constructor.
@Override | ||
public void onTimelineChanged(Timeline timeline, Object manifest) { | ||
HashMap<String, String> keyValuePairs = new HashMap<>(); | ||
keyValuePairs.put("timeline", String.valueOf(timeline)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inb4 "extract constants", I am ok with one-off strings not being extracted here 👍
|
||
@Override | ||
public void onPlayerError(ExoPlaybackException error) { | ||
//Sent by ErrorForwarder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this different from the others?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. This particular event is handled by the errorForwarder
and should not be handled by this Forwarder
. This is because it would be a bit strange to notify the no-player
complete listeners of an error, when that is handled by the no-player
error listeners.
This is a small problem with using the interfaces we are interested in from ExoPlayer
it leads to explicit no-ops in the specific implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Figured that was the case, ok :)
|
||
@Override | ||
public void onPlayerError(ExoPlaybackException error) { | ||
//Sent by ErrorForwarder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for the onCompletionListener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as onCompletionListener
response 👅
|
||
@Override | ||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { | ||
//Handled by OnPrepared and OnCompletion forwarders |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why this is here then? Is it because the Exoplayer interface is having both methods and we just split them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, it is because ExoPlayer.EventListener
is too broad a listener 😢 but we decided it was better than having an abstract class. Better to be explicit about these in the implementations then to hide it in the abstraction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep agreed, I'm ok with that
@@ -30,7 +30,7 @@ protected void onCreate(Bundle savedInstanceState) { | |||
@Override | |||
protected void onStart() { | |||
super.onStart(); | |||
player = new PlayerFactory(this, PrioritisedPlayers.prioritiseMediaPlayer()).create(); | |||
player = new PlayerFactory(this, PrioritisedPlayers.prioritiseExoPlayer()).create(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave a TODO maybe?
exoPlayer.addListener(forwarder.exoPlayerEventListener()); | ||
exoPlayer.setVideoDebugListener(forwarder.videoRendererEventListener()); | ||
|
||
exoPlayer.setPlayWhenReady(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the reason for this change? it'll break symmetry with the media player as the we're relying on
loadVideo -> onPrepared -> play
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we no longer need onPrepared step in exoplayer2.
But if that's the case in mediaPlayer then probably we would need to bring it back.
Problem
ExoPlayerForwarder
contained all of the events that we listen to fromExoPlayer
and we createdForwarders
that adapted theExoPlayer
events to ourno-player
events. Some of theseForwarders
contained state.Facade
andImple
were mixing responsibilities with no clear boundary.Solution
Forwarder
and implement specific forwarders for the events we want to listen to.Facade
from exo-player because the code is small enough to be encapsulated in one class with collaborators.Test(s) added
No tests atm, we hope to branch off and have these covered soon.
Screenshots
No UI changes.
Paired with
@Dorvaryn and @jackSzm