Quickstart
This quickstart gives you a quick overview of how Stream's video SDKs work
Client setup & calls
The example below creates the client. Normally you'd do that in your Application
class.
Next you create a call object and join the call. We'll specify create=true to create the call if it doesn't exist
val client = StreamVideoBuilder(
context = context,
apiKey = apiKey,
geo = GEO.GlobalEdgeNetwork,
user = user,
token = token,
).build()
val call = client.call("default", "123")
val joinResult = call.join(create=true)
Note: While you can initialise the SDK on-demand and it's not mandatory to initialise the SDK in the Application.onCreate()
- it is required to initialise it this way for it to be able to handle incoming calls and other types of push notifications. Otherwise, the application process will start, the push notification will be delivered to the SDK automatically but the SDK will not be initialised at this point and will ignore the push notification.
default
is a call type. There are 4 built-in call types and you can also create your own.
The call type controls the permissions and which features are enabled.
The second argument is the call id and is optional. It's convenient to specify an ID if the call is associated with an object in your database. As an example if you're building a ride sharing app like Uber, you could use the ride id as the call id to easily align with your internal systems.
Incoming / outgoing calls
If you intend to support incoming and outgoing calls the SDK must know which activities to call in the notification PendingIntent
.
In order to be able to accept and send incoming calls via the default notification handler provided by the SDK, you need to handle the intent actions in your manifest.
The SDK defines the following actions:
ACTION_NOTIFICATION = "io.getstream.video.android.action.NOTIFICATION"
ACTION_LIVE_CALL = "io.getstream.video.android.action.LIVE_CALL"
ACTION_INCOMING_CALL = "io.getstream.video.android.action.INCOMING_CALL"
ACTION_OUTGOING_CALL = "io.getstream.video.android.action.OUTGOING_CALL"
ACTION_ACCEPT_CALL = "io.getstream.video.android.action.ACCEPT_CALL"
ACTION_REJECT_CALL = "io.getstream.video.android.action.REJECT_CALL"
ACTION_LEAVE_CALL = "io.getstream.video.android.action.LEAVE_CALL"
ACTION_ONGOING_CALL = "io.getstream.video.android.action.ONGOING_CALL"
If you do not support incoming and outgoing calls, you can skip the <intent-filter>
declarations.
In order to be able to fully utilize the incoming / outgoing feature the SDK needs to know which activity these actions resolve to in order to construct the PendingIntent
s.
You have to provide this information into your manifest.
The ACTION_REJECT_CALL
and ACTION_LEAVE_CALL
are handled by default by the SDK and you do not have to do anything about them.
The ACTION_ONGOING_CALL
does not mandate an <intent-filter>
with the consequence that omitting this will result in reduced functionality where the user will not be returned to your app if the notification is clicked.
All the other actions must be declared in your manifest, otherwise the internal CallService
will fail to create the required notification for a foreground service and thus not start, resulting in an exception.
<manifest>
<application>
<activity
android:name=".Activity"
android:exported="false"
android:showOnLockScreen="true"
android:showWhenLocked="true"
>
<intent-filter android:priority="1">
<action android:name="io.getstream.video.android.action.INCOMING_CALL" />
<action android:name="io.getstream.video.android.action.ONGOING_CALL" />
<action android:name="io.getstream.video.android.action.ACCEPT_CALL" />
<action android:name="io.getstream.video.android.action.OUTGOING_CALL" />
<action android:name="io.getstream.video.android.action.NOTIFICATION" />
</intent-filter>
</activity>
</application>
<manifest>
You can handle multiple IntentFilter
within a single activity
if you prefer or have separate activity for each action.
For more details on notification customization see our Push Notification Guide.
Rendering video
The call's state is available in call.state
and you'll often work with call.state.participants
.
Have a look below at a basic Compose example of how to render the video of all participants.
val participants by call.state.participants.collectAsState()
participants.forEach {
val videoTrack = it.videoTrack // contains the video track
val userName = it.userNameOrId // the user name
..
}
As you can see the example above, participants (ParticipantState)
contains all essential information to render videos, such as audio/video tracks, user information, audio/video enabled, etc. You can simply render the video track with our Compose components like the sample below:
ParticipantVideo(
modifier = Modifier
.fillMaxSize()
.clip(RoundedCornerShape(16.dp)),
call = call,
participant = participant
)
The fields available on the participants are documented here.
Camera & Audio
Most video apps will show buttons to mute/unmute the audio or video and flip the camera. The example below shows how to use the camera
val call = client.call("default", "123")
val camera = call.camera
camera.enable()
camera.disable()
camera.flip()
And here's how to enable the microphone or control the speaker volume.
call.microphone.enable()
call.microphone.disable()
call.speaker.setVolume(100)
call.speaker.setVolume(0)
call.speaker.enableSpeakerPhone()
UI components
The goal of this library is to make it easy to build any type of video/calling experience. You have a few options for the UI:
- Build your own UI components using the state as shown above.
- Use our library of built-in components.
- Mix & match between your own and built-in components.
You can customize the built-in components by using theming and modifiers. Compose is pretty flexible, but there are limits, so if you get stuck with the built-in components you can always work around it by building your own.