Flutter Audio Room Tutorial

In this tutorial, we will learn how to build an audio room experience similar to Twitter Spaces or Clubhouse using Stream Video.

Before we dive into the Audio Rooms APIs, there are a few fundamental things to understand:

  • Backstage: When an audio_room call is created, it exists in backstage mode by default. This means that the call creator and co-hosts can chat with each other privately before the call is set live and others can join.
  • All calls run on Stream's global edge network for improved latency and quality. When a user connects to a call, they connect to a server closest to their location. Stream further optimizes this in the background.
  • There are no limits to the number of users you can have in a room.
  • By default, listeners are muted and require speaking permission before they can send audio. The call host can grant this permission.
  • Stream sends audio tracks multiple times for improved quality and reliability.

Create a new project

Let's begin by creating a new Flutter project and adding the stream_video_flutter package to the project.

Next, you can create a project on Stream’s dashboard to obtain an API key for your project.

For detailed instructions on how to create a project on the Stream Dashboard, please see our blog post.

Setting up the UI

Audio Room Example

The UI we will be building for this example will be minimal, but the principles and structures can be used to create more elaborate designs.

To get started, we prepared a sample project which can be cloned from this repository. The project contains three screens, a login, home feed and room screen which we will add functionality to.

Setting up the client and loging in

For this example, we are going to use three hard-coded users. Looking at the code in our login_screen.dart, we are creating a simple list that provides users with the options to select a user and continue to the main screen of our application.

When user is chosen we initialize our StreamVideo client using API key and user token (in this case we get it from our backend)

Creating and displaying a list of rooms

After a user is selected, they are taken to the HomeScreen where a list of active rooms is displayed. By clicking on a room, the user can join and listen to the ongoing conversation. At the moment, we do not display anything in our app but we will implement this soon.

Let’s start by implementing the room creation methods before we add the ability to query rooms.

In our example project, let's open lib/screens/home_screen.dart and start our implementation by adding the ability to create a room in createRoom and _onDialogPressed.

To begin let’s look at the createRoom method. We can call makeCall on the StreamVideo class and supply the call type as audio_room. Unlike the default room type, which allows full video and audio transmission as well as the ability for users to un-mute themselves and speak by default, the audio_room type applies a few restrictions to calls so that the host and speakers have more granular controls.

Next, we can call our function using the data supplied by the user when they complete the “create room” dialog:

The code above calls the createRoom function we just defined passing it the room title and description as parameters. Unlike default meeting rooms, audio rooms are started in a “backstage” mode by default.

This allows the room creator or host to invite other speakers before the room is made public and before participants are allowed to join. When the room is ready, goLive can be invoked to publish the room and make it possible for other participants to join. We will implement this logic in the next screen.

The remaining code in this section pushed the newly created room to a new page which we will cover in a later section.

Querying rooms

With our room created, we can query the list of live and active audio rooms in our application by using Stream’s queryCalls method.

As we talked in about in a previous tutorial, there are many ways in which developers can query calls on the Stream platform. The method we are using in this example is querying calls based on a the custom property flutterAudioRoomCall: true. This narrows the number of call to those created from our sample application ensure they contain the right structure and permissions. We also want to show only the rooms that are ready for other participants to join, so we are adding an additional backstage: false filter. Feel free to experiment by setting custom properties or applying other filters.

With filtering in place, if you hot restart the application, there should be one room in our app created earlier. To join the room, we can implement the final method in our home screen joinRoom:

Room screen

Opening lib/screens/audio_room_screen.dart, we can tour the implementation of displaying participants.

Every call object has an associated CallState which can be observed as a stream for changes. These changes can then be used to update the UI of our application. The most common way to interact with the call state in our UI layer would be to observe the state using a StreamBuilder and handle the new data as it comes in.

To see this in use, let’s take a look at the _buildParticipants and _buildBackstageBanner methods:

In the above method, we are listening for changes to the call, such as when a participant begins speaking, joins, or leaves the call, etc., and updating the SliverGrid. Even though we are using the default StreamCallParticipant to handle the heavy lifting of rendering our call participant and speaking indicators, developers are free to use their own custom UI here. The CallParticipantState object exposes many properties to the user, providing flexibility for customization.

In this method, we are observing the isBackstage property of CallState to display a banner indicating that the Call is not yet live. We also show a button that, as mentioned before, invokes the call.goLive() method.

Controlling the microphone

An audio room example would not be complete without the ability to control whether the user is speaking or not. For this, the setMicrophoneEnabled method can be invoked on the Call object. If the user has speaking permissions, their audio tracks will be published and they will be allowed to speak during the call.

Permissions and speaking requests

Should the user not have permission, it can be request using requestPermissions before enabling the microphone:

For hosts or moderators, a UI can be added to show permission requests. In the case of our simple example, we can grant them automatically be adding the following code snippet to our initState method:

Other built-in features

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

  • 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 the participants and show a preview
  • Reactions & Custom events: Reactions and custom events are supported
  • Recording & Broadcasting: You can record your calls
  • Chat: Stream's chat SDKs are fully featured and you can integrate them into the call
  • Moderation: Moderation capabilities are built-in to the product
  • Transcriptions: Transcriptions aren't available yet, but they are due to launch soon

Recap

In just a few minutes, we were able to create our first audio-room experience for our app. Please let us know if you run into any issues during the process. Our team constantly reviews feedback and applies changes to improve the overall experience.

This is just a small example of what's possible with Stream and audio. For more advanced use cases like using OPUS DTX and OPUS RED, check out some of our other examples and guides on our website and GitHub.

We hope you enjoyed this tutorial and look forward to hearing your suggestions and feedback.

Final Thoughts

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

Both the video SDK for Flutter 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 Flutter 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