对于与其他创作者的协作直播,有一些非常好的解决方案。但如果你也像我一样觉得价格有点小贵,那你肯定也希望它们可以自定义。值得庆幸的是,Agora 就可以帮你创建自己的服务!
要求
- Agora 开发者账号(详见如何开始使用 Agora)
- Flutter SDK
- Agora RTC 包
- Agora RTM 包
由于这个项目很大,因此本文将其分解成几个重要的概念。如果你想要完整的代码,你可以点击以下链接:GitHub仓库地址
应用总述
在切入要点之前,让我们先理清我们的目标以及实现的方法。此应用程序的目标很简单:通过用一个能管理用户和传到流平台内容的主机应用程序,允许多个用户加入并将他们的视频传输到流媒体平台上。
应用程序的流程尽可能简单。从主屏幕开始,输入你尝试加入的频道和自己的姓名。然后你有两个身份选择:主播或是观众:
- Director: 管理所有用户以及流发送的位置和方式
- 参与者: 加入通话并有一个用于协作的简易通话界面
在本文中,我们不会具体介绍 Agora 的基础知识及其工作原理。如果对 Agora不是很了解,可点击以下链接做简单了解:
- 视频通话: https://www.youtube.com/watch?v=zVqs1EIpVxs&t=12s
- 直播: https://www.youtube.com/watch?v=kE0ehPMGgVc
- RTM: https://www.youtube.com/watch?v=TBgHmFcDd1U
观众视图
本教程不会在观众视图上花费太多时间。这里的逻辑应该与其他类型的视频通话非常相似,除了以下四个方面:
- 当用户第一次加入大厅时,他们的摄像头和音频是关闭的。
- 当主播让他们上麦时,他们的视频和音频应该打开。
- 视频和音频可由主播控制。
- 其他观众不会看到通话中的其他人。
使用该设备的人应该不会发现与常规视频通话之间的明显区别。唯一的区别是他们在加入通话之前看到的大厅屏幕。如果舞台上有人,当前参与者可以看到他们,即使当前参与者尚未在舞台上,他们会查看发送到流媒体平台但没有自定义转码的输出通话。现在,所有复杂的操作都是使用 Agora 的 RTM 消息完成的。
RTM消息
由于这不是一个简单的视频通话应用程序,因此发起者需要某种方式来控制参与者。为此,我们将使用agora_rtm
包。这个包允许频道中的每个人之间发送实时数据。该agora_rtc_engine
软件包建立在agora_rtm
顶端, 不同的是,RTM 允许你发送任何数据,而 RTC 则可以轻松发送视频和音频数据。对于此应用程序,只有发起者可以发送 RTM 消息,参与者只能接收。我们需要给予发起者三种功能:
- 对音频静音或取消静音。
- 启用或禁用视频。
- 发送活动用户列表。
为了使用户静音,发起者以“mute uid”格式发送通道范围的 RTM 消息,其中“uid”被替换为要静音用户的特定uid
。收到此消息后,参与者检查这uid
是否是他们的uid
. 如果是,则用户将自己静音。除了使用关键字“unmute uid”、“enable uid”和“disable uid”之外,取消静音、禁用和启用视频的工作方式相同。
稍微棘手的部分是使用户活跃。通常情况下,如果你使用 Agora,就会显示该通话中的所有直播公司。但在这种情况下,其中一些在大厅中,因此不应向观众展示。为了解决这个问题,我们再次使用 RTM 消息发送所有应该 显示的用户。格式为“activeUsers uid,uid,uid”,其中“uid”替换为活动用户的特定uid
。
到目前为止,从参与者的角度来看,我们几乎涵盖了所有内容。现在让我们讲发起者这部分,这是最神奇的部分。
指挥控制器
此应用程序中控制器有很多功能和要跟踪的东西。为了让事情井井有条,我们将为Flutter使用 流行状态管理解决方案riverpod
。
如果你从未使用过 Riverpod,这里是一个很好的起点:https://www.youtube.com/watch?v=8qzip8tVmqU
我们在此处定义的DirectorController
会成为一个StateNotifierProvider
。这有助于将我们的业务逻辑与应用程序的 UI 部分分开。
该控制器包含我们可以访问代码的函数,包括joinCall()
,leaveCall()
,toggleUserAudio()
,addUserToLobby()
,promoteToActiveUser()
,startStream()
等等。该控制器还将存储我们要在应用程序中跟踪的所有数据。
由于参与者只接收 RTM 消息,所以指挥器只发送 RTM 消息。
为了让指挥控制器发送 RTM 消息,你需要使用 RTM 设置客户端和通道。这与 RTC 引擎在幕后运行的情况非常相似。你需要创建并登陆客户端,然后创建频道并加入频道。完成此操作后,你就可以发送 RTM 消息了。参与者需要做同样的事情才能在onMessageReceived
回调中接收消息。
要发送消息,你需要使用该sendMessage
频道提供的功能。要正确格式化消息,需使用以下命令:
对所有其他消息使用相同的方法,例如“静音 uid”、“启用 uid”、“禁用 uid”和“activeUsers uid,uid,uid”。
所以这些是使我们能够管理用户和流的基础设施细节。让我们详细了解这个应用程序的指挥部分是如何工作的。以下是要介绍的三个主要功能:
- 静音和禁用其他用户的视频
- 在舞台和大厅之间移动用户
- 转码每个视频并将其推送到流媒体平台
静音和禁用视频
现在我们已经设置了所有带有 RTM 消息传递的基础设施,这部分可能听起来微不足道,但实际上有很多部分都需要考虑并做到同步。
- 对音频静音/取消静音。
- 禁用/启用用户的视频。
- 用户音频和视频的当前状态。
- 用户更改自己的状态时更新。
参与者应用
- 自己静音/取消静音。
- 禁用/启用自己的视频。
- 从指挥器中静音/取消静音。
- 禁用/启用来自发起者的视频。
- 音频和视频的当前状态。
要完成所有这些并使其同步,很多部分可以控制音频。解决此问题的最佳方法是查看各种场景:
-
参与者将自己静音/取消静音。 当参与者决定将自己静音时,他们需要调用
muteLocalAudioStream()
并更新自己的按钮状态以显示他们已静音。在指挥端,触发remoteAudioStateChanged
事件 ,它应该更新该特定用户的当前状态。 -
参与者禁用/启用视频。 除了调用函数
muteLocalVideoStream()
外,过程同上。指挥器事件应该是remoteVideoStateChanged
。 -
指挥器将用户静音/取消静音。 Director 需要发送带有“mute uid”或“unmute uid”的 RTM 消息。然后匹配的用户
uid
将执行与他们自己静音一样的执行。指挥器应该再次看到remoteAudioStateChanged
事件触发器,他们可以更新本地状态。 -
指挥器禁用/启用视频。 与静音相同的过程,但流消息将是“启用 uid”或“禁用 uid”。
让我们为此加一点难度。
舞台和大堂
这里并不太复杂,但它有一些需要注意的事情。唯一能同时看到大厅和舞台的人是指挥。在DirectorController
将举行的活跃用户和大堂用户的单独列表。参与者用户的正常流程是加入频道并直接添加到大厅。然后指挥器完全控制,可以随意移动它们进出舞台。
将人移入和移出舞台的流程非常相似。首先,将它们从上一个列表(大厅或活动)中删除,然后将它们添加到另一个列表中。接着更新并使用 RTM 消息activeUsers
向所有人发送新的列表。
效果还不错,但这就是难点。你不希望大厅用户能在舞台上与其他用户交谈,因此他们应该在大厅中被静音。而且由于他们在大厅里,因此也不需要为他们的视频占用额外的带宽。因此,我们需要为音频和视频控制添加更多场景:
- 参与者首先加入频道。 由于它们是直接添加到大厅中的,因此需要立即将它们静音并禁用其视频。每当参与者加入频道时,他们会自动将自己静音。
- 参与者走上舞台。 当他们移到主舞台时,需要启用他们的视频和音频,以便观众可以看到他们。这应该遵循与导演取消静音或启用视频相同的逻辑。
- 参与者移到大厅。 当他们被移动到大厅时,他们的视频和音频需要启用,以便观众可以看到和听到他们。这应该遵循与指挥器静音或禁用视频相同的逻辑。
转码
将activeUser
列表与应用程序的指挥部分和应用程序的参与者部分同步后,最后一步是将其直播到流媒体平台。为此,我们首先将所有传入的视频转码为所需的布局,然后使用实时消息传递协议 (RTMP) 将我们的流发布和取消发布到所需的平台。
首先,我们需要定义输出视频的布局。在这种情况下,我们最多只能支持 8 人的通话。但是你可以根据需要将相同的概念扩展到任意数量的用户。我们还考虑到我们的流将是 1080p 流,因此我们有 1920×1080 像素可供使用。鉴于这些信息,布局将如下所示:
要发送此信息,我们需要创建一个列表TranscodingUser
并相应地设置每个用户布局。一旦它们在列表中,我们就用列表创建一个LiveTranscoding
对象,并告诉RTCEngine
这是我们理想中的布局。
现在我们已经配置了音视频流的布局,我们需要发送它。使用此应用程序,我们可以将其发送到多个位置。为此,你将需要一个 URL,你的流应该被推送到该 URL。对于 YouTube,这非常简单。你将需要Stream Url + backslash ("/") + Stream Key
,这些都在你的直播仪表板中有所提供。Twitch 有一个类似的概念,你可以点击这里阅读: Twitch指南
现在,你已经拥有全部链接,用transcodingEnabled
调用RTCEngine
的addPublishUrl()
到参数集true
。现在你的流应该已经出现在平台上了。
最后,当有人从主舞台添加或删除时,你将需要更新转码,并结束流。要更新,你需要相应地更新转码布局,然后setLiveTranscoding()
再次更新。要删除流,调用removePublishUrl()
.
结论
如果这个应用程序看起来有点复杂,可事实就是如此。有些成熟的公司需要几个月的时间来为这样的事情创建建 MVP(最小可行产品)。即使他们可以创建它,他们也无法与 SD-RTN 带来的基础设施和可靠性相提并论。这是一个非常复杂的应用程序,但有了 Agora 就可以实现。
你可以在GitHub仓库找到此应用程序的代码。
原文作者 Tadas Petra
原文链接 https://www.agora.io/en/blog/live-streaming-to-multiple-platforms-with-multiple-users/