Features

Developers

Build your Flutter live streaming application with api.video

March 30, 2023 - Thibault Beyou in iOS, Android, Dart

A few months ago, my colleague Yohann wrote a fantastic article on How to create a React Native live streaming application for mobile targets. This time, you will learn how to create the same application with a React Native competitor: Flutter.

In this article, you will develop a live streaming application in Dart. For further details, check out our official Flutter live stream repository.

Few words about Flutter

Google developed Flutter in 2015. In 2021, it was the most used cross-platform mobile framework (42% against 38% for React Native, source). It is used to develop cross-platform applications (including iOS and Android) quickly. The main difference between Flutter and React Native is that Flutter compiles Dart code to native bytecode/libraries, whereas React Native uses an engine to interpret JavaScript or TypeScript code. If you haven't heard of Flutter, you can learn more on the Flutter website.

Getting started

First, follow the development setup steps from Flutter's official documentation.

If you're new to Flutter, you may also need to learn the basics.

Quick reminder: iOS development is only enabled for macOS users. If you're on Windows or Linux, you can develop for Android.

Create a new Flutter app

  1. Open Android Studio.
  2. You should see a “New Flutter Project” button. Click on it.
  3. Verify the Flutter SDK path and click on “Next.”
  4. Enter your project name: “live_stream_app” (according to the pubspec documentation, the name must be lower_case_with_underscore.)
  5. Make sure the project type is set to Application.
  6. Click on “Finish.”

Launch the application

Once Android Studio is launched, you can directly run your application with the control toolbar:

run your application with the control toolbar
  1. Select your phone.
  2. Click on the Run ▶️ icon.

It will take several minutes to finish, stay calm and grab a coffee ☕️

When the application build completes, it will be launched on your phone. Check your phone 🤳🏾

Check your phone

🎉🎉🎉Congratulations, you have created your first Flutter application 🎉🎉🎉

Signs your iOS application (optional)

If you have trouble building the application for an iOS device, it might be because the application is not associated with a development profile.

Open Xcode, click "Open a project or file," and open the Runner.xcworkspace located in live_stream_app/ios.

Click on Runner, go to the Signing & Capabilities tab, add your team, and create a unique bundle identifier.

Add the live streaming client to your app

Now let's install the Flutter live streaming client!

Installation

Open a terminal in your live_stream_app folder and the following command:

flutter pub add apivideo_live_stream

Also, you need to set the Android minSdkVersion to the one supported by Flutter live stream client.

Open your application build.gradle. It's located in the live_stream_app/android/app directory and replace:

minSdkVersion flutter.minSdkVersion

to:

minSdkVersion 21

Permissions

⚠️ Both iOS and Android need permission to broadcast from your device's camera and record audio.

You will also need to ask for internet permission for Android.

Android

From your project folder, open the AndroidManifest.xml file. It’s located in the live_stream_app/android/app/src/main directory. Add the following content just under the opening <manifest> tag to enable internet, audio recording, and the camera for your application:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />

iOS

From your project folder, open the Info.plist file. It's located in the live_stream_app/ios/Runner directory. Add the following content just under the opening <dict> tag to enable the camera and microphone:

<key>NSCameraUsageDescription</key>
<string>Your description of the application</string>
<key>NSMicrophoneUsageDescription</key>
<string>Your description of the application</string>

Don't forget to add the app description, as shown above, if you want to deploy your application in app stores.

Usage

You can check the Flutter live streaming sample application for the whole application picture.

Create a controller and the camera preview

Change your main.dart file located in the live_stream_app/lib with the following code:

import 'package:apivideo_live_stream/apivideo_live_stream.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'My live stream app'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final ApiVideoLiveStreamController _controller;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // Fills the whole view
            Expanded(
              child: Container(
                child: Padding(
                  padding: const EdgeInsets.all(1.0),
                  child: Center(
                    child: ApiVideoCameraPreview(controller: _controller),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  
  void initState() {
    _controller = createLiveStreamController();
    _controller.initialize().catchError((e) {
      print('Failed to initialize controller: $e');
    });

    super.initState();
  }

  ApiVideoLiveStreamController createLiveStreamController() {
    return ApiVideoLiveStreamController(
        initialAudioConfig: AudioConfig(),
        initialVideoConfig: VideoConfig.withDefaultBitrate(),
        onConnectionSuccess: () {
          print('Connection succeeded');
        },
        onConnectionFailed: (error) {
          print('Connection failed: $error');
        },
        onDisconnection: () {
          print('Disconnected');
        });
  }
}

Launch your application. You now have the camera preview.

Manage application lifecycle

The next step is to manage application lifecycle. You will have to stop/start the camera when your application goes to/from the background.

The class _MyHomePageState must implement the abstract class WidgetsBindingObserver. Replace its declaration with:

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver

Register the lifecycle observer, add in initState:

WidgetsBinding.instance.addObserver(this);

Manage lifecycle:


void didChangeAppLifecycleState(AppLifecycleState state) {
  if (state == AppLifecycleState.inactive) {
    _controller.stop();
  } else if (state == AppLifecycleState.resumed) {
    _controller.startPreview();
  }
}

Add a control panel

You still can't start a live stream because there is no way to do it.

We are going to add a Row of IconButton that can control your live streaming.

Import the following package:

import 'package:flutter/services.dart';

Then, add the following code:

/// Keeps the streaming state in sync with the controller.
var _isStreaming = false;

/// Display the control bar with buttons to take pictures and record videos.
Widget _controlRowWidget() {
  final ApiVideoLiveStreamController? controller = _controller;

  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      IconButton(
        icon: const Icon(Icons.fiber_manual_record),
        color: Colors.red,
        onPressed: controller != null && !_isStreaming
            ? onStartStreamingButtonPressed
            : null,
      ),
      IconButton(
          icon: const Icon(Icons.stop),
          color: Colors.red,
          onPressed: controller != null && _isStreaming
              ? onStopStreamingButtonPressed
              : null),
    ],
  );
}

void onStartStreamingButtonPressed() {
  startStreaming().then((_) {
    if (mounted) {
      setIsStreaming(true);
    }
  }).catchError((error) {
    if (error is PlatformException) {
      print("Error: failed to start stream: ${error.message}");
    } else {
      print("Error: failed to start stream: $error");
    }
  });
}

void onStopStreamingButtonPressed() {
  stopStreaming().then((_) {
    if (mounted) {
      setIsStreaming(false);
    }
  }).catchError((error) {
    if (error is PlatformException) {
      print("Error: failed to stop stream: ${error.message}");
    } else {
      print("Error: failed to stop stream: $error");
    }
  });
}

Future<void> startStreaming() async {
  final ApiVideoLiveStreamController? controller = _controller;

  if (controller == null) {
    print('Error: create a camera controller first.');
    return;
  }

  await controller.startStreaming(streamKey: 'YOUR_STREAM_KEY');
}

Future<void> stopStreaming() async {
  final ApiVideoLiveStreamController? controller = _controller;

  if (controller == null) {
    print('Error: create a camera controller first.');
    return;
  }

  await controller.stopStreaming();
}

void setIsStreaming(bool isStreaming) {
  setState(() {
    _isStreaming = isStreaming;
  });
}

Then, add the _controlRowWidget() in the Colum under the ApiVideoCameraPreview. Replace your _MyHomePageState build method by:


Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          // Fills the whole view
          Expanded(
            child: Container(
              child: Padding(
                padding: const EdgeInsets.all(1.0),
                child: Center(
                  child: ApiVideoCameraPreview(controller: _controller),
                ),
              ),
            ),
          ),
          _controlRowWidget(),
        ],
      ),
    ),
  );
}

Finally, update the _isStreaming variable in the controller’s callbacks to update the IconButton state when the live streaming is stopped.

Replace createLiveStreamController by:

ApiVideoLiveStreamController createLiveStreamController() {
  return ApiVideoLiveStreamController(
      initialAudioConfig: AudioConfig(),
      initialVideoConfig: VideoConfig.withDefaultBitrate(),
      onConnectionSuccess: () {
        print('Connection succeeded');
      },
      onConnectionFailed: (error) {
        print('Connection failed: $error');
        if (mounted) {
          setIsStreaming(false);
        }
      },
      onDisconnection: () {
        print('Disconnected');
        if (mounted) {
          setIsStreaming(false);
        }
      });
  }

Run ▶️ your application again.

Run  your application again.

Launch your first live stream

⚠️⚠️⚠️ If you want to run your live stream, you will need to change YOUR_STREAM_KEY to a real one.

You can find yours in the api.video dashboard. If you don't have an account yet, create one, it's free. Then, create a livestream from the overview or the “Live streams” page.

Start a live stream

A modal will appear with several pieces of information in it, including the shareable link and stream key. Save the shareable link to access your live stream later.

Save the shareable link to access your live stream later.
💡 You can also use the api.video API to create a live stream and retrieve your stream key dynamically. Find how to do this right here.
Paste your stream key in place of `YOUR_STREAM_KEY`.

Click on the live button in your application; it should be disabled if the live streaming properly starts. Then, go to the shareable link you just saved.

There you go! You can see what your mobile is streaming in real-time! If not, wait a few seconds and check your stream key value.

🎉🎉🎉 Congratulations, you have created your first live streaming Flutter application 🎉🎉🎉

You can now do an actual live stream directly from your Android and iOS devices.

And now what?

api.video provides two development environments. The sandbox allows you to live stream directly from your computer or mobile, but a watermark will be applied to your video, and there is a 30-minute limit for live streams.

To avoid these limitations, subscribes to api.video and go into production mode 🚀.

Also, the Flutter RTMP live stream client allows us to do much more in terms of configuration!

You can match both audio and video configuration to your needs.

Also, there are some properties can be updated during the live stream:

  • Camera: front or back
  • Audio: muted or unmuted.

Check out the README for exhaustive information about the apivideo_live_stream package.

Thibault Beyou

Senior Mobile Developer

Create your free account

Start building with video now