Picture in Picture (PiP)

Picture in picture (PIP) keeps the call running and visible while you navigate to other apps.

Enable Picture-in-Picture

To enable Picture-in-Picture (PiP), set the enablePictureInPicture property to true in the PictureInPictureConfiguration provided to the StreamCallContainer or StreamCallContent widget. Additionally, you can control whether PiP remains enabled when the local device is screen sharing using the disablePictureInPictureWhenScreenSharing parameter (disabled by default).

StreamCallContainer(
    call: widget.call,
    pictureInPictureConfiguration: const PictureInPictureConfiguration(
        enablePictureInPicture: true,
        disablePictureInPictureWhenScreenSharing: true,
    ),
)

Keep the Connection Active in Background

For Picture-in-Picture to function properly while the app is in the background, it is important to keep the connection to Stream backend active. This is controlled by the keepConnectionsAliveWhenInBackground property in StreamVideoOptions, which must be set to true.

Additionally, to ensure the local participant remains visible and audible in PiP mode, ensure muteVideoWhenInBackground and muteAudioWhenInBackground are set to false (false by default).

  StreamVideo(
    apiKey,
    user: user,
    token: token,
    options: const StreamVideoOptions(
      muteAudioWhenInBackground: false,
      muteVideoWhenInBackground: false,
      keepConnectionsAliveWhenInBackground: true,
    ),
  );

Android

Android Configuration

To enable Picture in Picture on Android, you need to add the following configuration to your AndroidManifest.xml file.

<activity android:name=".MainActivity"
    android:supportsPictureInPicture="true"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
    ..
 />

Then you need to add this code to your MainActivity class. It will enter Picture in Picture mode when the user leaves the app but only if the call is active.

import io.flutter.embedding.android.FlutterActivity
import io.getstream.video.flutter.stream_video_flutter.service.PictureInPictureHelper

class MainActivity: FlutterActivity() {
    override fun onUserLeaveHint() {
        super.onUserLeaveHint()
        PictureInPictureHelper.enterPictureInPictureIfInCall(this)
    }
}

Android Customization

For Android, you can customize the widget rendered while app is in Picture-in-Picture mode by providing callPictureInPictureBuilder to PictureInPictureConfiguration.

  StreamCallContainer(
    call: widget.call,
    callContentBuilder: (
        BuildContext context,
        Call call,
        CallState callState,
        ) {
      return StreamCallContent(
        call: call,
        callState: callState,
        pictureInPictureConfiguration: const PictureInPictureConfiguration(
          enablePictureInPicture: true,
          androidPiPConfiguration: AndroidPictureInPictureConfiguration(
            callPictureInPictureBuilder: (context, call, callState) {
              // YOUR CUSTOM WIDGET
            },
          )
        ),
      );
    },
  );

iOS

Local camera feed in Picture-in-Picture mode

By default, iOS does not allow access to the user’s camera while the app is in the background. To enable it, the multitasking camera access property must be set to true.

For apps linked against iOS 18 or later, this property is automatically true if voip is included in UIBackgroundModes. Additionally, apps with the com.apple.developer.avfoundation.multitasking-camera-access entitlement will also have multitasking camera access enabled.

If the multitasking camera access property is true for your app based on the above conditions, the local camera feed will be visible in PiP mode. However, if you prefer to disable the local feed in PiP mode, set includeLocalParticipantVideo to false:

  StreamCallContainer(
    call: widget.call,
    callContentBuilder: (
        BuildContext context,
        Call call,
        CallState callState,
        ) {
      return StreamCallContent(
        call: call,
        callState: callState,
        pictureInPictureConfiguration: const PictureInPictureConfiguration(
          enablePictureInPicture: true,
          iOSPiPConfiguration: IOSPictureInPictureConfiguration(
            includeLocalParticipantVideo: false,
          )
        ),
      );
    },
  );

Enabling PiP support with custom call content widget

If you are not using our StreamCallContent and instead building custom call content widget you can still enable Picture in Picture mode by adding StreamPictureInPictureUiKitView anywhere in the widget tree. This widget will handle the Picture in Picture mode in iOS for you.

  StreamCallContainer(
    call: widget.call,
    callContentBuilder: (
        BuildContext context,
        Call call,
        CallState callState,
        ) {
      return Stack(
        children: [
          StreamPictureInPictureUiKitView(call: call),
          // YOUR CUSTOM WIDGET
        ],
      );
    },
  );

Done. Now after leaving the app, you’ll see that the call will be still alive in the background like the one below:

Picture in Picture example

© Getstream.io, Inc. All Rights Reserved.