¿Deshabilitar la solicitud de VideoView de AndroidAudioFocus al reproducir un video?
Estoy creando una aplicación que graba y reproduce video. Me gustaría hacerlo sin afectar la reproducción de música de fondo, es decir, si empiezo a reproducir un vídeo, no quiero detener el audio de otras aplicaciones. Sin embargo, en Lollipop, la clase VideoView de Android solicita automáticamente el enfoque de audio cuando se llama al método privado VideoView.openVideo()
:
AudioManager am = (AudioManager) super.getSystemService(name); am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
¿Alguna sugerencia sobre cómo superar esto?
- Cómo obtener el porcentaje de búfer de VideoView en Android
- VideoView no se procesa correctamente después de desaparecer el teclado de Dialog
- Calidad de vídeo del flujo de http en VideoView (Adaptive streaming)
- ¿El video de Android VideoView almacenó videos en streaming?
- Android WebView transparente en la parte superior de VideoView
- Lista de vídeos de Android ListView
- Android - MediaController de VideoView dentro de diálogo aparece detrás del diálogo
- Android: ¿Cualquier forma de reducir el retardo de los medios / latencia en VideoView / MediaPlayer?
- VideoView en un fondo de pantalla en vivo?
- El video no se detiene en el fragmento ViewPager
- Android 3.1 / Galaxy Tab / VideoView no se reproducirá
- MediaPlayer / VideoView - Stream de una URL y luego guardar el video después de la caché?
- VideoView y Progressive descargar
Conseguí alrededor de esto con una solución estúpida copiando el código fuente entero de android.widget.VideoView
de Lollipop y quitando la línea que usted mencionó.
Haga su propia clase VideoView
. No utilice extends VideoView
ya que no puede anular el método openVideo()
.
No recomiendo esto como pienso que es una solución temporal. VideoView
Cambiado mucho entre 4.1-5.0 por lo que esto puede hacer RuntimeException en la versión de Android que no sea Lollipop
Editar
Hice la aproximación MediaPlayer + SurfaceView como pinxue nos dijo; Respeta la relación de aspecto en viewWidth
y viewHeight
.
final String finalFilePath = filePath; final SurfaceHolder surfaceHolder = sv.getHolder(); final MediaPlayer mediaPlayer = new MediaPlayer(); final LinearLayout.LayoutParams svLayoutParams = new LinearLayout.LayoutParams(viewWidth,viewHeight); surfaceHolder.addCallback(new SurfaceHolder.Callback(){ @Override public void surfaceCreated(SurfaceHolder holder) { try { if(isDebug) { System.out.println("setting VideoPath to VideoView: "+finalFilePath); } mediaPlayer.setDataSource(finalFilePath); }catch (IOException ioe){ if(isDebug){ ioe.printStackTrace(); } //mediaPlayer = null; } mediaPlayer.setDisplay(surfaceHolder); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { if(isDebug){ System.out.println("Video is starting..."); } // for compatibility, we adjust size based on aspect ratio if ( mp.getVideoWidth() * svLayoutParams.height < svLayoutParams.width * mp.getVideoHeight() ) { //Log.i("@@@", "image too wide, correcting"); svLayoutParams.width = svLayoutParams.height * mp.getVideoWidth() / mp.getVideoHeight(); } else if ( mp.getVideoWidth() * svLayoutParams.height > svLayoutParams.width * mp.getVideoHeight() ) { //Log.i("@@@", "image too tall, correcting"); svLayoutParams.height = svLayoutParams.width * mp.getVideoHeight() / mp.getVideoWidth(); } sv.post(new Runnable(){ @Override public void run() { sv.setLayoutParams(svLayoutParams); } }); mp.start(); } }); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if(isDebug){ System.out.println("surfaceChanged(holder, "+format+", "+width+", "+height+")"); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { try { mediaPlayer.setDataSource(""); }catch (IOException ioe){ if(isDebug){ ioe.printStackTrace(); } } } }); if(sv.post(new Runnable() { @Override public void run() { sv.setLayoutParams(svLayoutParams);/// sv.setVisibility(View.VISIBLE); }})){ if(isDebug) { System.out.println("post Succeded"); } }else{ if(isDebug) { System.out.println("post Failed"); } }
Puede utilizar MediaPlayer + SurfaceView en su lugar.
La solución aceptada no garantiza la compatibilidad entre todas las versiones de Android y es un hack sucio más que una verdadera solución. He intentado todas las formas de hacks para conseguir este trabajo, pero ninguno ha funcionado a mi satisfacción.
He llegado con una solución mucho mejor sin embargo – cambiar de un VideoView
a un TextureView
y cargar con un MediaPlayer
. No hay diferencia desde la perspectiva del usuario, simplemente no hay detención de audio.
Aquí está mi caso de uso para jugar un bucle MP4:
private TextureView _introVideoTextureView; private MediaPlayer _introMediaPlayer; ... @Override public void onCreate(...) { _introVideoTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { try { destoryIntroVideo(); _introMediaPlayer = MediaPlayer.create(SignInActivity.this, R.raw.intro_video); _introMediaPlayer.setSurface(new Surface(surfaceTexture)); _introMediaPlayer.setLooping(true); _introMediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); _introMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.start(); } }); } catch (Exception e) { System.err.println("Error playing intro video: " + e.getMessage()); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} }); } @Override public void onDestroy() { super.onDestroy(); destoryIntroVideo(); } private void destoryIntroVideo() { if (_introMediaPlayer != null) { _introMediaPlayer.stop(); _introMediaPlayer.release(); _introMediaPlayer = null; } }
Use audioManager.abandonAudioFocus (null)
Si miras el código de VideoView notarás que llama al método audioManager.requestAudioFocus con null para OnAudioFocusChangeListener. Cuando registra un oyente con el AudioManager utiliza este método para crear un ID para el oyente
private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { if (l == null) { return new String(this.toString()); } else { return new String(this.toString() + l.toString()); } }
Que genera el mismo ID cada vez que utiliza null. Así que si llama a abandonAudioFocus con null se eliminará cualquier oyente que se agregó con null como el parámetro para OnAudioFocusChangeListener
- ¿No puede ejecutar node.js en el teléfono Android?
- Cuándo cerrar Cursor utilizado en SimpleCursorAdapter