Building Your Own Audio Streaming Application Using the Agora Flutter SDK

Building Your Own Audio Streaming Application Using the Agora Flutter SDK

What has real-time communication made possible? In this pandemic, real-time communication has been a driving force behind engagement, and it has enabled various industries to run easily from the comfort of home.

In this article, I will walk you through the steps on how to create your own audio streaming application. And you will see how something that is supposedly complex to build can be simplified by using the Agora Flutter SDK. In the next few minutes, we will be making a cross-platform application for streaming, creating a podcast, or streaming. The use cases are endless.

We will walk through how to create multiple rooms or channels that run in parallel such that an audience can join and listen to the streams or podcasts.

Requirements

  • Flutter SDK
  • VS Code or Android Studio
  • A basic understanding of Flutter Development

Project Setup

flutter create agora_audio_streaming

2. Navigate to your pubspec.yamlfile and inside that file add the following dependencies:

pubspec.yaml

Be careful with the indentation when adding the packages because you might get an error if the indentation is off.

3. In your project folder, run the following command to install all the dependencies:

flutter pub get

4. Once we have all the dependencies, we can create the file structure. Navigate to the lib folder and create a file structure something like this:

Project Structure

Building an Audio Broadcasting Interface

main.dart

This code just initializes your flutter application and calls MyHomePage() that we have defined in homepage.dart

Building our Home Page

Here is what the code for that looks like:

homepage.dart

This will give us a page that looks something like this:

homepage

Connecting to RTC

var appID = '<--- Enter your app id here --->'

Once we have added the appID we can navigate back to call_screen.dart and start connecting to RTC. The process is similar to the video version of the app, where we follow the steps in the same order:

  1. Create an instance of RtcEngine by passing the App ID.
  2. Enable audio using the enableAudio() method on the previously created RtcEngine instance.
  3. Set the channel profile and client role using the setChannelProfile() and setClientRole() methods on the same instance. Here, we will use the channel profile as LiveBroadcasting, and the user role will be based on the user input from the home page.
  4. Join the channel by passing the token (optional), channel name, and uid of the user to the joinChannel() function.

Note: This project is meant for reference purposes and development environments, it is not intended for production environments. Token authentication is recommended for all RTE apps running in production environments. For more information about token based authentication within the Agora platform please refer to this guide: https://bit.ly/3sNiFRs

The process can be summarized as:

connecting to rtc

RTC Event Handlers

Here, we use callbacks not only to maintain the logs but also to maintain a list of all the users in the channel as well as a list of broadcasters.

_addAgoraEventHandlers()

Connecting to RTM

  • Create an instance of AgoraRtmClient by passing the App ID
_client = await AgoraRtmClient.createInstance(appID);
  • Log in to the Agora RTM by using the login() method of the same instance we created. The login method is called by passing token (optional) and username (our input field from the home page):
_client.login(null, widget.userName);
  • Create a channel for a group of people who can share messages. We do this with the createChannel() method and passing the name of the channel (input value from the homepage):
AgoraRtmChannel channel = await _client.createChannel(widget.channelName);
  • Join the channel that you just created by calling the join() method.
await _channel.join();

Associating Usernames

To create a mapping between this uid and usernames, we will have three scenarios:

  • When a user joins the channel: The process is very simple. We just have to send a broadcast message to the channel declaring that a new user has joined the channel. We do this by using the sendMessage() method, which takes an argument of type AgoraRtmMessage in which we pass a string with the uid of the person and the status.
 _channel.sendMessage(AgoraRtmMessage.fromText('$localUid:join'));
  • When a user leaves the channel: Using a similar process, we send a message to the channel and declare the status as leave.
var reversedMap = _allUsers.map((k, v) => MapEntry(v, k));channel.sendMessage(AgoraRtmMessage.fromText('${reversedMap[member.userId]}:leave'));
  • To get a list of users in the channel before your joining: Instead of sending a broadcast message to the channel where everyone can see it, we send a peer-to-peer message. This is done by sendMessageToPeer(), where we pass the username of the person to whom we want to send this message and of course the message text. This way every existing user in the channel contacts the new user with their uid and username.
_client.sendMessageToPeer(member.userId, AgoraRtmMessage.fromText('$localUid:join'));

Adding removing people

Now, based on the status message (“leave” or “join”) that we sent in our message, we remove or add a user from the map. Our logic looks something like this:

adding and removing users

Building the user view

  • Displaying a user: To style a user, I simply use a container with a username below it:
user_view.dart

Our final widget will look something like this:

useer_view
  • Creating a toolbar: We will create two buttons for user interaction: to mute the user’s stream and to disconnect from the stream. To style this, we simply use two RawMaterialButton():
_toolbar widget

On pressing these buttons we call two functions: _onToggleMute() and _onCallEnd(). Here is how you can define it:

_onToggleMute
_onCallEnd

The final result would be something like:

_toolbar
  • Displaying all this in your build: We add all these widgets and categorize broadcasters and audiences. To do that, we use the list _users[] that contains the uid of all the broadcasters that we got from the userJoined() callback. We use these uids and map them to get the username of the broadcasters, and the remaining username goes into the broadcasters list.

And finally our screen will look something like this:

call_screen

With this, the audience in a channel can hear all the broadcasters present in the channel.

Testing

flutter run

Conclusion

You can get the complete code for this application over here

Other Resources

You can also have a look at the complete documentation for the functions discussed above and many more over here.

I also invite you to join the Agora.io Developer Slack Communit

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store