void DefaultSignalingClient::HandleIndexFrame()

in chime-sdk-signaling-cpp/src/signaling/default_signaling_client.cc [378:469]


void DefaultSignalingClient::HandleIndexFrame(const signal_sdk::SdkIndexFrame& index_frame) {
  if (state_ != SignalingState::kConnected || !is_joined_) {
    CHIME_LOG(LogLevel::kWarning, "Should not receive index frame before join")
    return;
  }

  if (index_frame.has_at_capacity() && index_frame.at_capacity()) {
    // TODO @hokyungh: handle capacity
    CHIME_LOG(LogLevel::kWarning, "It reached video max capacity")
    return;
  }

  CHIME_LOG(LogLevel::kDebug, SignalFrameDebugUtils::IndexFrameDebugString(index_frame))

  std::vector<RemoteVideoSourceInfo> removed;
  for (const auto& pair : attendee_id_to_internal_configurations_) {
    auto it = std::find_if(index_frame.sources().begin(), index_frame.sources().end(),
                           [&](const signal_sdk::SdkStreamDescriptor& stream) {
                             return pair.second.attendee.attendee_id == stream.attendee_id();
                           });
    // previous index does not exist anymore, so added to remove list
    if (it == index_frame.sources().end()) {
      RemoteVideoSourceInfo remote_video_source;
      remote_video_source.max_bitrate_kbps = pair.second.max_bitrate_kbps;
      remote_video_source.attendee.attendee_id = pair.second.attendee.attendee_id;
      remote_video_source.attendee.external_user_id = pair.second.attendee.external_user_id;
      removed.push_back(remote_video_source);
    }
  }

  for (const auto& remote_video_source : removed) {
    attendee_id_to_internal_configurations_.erase(remote_video_source.attendee.attendee_id);
  }

  std::vector<RemoteVideoSourceInfo> sources;
  for (const signal_sdk::SdkStreamDescriptor& stream : index_frame.sources()) {
    auto attend_id_to_internal_config_it = attendee_id_to_internal_configurations_.find(stream.attendee_id());
    if (attend_id_to_internal_config_it == attendee_id_to_internal_configurations_.end()) {
      // Sets internal configuration for local mapping
      InternalStreamConfiguration remote_configuration;
      RemoteVideoSourceInfo remote_video_source;
      remote_configuration.stream_id = stream.stream_id();
      remote_configuration.group_id = stream.group_id();
      remote_configuration.attendee.attendee_id = stream.attendee_id();
      remote_configuration.attendee.external_user_id = stream.external_user_id();
      remote_configuration.max_bitrate_kbps = stream.max_bitrate_kbps();

      attendee_id_to_internal_configurations_[stream.attendee_id()] = remote_configuration;

      // Sets remote video sources as well
      remote_video_source.attendee.attendee_id = stream.attendee_id();
      remote_video_source.attendee.external_user_id = stream.external_user_id();
      remote_video_source.max_bitrate_kbps = stream.max_bitrate_kbps();
      remote_video_source.stream_id = stream.stream_id();

      sources.push_back(remote_video_source);
    } else {
      // Just updates value from the stream
      attend_id_to_internal_config_it->second.max_bitrate_kbps = stream.max_bitrate_kbps();
      attend_id_to_internal_config_it->second.attendee.attendee_id = stream.attendee_id();
      attend_id_to_internal_config_it->second.attendee.external_user_id = stream.external_user_id();
      attend_id_to_internal_config_it->second.group_id = stream.group_id();
    }
  }

  if (!has_received_first_index_) {
    has_received_first_index_ = true;
    
    if (TurnCredentialsExpired()) {
      CHIME_LOG(LogLevel::kError, "TURN credentials expired.")
      return;
    }
    TurnCredentials credentials = turn_credentials_;

    NotifySignalingObserver([&credentials, &sources](SignalingClientObserver* observer) -> void {
      observer->OnSignalingClientStarted({credentials, sources});
    });

    // No need to call OnRemoteVideoSourcesAvailable or OnRemoteVideoSourcesUnavailable for the first time
    return;
  }

  if (!sources.empty()) {
    NotifySignalingObserver(
        [&sources](SignalingClientObserver* observer) -> void { observer->OnRemoteVideoSourcesAvailable(sources); });
  }

  if (!removed.empty()) {
    NotifySignalingObserver(
        [&removed](SignalingClientObserver* observer) -> void { observer->OnRemoteVideoSourcesUnavailable(removed); });
  }
}