webrtc 代码学习(五)AddAudioTrack

AddAudioTrack
作者:LanPZzzz
本章我们简单讲述下pc->AddAudioTrack

文章目录

          • 1. 如下代码\examples\peerconnection\client\conductor.cc(528行)
          • 2. CreateAudioTrack,需要先CreateAudioSource
          • 3. CreateAudioTrack (pc\audiotrack.h ),AudioTrack 就是MediaTrack,也继承了AudioTrackInterface
          • 4. 这里简单的介绍下AudioTrack,正好代码也不多
          • 5. 上面CreateAudioTrack 已经完成,下面是AddTrack (pc\peerconnection.cc 1160行)
          • 6. AddTrackUnifiedPlan(pc\peerconnection.cc 1233 行)
          • 7. CreateSender (pc\peerconnection.cc 1427 行)
          • 8. CreateReceiver(pc\peerconnection.cc 1456 行)
          • 9. CreateAndAddTransceiver(pc\peerconnection.cc 1476 行)
          • 总结
          • sender 和 receiver 请看学习六

1. 如下代码\examples\peerconnection\client\conductor.cc(528行)
  kAudioLabel = "xxxxxxxx"
  rtc::scoped_refptr audio_track(
      peer_connection_factory_->CreateAudioTrack(
          kAudioLabel, peer_connection_factory_->CreateAudioSource(
                           cricket::AudioOptions())));
  auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId});
2. CreateAudioTrack,需要先CreateAudioSource
rtc::scoped_refptr
PeerConnectionFactory::CreateAudioSource(const cricket::AudioOptions& options) {
  RTC_DCHECK(signaling_thread_->IsCurrent());
  rtc::scoped_refptr source(
      LocalAudioSource::Create(&options));
  return source;
}

最后创建的是LocalAudioSource(pc\localaudiosource.cc),这是在options 上进行赋值

3. CreateAudioTrack (pc\audiotrack.h ),AudioTrack 就是MediaTrack,也继承了AudioTrackInterface

返回AudioTrackInterface

T = AudioTrackInterface 
class AudioTrack : public MediaStreamTrack,
                   public ObserverInterface
                   
template 
class MediaStreamTrack : public Notifier

template 
class Notifier : public T

这样层层继承,返回就是AudioTrackInterface,他们太优秀了,整的我代码看着好难受

4. 这里简单的介绍下AudioTrack,正好代码也不多
void AudioTrack::AddSink(AudioTrackSinkInterface* sink) {
  RTC_DCHECK(thread_checker_.CalledOnValidThread());
  if (audio_source_)
    audio_source_->AddSink(sink);
}

void AudioTrack::RemoveSink(AudioTrackSinkInterface* sink) {
  RTC_DCHECK(thread_checker_.CalledOnValidThread());
  if (audio_source_)
    audio_source_->RemoveSink(sink);
}

AddSink + RemoveSink 都是加入到audio_source中,但是我们的audio_source 是LocalAudioSource,木有用,空方法

5. 上面CreateAudioTrack 已经完成,下面是AddTrack (pc\peerconnection.cc 1160行)

AddTrack audio 和 video 都使用同一个,所以在AddVideoTrack的时候这里可能就不讲了

RTCErrorOr> PeerConnection::AddTrack(
    rtc::scoped_refptr track,
    const std::vector& stream_ids) {
  TRACE_EVENT0("webrtc", "PeerConnection::AddTrack");
  if (!track) {
    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Track is null.");
  }
  
  if (!(track->kind() == MediaStreamTrackInterface::kAudioKind ||
        track->kind() == MediaStreamTrackInterface::kVideoKind)) {
    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
                         "Track has invalid kind: " + track->kind());
  }

  if (IsClosed()) {
    LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
                         "PeerConnection is closed.");
  }

  1. 查找是否有当前的track
  if (FindSenderForTrack(track)) {
    LOG_AND_RETURN_ERROR(
        RTCErrorType::INVALID_PARAMETER,
        "Sender already exists for track " + track->id() + ".");
  }

  2. 我们使用UnifiedPlan,直接调用AddTrackUnifiedPlan
  auto sender_or_error =
      (IsUnifiedPlan() ? AddTrackUnifiedPlan(track, stream_ids)
                       : AddTrackPlanB(track, stream_ids));
  if (sender_or_error.ok()) {
    3. 回到到observer 上,我们上层没有实现此方法
    observer_->OnRenegotiationNeeded();
    4. 这里创建每个track的stat report,需要查看下,具体什么使用
    stats_->AddTrack(track);
  }

  return sender_or_error;
}
6. AddTrackUnifiedPlan(pc\peerconnection.cc 1233 行)
RTCErrorOr>
PeerConnection::AddTrackUnifiedPlan(
    rtc::scoped_refptr track,
    const std::vector& stream_ids) {
  1. 我们第一次添加都是没有transceiver 的
  auto transceiver = FindFirstTransceiverForAddedTrack(track);
  if (transceiver) {
    RTC_LOG(LS_INFO) << "Reusing an existing "
                     << cricket::MediaTypeToString(transceiver->media_type())
                     << " transceiver for AddTrack.";
    if (transceiver->direction() == RtpTransceiverDirection::kRecvOnly) {
      transceiver->internal()->set_direction(
          RtpTransceiverDirection::kSendRecv);
    } else if (transceiver->direction() == RtpTransceiverDirection::kInactive) {
      transceiver->internal()->set_direction(
          RtpTransceiverDirection::kSendOnly);
    }

    transceiver->sender()->SetTrack(track);
    transceiver->internal()->sender_internal()->set_stream_ids(stream_ids);
  } else {
    cricket::MediaType media_type =
        (track->kind() == MediaStreamTrackInterface::kAudioKind
             ? cricket::MEDIA_TYPE_AUDIO
             : cricket::MEDIA_TYPE_VIDEO);
    RTC_LOG(LS_INFO) << "Adding " << cricket::MediaTypeToString(media_type)
                     << " transceiver in response to a call to AddTrack.";

    std::string sender_id = track->id();
    // Avoid creating a sender with an existing ID by generating a random ID.
    // This can happen if this is the second time AddTrack has created a sender
    // for this track.
    if (FindSenderById(sender_id)) {
      sender_id = rtc::CreateRandomUuid();
    }

    2. 看下下面的各个函数是什么作用
    auto sender = CreateSender(media_type, sender_id, track, stream_ids);
    auto receiver = CreateReceiver(media_type, rtc::CreateRandomUuid());
    transceiver = CreateAndAddTransceiver(sender, receiver);
    transceiver->internal()->set_created_by_addtrack(true);
    transceiver->internal()->set_direction(RtpTransceiverDirection::kSendRecv);
  }
  return transceiver->sender();
}
  1. FindFirstTransceiverForAddedTrack 获取 transceiver 是否可以使用
  2. 通过打日志发现 hasUsedToSendFlag = 1 获取 isStop = 1, 就代表当前的 transceiver 是不可用的,需要重新创建一个 transceiver,因此 PC 下有多个 transceiver, 每个 transceiver 有多个 sender + receiver
    auto strType = cricket::MediaTypeToString(transceiver->media_type());
    auto kind = track->kind();
    auto hasUsedToSendFlag = transceiver->internal()->has_ever_been_used_to_send();
    auto isStop = transceiver->stopped();
  1. audio 和 video 的 transceiver 是区分开的
7. CreateSender (pc\peerconnection.cc 1427 行)
rtc::scoped_refptr>
PeerConnection::CreateSender(
    cricket::MediaType media_type,
    const std::string& id,
    rtc::scoped_refptr track,
    const std::vector& stream_ids) {
  rtc::scoped_refptr> sender;
  
  1. Video send 是 VideoRtpSender, Audio send 是AudioRtpSender,并且会传入stats_
  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
    RTC_DCHECK(!track ||
               (track->kind() == MediaStreamTrackInterface::kAudioKind));
    sender = RtpSenderProxyWithInternal::Create(
        signaling_thread(),
        new AudioRtpSender(worker_thread(), id, stats_.get()));
    NoteUsageEvent(UsageEvent::AUDIO_ADDED);
  } else {
    RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
    RTC_DCHECK(!track ||
               (track->kind() == MediaStreamTrackInterface::kVideoKind));
    sender = RtpSenderProxyWithInternal::Create(
        signaling_thread(), new VideoRtpSender(worker_thread(), id));
    NoteUsageEvent(UsageEvent::VIDEO_ADDED);
  }
  
  2. 设置track
  bool set_track_succeeded = sender->SetTrack(track);
  RTC_DCHECK(set_track_succeeded);
  sender->internal()->set_stream_ids(stream_ids);
  return sender;
}
8. CreateReceiver(pc\peerconnection.cc 1456 行)

PeerConnection::CreateReceiver 没有什么好解释的,AudioRtpReceiver 和 VideoRtpReceiver,入参 receiver_id,stream_ids = std::vectorstd::string({}),有一个默认的stream

  1. sender 中的 track 是外层创建传入的
  2. receiver 的track 是内部自己创建的
9. CreateAndAddTransceiver(pc\peerconnection.cc 1476 行)
  auto transceiver = RtpTransceiverProxyWithInternal::Create(
      signaling_thread(), new RtpTransceiver(sender, receiver));
  transceivers_.push_back(transceiver);
  1. new RtpTransceiver,入参sender, receiver
  2. PC 保存transceivers_ 用于管理transceiver
  3. 这里描述下RtpTransceiver 的作用
    1. 管理RtpSenders, RtpReceivers, and BaseChannel
    2. Audio RtpTransceivers 有 AudioRtpSenders, AudioRtpReceivers 和 a VoiceChannel
    3. Video RtpTransceivers 有 VideoRtpSenders, VideoRtpReceivers 和 a VideoChannel

Plan B 有多个 senders 和 receivers 在sdp 中有 m= 片段
// With Plan B SDP, an RtpTransceiver can have any number of senders and
// receivers which map to a=ssrc lines in the m= section.
Unified Plan 只有一个 senders 和 receivers 在sdp 中有 m= 片段,复用
// With Unified Plan SDP, an RtpTransceiver will have exactly one sender and one
// receiver which are encapsulated by the m= section.

总结

本篇讲述了AddAudioTrack,讲述了里面的步骤,包括一些属性

sender 和 receiver 请看学习六

你可能感兴趣的:(webrtc学习)