Android Audio Room Tutorial

Learn to quickly build a fully functional Clubhouse or Twitter Spaces clone with Kotlin and Jetpack Compose using the Android Video SDK of Stream. Find out how you can broadcast a live audio room from any Android device and let listeners join the conversation with our companion drop-in audio web app.

This tutorial will teach you how to build an audio room experience like Twitter Spaces or Clubhouse. The end result will look like the image below and support the following features:

  • Backstage mode. You can start the call with your co-hosts and chat a bit before going live.
  • Calls run on Stream's global edge network for optimal latency and scalability.
  • There is no cap to how many listeners you can have in a room.
  • Listeners can raise their hand, and be invited to speak by the host.
  • Audio tracks are sent multiple times for optimal reliability.

Audio Room

Time to get started building an audio-room for your app.

Step 1 - Create a new project in Android Studio

Note that this tutorial was written using Android Studio Giraffe. Setup steps can vary slightly across Android Studio versions. We recommend using Android Studio Giraffe or newer.

  1. Create a new project
  2. Select Phone & Tablet -> Empty Activity
  3. Name your project AudioRoom.

Step 2 - Install the SDK & Setup the client

The Stream Video SDK has two main artifacts:

  • Core Client: io.getstream:stream-video-android-core - includes only the core part of the SDK.
  • Compose UI Components: io.getstream:stream-video-android-ui-compose - includes the core + Compose UI components.

Add the Video Compose SDK dependency to your app's build.gradle.kts file found in app/build.gradle.kts. If you're new to Android, note that there are 2 build.gradle.kts files, you want to open the one located in the app folder.

:exclamation: Replace <latest-version> with the version number indicated below (e.g. 0.5.7). Also, you can check the Releases page.

:exclamation: Make sure compileSdk (or compileSdkVersion if you're the older syntax) is set to 34 in your app/build.gradle.kts file.

:exclamation: Make sure you sync the project after doing these changes. Click on the Sync Now button above the file contents.

Step 3 - Create & Join a call

To keep this tutorial short and easy to understand we'll place all the code in MainActivity.kt. For a production app you'd want to initialize the client in your Application class or DI module. You'd also want to use a View Model.

Open up MainActivity.kt and replace the MainActivity class with the following code:

You can find below the import statements that are used throughout this tutorial. Paste them into your MainActivity.kt file to follow along easily.

import statements

Let's review the example above and go over the details.

Create a user. First we create a user object. You typically sync these users via a server side integration on your own backend. Alternatively, you can also use guest or anonymous users.

Initialize the Stream Client. Next we initialize the client by passing the API Key, user and user token.

Create the call. After the user and client are created, we create a call.

Request runtime permissions. Before joining the call, we request the microphone runtime permission to capture audio.

Review the permissions docs to learn more about how you can easily request permissions.

Join the call. We join the call in the onPermissionsResult block.

  • This creates and joins a call with the type audio_room and the specified callId.
  • You add yourself as a member with the host role. You can create custom roles and grant them permissions to fit your app.
  • The title and description custom fields are set on the call object.
  • Shows an error toast if you fail to join an audio room.

To actually run this sample, we need a valid user token. The user token is typically generated by your server side API. When a user logs in to your app you return the user token that gives them access to the call.

To make this tutorial easier to follow we'll generate a user token for you. Please update REPLACE_WITH_API_KEY, REPLACE_WITH_TOKEN, REPLACE_WITH_USER_ID and REPLACE_WITH_CALL_ID with the actual values shown below:

Here are credentials to try out the app with:

PropertyValue
API KeyWaiting for an API key ...
Token Token is generated ...
User IDLoading ...
Call IDCreating random call ID ...
For testing you can join the call on our web-app: Join Call

With valid credentials in place, we can join the call.

When you run the app you'll see the following result:

Audio Room

Step 4 - Audio Room & Description

Now that we've successfully connected to the audio room. Let's setup a basic UI and description.

In the MainActivity.kt file, replace the code inside VideoTheme with the example below:

All the state for a call is available in call.state. In the example above we're observing the connection state and the active speakers. The ParticipantState docs explain the available StateFlow objects.

You'll see that the AudioRoom composable hasn't been implemented yet. In MainActivity, add the following AudioRoom composable:

The code above observes the participants, active speakers and backstage StateFlow objects from call.state.

We still need to implement a Controls, Participants, and Description composables. Let's add them below the AudioRoom composable.

That's it for the basics. Now when you run your app, you'll see the following UI:

Audio Room

The approach is the same for all components. We take the states of the call by observing call.state properties, such as call.state.participants and use it to power our UI. The ParticipantState docs exposes all the state objects we need for the name, avatar, audio levels, speaking, etc.

Step 5 - Audio Room Controls

Now let's have a look at the Controls composable. Replace the Controls composable with the following code:

Now when you run the app, you'll see a button to disable/enable the microphone and to start or end the broadcast.

To make this a little more interactive, let's join the audio room from your browser.

For testing you can join the call on our web-app: Join Call

At first you won't be allowed to join the room since it's not live yet. By default the audio_room call type has backstage mode enabled. This makes it easy to try out your room and talk to your co-hosts before going live. You can enable/disable the usage of backstage mode in the dashboard.

Let's go live and join the call:

  • Click Go Live on Android
  • Join the room from the browser
  • You'll see the participant count increase to 2

Step 6 - Participants UI

Time to build a pretty UI for the participants. Replace the Participants composable with the following code:

The Participants composable is responsible for rendering all participants in the audio room as a grid list.

Now we'll add a ParticipantAvatar composable, which represents a user in the audio room:

The ParticipantAvatar composable represents each participant in the audio room. It displays the initials of the user and the status of the microphone. Now when you run the app, you'll see a pretty UI for the participants.

Audio Room

In the above example, we use the following state flow objects:

The ParticipantState docs include all the other attributes that are also available. For audio rooms, participant.audioLevel and participant.audioLevels can be convenient to implement an audio visualizer.

Other built-in features

There are a few more exciting features that you can use to build audio rooms:

  • Requesting Permissions: Participants can ask the host for permission to speak, share video etc
  • Query Calls: You can query calls to easily show upcoming calls, calls that recently finished etc
  • Call Previews: Before you join the call you can observe it and show a preview. IE John, Sarah and 3 others are on this call.
  • Reactions & Custom events: Reactions and custom events are supported
  • Recording & Broadcasting: You can record your calls, or broadcast them to HLS
  • Chat: Stream's chat SDKs are fully featured and you can integrate them in the call
  • Moderation: Moderation capabilities are built-in to the product
  • Transcriptions: Transcriptions aren't available yet, but are coming soon

Recap

It was fun to see just how quickly you can build an audio-room for your app. Please do let us know if you ran into any issues. Our team is also happy to review your UI designs and offer recommendations on how to achieve it with Stream.

To recap what we've learned:

  • You setup a call with val call = client.call("audio_room", "222").
  • The call type audio_room controls which features are enabled and how permissions are set up.
  • The audio_room by default enables backstage mode, and only allows admins to join before the call goes live.
  • When you join a call, realtime communication is setup for audio & video calling with call.join().
  • Stateflow objects in call.state and call.state.participants make it easy to build your own UI.

Calls run on Stream's global edge network of video servers. Being closer to your users improves the latency and reliability of calls. For audio rooms we use Opus RED and Opus DTX for optimal audio quality.

The SDKs enable you to build audio rooms, video calling and livestreaming in days.

We hope you've enjoyed this tutorial, and please do feel free to reach out if you have any suggestions or questions.

Final Thoughts

In this video app tutorial we built a fully functioning Android messaging app with our Android SDK component library. We also showed how easy it is to customize the behavior and the style of the Android video app components with minimal code changes.

Both the video SDK for Android and the API have plenty more features available to support more advanced use-cases.

Give us Feedback!

Did you find this tutorial helpful in getting you up and running with Android for adding video to your project? Either good or bad, we’re looking for your honest feedback so we can improve.

Next Steps

Create your free Stream account to start building with our Video & Audio SDKs, or contact our team if you have additional questions.

Chat Messaging

Build any kind of chat messaging experience without scalability or reliability issues.

Learn more about $ Chat Messaging

Enterprise

Available 99.999% uptime SLAs and industry-leading security to power the world's largest apps.

Learn more about $ Enterprise