android listener progress exoplayer

Android ExoPlayer en ProgressChanged



listener (9)

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


Amplíe su clase de jugador actual (SimpleExoPlayer por ej.) Y agregue

public interface PlayerEventsListener { void onSeek(int from, int to); void onProgressUpdate(long progress); } private PlayerEventsListener mListener; private Handler mHandler; private Runnable mProgressUpdater; private boolean isUpdatingProgress = false; public SomePlayersConstructor(Activity activity, /*...*/) { //... mListener = (PlayerEventsListener) activity; mHandler = new Handler(); mProgressUpdater = new ProgressUpdater(); } // Here u gain access to seek events @Override public void seekTo(long positionMs) { mListener.onSeek(-1, (int)positionMs/1000); super.seekTo(positionMs); } @Override public void seekTo(int windowIndex, long positionMs) { mListener.onSeek((int)getCurrentPosition()/1000, (int)positionMs/1000); super.seekTo(windowIndex, positionMs); } // Here u gain access to progress public void startProgressUpdater() { if (!isUpdatingProgress) { mProgressUpdater.run(); isUpdatingProgress = true; } } private class ProgressUpdater implements Runnable { private static final int TIME_UPDATE_MS = 500; @Override public void run() { mListener.onProgressUpdate(getCurrentPosition()); mHandler.postDelayed(mProgressUpdater, TIME_UPDATE_MS); } }

Luego, dentro de la actividad del jugador, simplemente implementa la interfaz y comienza las actualizaciones con player.startProgressUpdater();


Esto funciona al menos con Exoplayer 2.

Hay cuatro estados de reproducción: STATE_IDLE, STATE_BUFFERING, STATE_READY y STATE_ENDED.

Verificar el estado de reproducción es fácil de hacer. Hay al menos dos soluciones: if-statement o switch-statement.

Cualquiera que sea el estado de reproducción en curso, puede ejecutar su método o configurar otra cosa, por ejemplo, barra de progreso.

@Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { if (playbackState == ExoPlayer.STATE_ENDED) { showControls(); Toast.makeText(getApplicationContext(), "Playback ended", Toast.LENGTH_LONG).show(); } else if (playbackState == ExoPlayer.STATE_BUFFERING) { progressBar.setVisibility(View.VISIBLE); Toast.makeText(getApplicationContext(), "Buffering..", Toast.LENGTH_SHORT).show(); } else if (playbackState == ExoPlayer.STATE_READY) { progressBar.setVisibility(View.INVISIBLE); } }


He encontrado 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 1 segundo.

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

La lógica aquí es que creamos un Observable que emitirá un número secuencial cada segundo. Luego usamos el operador del map 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, simplemente llame a suscribirse, y los cambios de progreso se emitirán cada segundo:

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

Nota: Observable.interval ejecuta en un Scheduler predeterminado de Schedulers.computation() . Por lo tanto, es probable que deba agregar un operador observeOn() para asegurarse de que los resultados se envíen al hilo correcto.

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

La declaración anterior le proporcionará un Desechable que debe eliminarse 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 el recurso ->

playbackDisposable?.dispose()


No estoy seguro de que sea la mejor manera, pero logré esto al sobrecargar el TrackRenderer .

Estoy usando videoPlayer.getBufferedPercentage() , pero es posible que usted también pueda calcular el porcentaje mediante el uso de 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); } }


No estoy seguro de si es el enfoque correcto, pero utilicé EventBus y TimerTask para actualizar el progreso del audio que se está reproduciendo. En mi clase de 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 de onPlayerStateChanged al agregar el escucha a mi instancia de SimpleExoPlayer. El código anterior envía la duración transcurrida y total del audio que se reproduce cada 1 segundo (1000 ms) a través de EventBus. Luego dentro de la actividad que alberga el SeekBar:

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


Para que quede claro, no hay una compilación en EventListener para el evento progress, 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 Exoplayer


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

Por lo tanto, he seguido los siguientes métodos para realizar un seguimiento del progreso de la reproducción. Así es como se hace en Google Docs de ExoPlayer . Funciona como sea necesario.

Checkout PlayerControlView.java en el repositorio de Google ExoPlayer

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

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(); } };

Llamamos a updateProgressBar() dentro de updateProgressAction repetidamente hasta que la reproducción se detiene. La función se llama la primera vez siempre que hay un cambio de estado. Usamos removeCallbacks(Runnable runnable) para que siempre haya un updateProgressAction para cuidar.

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

¡Espero que esto ayude!


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() : return La posición de reproducción actual en milisegundos.
  • getDuration() : la duración de la pista en milisegundos.

Solo use onTouchListener con MotionEvent.ACTION_UP

SeekBar exo_progress = (SeekBar) findViewById(R.id.exo_progress); exo_progress.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { //put your code here!! } return false; } });