使用Agora SDK进行直播

1_Qe7V0XhcaTgzkYoNWCQ6Aw

很多人对Instagram和Facebook中的实时功能都感到十分好奇,如果你是flutter开发人员或正准备开发Flutter,你可以使用Agora在flutter中打造实时聊天功能。Agora提供了RTC SDK,为很多平台如Android、iOS、Web、Windows、macOS、Unity、 electron和flutter等提供SDK。其中SDK的类型包括视频SDK、语音SDK、交互式游戏SDK、实时消息SDK、云录制等。

我们将会在项目中使用Agora视频SDK和实时消息SDK,让我们开始吧。

创建一个新的Flutter项目。你可以使用以下两种方法执行此操作:

  • 命令行
  • Android Studio。

我将在此项目中使用Android Studio。因此,创建一个新项目(你可以在此处找到创建新flutter项目的教程),并根据个人喜好为项目命名。

现在,让我们清理main.dart文件。我们需添加一个带有Logo的启动屏幕。因为我们使用的是Agora SDK以及与其类似的Instagram软件,所以我将其命名为 Agoragram,

启动画面

先从 启动画面 入手,你可以从这里获取代码。设计如下所示:

我把定时器结束时的路由改为HomeScreen。以后我将使用HomeScreen作为基本路由。

完成SplashScreen之后,我们需要构建一个登录页面。在这里,我已将Firebase身份验证用于登录和注册页面的后端。因此,首先创建一个Firebase项目,并将其与flutter链接。在这里找到参考。如果我把它添加到本教程中,会使本教程变得更冗长。

将Firebase集成到Flutter项目中后,构建login.dart文件。用于登录的小部件设计如下所示:

  • 一段文本
  • 两个文本字段,分别用于输入电子邮件和密码

要注意,在这我使用了某些在此dart文件中定义的功能,这是因为我已在另一个文件中提出了所有Firebase请求。我会在文末分享这些细节。你可以在此处浏览登录代码

登录后,创建一个 注册 小部件。要进行注册,我们需要一个头像、一个用户名、电子邮件和密码。我们还需要提示输入的值是否有效。因此,我们也需要把它添加进去,这里浏览代码

我添加了一个页脚,单击该页脚就会返回登录页面。我们需要一个可以显示人相的头像,这里的用户名应该是独一无二的,以便我们区分每一个人。

完成登录或注册后,我还将数据(包括名称、电子邮件、头像)保存在Firebase服务器和共享的“Preference”中(以便随时获取详细信息)。

Home Screen

下一个我们要构建的画面是 Home Screen 。我正在添加2个带有图像和评论的帖子,它们都在app本身中。本教程没有将这一部分囊括在内而是之前就自带用户的头像和名称了。在图片下方,我们可以添加心形图标、评论、分享和保存。我们还可以为图像添加描述。这是我打算构建的基本布局。

这是主屏幕中单个帖子的布局。在我的项目中,我为帖子使用了一个类,以便轻松管理UI。

当我们要构建 实时 直播 时,我们需要一个UI来承载直播,并需要另一个UI来观看直播视频。具体如下所示:

这里的“test”是我们的用户名,“ y”是另一个用户的用户名,所以看起来更像故事吧?嗯……为了使设计如“ y”所示,我们需要堆叠一些小部件。所以我的想法是当用户主持现场直播时,在Firebase中创建一个文档,并将其反映在此处。因此,我们需要滚动视图来水平管理实时用户。我也为直播用户使用类,以便我们可以轻松管理数据。 主屏幕 代码可在此处找到。现在主页的最终版本如下所示:

之后,让我们开始使用直播功能。 这里我们想要的是,发起直播的人(我们称他为主机用户)可以向其他用户分享他们的摄像头视图和声音。 观看直播的其他人仅限于观看,他们的摄像头和音频不会被共享。 主机有一个添加观众的功能,但我们现在不会建立该功能,我们得慢慢来。 对于视频共享平台,我用的是Agora的SDK,就它们的合理性与其他RTC SDK的适用性来说还是非常令人信服的。 我使用 GitHub Repo的引用来构建这个app,方便随时查看。 具体遵循有关 Agora 平台的以下步骤:

第一步:创建一个帐户

1、在www.agora.io上创建一个开发者帐户

2、单击右上角的注册按钮。

3、填写注册信息以创建帐户。

4、创建完帐户后进行登录。

第二步:开发人员面板

1、登录上来后,你会进入开发人员面板-在这里你能访问所有开发者资源。

2、导航到左上角的“Projects”选项卡,默认项目创建完成。

3、你将看到App ID,它是你使用Agora服务的API密钥。

We need that App ID for running the SDK in our project.

我们需要该App ID在我们的项目中运行SDK。

因此,我们需添加依赖项,打开pubspec.yaml输入以下内容:

agora_rtc_engine: 1.0.5   # for video
agora_rtm: 0.9.11         # for chatting 

现在,你可以在存储App ID的我的项目中找到
setting.dart文件,在此粘贴App ID。

const APP_ID = "";  // Enter the App ID in between the double quotes

现在让我们获取项目中的所有依赖项

flutter pub get

The intended UI for Live is shown below:

Live 的预期UI如下所示:

在这里,我们需要使用Agora Engine初始化视频和音频,对于评论,我们使用的是Agora RTM。 我们有一个功能可以查看加入直播场景中的直播用户,还可以静音、切换摄像头以及用一个按钮结束直播。布局如右图。

你可以将此文件 作为完整的dart文件进行参考,我将说明这里使用哪个文件及使用原因。

Future<void> initialize() async {

  await _initAgoraRtcEngine();
  _addAgoraEventHandlers();
  await AgoraRtcEngine.enableWebSdkInteroperability(true);
  await AgoraRtcEngine.setParameters(
      '''{\"che.video.lowBitRateStreamParameter\":{\"width\":320,\"height\":180,\"frameRate\":15,\"bitRate\":140}}''');
  await AgoraRtcEngine.joinChannel(null, widget.channelName, null, 0);
}

/// Create agora sdk instance and initialize
Future<void> _initAgoraRtcEngine() async {
  await AgoraRtcEngine.create(APP_ID);
  await AgoraRtcEngine.enableVideo();
}

/// Add agora event handlers
void _addAgoraEventHandlers() {

  AgoraRtcEngine.onJoinChannelSuccess = (
    String channel,
    int uid,
    int elapsed,
  ) async{

    final documentId = widget.channelName;
    channelName= documentId;
    FireStoreClass.createLiveUser(name: documentId,id: uid,time: widget.time,image:widget.image);
    // The above line create a document in the firestore with username as documentID

    await Wakelock.enable();
    // This is used for Keeping the device awake. Its now enabled

  };

  AgoraRtcEngine.onLeaveChannel = () {
    setState(() {
      _users.clear();
    });
  };

  AgoraRtcEngine.onUserJoined = (int uid, int elapsed) {
    setState(() {
      _users.add(uid);
    });
  };

  AgoraRtcEngine.onUserOffline = (int uid, int reason) {
    setState(() {
      _users.remove(uid);
    });
  };
}

我们正在初始化Agora Engine,在initState()内部调用initialize函数。 我还在使用Wakelock软件包来使设备保持唤醒状态,否则,它会在过特定时间后锁定。 另外,别忘了在结束直播时禁用Wakelock。

@override
void initState() {
  super.initState();
  // initialize agora sdk
  initialize(); // Initialise agora engine
  _createClient(); // initialise agora RTM
}

为Agora RTM创建一个客户端,我们还需要在initState()中添加该函数。

另外,我们还需获取Rendered Widget来显示画面,为此使用以下命令

AgoraRenderWidget(0, local: true, preview: true),

现在,Layout都已经准备好,但我们所需的只是主机用户的屏幕。 要启动视频频道,我们需要channelName,它也应该是唯一的,以便没有其他人拥有相同的channelName造成交叉混淆。 因为之前我们已经将用户名设为唯一,所以我们把用户名作为创建频道的频道名称。

现在,让我们利用Agora RTM搭建评论功能。 我已经在主机文件的initState()中调用了一个函数createClient()。 此函数定义了一个为用户发送消息的RTM通道。

void _createClient() async {
  _client =
  await AgoraRtmClient.createInstance('<Your App ID Here>');
  _client.onMessageReceived = (AgoraRtmMessage message, String peerId) {
    _log(user: peerId,  info: message.text, type: 'message');
  };
  _client.onConnectionStateChanged = (int state, int reason) {
    if (state == 5) {
      _client.logout();
     setState(() {
        _isLogin = false;
      });
    }
  };
  await _client.login(null, widget.channelName );
  _channel = await _createChannel(widget.channelName);
  await _channel.join();
}

别忘了在AgoraRtmClient.createInstance()中添加你的App ID。

现在要想知道有多少用户加入直播,我会利用channel.getMembers().length上的RTM功能,此功能可以返回加入该频道的用户数的信息。 让我们看一下代码:

Future<AgoraRtmChannel> _createChannel(String name) async {
  AgoraRtmChannel channel = await _client.createChannel(name);
  channel.onMemberJoined = (AgoraRtmMember member) async {
    var img = await FireStoreClass.getImage(username: member.userId);
    userMap.putIfAbsent(member.userId, () => img);
    var len;
    _channel.getMembers().then((value) {
      len = value.length;
      setState(() {
        userNo= len-1 ;
      });
    });

    _log(info: 'Member joined: ',  user: member.userId,type: 'join');
  };
  channel.onMemberLeft = (AgoraRtmMember member) {
    var len;
    _channel.getMembers().then((value) {
      len = value.length;
      setState(() {
        userNo= len-1 ;
      });
    });

  };
  channel.onMessageReceived =
      (AgoraRtmMessage message, AgoraRtmMember member) {
    _log(user: member.userId, info: message.text,type: 'message');
  };
  return channel;
}

void _log({String info,String type,String user}) {
  
  var image = userMap[user];
  Message m = new Message(
      message: info, type: type, user: user, image: image);
  setState(() {
   _infoStrings.insert(0, m);
  }); 
}

当他/她加入频道后,我会在此处获取用户的头像并将其添加到地图中,这样我们就无需在用户评论时一次又一次调用 image函数。 这样,就可以仅一次就能从服务器中获取图像了。

每当用户加入频道时,聊天框中都会显示一条消息,代表已加入频道。 每当有人发送评论时,另一条带有用户图像、用户名都会连同消息一起显示出来。

我认为这是主持人频道中所使用的主要功能,你可以在此处查看完整设计。

我们接下来要加入画面,即用户想要观看实时直播时的画面。 因此,除了主持人之外,我们在这里进行了一些更改。 此处,我们不需要使用麦克风和摄像头图标,因为我们不需要它们的反馈。 然后就可以看一下加入画面的设计了。

在这里,我们需要主机用户的头像在左上角显示出来,并且需要在右上角查看用户数。 在下面,我们有comment选项和heart选项。 好吧,我不会精确制作heart动画,但我们可以制作与其相似度高达90%的动画。

那就来看看我们需要进行更改的地方。 在_initAgoraRtcEngine()中,我们需要使用户的音频静音并禁用本地视频。

Future<void> _initAgoraRtcEngine() async {
  await AgoraRtcEngine.create(APP_ID);
  await AgoraRtcEngine.enableVideo();
  await AgoraRtcEngine.muteLocalAudioStream(muted);  // Changes
  await AgoraRtcEngine.enableLocalVideo(!muted);     // Changes 
}

对于heart动画,我正在使用一个带有数学运算的自定义dart文件,你可以 在此处找到该自定义的dart文件。 在join.dart中,要调用HeartAnim,我用的是以下代码:

Widget heartPop(){
  final size = MediaQuery.of(context).size;
  final confetti = <Widget>[];
  for (var i = 0; i < _numConfetti; i++) {
    final height = _random.nextInt(size.height.floor());
    final width = 20;
    confetti.add(HeartAnim(height % 200.0,
        width.toDouble(),1));
  }


  return Container(
    child: Padding(
      padding: const EdgeInsets.only(bottom:20),
      child: Align(
        alignment: Alignment.bottomRight,
        child: Container(
          height: 400,
          width: 200,
          child: Stack(
            children: confetti,
          ),
        ),
      ),
    ),
  );
}

好吧,这只会一次制作出10个大小不同且图形不同的心形图标,但我们是要以动画形式显示它,让其循环4秒钟:

void popUp() async{
  setState(() {
    heart=true;
  });
  Timer(Duration(seconds: 4), () =>
  {
    _timer.cancel(),
    setState(() {
      heart=false;
    })
  });
  _timer = Timer.periodic(Duration(milliseconds: 125), (Timer t) {
    setState(() {
      _height += _random.nextInt(20);
    });
  });
}

上面的代码将在剩余的4秒钟内调用heartPop。

我认为所有更改均已设置为加入页面,你能在此处找到代码。

总结

以上就是主要的说明。 我已经对需要注意的代码的每一部分都进行了说明,至于代码的其他部分无非是小部件或可以自解释。 我希望这篇文章可以帮到你。

你可以在此处找到GitHub仓库,如果愿意的话可以试着做一下,或者Fork这个仓库。 请仔细阅读文章,如果发现有任何错误或者你有更好的方法,可以随时告诉我。

原文作者 Akarsh Ashok

原文链接 https://medium.com/@akarshashok12/live-broadcast-using-agora-sdk-5befba0fbbed