Skip to content
Closed
Changes from 1 commit
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
Prev Previous commit
Refactor ExoPlayerEventListener for timeline changes
Removed sendInitialized() from onPlaybackStateChanged and handled it in onTimelineChanged. Added timeline handling to check for initialization.
  • Loading branch information
AbdeMohlbi authored Oct 17, 2025
commit 9331ca61627aa8eec38365dbe91c89ef99b436ea
Original file line number Diff line number Diff line change
@@ -1,3 +1,95 @@
//// Copyright 2013 The Flutter Authors
//// Use of this source code is governed by a BSD-style license that can be
//// found in the LICENSE file.
//
//package io.flutter.plugins.videoplayer;
//
//import androidx.annotation.NonNull;
//import androidx.media3.common.PlaybackException;
//import androidx.media3.common.Player;
//import androidx.media3.exoplayer.ExoPlayer;
//
//public abstract class ExoPlayerEventListener implements Player.Listener {
// private boolean isInitialized = false;
// protected final ExoPlayer exoPlayer;
// protected final VideoPlayerCallbacks events;
//
// protected enum RotationDegrees {
// ROTATE_0(0),
// ROTATE_90(90),
// ROTATE_180(180),
// ROTATE_270(270);
//
// private final int degrees;
//
// RotationDegrees(int degrees) {
// this.degrees = degrees;
// }
//
// public static RotationDegrees fromDegrees(int degrees) {
// for (RotationDegrees rotationDegrees : RotationDegrees.values()) {
// if (rotationDegrees.degrees == degrees) {
// return rotationDegrees;
// }
// }
// throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees);
// }
//
// public int getDegrees() {
// return this.degrees;
// }
// }
//
// public ExoPlayerEventListener(
// @NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) {
// this.exoPlayer = exoPlayer;
// this.events = events;
// }
//
// protected abstract void sendInitialized();
//
// @Override
// public void onPlaybackStateChanged(final int playbackState) {
// PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN;
// switch (playbackState) {
// case Player.STATE_BUFFERING:
// platformState = PlatformPlaybackState.BUFFERING;
// break;
// case Player.STATE_READY:
// platformState = PlatformPlaybackState.READY;
// if (!isInitialized) {
// isInitialized = true;
// sendInitialized();
// }
// break;
// case Player.STATE_ENDED:
// platformState = PlatformPlaybackState.ENDED;
// break;
// case Player.STATE_IDLE:
// platformState = PlatformPlaybackState.IDLE;
// break;
// }
// events.onPlaybackStateChanged(platformState);
// }
//
// @Override
// public void onPlayerError(@NonNull final PlaybackException error) {
// if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
// // See
// // https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window
// exoPlayer.seekToDefaultPosition();
// exoPlayer.prepare();
// } else {
// events.onError("VideoError", "Video player had error " + error, null);
// }
// }
//
// @Override
// public void onIsPlayingChanged(boolean isPlaying) {
// events.onIsPlayingStateUpdate(isPlaying);
// }
//}

// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
Expand All @@ -7,85 +99,94 @@
import androidx.annotation.NonNull;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.Timeline;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.common.C;


public abstract class ExoPlayerEventListener implements Player.Listener {
private boolean isInitialized = false;
protected final ExoPlayer exoPlayer;
protected final VideoPlayerCallbacks events;
private boolean isInitialized = false;
protected final ExoPlayer exoPlayer;
protected final VideoPlayerCallbacks events;

protected enum RotationDegrees {
ROTATE_0(0),
ROTATE_90(90),
ROTATE_180(180),
ROTATE_270(270);
protected enum RotationDegrees {
ROTATE_0(0),
ROTATE_90(90),
ROTATE_180(180),
ROTATE_270(270);

private final int degrees;
private final int degrees;

RotationDegrees(int degrees) {
this.degrees = degrees;
}
RotationDegrees(int degrees) {
this.degrees = degrees;
}

public static RotationDegrees fromDegrees(int degrees) {
for (RotationDegrees rotationDegrees : RotationDegrees.values()) {
if (rotationDegrees.degrees == degrees) {
return rotationDegrees;
public static RotationDegrees fromDegrees(int degrees) {
for (RotationDegrees rotationDegrees : RotationDegrees.values()) {
if (rotationDegrees.degrees == degrees) {
return rotationDegrees;
}
}
throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees);
}
}
throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees);

public int getDegrees() {
return this.degrees;
}
}

public ExoPlayerEventListener(
@NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) {
this.exoPlayer = exoPlayer;
this.events = events;
}

public int getDegrees() {
return this.degrees;
protected abstract void sendInitialized();

@Override
public void onPlaybackStateChanged(final int playbackState) {
PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN;
switch (playbackState) {
case Player.STATE_BUFFERING:
platformState = PlatformPlaybackState.BUFFERING;
break;
case Player.STATE_READY:
platformState = PlatformPlaybackState.READY;
// ⚠️ Removed sendInitialized() from here — handled by onTimelineChanged()
break;
case Player.STATE_ENDED:
platformState = PlatformPlaybackState.ENDED;
break;
case Player.STATE_IDLE:
platformState = PlatformPlaybackState.IDLE;
break;
}
events.onPlaybackStateChanged(platformState);
}
}

public ExoPlayerEventListener(
@NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) {
this.exoPlayer = exoPlayer;
this.events = events;
}

protected abstract void sendInitialized();

@Override
public void onPlaybackStateChanged(final int playbackState) {
PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN;
switch (playbackState) {
case Player.STATE_BUFFERING:
platformState = PlatformPlaybackState.BUFFERING;
break;
case Player.STATE_READY:
platformState = PlatformPlaybackState.READY;
if (!isInitialized) {
isInitialized = true;
sendInitialized();

@Override
public void onTimelineChanged(@NonNull Timeline timeline, int reason) {
long duration = exoPlayer.getDuration();
if (!isInitialized && duration != C.TIME_UNSET){
isInitialized = true;
sendInitialized();
}
break;
case Player.STATE_ENDED:
platformState = PlatformPlaybackState.ENDED;
break;
case Player.STATE_IDLE:
platformState = PlatformPlaybackState.IDLE;
break;
}
events.onPlaybackStateChanged(platformState);
}

@Override
public void onPlayerError(@NonNull final PlaybackException error) {
if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
// See
// https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window
exoPlayer.seekToDefaultPosition();
exoPlayer.prepare();
} else {
events.onError("VideoError", "Video player had error " + error, null);

@Override
public void onPlayerError(@NonNull final PlaybackException error) {
if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
// See
// https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window
exoPlayer.seekToDefaultPosition();
exoPlayer.prepare();
} else {
events.onError("VideoError", "Video player had error " + error, null);
}
}
}

@Override
public void onIsPlayingChanged(boolean isPlaying) {
events.onIsPlayingStateUpdate(isPlaying);
}
@Override
public void onIsPlayingChanged(boolean isPlaying) {
events.onIsPlayingStateUpdate(isPlaying);
}
}