How to prevent VideoView/MediaPlayer from stopping other apps' audio?
Asked Answered
S

4

10

In one screen I have a looping background video (upon which normal UI elements are shown), implemented with VideoView like this:

String resPath = "android.resource://" + getPackageName() + "/" + R.raw.bg_video;
videoView.setVideoURI(Uri.parse(resPath));

// Hide controls:
MediaController controller = new MediaController(getActivity());
controller.setVisibility(View.GONE);
videoView.setMediaController(controller);

// Use looping:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.setLooping(true);
    }
});

videoView.start();

The video works great. The only problem is that when this view is shown (or even before if using e.g. ViewPager), music playback from other applications stops.

The video I'm using has no sound itself. Is there a way to set the VideoView, or the MediaPlayer it uses, in a "muted mode"? I.e., tell it not to do audio at all, and especially not to mess with other apps' audio.

Tried mp.setVolume(0, 0); in onPrepared() but it has no effect.

Skirret answered 26/3, 2015 at 13:50 Comment(4)
I haven't tried it, but I believe your answer is going to involve going through the AudioManager and playing with mute/solo settings for the stream. Because it is music from other apps you want to keep playing, you will need to set the audio stream for your MediaPlayer to a different value before calling prepare().Melendez
@ab.helly: Yep, I'll post an answer when I have time.Skirret
@Jonik, can you post the answer?Agreement
@Ana: Actually what I ended up going was essentially the same as what Łukasz posted. As ugly as it feels, copy-paste VideoView from Android sources and comment out requestAudioFocus call.Skirret
H
15

Copy paste VideoView from Android sources and comment out these lines:

AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

You could name the new class MutedVideoView, for example.

gist here: https://gist.github.com/vishna/7e9d3466bced8502fcdd

Hemi answered 22/7, 2015 at 17:21 Comment(3)
How do I compile the copied VideoView class. it complains 'cannot resolve symbol' on: import android.media.Metadata; import android.media.SubtitleController; import android.media.SubtitleTrack.RenderingWidget; import android.media.TtmlRenderer; import android.media.WebVttRenderer;Mirtamirth
The solution I went with (back in 2015) was essentially the same as this. "Ugly but it works." In the VideoView copy-pasted from Android sources, I also had to comment out some Subtitle and Metadata related code that wasn't compiling for some reason.Skirret
Is there a way to accomplish this with reflection?Proleg
S
10

The accepted solution does not guarantee compatibility across all Android versions and is a dirty hack more than a true solution. I've tried all forms of hacks to get this working, yet none have worked to my satisfaction.

I have come up with a much better solution though - switch from a VideoView to a TextureView and load it with a MediaPlayer. There is no difference from the user's perspective, just no more audio stoppage.

Here's my use case for playing an MP4 looping:

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;
    }
}
Sattler answered 4/1, 2017 at 8:30 Comment(0)
M
6

This worked for me:

videoView.setAudioFocusRequest(AudioManager.AUDIOFOCUS_NONE);

(before .setVideUri() call)

Mchugh answered 16/4, 2018 at 11:14 Comment(2)
this is available in api level 26 and above,w hat about devices with os below thatHenleyonthames
did you find any other answer for API level less than 26?Egor
H
0

There's a solution for API level 26 and further. This is Kotlin way of keep video mute.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            binding.viewView2.setAudioFocusRequest(AudioManager.AUDIOFOCUS_NONE)
        }
Hitchcock answered 21/10, 2022 at 5:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.