Skip to content

Background Audio capability in video player #62739

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
shashikantshaale opened this issue Aug 2, 2020 · 13 comments · May be fixed by flutter/packages#9212
Open

Background Audio capability in video player #62739

shashikantshaale opened this issue Aug 2, 2020 · 13 comments · May be fixed by flutter/packages#9212
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter p: video_player The Video Player plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team

Comments

@shashikantshaale
Copy link

Use case

Playing media when app is in background

Proposal

Please look into how https://pub.dev/packages/flutter_vlc_player could able to do it

@darshankawar darshankawar added p: first party p: video_player The Video Player plugin c: proposal A detailed proposal for a change to Flutter labels Aug 3, 2020
@pedromassangocode pedromassangocode added passed first triage c: new feature Nothing broken; request for a new capability labels Dec 29, 2020
@ryanheise
Copy link

In case it helps, I created a proof-of concept of a background video player back in August 2019 as a very simple fork of an old version of video_player.

Note that there is already a plugin called audio_service which does all of the heavy lifting for allowing audio to play in the background. The basic idea is that audio_service wraps around any audio code allowing it to run in the background, and sets up the appropriate platform specific background remote controls. For example, on iOS, it links media control buttons to the Control Center, and on Android, it provides a service with a media notification. On both platforms, it also links to the lock screen, headset buttons, and even smart watches and cars (CarPlay/Android Auto). The key is that audio_service is media agnostic. It does not care what audio your app plays, it just provides your app with a container for background execution and provides callbacks to handle when the user presses remote media controls. Your app could be a video player, an audio player, a text-to-speech reader, or even some combination of those. (e.g. a text-to-speech reader that plays a chime in between articles, or a fitness trainer that operates in the background and similarly communicates to you through a combination of text-to-speech and sound files).

The audio service that enables background audio should also exist at a higher scope than the individual "player" plugins, because there are applications where you need to be able to include multiple audio/media plugins under the same audio session and be tied to the same audio service. If every plugin hard codes and builds in its own audio service, these will actually clash with each other and make it impossible for app developers to mix and match different audio/media plugins within the same app (I'll give an example at the end). I think we could agree that our plugin ecosystem would look better if plugins were able to be mixed together in the same app.

So with all of what audio_service does, it makes sense to just reuse that. As such, very minor changes needed to be made to the video_player plugin itself to allow the surface texture to be released and detached from the player when entering background mode, and to then be able to reattach it to the player when entering foreground mode.

The reason it never went beyond a proof-of concept was because the person who originally commissioned me to create it for him didn't need it anymore, and my time was already stretched maintaining the audio_service, just_audio and audio_session plugins.

Note that just_audio takes the same approach. It does not itself build all of the heavyweight background code directly into the plugin, but simply focuses on a single responsibility so as to make it easier to cooperate with other plugins. audio_service can then be wrapped around all of the app's media plugins to allow them to run in the background.

As for an example of the type of ecosystem conflict that we want to avoid, right now, flutter_sound contains an excellent audio recorder component. But it also contains an audio player in the same plugin, and more than that, the audio player also contains its own Android service, and a broadcast receiver to intercept headset button presses. What this means is that it is impossible to use the recorder from flutter_sound in the same app as another plugin that also needs to create those same resources, as they will conflict. If video_player goes down that route, then it would be impossible to use video_player and flutter_sound's audio recorder in the same app. It's an unfortunate situation that we can't use an excellent plugin, but if the recorder, the player and the service were separate packages, app developers could then mix and match their favourite plugins in each category without running into potential conflicts between plugins that have overlapping responsibilities.

Anyway, although I definitely would not have time to maintain a background video player, I will try to dig up my old code from 2019 in case it helps someone else to create a pull request and get this officially included into video_player.

@ryanheise
Copy link

I was able to dig up my old Android code from 2019. As mentioned, only minor changes are needed in video_player. Specifically, to release and detach the surface texture when entering background mode, and then to re-attach a surface when re-entering foreground mode.

Here is that code (for Android):

    private void enterBackground() {
      System.out.println("enterBackground. setVideoSurface: null");
      exoPlayer.setVideoSurface(null);
      textureEntry.release();
      surface.release();
      eventChannel.setStreamHandler(null);
      eventSink.setDelegate(null);
    }

    private void enterForeground(EventChannel eventChannel, TextureRegistry.SurfaceTextureEntry textureEntry) {
      this.textureEntry = textureEntry;
      this.eventChannel = eventChannel;
      surface = new Surface(textureEntry.surfaceTexture());
      System.out.println("enterForeground. setVideoSurface again: " + surface);
      exoPlayer.setVideoSurface(surface);
      eventChannel.setStreamHandler(
          new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object o, EventChannel.EventSink sink) {
              System.out.println("enterForeground. onListen. setDelegate: " + sink);
              eventSink.setDelegate(sink);
            }

            @Override
            public void onCancel(Object o) {
              eventSink.setDelegate(null);
            }
          });
      sendInitialized(true);
    }

Hopefully this helps someone else who is interested to try to get this working in the current version of video_player.

@stuartmorgan-g stuartmorgan-g added the P3 Issues that are less important to the Flutter project label Aug 16, 2021
@IlyaMax
Copy link

IlyaMax commented Aug 19, 2021

@ryanheise could you please clarify what issue do these changes fix? And maybe you have some examples how to use video_player and audio_service together on dart side? I faced a problem that I need VideoController instance to be in async task to operate video but in same time I need to render it in VideoPlayer widget. Did you manage to solve this?

@ryanheise
Copy link

Yes, I did get it working pretty much exactly like the premium version of the YouTube app. But it was a long time ago and I lost the demo app and only found the modifications I made to the video_player plugin.

The above code just allows you to release the surface (view) when the app goes into the background and then recreate and reattach the surface when entering the foreground. I don't guarantee that that code is still relevant today since both video_player and audio_service have changed since then.

But that code above takes care of the video_player portion of the solution. In addition to that, audio_service adds the media notification and requests permission from the OS to continue playing audio in the background.

I do wonder now with the latest version of audio_service (the beta release) whether the above code is actually still needed anymore. In the old audio_service, the main activity could be destroyed along with the FlutterEngine containing the video player surface. But now in the new beta release it retains the FlutterEngine and converts it into background mode. I'm not sure exactly what video_player does with the surface when the Android activity is paused/stopped/destroyed but the FlutterEngine is still active....

@IlyaMax
Copy link

IlyaMax commented Aug 20, 2021

@ryanheise I was able to run videoplayer in BackgroundAudioTask (without AppLifecycleHandler which stops playback on pause) and it works almost fine. With some issues which are not related I think to these changes. And still I'm not able to figure out how to show video on ui side, only audio playback is implemented. I will try to implement the same with prerelease version and give you feedback. When are you going to release 0.18.0? I am actively developing background video playback feature, so maybe I will contribute to audio_service a bit.

@ryanheise
Copy link

I can't give you a date on 0.18.0 stable, but I consider the beta to be fairly stable at this point, and people are using it in production. Certainly development has stopped on the 0.17.x release.

If you are interested in working together on the video player use case I would be more than happy to collaborate.

@IlyaMax
Copy link

IlyaMax commented Aug 20, 2021

@ryanheise 0.18.0 has much simplier api, I've made prototype already. Basic functional works. I will contribute example if I have enough time after implementing the feature.

@ryanheise
Copy link

Good to hear 👍 I suspected as much since the activity and the FlutterEngine are never destroyed in the beta. That said, it doesn't sound ideal if video_player wastes battery continuing to render to the surface while in background mode. I don't know if perhaps there are some lower level optimisations within ExoPlayer that prevent that from happening.

@0x3dev
Copy link

0x3dev commented Apr 5, 2022

Hi @IlyaMax, I'm actually looking to implement the same with video_player and audio_service. Since this discussion happened a while ago, may you provide some insight if you managed to do it right (maybe some piece of code if available) Thanks!

@IlyaMax
Copy link

IlyaMax commented Apr 5, 2022

@cmalex23 you can check this implementation ryanheise/audio_service#803. that's not an ideal and anyway you will have to finish this for your needs.

@flutter-triage-bot flutter-triage-bot bot added the package flutter/packages repository. See also p: labels. label Jul 5, 2023
@Hixie Hixie removed the plugin label Jul 6, 2023
@flutter-triage-bot flutter-triage-bot bot added team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team labels Jul 8, 2023
@LNMCode

This comment has been minimized.

@jpacierpnik

This comment has been minimized.

@orangex

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter p: video_player The Video Player plugin P3 Issues that are less important to the Flutter project package flutter/packages repository. See also p: labels. team-ecosystem Owned by Ecosystem team triaged-ecosystem Triaged by Ecosystem team
Projects
None yet
Development

Successfully merging a pull request may close this issue.