Skip to content
This repository has been archived by the owner on Feb 11, 2022. It is now read-only.

Provide both Surface and SurfaceHolder in MediaPlayer #162

Merged
merged 5 commits into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static PlayerSurfaceHolder create(SurfaceView surfaceView) {
public static PlayerSurfaceHolder create(TextureView textureView) {
PlayerViewSurfaceHolder surfaceHolder = new PlayerViewSurfaceHolder();
textureView.setSurfaceTextureListener(surfaceHolder);
return new PlayerSurfaceHolder(null, textureView, new PlayerViewSurfaceHolder());
return new PlayerSurfaceHolder(null, textureView, surfaceHolder);
}

PlayerSurfaceHolder(@Nullable SurfaceView surfaceView, @Nullable TextureView textureView, PlayerViewSurfaceHolder surfaceHolder) {
Expand Down
33 changes: 17 additions & 16 deletions core/src/main/java/com/novoda/noplayer/PlayerViewSurfaceHolder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import com.novoda.noplayer.model.Either;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -13,12 +14,12 @@ class PlayerViewSurfaceHolder implements SurfaceHolder.Callback, TextureView.Sur

private final List<Callback> callbacks = new ArrayList<>();
@Nullable
private Surface surface;
private Either<Surface, SurfaceHolder> eitherSurface;

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
this.surface = surfaceHolder.getSurface();
notifyListeners(surface);
this.eitherSurface = Either.right(surfaceHolder);
notifyListeners(eitherSurface);
callbacks.clear();
}

Expand All @@ -35,11 +36,17 @@ public void surfaceDestroyed(SurfaceHolder holder) {

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
this.surface = new Surface(surfaceTexture);
notifyListeners(surface);
this.eitherSurface = Either.left(new Surface(surfaceTexture));
notifyListeners(eitherSurface);
callbacks.clear();
}

private void notifyListeners(Either<Surface, SurfaceHolder> either) {
for (Callback callback : callbacks) {
callback.onSurfaceReady(either);
}
}

@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// do nothing
Expand All @@ -58,27 +65,21 @@ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// do nothing
}

private void notifyListeners(Surface surface) {
for (Callback callback : callbacks) {
callback.onSurfaceReady(surface);
}
}

private void setSurfaceNotReady() {
surface = null;
eitherSurface = null;
}

@Override
public void requestSurface(Callback callback) {
if (isSurfaceHolderReady()) {
callback.onSurfaceReady(surface);
if (isSurfaceReady()) {
callback.onSurfaceReady(eitherSurface);
} else {
callbacks.add(callback);
}
}

private boolean isSurfaceHolderReady() {
return surface != null;
private boolean isSurfaceReady() {
return eitherSurface != null;
}

@Override
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/com/novoda/noplayer/SurfaceRequester.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.novoda.noplayer;

import android.view.Surface;
import android.view.SurfaceHolder;
import com.novoda.noplayer.model.Either;

public interface SurfaceRequester {

Expand All @@ -10,8 +12,7 @@ public interface SurfaceRequester {

interface Callback {

void onSurfaceReady(Surface surface);

void onSurfaceReady(Either<Surface, SurfaceHolder> surface);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
import android.net.Uri;
import android.support.annotation.Nullable;
import android.view.Surface;

import android.view.SurfaceHolder;
import com.novoda.noplayer.internal.mediaplayer.PlaybackStateChecker.PlaybackState;
import com.novoda.noplayer.internal.mediaplayer.forwarder.MediaPlayerForwarder;
import com.novoda.noplayer.internal.utils.NoPlayerLog;
import com.novoda.noplayer.internal.utils.Optional;
import com.novoda.noplayer.model.AudioTracks;
import com.novoda.noplayer.model.Either;
import com.novoda.noplayer.model.PlayerAudioTrack;
import com.novoda.noplayer.model.PlayerSubtitleTrack;
import com.novoda.noplayer.model.PlayerVideoTrack;
Expand Down Expand Up @@ -67,7 +68,7 @@ static AndroidMediaPlayerFacade newInstance(Context context, MediaPlayerForwarde
this.mediaPlayerCreator = mediaPlayerCreator;
}

void prepareVideo(Uri videoUri, Surface surface) {
void prepareVideo(Uri videoUri, Either<Surface, SurfaceHolder> surface) {
requestAudioFocus();
release();
try {
Expand All @@ -83,7 +84,7 @@ private void requestAudioFocus() {
audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}

private MediaPlayer createAndBindMediaPlayer(Surface surface,
private MediaPlayer createAndBindMediaPlayer(Either<Surface, SurfaceHolder> surface,
Uri videoUri) throws IOException, IllegalStateException, IllegalArgumentException {
MediaPlayer mediaPlayer = mediaPlayerCreator.createMediaPlayer();
mediaPlayer.setOnPreparedListener(internalPreparedListener);
Expand All @@ -92,7 +93,7 @@ private MediaPlayer createAndBindMediaPlayer(Surface surface,
mediaPlayer.setOnErrorListener(internalErrorListener);
mediaPlayer.setOnBufferingUpdateListener(internalBufferingUpdateListener);
mediaPlayer.setDataSource(context, videoUri, NO_HEADERS);
mediaPlayer.setSurface(surface);
attachSurface(mediaPlayer, surface);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setScreenOnWhilePlaying(true);

Expand Down Expand Up @@ -173,13 +174,29 @@ void release() {
}
}

void start(Surface surface) throws IllegalStateException {
void start(Either<Surface, SurfaceHolder> surface) throws IllegalStateException {
assertIsInPlaybackState();
mediaPlayer.setSurface(surface);
attachSurface(mediaPlayer, surface);
currentState = PLAYING;
mediaPlayer.start();
}

private void attachSurface(final MediaPlayer mediaPlayer, Either<Surface, SurfaceHolder> surface) {
Either.Consumer<Surface> setSurface = new Either.Consumer<Surface>() {
@Override
public void accept(Surface value) {
mediaPlayer.setSurface(value);
}
};
Either.Consumer<SurfaceHolder> setDisplay = new Either.Consumer<SurfaceHolder>() {
@Override
public void accept(SurfaceHolder value) {
mediaPlayer.setDisplay(value);
}
};
surface.apply(setSurface, setDisplay);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really digging this 👍

}

void pause() throws IllegalStateException {
assertIsInPlaybackState();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import com.novoda.noplayer.Listeners;
import com.novoda.noplayer.NoPlayer;
import com.novoda.noplayer.Options;
import com.novoda.noplayer.PlayerInformation;
import com.novoda.noplayer.PlayerState;
import com.novoda.noplayer.PlayerView;
import com.novoda.noplayer.PlayerSurfaceHolder;
import com.novoda.noplayer.PlayerView;
import com.novoda.noplayer.SurfaceRequester;
import com.novoda.noplayer.internal.Heart;
import com.novoda.noplayer.internal.listeners.PlayerListenersHolder;
import com.novoda.noplayer.internal.mediaplayer.forwarder.MediaPlayerForwarder;
import com.novoda.noplayer.internal.utils.Optional;
import com.novoda.noplayer.model.AudioTracks;
import com.novoda.noplayer.model.Either;
import com.novoda.noplayer.model.LoadTimeout;
import com.novoda.noplayer.model.PlayerAudioTrack;
import com.novoda.noplayer.model.PlayerSubtitleTrack;
Expand Down Expand Up @@ -146,7 +148,7 @@ public void play() throws IllegalStateException {
heart.startBeatingHeart();
requestSurface(new SurfaceRequester.Callback() {
@Override
public void onSurfaceReady(Surface surface) {
public void onSurfaceReady(Either<Surface, SurfaceHolder> surface) {
mediaPlayer.start(surface);
listenersHolder.getStateChangedListeners().onVideoPlaying();
}
Expand All @@ -160,7 +162,7 @@ public void playAt(final long positionInMillis) throws IllegalStateException {
} else {
requestSurface(new SurfaceRequester.Callback() {
@Override
public void onSurfaceReady(Surface surface) {
public void onSurfaceReady(Either<Surface, SurfaceHolder> surface) {
initialSeekWorkaround(surface, positionInMillis);
}
});
Expand All @@ -171,7 +173,7 @@ public void onSurfaceReady(Surface surface) {
* Workaround to fix some devices (nexus 7 2013 in particular) from natively crashing the mediaplayer
* by starting the mediaplayer before seeking it.
*/
private void initialSeekWorkaround(Surface surface, final long initialPlayPositionInMillis) throws IllegalStateException {
private void initialSeekWorkaround(Either<Surface, SurfaceHolder> surface, final long initialPlayPositionInMillis) throws IllegalStateException {
listenersHolder.getBufferStateListeners().onBufferStarted();
initialisePlaybackForSeeking(surface);
delayedActionExecutor.performAfterDelay(new DelayedActionExecutor.Action() {
Expand All @@ -182,7 +184,7 @@ public void perform() {
}, INITIAL_PLAY_SEEK_DELAY_IN_MILLIS);
}

private void initialisePlaybackForSeeking(Surface surface) {
private void initialisePlaybackForSeeking(Either<Surface, SurfaceHolder> surface) {
mediaPlayer.start(surface);
mediaPlayer.pause();
}
Expand Down Expand Up @@ -231,7 +233,7 @@ public void loadVideo(final Uri uri, final Options options) {
listenersHolder.getBufferStateListeners().onBufferStarted();
requestSurface(new SurfaceRequester.Callback() {
@Override
public void onSurfaceReady(Surface surface) {
public void onSurfaceReady(Either<Surface, SurfaceHolder> surface) {
mediaPlayer.prepareVideo(uri, surface);
}
});
Expand Down
50 changes: 50 additions & 0 deletions core/src/main/java/com/novoda/noplayer/model/Either.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.novoda.noplayer.model;
Copy link
Contributor

@ouchadam ouchadam Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we exposing this to clients? If not the project is using the convention of an internal package to describe public classes which do not provide a guaranteed api.

Copy link
Contributor Author

@JozefCeluch JozefCeluch Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not directly, but it's used in SurfaceRequester which is kinda exposed in the public API through PlayerSurfaceHolder(the clients need to provide an instance of this when they implement a custom implementation of PlayerView).


public abstract class Either<L, R> {

public static <L, R> Either<L, R> left(L left) {
return new Left<>(left);
}

public static <L, R> Either<L, R> right(R right) {
return new Right<>(right);
}

Either() {
// restrict subclasses to the package
}

public abstract void apply(Consumer<L> leftConsumer, Consumer<R> rightConsumer);

static class Left<L, R> extends Either<L, R> {

private final L valueLeft;

Left(L valueLeft) {
this.valueLeft = valueLeft;
}

@Override
public void apply(Consumer<L> leftConsumer, Consumer<R> rightConsumer) {
leftConsumer.accept(valueLeft);
}
}

static class Right<L, R> extends Either<L, R> {

private final R valueRight;

Right(R valueRight) {
this.valueRight = valueRight;
}

@Override
public void apply(Consumer<L> leftConsumer, Consumer<R> rightConsumer) {
rightConsumer.accept(valueRight);
}
}

public interface Consumer<T> {
void accept(T value);
}
}
Loading