agora_rtc_engine 1.0.10

  • Readme
  • Changelog
  • Example
  • Installing
  • 89

AgoraRtcEngine #

pub package

This Flutter plugin is a wapper for Agora Video SDK.

Agora.io provides building blocks for you to add real-time voice and video communications through a simple and powerful SDK. You can integrate the Agora SDK to enable real-time communications in your own application quickly.

Note: This plugin is still under development, and some APIs might not be available yet.

Usage #

To use this plugin, add agora_rtc_engine as a dependency in your pubspec.yaml file.

Getting Started #

  • See the example directory for a sample app using AgoraRtcEngine.
  • Or checkout this tutorial for a simple video call app using Agora Flutter SDK.

Device Permission #

Agora Video SDK requires camera and microphone permission to start video call.

Android #

Open the AndroidManifest.xml file and add the required device permissions to the file.

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

<!-- The Agora SDK requires Bluetooth permissions in case users are using Bluetooth devices.-->
<uses-permission android:name="android.permission.BLUETOOTH" />
..

iOS #

Open the info.plist and add:

  • Privacy - Microphone Usage Description, and add a note in the Value column.
  • Privacy - Camera Usage Description, and add a note in the Value column.

Your application can still run the voice call when it is switched to the background if the background mode is enabled. Select the app target in Xcode, click the Capabilities tab, enable Background Modes, and check Audio, AirPlay, and Picture in Picture.

Error handling #

iOS memory leak #

if your flutter channel is stable, PlatformView will cause memory leak, you can run flutter channel beta

you can refer to this pull request

Android Black screen #

Tips: please make sure your all configurations are correct, but still black screen

if your MainActivity extends io.flutter.embedding.android.FlutterActivity and override the configureFlutterEngine function

please don't forget add super.configureFlutterEngine(flutterEngine)

please don't add GeneratedPluginRegistrant.registerWith(flutterEngine), plugins will be registered auto now

you can refer to the official documents

Android Release crash #

it causes by code obfuscation because of flutter set android.enableR8=true by the default

Add the following line in the app/proguard-rules.pro file to prevent code obfuscation:

-keep class io.agora.**{*;}

How to contribute #

To help work on this sdk, see our contributor guide.

Change log #

1.0.10 #

  • fix iOS encryption bug

1.0.9 #

  • fix android onUserInfoUpdated bug

1.0.8 #

  • fix onVideoSizeChanged bug

1.0.7 #

  • fix iOS setLiveTranscoding crash

1.0.6 #

  • upgrade Agora SDK to 2.9.4, not use IMEI now

1.0.5 #

  • fix iOS memory leak

1.0.4 #

  • AgoraRenderWidget use key now

1.0.3 #

  • add log functions

1.0.2 #

  • fix Android orientation bug

1.0.1 #

1.0.0 #

  • Support CDN Publish & Pull
  • Support Switch Channel
  • Update to Agora Rtc SDK 2.9.0 version.
  • deprecated methods: onUserMuteVideo onUserEnableVideo onUserEnableLocalVideo onFirstRemoteVideoDecoded onRemoteAudioTransportStats
  • add methods: switchChannel onLocalAudioStateChanged onRemoteAudioStateChanged onLocalAudioStats setLiveTranscoding addPublishStreamUrl removePublishStreamUrl addInjectStreamUrl removeInjectStreamUrl
  • enhancement RemoteVideoStats & LocalVideoStats & RtcStats

0.9.9 #

0.9.8 #

  • Add native result call.
  • Update to Agora Rtc SDK 2.8.0 version.

0.9.7 #

  • Move callback to main thread.

0.9.6 #

  • Update to Agora Rtc SDK 2.4.1 version.
  • Support encryption.
  • Adds the onLocalVideoStateChanged callback to indicate the local video state. This replaces the onCameraReady and onVideoStopped callbacks.
  • Adds the onNetworkTypeChanged callback to indicate the local network type.
  • Adds the onFirstRemoteAudioDecoded callback to report to the app that the SDK decodes first remote audio.

0.9.5 #

  • Fix onRtcStats

0.9.4 #

  • Update to Agora Rtc SDK 2.4.0 version
  • Refact setVideoEncoderConfiguration
  • Add setBeautyEffectOptions and setRemoteUserPriority

0.9.3 #

  • Added basic enumerations

0.9.2 beta #

  • Fix Android type specifiers issues

0.9.1 beta #

  • Added docs for SDK apis

0.9.0 beta #

  • Flutter for Agora Video SDK beta release

example/lib/main.dart

import 'dart:async';

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isInChannel = false;
  final _infoStrings = <String>[];

  static final _sessions = List<VideoSession>();
  String dropdownValue = 'Off';

  final List<String> voices = [
    'Off',
    'Oldman',
    'BabyBoy',
    'BabyGirl',
    'Zhubajie',
    'Ethereal',
    'Hulk'
  ];

  /// remote user list
  final _remoteUsers = List<int>();

  @override
  void initState() {
    super.initState();

    _initAgoraRtcEngine();
    _addAgoraEventHandlers();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Agora Flutter SDK'),
        ),
        body: Container(
          child: Column(
            children: [
              Container(height: 320, child: _viewRows()),
              OutlineButton(
                child: Text(_isInChannel ? 'Leave Channel' : 'Join Channel',
                    style: textStyle),
                onPressed: _toggleChannel,
              ),
              Container(height: 100, child: _voiceDropdown()),
              Expanded(child: Container(child: _buildInfoList())),
            ],
          ),
        ),
      ),
    );
  }

  Widget _voiceDropdown() {
    return Scaffold(
      body: Center(
        child: DropdownButton<String>(
          value: dropdownValue,
          onChanged: (String newValue) {
            setState(() {
              dropdownValue = newValue;
              VoiceChanger voice =
                  VoiceChanger.values[(voices.indexOf(dropdownValue))];
              AgoraRtcEngine.setLocalVoiceChanger(voice);
            });
          },
          items: voices.map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value),
            );
          }).toList(),
        ),
      ),
    );
  }

  Future<void> _initAgoraRtcEngine() async {
    AgoraRtcEngine.create('2b4b76e458cf439aa7cd313b9504f0a4');

    AgoraRtcEngine.setEncryptionMode('aes-128-xts');
    AgoraRtcEngine.setEncryptionSecret('ourSecret');
    AgoraRtcEngine.enableVideo();
    AgoraRtcEngine.enableAudio();
    // AgoraRtcEngine.setParameters('{\"che.video.lowBitRateStreamParameter\":{\"width\":320,\"height\":180,\"frameRate\":15,\"bitRate\":140}}');
    AgoraRtcEngine.setChannelProfile(ChannelProfile.Communication);

    VideoEncoderConfiguration config = VideoEncoderConfiguration();
    config.orientationMode = VideoOutputOrientationMode.FixedPortrait;
    AgoraRtcEngine.setVideoEncoderConfiguration(config);
  }

  void _addAgoraEventHandlers() {
    AgoraRtcEngine.onJoinChannelSuccess =
        (String channel, int uid, int elapsed) {
      setState(() {
        String info = 'onJoinChannel: ' + channel + ', uid: ' + uid.toString();
        _infoStrings.add(info);
      });
    };

    AgoraRtcEngine.onLeaveChannel = () {
      setState(() {
        _infoStrings.add('onLeaveChannel');
        _remoteUsers.clear();
      });
    };

    AgoraRtcEngine.onUserJoined = (int uid, int elapsed) {
      setState(() {
        String info = 'userJoined: ' + uid.toString();
        _infoStrings.add(info);
        _remoteUsers.add(uid);
      });
    };

    AgoraRtcEngine.onUserOffline = (int uid, int reason) {
      setState(() {
        String info = 'userOffline: ' + uid.toString();
        _infoStrings.add(info);
        _remoteUsers.remove(uid);
      });
    };

    AgoraRtcEngine.onFirstRemoteVideoFrame =
        (int uid, int width, int height, int elapsed) {
      setState(() {
        String info = 'firstRemoteVideo: ' +
            uid.toString() +
            ' ' +
            width.toString() +
            'x' +
            height.toString();
        _infoStrings.add(info);
      });
    };
  }

  void _toggleChannel() {
    setState(() async {
      if (_isInChannel) {
        _isInChannel = false;
        await AgoraRtcEngine.leaveChannel();
        await AgoraRtcEngine.stopPreview();
      } else {
        _isInChannel = true;
        await AgoraRtcEngine.startPreview();
        await AgoraRtcEngine.joinChannel(null, 'flutter', null, 0);
      }
    });
  }

  Widget _viewRows() {
    return Row(
      children: <Widget>[
        for (final widget in _renderWidget)
          Expanded(
            child: Container(
              child: widget,
            ),
          )
      ],
    );
  }

  Iterable<Widget> get _renderWidget sync* {
    yield AgoraRenderWidget(0, local: true, preview: false);

    for (final uid in _remoteUsers) {
      yield AgoraRenderWidget(uid);
    }
  }

  VideoSession _getVideoSession(int uid) {
    return _sessions.firstWhere((session) {
      return session.uid == uid;
    });
  }

  List<Widget> _getRenderViews() {
    return _sessions.map((session) => session.view).toList();
  }

  static TextStyle textStyle = TextStyle(fontSize: 18, color: Colors.blue);

  Widget _buildInfoList() {
    return ListView.builder(
      padding: const EdgeInsets.all(8.0),
      itemExtent: 24,
      itemBuilder: (context, i) {
        return ListTile(
          title: Text(_infoStrings[i]),
        );
      },
      itemCount: _infoStrings.length,
    );
  }
}

class VideoSession {
  int uid;
  Widget view;
  int viewId;

  VideoSession(int uid, Widget view) {
    this.uid = uid;
    this.view = view;
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  agora_rtc_engine: ^1.0.10

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:agora_rtc_engine/agora_rtc_engine.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
94
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
60
Overall:
Weighted score of the above. [more]
89
Learn more about scoring.

We analyzed this package on Apr 7, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Fix lib/agora_rtc_engine.dart. (-1 points)

Analysis of lib/agora_rtc_engine.dart reported 2 hints:

line 428 col 5: 'await' applied to 'void', which is not a 'Future'.

line 1592 col 26: The declaration '_videoRenderModeFromInt' isn't referenced.

Maintenance issues and suggestions

Homepage URL doesn't exist. (-20 points)

At the time of the analysis the homepage field https://www.agora.io was unreachable.

The package description is too short. (-20 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.5.2 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8