Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  rtp_transmission_manager.cc

  Sprache: C
 

/*
 *  Copyright 2020 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


#include "pc/rtp_transmission_manager.h"

#include <cstdint>
#include <iterator>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "absl/algorithm/container.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "api/audio_options.h"
#include "api/crypto/crypto_options.h"
#include "api/environment/environment.h"
#include "api/make_ref_counted.h"
#include "api/media_stream_interface.h"
#include "api/media_types.h"
#include "api/peer_connection_interface.h"
#include "api/rtc_error.h"
#include "api/rtp_parameters.h"
#include "api/rtp_receiver_interface.h"
#include "api/rtp_sender_interface.h"
#include "api/rtp_transceiver_direction.h"
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "media/base/media_channel.h"
#include "media/base/media_config.h"
#include "media/base/media_engine.h"
#include "pc/audio_rtp_receiver.h"
#include "pc/channel_interface.h"
#include "pc/codec_vendor.h"
#include "pc/connection_context.h"
#include "pc/legacy_stats_collector_interface.h"
#include "pc/rtp_receiver.h"
#include "pc/rtp_receiver_proxy.h"
#include "pc/rtp_sender.h"
#include "pc/rtp_sender_proxy.h"
#include "pc/rtp_transceiver.h"
#include "pc/scoped_operations_batcher.h"
#include "pc/simulcast_description.h"
#include "pc/usage_pattern.h"
#include "pc/video_rtp_receiver.h"
#include "rtc_base/checks.h"
#include "rtc_base/crypto_random.h"
#include "rtc_base/logging.h"
#include "rtc_base/system/plan_b_only.h"

namespace webrtc {

namespace {

const char kDefaultAudioSenderId[] = "defaulta0";
const char kDefaultVideoSenderId[] = "defaultv0";

template <typename T>
MediaType TrackType(T& track) {
  return track->kind() == MediaStreamTrackInterface::kAudioKind
             ? MediaType::AUDIO
             : MediaType::VIDEO;
}

std::optional<uint32_t> GetSenderSsrc(const std::vector<RtpSenderInfo>& infos,
                                      absl::string_view stream_id,
                                      absl::string_view sender_id) {
  auto it = absl::c_find_if(infos, [&](const RtpSenderInfo& info) {
    return info.stream_id == stream_id && info.sender_id == sender_id;
  });
  return it == infos.end() ? std::nullopt
                           : std::optional<uint32_t>((*it).first_ssrc);
}
}  // namespace

RtpTransmissionManager::RtpTransmissionManager(
    const Environment& env,
    Call* call,
    bool is_unified_plan,
    ConnectionContext* context,
    CodecLookupHelper* codec_lookup_helper,
    UsagePattern* usage_pattern,
    PeerConnectionObserver* observer,
    LegacyStatsCollectorInterface* legacy_stats,
    absl::AnyInvocable<void()> on_negotiation_needed)
    : env_(env),
      is_unified_plan_(is_unified_plan),
      call_(call),
      context_(context),
      codec_lookup_helper_(codec_lookup_helper),
      usage_pattern_(usage_pattern),
      observer_(observer),
      legacy_stats_(legacy_stats),
      on_negotiation_needed_(std::move(on_negotiation_needed)),
      weak_ptr_factory_(this) {}

void RtpTransmissionManager::Close() {
  closed_ = true;
  observer_ = nullptr;
}

// Implementation of SetStreamsObserver
void RtpTransmissionManager::OnSetStreams() {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(IsUnifiedPlan());
  OnNegotiationNeeded();
}

// Function to call back to the PeerConnection when negotiation is needed
void RtpTransmissionManager::OnNegotiationNeeded() {
  on_negotiation_needed_();
}

std::vector<RtpHeaderExtensionCapability>
RtpTransmissionManager::GetDefaultHeaderExtensions(MediaType media_type) {
  if (media_type == MediaType::AUDIO) {
    return media_engine()->voice().GetRtpHeaderExtensions(&env_.field_trials());
  }
  RTC_DCHECK_EQ(media_type, MediaType::VIDEO);
  return media_engine()->video().GetRtpHeaderExtensions(&env_.field_trials());
}

void RtpTransmissionManager::RunWithObserver(
    absl::AnyInvocable<void(PeerConnectionObserver*) &&> task) {  // NOLINT
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(observer_);
  std::move(task)(observer_);
}

PLAN_B_ONLY VoiceMediaSendChannelInterface*
RtpTransmissionManager::voice_media_send_channel() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  return GetAudioTransceiver()->internal()->voice_media_send_channel();
}

PLAN_B_ONLY VideoMediaSendChannelInterface*
RtpTransmissionManager::video_media_send_channel() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  return GetVideoTransceiver()->internal()->video_media_send_channel();
}
PLAN_B_ONLY VoiceMediaReceiveChannelInterface*
RtpTransmissionManager::voice_media_receive_channel() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  return GetAudioTransceiver()->internal()->voice_media_receive_channel();
}

PLAN_B_ONLY VideoMediaReceiveChannelInterface*
RtpTransmissionManager::video_media_receive_channel() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  return GetVideoTransceiver()->internal()->video_media_receive_channel();
}

PLAN_B_ONLY RTCErrorOr<scoped_refptr<RtpSenderInterface>>
RtpTransmissionManager::AddTrackPlanB(
    scoped_refptr<MediaStreamTrackInterface> track,
    const std::vector<std::string>& stream_ids,
    const std::vector<RtpEncodingParameters>* init_send_encodings) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  if (stream_ids.size() > 1u) {
    return LOG_ERROR(RTCError::UnsupportedOperation()
                     << "AddTrack with more than one stream is not supported "
                        "with Plan B semantics.");
  }
  std::vector<std::string> adjusted_stream_ids;
  if (stream_ids.empty()) {
    adjusted_stream_ids.push_back(CreateRandomUuid());
  } else {
    adjusted_stream_ids.reserve(stream_ids.size());
    absl::c_copy_if(stream_ids, std::back_inserter(adjusted_stream_ids),
                    [&](const auto& id) {
                      return !absl::c_linear_search(adjusted_stream_ids, id);
                    });
  }

  MediaType media_type = TrackType(track);
  RtpTransceiver* transceiver = media_type == MediaType::AUDIO
                                    ? GetAudioTransceiver()->internal()
                                    : GetVideoTransceiver()->internal();
  scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
      transceiver->AddSenderPlanB(track, track->id(), adjusted_stream_ids,
                                  init_send_encodings
                                      ? *init_send_encodings
                                      : std::vector<RtpEncodingParameters>(1));
  RTC_DCHECK(new_sender->internal()->stream_ids() == adjusted_stream_ids);
  std::optional<uint32_t> ssrc =
      GetSenderSsrc(media_type == MediaType::AUDIO ? local_audio_sender_infos_
                                                   : local_video_sender_infos_,
                    adjusted_stream_ids[0], track->id());
  if (ssrc) {
    new_sender->internal()->SetSsrc(*ssrc);
  }
  NoteUsageEvent(media_type == MediaType::AUDIO ? UsageEvent::AUDIO_ADDED
                                                : UsageEvent::VIDEO_ADDED);
  return scoped_refptr<RtpSenderInterface>(new_sender);
}

RTCErrorOr<scoped_refptr<RtpSenderInterface>>
RtpTransmissionManager::AddTrackUnifiedPlan(
    const MediaConfig& media_config,
    const AudioOptions& audio_options,
    const VideoOptions& video_options,
    const CryptoOptions& crypto_options,
    VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
    scoped_refptr<MediaStreamTrackInterface> track,
    const std::vector<std::string>& stream_ids,
    const std::vector<RtpEncodingParameters>* init_send_encodings) {
  RTC_DCHECK(IsUnifiedPlan());
  auto transceiver =
      FindFirstTransceiverForAddedTrack(track, init_send_encodings);
  if (transceiver) {
    RTC_LOG(LS_INFO) << "Reusing an existing "
                     << MediaTypeToString(transceiver->media_type())
                     << " transceiver for AddTrack.";
    if (transceiver->stopping()) {
      return LOG_ERROR(RTCError::InvalidParameter()
                       << "The existing transceiver is stopping.");
    }

    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.get());
    transceiver->internal()->sender_internal()->set_stream_ids(stream_ids);
    transceiver->internal()->set_reused_for_addtrack(true);
  } else {
    MediaType media_type = TrackType(track);
    RTC_LOG(LS_INFO) << "Adding " << 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 = CreateRandomUuid();
    }
    ScopedOperationsBatcher worker_tasks(context_->worker_thread());
    transceiver = CreateAndAddTransceiver(
        media_config, audio_options, video_options, crypto_options,
        video_bitrate_allocator_factory, media_type, track, stream_ids,
        init_send_encodings
            ? *init_send_encodings
            : std::vector<RtpEncodingParameters>(1, RtpEncodingParameters{}),
        /*header_extensions_to_negotiate=*/{},
        /*simulcast_rejected=*/false, /*initial_simulcast_layers=*/{},
        worker_tasks, sender_id, /*receiver_id=*/"");
    RTCError error = worker_tasks.Run();
    RTC_DCHECK(error.ok());
    transceiver->internal()->set_created_by_addtrack(true);
    transceiver->internal()->set_direction(RtpTransceiverDirection::kSendRecv);
  }
  return transceiver->sender();
}

scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
RtpTransmissionManager::CreateAndAddTransceiver(
    const MediaConfig& media_config,
    const AudioOptions& audio_options,
    const VideoOptions& video_options,
    const CryptoOptions& crypto_options,
    VideoBitrateAllocatorFactory* video_bitrate_allocator_factory,
    MediaType media_type,
    scoped_refptr<MediaStreamTrackInterface> track,
    const std::vector<std::string>& stream_ids,
    const std::vector<RtpEncodingParameters>& init_send_encodings,
    const std::vector<RtpHeaderExtensionCapability>&
        header_extensions_to_negotiate,
    bool simulcast_rejected,
    const std::vector<SimulcastLayer>& initial_simulcast_layers,
    ScopedOperationsBatcher& worker_tasks,
    absl::string_view sender_id,
    absl::string_view receiver_id) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  // Ensure that the new sender does not have an ID that is already in use by
  // another sender.
  // Allow receiver IDs to conflict since those come from remote SDP (which
  // could be invalid, but should not cause a crash).
  RTC_DCHECK(!FindSenderById(sender_id));
  std::vector<RtpHeaderExtensionCapability> header_extensions =
      std::move(header_extensions_to_negotiate);
  if (!env_.field_trials().IsDisabled(
          "WebRTC-HeaderExtensionNegotiateMemory")) {
    // If we have already negotiated header extensions for this type,
    // and it is not stopped,
    // reuse the negotiated state for new transceivers of the same type.
    for (const auto& transceiver : transceivers()->List()) {
      if (transceiver->media_type() == media_type && !transceiver->stopping()) {
        header_extensions = transceiver->GetHeaderExtensionsToNegotiate();
        break;
      }
    }
  }
  if (header_extensions.empty()) {
    header_extensions = GetDefaultHeaderExtensions(media_type);
  }

  RtpSenderBase::SetStreamsObserver* observer =
      IsUnifiedPlan() ? this : nullptr;
  auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
      signaling_thread(),
      make_ref_counted<RtpTransceiver>(
          env_, call_, media_config, sender_id, receiver_id, media_type, track,
          stream_ids, std::move(init_send_encodings), context_,
          codec_lookup_helper_, legacy_stats_, observer, audio_options,
          video_options, crypto_options, video_bitrate_allocator_factory,
          std::move(header_extensions), simulcast_rejected,
          initial_simulcast_layers, worker_tasks,
          [this_weak_ptr = weak_ptr_factory_.GetWeakPtr()]() {
            if (this_weak_ptr) {
              this_weak_ptr->OnNegotiationNeeded();
            }
          }));
  transceivers()->Add(transceiver);
  NoteUsageEvent(media_type == MediaType::AUDIO ? UsageEvent::AUDIO_ADDED
                                                : UsageEvent::VIDEO_ADDED);
  return transceiver;
}

scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
RtpTransmissionManager::FindFirstTransceiverForAddedTrack(
    scoped_refptr<MediaStreamTrackInterface> track,
    const std::vector<RtpEncodingParameters>* init_send_encodings) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(track);
  if (init_send_encodings != nullptr) {
    return nullptr;
  }
  const MediaType media_type = TrackType(track);
  for (auto& transceiver : transceivers()->List()) {
    if (!transceiver->sender()->track() &&
        transceiver->media_type() == media_type && !transceiver->stopped() &&
        !transceiver->internal()->has_ever_been_used_to_send()) {
      return transceiver;
    }
  }
  return nullptr;
}

std::vector<scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
RtpTransmissionManager::GetSendersInternal() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  std::vector<scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>
      all_senders;
  for (const auto& transceiver : transceivers_.List()) {
    if (IsUnifiedPlan() && transceiver->internal()->stopped())
      continue;

    RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN()
    auto senders = transceiver->internal()->senders();
    RTC_ALLOW_PLAN_B_DEPRECATION_END()
    all_senders.insert(all_senders.end(), senders.begin(), senders.end());
  }
  return all_senders;
}

std::vector<scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
RtpTransmissionManager::GetReceiversInternal() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  std::vector<scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>>
      all_receivers;
  for (const auto& transceiver : transceivers_.List()) {
    if (IsUnifiedPlan() && transceiver->internal()->stopped())
      continue;

    RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN()
    auto receivers = transceiver->internal()->receivers();
    RTC_ALLOW_PLAN_B_DEPRECATION_END()
    all_receivers.insert(all_receivers.end(), receivers.begin(),
                         receivers.end());
  }
  return all_receivers;
}

PLAN_B_ONLY scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
RtpTransmissionManager::GetAudioTransceiver() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  // This method only works with Plan B SDP, where there is a single
  // audio/video transceiver.
  RTC_DCHECK(!IsUnifiedPlan());
  for (auto transceiver : transceivers_.List()) {
    if (transceiver->media_type() == MediaType::AUDIO) {
      return transceiver;
    }
  }
  RTC_DCHECK_NOTREACHED();
  return nullptr;
}

PLAN_B_ONLY scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>
RtpTransmissionManager::GetVideoTransceiver() const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  // This method only works with Plan B SDP, where there is a single
  // audio/video transceiver.
  RTC_DCHECK(!IsUnifiedPlan());
  for (auto transceiver : transceivers_.List()) {
    if (transceiver->media_type() == MediaType::VIDEO) {
      return transceiver;
    }
  }
  RTC_DCHECK_NOTREACHED();
  return nullptr;
}

PLAN_B_ONLY void RtpTransmissionManager::AddTrackPlanB(
    MediaStreamTrackInterface* track,
    MediaStreamInterface* stream) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(track);
  RTC_DCHECK(stream);
  RTC_DCHECK(!IsUnifiedPlan());
  auto sender = FindSenderForTrack(track);
  if (sender) {
    // We already have a sender for this track, so just change the stream_id
    // so that it's correct in the next call to CreateOffer.
    sender->internal()->set_stream_ids({stream->id()});
    return;
  }

  // Normal case; we've never seen this track before.
  MediaType media_type = TrackType(track);
  RtpTransceiver* transceiver = media_type == MediaType::AUDIO
                                    ? GetAudioTransceiver()->internal()
                                    : GetVideoTransceiver()->internal();
  scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
      transceiver->AddSenderPlanB(
          scoped_refptr<MediaStreamTrackInterface>(track), track->id(),
          {stream->id()}, {});
  // If the sender has already been configured in SDP, we call SetSsrc,
  // which will connect the sender to the underlying transport. This can
  // occur if a local session description that contains the ID of the sender
  // is set before AddStream is called. It can also occur if the local
  // session description is not changed and RemoveStream is called, and
  // later AddStream is called again with the same stream.
  std::optional<uint32_t> ssrc =
      GetSenderSsrc(media_type == MediaType::AUDIO ? local_audio_sender_infos_
                                                   : local_video_sender_infos_,
                    stream->id(), track->id());
  if (ssrc) {
    new_sender->internal()->SetSsrc(*ssrc);
  }
}

// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
// indefinitely, when we have unified plan SDP.
PLAN_B_ONLY void RtpTransmissionManager::RemoveTrackPlanB(
    MediaStreamTrackInterface* track,
    MediaStreamInterface* stream) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  auto sender = FindSenderForTrack(track);
  if (!sender) {
    RTC_LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
                        << " doesn't exist.";
    return;
  }
  RtpTransceiver* transceiver = TrackType(track) == MediaType::AUDIO
                                    ? GetAudioTransceiver()->internal()
                                    : GetVideoTransceiver()->internal();
  transceiver->RemoveSenderPlanB(sender.get());
}

PLAN_B_ONLY void RtpTransmissionManager::CreateAudioReceiverPlanB(
    MediaStreamInterface* stream,
    const RtpSenderInfo& remote_sender_info) {
  RTC_DCHECK(!IsUnifiedPlan());
  RTC_DCHECK(!closed_);
  std::vector<scoped_refptr<MediaStreamInterface>> streams;
  streams.push_back(scoped_refptr<MediaStreamInterface>(stream));
  // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use
  // the constructor taking stream IDs instead.
  auto audio_receiver = make_ref_counted<AudioRtpReceiver>(
      worker_thread(), remote_sender_info.sender_id, streams, false,
      voice_media_receive_channel());
  auto task = (remote_sender_info.sender_id == kDefaultAudioSenderId)
                  ? audio_receiver->GetSetupForUnsignaledMediaChannel()
                  : audio_receiver->GetSetupForMediaChannel(
                        remote_sender_info.first_ssrc);
  worker_thread()->BlockingCall([&]() mutable { std::move(task)(); });

  auto receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
      signaling_thread(), worker_thread(), std::move(audio_receiver));
  GetAudioTransceiver()->internal()->AddReceiverPlanB(receiver);
  RunWithObserver(
      [&](auto observer) { observer->OnAddTrack(receiver, streams); });
  NoteUsageEvent(UsageEvent::AUDIO_ADDED);
}

PLAN_B_ONLY void RtpTransmissionManager::CreateVideoReceiverPlanB(
    MediaStreamInterface* stream,
    const RtpSenderInfo& remote_sender_info) {
  RTC_DCHECK(!IsUnifiedPlan());
  RTC_DCHECK(!closed_);
  std::vector<scoped_refptr<MediaStreamInterface>> streams;
  streams.push_back(scoped_refptr<MediaStreamInterface>(stream));
  // TODO(https://crbug.com/webrtc/9480): When we remove remote_streams(), use
  // the constructor taking stream IDs instead.
  auto video_receiver = make_ref_counted<VideoRtpReceiver>(
      worker_thread(), remote_sender_info.sender_id, streams,
      /*enable_sframe_at_owner=*/nullptr);

  auto task = video_receiver->GetSetupForMediaChannel(
      remote_sender_info.sender_id == kDefaultVideoSenderId
          ? std::nullopt
          : std::optional<uint32_t>(remote_sender_info.first_ssrc),
      video_media_receive_channel());
  worker_thread()->BlockingCall([&]() mutable { std::move(task)(); });

  auto receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
      signaling_thread(), worker_thread(), std::move(video_receiver));
  GetVideoTransceiver()->internal()->AddReceiverPlanB(receiver);
  RunWithObserver(
      [&](auto observer) { observer->OnAddTrack(receiver, streams); });
  NoteUsageEvent(UsageEvent::VIDEO_ADDED);
}

// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
// description.
PLAN_B_ONLY scoped_refptr<RtpReceiverInterface>
RtpTransmissionManager::RemoveAndStopReceiver(
    const RtpSenderInfo& remote_sender_info) {
  RTC_DCHECK(!IsUnifiedPlan());
  auto receiver = FindReceiverById(remote_sender_info.sender_id);
  if (!receiver) {
    RTC_LOG(LS_WARNING) << "RtpReceiver for track with id "
                        << remote_sender_info.sender_id << " doesn't exist.";
    return nullptr;
  }
  if (receiver->media_type() == MediaType::AUDIO) {
    GetAudioTransceiver()->internal()->RemoveReceiverPlanB(receiver.get());
  } else {
    GetVideoTransceiver()->internal()->RemoveReceiverPlanB(receiver.get());
  }
  return receiver;
}

PLAN_B_ONLY void RtpTransmissionManager::OnRemoteSenderAddedPlanB(
    const RtpSenderInfo& sender_info,
    MediaStreamInterface* stream,
    MediaType media_type) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  RTC_LOG(LS_INFO) << "Creating " << MediaTypeToString(media_type)
                   << " receiver for track_id=" << sender_info.sender_id
                   << " and stream_id=" << sender_info.stream_id;

  if (media_type == MediaType::AUDIO) {
    CreateAudioReceiverPlanB(stream, sender_info);
  } else if (media_type == MediaType::VIDEO) {
    CreateVideoReceiverPlanB(stream, sender_info);
  } else {
    RTC_DCHECK_NOTREACHED() << "Invalid media type";
  }
}

PLAN_B_ONLY void RtpTransmissionManager::OnRemoteSenderRemovedPlanB(
    const RtpSenderInfo& sender_info,
    MediaStreamInterface* stream,
    MediaType media_type) {
  RTC_DCHECK(!IsUnifiedPlan());
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_LOG(LS_INFO) << "Removing " << MediaTypeToString(media_type)
                   << " receiver for track_id=" << sender_info.sender_id
                   << " and stream_id=" << sender_info.stream_id;

  scoped_refptr<RtpReceiverInterface> receiver;
  if (media_type == MediaType::AUDIO) {
    // When the MediaEngine audio channel is destroyed, the RemoteAudioSource
    // will be notified which will end the AudioRtpReceiver::track().
    receiver = RemoveAndStopReceiver(sender_info);
    scoped_refptr<AudioTrackInterface> audio_track =
        stream->FindAudioTrack(sender_info.sender_id);
    if (audio_track) {
      stream->RemoveTrack(audio_track);
    }
  } else if (media_type == MediaType::VIDEO) {
    // Stopping or destroying a VideoRtpReceiver will end the
    // VideoRtpReceiver::track().
    receiver = RemoveAndStopReceiver(sender_info);
    scoped_refptr<VideoTrackInterface> video_track =
        stream->FindVideoTrack(sender_info.sender_id);
    if (video_track) {
      // There's no guarantee the track is still available, e.g. the track may
      // have been removed from the stream by an application.
      stream->RemoveTrack(video_track);
    }
  } else {
    RTC_DCHECK_NOTREACHED() << "Invalid media type";
  }
  if (receiver) {
    RTC_DCHECK(!closed_);
    RunWithObserver([&](auto observer) { observer->OnRemoveTrack(receiver); });
  }
}

PLAN_B_ONLY void RtpTransmissionManager::OnLocalSenderAdded(
    const RtpSenderInfo& sender_info,
    MediaType media_type) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  RTC_DCHECK(!IsUnifiedPlan());
  auto sender = FindSenderById(sender_info.sender_id);
  if (!sender) {
    RTC_LOG(LS_WARNING) << "An unknown RtpSender with id "
                        << sender_info.sender_id
                        << " has been configured in the local description.";
    return;
  }

  if (sender->media_type() != media_type) {
    RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local"
                           " description with an unexpected media type.";
    return;
  }

  sender->internal()->set_stream_ids({sender_info.stream_id});
  sender->internal()->SetSsrc(sender_info.first_ssrc);
}

PLAN_B_ONLY void RtpTransmissionManager::OnLocalSenderRemoved(
    const RtpSenderInfo& sender_info,
    MediaType media_type) {
  RTC_DCHECK_RUN_ON(signaling_thread());
  auto sender = FindSenderById(sender_info.sender_id);
  if (!sender) {
    // This is the normal case. I.e., RemoveStream has been called and the
    // SessionDescriptions has been renegotiated.
    return;
  }

  // A sender has been removed from the SessionDescription but it's still
  // associated with the PeerConnection. This only occurs if the SDP doesn't
  // match with the calls to CreateSender, AddStream and RemoveStream.
  if (sender->media_type() != media_type) {
    RTC_LOG(LS_WARNING) << "An RtpSender has been configured in the local"
                           " description with an unexpected media type.";
    return;
  }

  sender->internal()->SetSsrc(0);
}

std::vector<RtpSenderInfo>* RtpTransmissionManager::GetRemoteSenderInfos(
    MediaType media_type) {
  RTC_DCHECK(media_type == MediaType::AUDIO || media_type == MediaType::VIDEO);
  return (media_type == MediaType::AUDIO) ? &remote_audio_sender_infos_
                                          : &remote_video_sender_infos_;
}

std::vector<RtpSenderInfo>* RtpTransmissionManager::GetLocalSenderInfos(
    MediaType media_type) {
  RTC_DCHECK(media_type == MediaType::AUDIO || media_type == MediaType::VIDEO);
  return (media_type == MediaType::AUDIO) ? &local_audio_sender_infos_
                                          : &local_video_sender_infos_;
}

scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
RtpTransmissionManager::FindSenderForTrack(
    MediaStreamTrackInterface* track) const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  for (const auto& transceiver : transceivers_.List()) {
    RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN()
    for (auto sender : transceiver->internal()->senders()) {
      if (sender->track() == track) {
        return sender;
      }
    }
    RTC_ALLOW_PLAN_B_DEPRECATION_END()
  }
  return nullptr;
}

scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>
RtpTransmissionManager::FindSenderById(absl::string_view sender_id) const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  for (const auto& transceiver : transceivers_.List()) {
    RTC_ALLOW_PLAN_B_DEPRECATION_BEGIN();
    // Under Unified Plan, senders() always has exactly one entry,
    // and one can use sender() not senders().
    // Since this function is used both in Plan B and Unified, this is
    // left as-is for now.
    for (auto sender : transceiver->internal()->senders()) {
      if (sender->id() == sender_id) {
        return sender;
      }
    }
    RTC_ALLOW_PLAN_B_DEPRECATION_END();
  }
  return nullptr;
}

PLAN_B_ONLY scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
RtpTransmissionManager::FindReceiverById(absl::string_view receiver_id) const {
  RTC_DCHECK_RUN_ON(signaling_thread());
  for (const auto& transceiver : transceivers_.List()) {
    for (auto receiver : transceiver->internal()->receivers()) {
      if (receiver->id() == receiver_id) {
        return receiver;
      }
    }
  }
  return nullptr;
}

const MediaEngineInterface* RtpTransmissionManager::media_engine() const {
  return context_->media_engine();
}

}  // namespace webrtc

Messung V0.5 in Prozent
C=92 H=99 G=95

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-08-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=434850
#Domains=655579