Skip to content
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
4 changes: 4 additions & 0 deletions packages/video_player/video_player_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.8.9

* Restructures the communication between Dart and Java code.

## 2.8.8

* * Updates Media3-ExoPlayer to 1.5.1.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v22.6.1), do not edit directly.
// Autogenerated from Pigeon (v25.5.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.videoplayer;
Expand Down Expand Up @@ -380,28 +380,12 @@ public interface AndroidVideoPlayerApi {

void dispose(@NonNull Long playerId);

void setLooping(@NonNull Long playerId, @NonNull Boolean looping);

void setVolume(@NonNull Long playerId, @NonNull Double volume);

void setPlaybackSpeed(@NonNull Long playerId, @NonNull Double speed);

void play(@NonNull Long playerId);

@NonNull
Long position(@NonNull Long playerId);

void seekTo(@NonNull Long playerId, @NonNull Long position);

void pause(@NonNull Long playerId);

void setMixWithOthers(@NonNull Boolean mixWithOthers);

/** The codec used by AndroidVideoPlayerApi. */
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
}

/**
* Sets up an instance of `AndroidVideoPlayerApi` to handle messages through the
* `binaryMessenger`.
Expand Down Expand Up @@ -493,18 +477,17 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setLooping"
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Boolean loopingArg = (Boolean) args.get(1);
Boolean mixWithOthersArg = (Boolean) args.get(0);
try {
api.setLooping(playerIdArg, loopingArg);
api.setMixWithOthers(mixWithOthersArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand All @@ -515,22 +498,59 @@ static void setUp(
channel.setMessageHandler(null);
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface VideoPlayerInstanceApi {

void setLooping(@NonNull Boolean looping);

void setVolume(@NonNull Double volume);

void setPlaybackSpeed(@NonNull Double speed);

void play();

@NonNull
Long getPosition();

void seekTo(@NonNull Long position);

void pause();

/** The codec used by VideoPlayerInstanceApi. */
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
}
/**
* Sets up an instance of `VideoPlayerInstanceApi` to handle messages through the
* `binaryMessenger`.
*/
static void setUp(
@NonNull BinaryMessenger binaryMessenger, @Nullable VideoPlayerInstanceApi api) {
setUp(binaryMessenger, "", api);
}

static void setUp(
@NonNull BinaryMessenger binaryMessenger,
@NonNull String messageChannelSuffix,
@Nullable VideoPlayerInstanceApi api) {
messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setVolume"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.setLooping"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Double volumeArg = (Double) args.get(1);
Boolean loopingArg = (Boolean) args.get(0);
try {
api.setVolume(playerIdArg, volumeArg);
api.setLooping(loopingArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand All @@ -545,18 +565,17 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setPlaybackSpeed"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.setVolume"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Double speedArg = (Double) args.get(1);
Double volumeArg = (Double) args.get(0);
try {
api.setPlaybackSpeed(playerIdArg, speedArg);
api.setVolume(volumeArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand All @@ -571,17 +590,17 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.play"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.setPlaybackSpeed"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Double speedArg = (Double) args.get(0);
try {
api.play(playerIdArg);
api.setPlaybackSpeed(speedArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand All @@ -596,18 +615,16 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.position"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.play"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
try {
Long output = api.position(playerIdArg);
wrapped.add(0, output);
api.play();
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
}
Expand All @@ -621,19 +638,16 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.seekTo"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.getPosition"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Long positionArg = (Long) args.get(1);
try {
api.seekTo(playerIdArg, positionArg);
wrapped.add(0, null);
Long output = api.getPosition();
wrapped.add(0, output);
} catch (Throwable exception) {
wrapped = wrapError(exception);
}
Expand All @@ -647,17 +661,17 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.pause"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.seekTo"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Long playerIdArg = (Long) args.get(0);
Long positionArg = (Long) args.get(0);
try {
api.pause(playerIdArg);
api.seekTo(positionArg);
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand All @@ -672,17 +686,15 @@ static void setUp(
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.video_player_android.AndroidVideoPlayerApi.setMixWithOthers"
"dev.flutter.pigeon.video_player_android.VideoPlayerInstanceApi.pause"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
ArrayList<Object> args = (ArrayList<Object>) message;
Boolean mixWithOthersArg = (Boolean) args.get(0);
try {
api.setMixWithOthers(mixWithOthersArg);
api.pause();
wrapped.add(0, null);
} catch (Throwable exception) {
wrapped = wrapError(exception);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
*
* <p>It provides methods to control playback, adjust volume, and handle seeking.
*/
public abstract class VideoPlayer {
public abstract class VideoPlayer implements Messages.VideoPlayerInstanceApi {
@NonNull protected final VideoPlayerCallbacks videoPlayerEvents;
@Nullable protected final SurfaceProducer surfaceProducer;
@Nullable private DisposeHandler disposeHandler;
@NonNull protected ExoPlayer exoPlayer;

/** A closure-compatible signature since {@link java.util.function.Supplier} is API level 24. */
Expand All @@ -37,6 +38,11 @@ public interface ExoPlayerProvider {
ExoPlayer get();
}

/** A handler to run when dispose is called. */
public interface DisposeHandler {
void onDispose();
}

public VideoPlayer(
@NonNull VideoPlayerCallbacks events,
@NonNull MediaItem mediaItem,
Expand All @@ -52,6 +58,10 @@ public VideoPlayer(
setAudioAttributes(exoPlayer, options.mixWithOthers);
}

public void setDisposeHandler(@Nullable DisposeHandler handler) {
disposeHandler = handler;
}

@NonNull
protected abstract ExoPlayerEventListener createExoPlayerEventListener(
@NonNull ExoPlayer exoPlayer, @Nullable SurfaceProducer surfaceProducer);
Expand All @@ -66,37 +76,48 @@ private static void setAudioAttributes(ExoPlayer exoPlayer, boolean isMixMode) {
!isMixMode);
}

void play() {
@Override
public void play() {
exoPlayer.play();
}

void pause() {
@Override
public void pause() {
exoPlayer.pause();
}

void setLooping(boolean value) {
exoPlayer.setRepeatMode(value ? REPEAT_MODE_ALL : REPEAT_MODE_OFF);
@Override
public void setLooping(@NonNull Boolean looping) {
exoPlayer.setRepeatMode(looping ? REPEAT_MODE_ALL : REPEAT_MODE_OFF);
}

void setVolume(double value) {
float bracketedValue = (float) Math.max(0.0, Math.min(1.0, value));
@Override
public void setVolume(@NonNull Double volume) {
float bracketedValue = (float) Math.max(0.0, Math.min(1.0, volume));
exoPlayer.setVolume(bracketedValue);
}

void setPlaybackSpeed(double value) {
@Override
public void setPlaybackSpeed(@NonNull Double speed) {
// We do not need to consider pitch and skipSilence for now as we do not handle them and
// therefore never diverge from the default values.
final PlaybackParameters playbackParameters = new PlaybackParameters(((float) value));
final PlaybackParameters playbackParameters = new PlaybackParameters(speed.floatValue());

exoPlayer.setPlaybackParameters(playbackParameters);
}

void seekTo(int location) {
exoPlayer.seekTo(location);
@Override
public @NonNull Long getPosition() {
long position = exoPlayer.getCurrentPosition();
// TODO(stuartmorgan): Move this; this is relying on the fact that getPosition is called
// frequently to drive buffering updates, which is a fragile hack.
Copy link
Collaborator Author

@stuartmorgan-g stuartmorgan-g Jun 27, 2025

Choose a reason for hiding this comment

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

This hack is pre-existing; it's just being moved from the VideoPlayerPlugin.java version of this method. I added the comment so that future people don't have to go through the same process I did of wondering why getting the position sends a buffer update as a side effect.

sendBufferingUpdate();
return position;
}

long getPosition() {
return exoPlayer.getCurrentPosition();
@Override
public void seekTo(@NonNull Long position) {
exoPlayer.seekTo(position);
}

@NonNull
Expand All @@ -105,6 +126,9 @@ public ExoPlayer getExoPlayer() {
}

public void dispose() {
if (disposeHandler != null) {
disposeHandler.onDispose();
}
exoPlayer.release();
}
}
Loading