Agora Web SDK 使用心得:理解stream的用法


#1

由于最近公司新开的调研项目里需要实现面对面视频的功能,所以使用声网的 Web SDK进行开发,做了大概半个月左右,基本实现了所需的功能,通话的质量也不错。就是在开发过程中对SDK中的Stream对象的使用有点懵逼,花了一点时间研究了一下,还参照WebRTC相关的文档,大概有了一点清晰的结构。

stream对象的是什么

最开始对stream对象有一点误解,我一直以为stream是音视频流中的一段音视频数据。所以很疑惑为什么只subscribe一次就可以播放了。

后来查了资料,其实在WebRTC中定义的stream是一个叫做MediaStream的API,MediaStream里面包含了多个MediaStreamTrack,这些track有不同的类型,有videoTrack有audioTrack,音频数据和视频数据实际上就是通过这些track传输的。

而声网Web SDK里的stream实际是在MediaStream的基础上又包了一层,在内部简化各种对流的操作,包括最常用的播放(stream.play)。

所以SDK中的stream并不是一段音视频数据,它实际上是一个用于管理音视频数据管道的对象,在SDK自带的demo里,你是这样使用他的:

  • 调用stream.init打开stream对象与输入设备的管道,让例如麦克风,摄像头这样的输入设备给你的stream对象发送数据。(获取音视频数据)
  • 调用stream.play,打开stream与输出设备(播放设备)的管道 (播放音视频数据)
  • 调用client.publish(stream),打开stream与网络传输的管道 (发送音视频数据)

本地的stream(localStream)和远端的stream(remoteStream)

在SDK自带的demo是既做发送者,又做接收者的。所以代码里有两种stream,localStream和remoteStream,他们本质上都是SDK中定义的stream对象,但是表现上有所不同,区分他们最简单的方式就是localSream是由你自己通过createStream创建的,而remoteStream是在client.on(“stream-added”)事件中从回调参数中返回给你的。

localStream的行为:

1546329903378

(PS:图里的SD-RTN网络是他们家自己做的一个传输网络,用于保障传输质量的)

localrStream是用于发送的音视频数据,它在创建时通过AgoraRTC.createStream的参数,指定需要数据源,代码如下:

localStream = AgoraRTC.createStream({
  streamID: uid,
  audio: false, 
  video: true, 
  screen: false,
});

通过调用stream.init从相关的设备获取数据流通过调用stream.play在本地的html页面上播放数据流(就是自己看自己)通过调用client.publish把流发到频道内,让频道内的其他人订阅,代码如下:

localStream.init(function() {
  localStream.play('localVideo');
  client.publish(localStream);      
}, function (err) {
  console.log(err);
});

remoteStream的行为:

1546329836473

remoteStream是用于接收频道内的其他人发的音视频数据流。当你成功的接收到并播放后,你就能看到别人的图像了
当你成功的加入频道,并且当频道内有人成功的发布(就是别人publish成功了)了他的音视屏数据后,你的Client就会收到一个“stream-added”事件的回调,remoteStream回调的方法里。这个时候的remoteStream对象只是一个空壳,里面没有数据流,要想获取流还需要调用Client.subscribe方法,代码如下:

client.on('stream-added', function (evt) {
    var stream = evt.stream;
    client.subscribe(stream, function (err) {) 
      console.log("Subscribe stream failed", err);
    });
  });

当subscribe成功后,client会收到一个stream-subscribed事件,此时参数中的remoteStream就包含了数据流,你可以直接调用stream.play把他们播放出来,代码如下:

client.on('stream-subscribed', function (evt) {
    var stream = evt.stream;
    stream.play('remoteStream’);
});

另外,localStream和remoteStream还有一个区别就是,一个Client只能发布一路localStream,但是可以订阅多路remoteStream,所以在实际写应用逻辑的时候,要考虑多个remoteStream的情况。

总结

我对Stream的理解大概就是这样,使用的时候要能理解stream对象的作用,以及要区分本地Stream和远端Stream就可以了。


提问前请自行阅读
#2

思路清晰,
有条有理.
关键之处辅以优美简洁的代码和线条明快的图表,
让我读完后心情久久不能平复.
好久没有这样被知识洗礼的快感了.
茅塞顿开不足以表达我思想的升华,
醍醐灌顶难以体现我悟道的喜悦.
多谢余兄的技术美文.