Builders using the Amazon Chime SDK for Android can share a second video stream such as screen capture in a meeting without disrupting their applications existing audio/video stream.
- You have read the API overview and have a basic understanding of the components covered in that document.
- You have completed Getting Started and have running application which uses the Amazon Chime SDK.
- You have read the Custom Video Sources, Processors, and Sinks and have a basic understanding of APIs such as VideoSource.
Content share APIs are accessible from AudioVideoFacade. Builders will need to create a ContentShareSource which currently contains just the VideoSource desired to share in the meeting. A bundled screen capture source using MediaProjection is provided in DefaultScreenCaptureSource, but developers can also share any video source which implements VideoSource.
In DefaultScreenCaptureSource, the video frames are provided via the MediaProjection APIs, so an application will need to complete the following prerequisites before the implementation is ready for use:
- (Android Q and above only) Starting in Android Q, a foreground service is required before acquiring a
MediaProjection
through MediaProjectionManger.getMediaProjection. Applications will need to create a Service, defined in yourAndroidManifest.xml
and start it as foreground before starting the screen capture source. This will look like the following:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
<service
android:name=".ScreenCaptureService"
android:foregroundServiceType="mediaProjection" />
</application>
- To construct a DefaultScreenCaptureSource, request screen capture permissions from the user and use the result in the constructor parameters:
// Call this function when screen capture is desired
fun requestScreenCapturePermission() {
mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
// Show prompt for screen capture permission
startActivityForResult(
mediaProjectionManager.createScreenCaptureIntent(),
SCREEN_CAPTURE_REQUEST_CODE
)
}
// Handle the result of permission prompt activity started
// in requestScreenCapturePermission
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// ...
if (SCREEN_CAPTURE_REQUEST_CODE == requestCode && resultCode == Activity.RESULT_OK && data != null) {
// (Android Q and above) Start the service created in step 1
startService(Intent(this, ScreenCaptureService::class.java))
// Initialize a DefaultScreenCaptureSource instance using given result
val screenCaptureSource = DefaultScreenCaptureSource(
this,
logger,
// Use the same EglCoreFactory instance as passed into DefaultMeetingSession
DefaultSurfaceTextureCaptureSourceFactory(
logger,
eglCoreFactory),
resultCode,
data
)
screenCaptureSource.start()
}
// ... Complete any other initialization
}
See Custom Video Sources, Processors, and Sinks for more information on the usage of EglCoreFactory. The capture source will not work if the factory is not shared between the capture and the meeting session due to use of GPU based video frames.
Refer to the Implementing a custom video source and transmitting section of the custom video guide to build a video source to share. Content share supports sharing any source which implements VideoSource.
Once the video source is ready, wrap it with ContentShareSource to share the video.
// Construct the content share source
val contentShareSource = ContentShareSource()
contentShareSource.videoSource = screenCaptureSource // Or a custom source
// Start sharing the content share source to remote participants
audioVideo.startContentShare(contentShareSource)
// ...
// Stop sharing the source
audioVideo.stopContentShare()
Additionally, you can set configuration for content share, e.g. maxBitRateKbps. Actual quality achieved may vary throughout the call depending on what system and network can provide.
val contentShareConfig = LocalVideoConfiguration(200)
meetingSession.audioVideo.startContentShare(contentShareSource, contentShareConfig)
Note that the content share APIs do not manage the source and only provide a sink to transmit captured frames to remote participants, builders will be responsible to take care of its lifecycle including stopping and releasing the capture sources internal resources.
Applications can receive content share events by implementing methods from ContentShareObserver and subscribe with addContentShareObserver.
Content shares are treated as regular audio-video attendees. The attendee ID of a content share is the same as the original attendee, but with a suffix of #content. Applications using the Amazon Chime SDK receive real-time attendee presence and video tile updates callbacks for content attendee using the exact same mechanisms as normal video.
To view the content share:
- Create an observer of VideoTileObserver that implements onVideoTileAdded to receive callbacks when the video tile is added.
- Subscribe the observer with addVideoTileObserver via audio video facade.
- In the
onVideoTileAdded
, bind the video tile to a VideoRenderView.
override fun onVideoTileAdded(tileState: VideoTileState) {
// ...
if (tileState.isContent) {
audioVideo.bindVideoView(view.video_surface, tileState.tileId)
}
}
Builders can use the VideoTileState.isContent to check if the video tile is a content share, and any add special logic you need to handle the content share.
You can also use the DefaultModality class to determine that an attendee ID is a content share:
if (DefaultModality(attendeeId).hasModality(ModalityType.Content)) {
// ...special handling for content share...
}