Android ExoPlayer en progreso cambiado

7 minutos de lectura

avatar de usuario
ascallonisi

¿Cómo puedo monitorear los cambios de progreso en ExoPlayer?
Traté de implementar un oculto MediaController y anulando setOnSeekBarChangeListener métodos, pero por ahora sin éxito. Me pregunto si hay otra manera de escuchar el ExoPlayer Progreso.

avatar de usuario
ankit agarwal

Sé que esta pregunta es muy antigua. Pero, aterricé en esto mientras implementaba ExoPlayer. Esto es para ayudar a otros que hagan lo mismo más adelante 🙂

Entonces, he seguido los siguientes métodos para rastrear el progreso de la reproducción. Esta es la forma en que se hace en el ExoPlayer Documentos de Google. Funciona según sea necesario.

Verificar PlayerControlView.java en Repositorio de Google ExoPlayer

updateProgressBar() es la función para actualizar el SeekBar Progreso:

private void updateProgressBar() {
    long duration = player == null ? 0 : player.getDuration();
    long position = player == null ? 0 : player.getCurrentPosition();
    if (!dragging) {
        mSeekBar.setProgress(progressBarValue(position));
    }
    long bufferedPosition = player == null ? 0 : player.getBufferedPosition();
    mSeekBar.setSecondaryProgress(progressBarValue(bufferedPosition));
    // Remove scheduled updates.
    handler.removeCallbacks(updateProgressAction);
    // Schedule an update if necessary.
    int playbackState = player == null ? Player.STATE_IDLE : player.getPlaybackState();
    if (playbackState != Player.STATE_IDLE && playbackState != Player.STATE_ENDED) {
        long delayMs;
        if (player.getPlayWhenReady() && playbackState == Player.STATE_READY) {
            delayMs = 1000 - (position % 1000);
            if (delayMs < 200) {
                delayMs += 1000;
            }
        } else {
            delayMs = 1000;
        }
        handler.postDelayed(updateProgressAction, delayMs);
    }
}

private final Runnable updateProgressAction = new Runnable() {
    @Override
    public void run() {
        updateProgressBar();
    }
};

Nosotros llamamos updateProgressBar() dentro de updateProgressAction repetidamente hasta que la reproducción se detenga. La función se llama la primera vez siempre que hay un cambio de estado. Usamos removeCallbacks(Runnable runnable) para que siempre haya uno updateProgressAction preocuparse.

@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
  updateProgressBar();
}

¡Espero que esto ayude!

  • Lo que en realidad significa que estás encuestando al estado

    – Tomás

    10 de abril de 2017 a las 12:15

  • @Thomas, que en realidad parece ser una especie de solución correcta, porque el propio exoplayer genera eventos de progreso con demasiada frecuencia para la interfaz de usuario.

    – kot331107

    29 de diciembre de 2017 a las 17:19

  • @AnkitAggarwal Tengo una barra de progreso personalizada. ¿Cómo puedo actualizar el progreso mientras reproduzco un video? Por favor, ayuda.

    – Sagar

    6 de marzo de 2018 a las 11:51

  • Bueno, a partir de hoy, con la versión 2.14.0 de exoplayer, el método anterior ha cambiado mucho, resultando difícil obtener los métodos/variables equivalentes para arrastrar, progresoBarValue,…

    – Velú

    10 de junio de 2021 a las 12:59

Solo prueba esto, está funcionando para mí:

handler = new Handler();
runnable = new Runnable() {
      @Override
      public void run() {
           progressbar.setProgress((int) ((exoPlayer.getCurrentPosition()*100)/exoPlayer.getDuration()));
           handler.postDelayed(runnable, 1000);
      }
};
handler.postDelayed(runnable, 0);

Aquí,

  • getCurrentPosition() : volver La posición de reproducción actual en milisegundos.
  • getDuration(): La duración de la pista en milisegundos.

  • gracias por tu respuesta

    – Sagar

    6 de marzo de 2018 a las 12:01

  • funciona … pero no se reinicia a cero después de reproducir un audio

    – anjujo

    6 de noviembre de 2019 a las 10:11

avatar de usuario
Felipe Roriz

Encontré una solución bastante elegante usando RxJava. Esto también implica un patrón de sondeo, pero nos aseguramos de usar un intervalo para sondear cada segundo.

public Observable<Long> playbackProgressObservable = 
                            Observable.interval(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())

La lógica aquí es que creamos un Observable que emitirá un número secuencial cada segundo. Entonces usamos el map operador para transformar el número en la posición de reproducción actual.

public Observable<Long> playbackProgressObservable = 
                        Observable.interval(1, TimeUnit.SECONDS)
                                  .map( { exoPlayer.getCurrentPosition() } );

Para finalmente conectar esto, solo llame a suscribirse, y las actualizaciones de progreso se emitirán cada segundo:

playbackProgressObservable.subscribe( { progress -> // Update logic here } )

Nota: Observable.interval se ejecuta de forma predeterminada Scheduler de Schedulers.computation(). Por lo tanto, probablemente necesitará agregar un observeOn() operador para asegurarse de que los resultados se envíen al subproceso correcto.

playbackProgressObservable
    .observeOn(AndroidSchedulers.mainThread())        
    .subscribe(progress -> {}) // Update logic here 

La declaración anterior le dará una Desechable que debe desecharse cuando haya terminado de observar. Puedes hacer algo como esto ->

private var playbackDisposable: Disposable? = null

       playbackDisposable = playbackProgressObservable
        .observeOn(AndroidSchedulers.mainThead())        
        .subscribe(progress -> {}) // Update logic here

luego para disponer del recurso ->

playbackDisposable?.dispose()

  • Es posible que esto no funcione en la nueva actualización del reproductor Exo. Es posible que aparezca una advertencia de acceso al reproductor en un subproceso incorrecto

    – Samrat

    17 de agosto de 2021 a las 5:41

No estoy seguro de que sea la mejor manera, pero lo logré sobrecargando el TrackRenderer.

Estoy usando videoPlayer.getBufferedPercentage()pero es posible que también pueda calcular el porcentaje usted mismo, simplemente usando TrackRenderer‘s getBufferedPositionUs() y getDurationUs()

public interface ProgressListener {
    public void onProgressChange(long progress);
}

public class CustomVideoRenderer extends  MediaCodecVideoTrackRenderer {

    long progress = 0;
    private final CopyOnWriteArraySet<ProgressListener> progressListeners = new CopyOnWriteArraySet();

    // [...]
    // Skipped constructors
    // [...]

    public void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
        super.doSomeWork(positionUs, elapsedRealtimeUs);

        long tmpProgress = videoPlayer.getBufferedPercentage();

        if (tmpProgress != this.progress) {
            this.progress = tmpProgress;

            for (ProgressListener progressListener : this.progressListeners) {
                progressListener.onProgressChange(progress);
            }
        }
    }

    public void addProgressListener(ProgressListener listener) {
        this.progressListeners.add(listener);
    }

}

Bueno, hice esto a través de kotlin flow…

private fun audioProgress(exoPlayer: SimpleExoPlayer?) = flow<Int> {
        while (true) {
            emit(((exoPlayer?.currentPosition?.toFloat()?.div(exoPlayer.duration.toFloat())?.times(100))?.toInt()!!))
            delay(1000)
        }
    }.flowOn(Dispatchers.IO)

luego recoge el progreso así…

val audioProgressJob = launch {
            audioProgress(exoPlayer).collect {
                MP_progress_bar.progress = it
            }
        }

  • exoPlayer.currentPosition solo se puede acceder desde Main Thread, de lo contrario arroja una excepción.

    – Jemshit Iskenderov

    4 de marzo de 2021 a las 16:15

  • lanza una advertencia, no una excepción… prueba esto… funciona perfectamente…

    – abhi

    9 de marzo de 2021 a las 18:01

  • Lo intenté y arroja una excepción en tiempo de ejecución. yo prob. usar la versión más reciente

    – Jemshit Iskenderov

    9 de marzo de 2021 a las 18:32

  • hermano, ¿puedes comentar el seguimiento de la pila de errores?

    – abhi

    9 de marzo de 2021 a las 19:12

  • La excepción se documenta en esta página: exoplayer.dev/…

    – Jemshit Iskenderov

    10 de marzo de 2021 a las 11:18

Para que quede claro, no hay una compilación en EventListener para el evento de progreso, pero puede llamar a Handler.postDelayed dentro de su función updateProgress() para obtener el progreso actual

 private void updateProgress(){

    //get current progress 
    long position = player == null ? 0 : player.getCurrentPosition();
    //updateProgress() will be called repeatedly, you can check 
    //player state to end it
    handler.postDelayed(updateProgressAction,1000)

}

 private final Runnable updateProgressAction = new Runnable() {
    @Override
    public void run() {        
      updateProgress();
    }
};

para más detalles, consulte la fuente de PlaybackControlView.java dentro de exojugador

  • exoPlayer.currentPosition solo se puede acceder desde Main Thread, de lo contrario arroja una excepción.

    – Jemshit Iskenderov

    4 de marzo de 2021 a las 16:15

  • lanza una advertencia, no una excepción… prueba esto… funciona perfectamente…

    – abhi

    9 de marzo de 2021 a las 18:01

  • Lo intenté y arroja una excepción en tiempo de ejecución. yo prob. usar la versión más reciente

    – Jemshit Iskenderov

    9 de marzo de 2021 a las 18:32

  • hermano, ¿puedes comentar el seguimiento de la pila de errores?

    – abhi

    9 de marzo de 2021 a las 19:12

  • La excepción se documenta en esta página: exoplayer.dev/…

    – Jemshit Iskenderov

    10 de marzo de 2021 a las 11:18

avatar de usuario
Javad Arjmandi

No estoy seguro de si es el enfoque correcto, pero usé EventBus y TimerTask para actualizar el progreso del audio que se está reproduciendo. En mi clase MusicController pongo:

private void sendElapsedDuration() {
    //To send the current elapsed time
    final Timer t = new Timer();
    Runnable r = new Runnable() {
        @Override
        public void run() {
            t.schedule(new TimerTask() {
                @Override
                public void run() {
                    EventBus.getDefault().post(
                            new ProgressNotification(
                                    player.getCurrentPosition(), player.getDuration())
                    );
                    if (player.getCurrentPosition() >= player.getDuration() ){
                        // The audio is ended, we pause the playback,
                        // and reset the position
                        player.seekTo(0);
                        player.setPlayWhenReady(false);
                        this.cancel();
                        // stopping the Runnable to avoid memory leak
                        mainHandler.removeCallbacks(this);
                    }
                }
            },0,1000);
        }
    };
    if(player != null) {
        if (player.getPlaybackState() != Player.STATE_ENDED)
            mainHandler.postDelayed(r, 500);
        else {
            //We put the TimerTask to sleep when audio is not playing
            t.cancel();
        }
    }

}

Luego llamé al método dentro del onPlayerStateChanged al agregar el oyente a mi instancia de SimpleExoPlayer. El código anterior envía la duración total y transcurrida del audio que se reproduce cada segundo (1000 ms) a través de EventBus. Luego, dentro de la actividad que alberga la SeekBar:

@Subscribe(threadMode = ThreadMode.MAIN)
    public void updateProgress(ProgressNotification pn) {
        seekBar.setMax((int) pn.duration);
        seekBar.setProgress((int) pn.currentPosition);
    }

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad