Files
nearby/cpp/core/internal/mediums/webrtc.cc
T

773 lines
29 KiB
C++

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "core/internal/mediums/webrtc.h"
#include <functional>
#include <memory>
#include <sstream>
#include "core/internal/mediums/webrtc/session_description_wrapper.h"
#include "core/internal/mediums/webrtc/signaling_frames.h"
#include "platform/base/byte_array.h"
#include "platform/base/listeners.h"
#include "platform/public/cancelable_alarm.h"
#include "platform/public/future.h"
#include "platform/public/logging.h"
#include "platform/public/mutex_lock.h"
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
#include "webrtc/api/jsep.h"
namespace location {
namespace nearby {
namespace connections {
namespace mediums {
namespace {
// The maximum amount of time to wait to connect to a data channel via WebRTC.
constexpr absl::Duration kDataChannelTimeout = absl::Milliseconds(5000);
// Delay between restarting signaling messenger to receive messages.
constexpr absl::Duration kRestartReceiveMessagesDuration = absl::Seconds(60);
} // namespace
WebRtc::WebRtc() = default;
WebRtc::~WebRtc() {
{
MutexLock lock(&mutex_);
NEARBY_LOGS(WARNING) << "Destructing Webrtc: " << InternalStatesToString();
}
// This ensures that all pending callbacks are run before we reset the medium
// and we are not accepting new runnables.
restart_receive_messages_executor_.Shutdown();
single_thread_executor_.Shutdown();
// Disconnect will also erase the connection info from map. Use a separate
// set to save the connection ids to avoid the iterator violation issue.
absl::flat_hash_set<std::string> connection_ids;
for (auto& item : accepting_map_) {
connection_ids.emplace(item.first);
}
for (const auto& connection_id : connection_ids) {
Disconnect(Role::kOfferer, connection_id);
}
connection_ids.clear();
for (auto& item : connecting_map_) {
connection_ids.emplace(item.first);
}
for (const auto& connection_id : connection_ids) {
Disconnect(Role::kAnswerer, connection_id);
}
connection_ids.clear();
}
const std::string WebRtc::GetDefaultCountryCode() {
return medium_.GetDefaultCountryCode();
}
bool WebRtc::IsAvailable() { return medium_.IsValid(); }
bool WebRtc::IsAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_);
ConnectionInfo* connection_info =
GetConnectionInfo(Role::kOfferer, service_id);
return connection_info && connection_info->self_id.IsValid();
}
bool WebRtc::StartAcceptingConnections(const std::string& service_id,
const PeerId& self_id,
const LocationHint& location_hint,
AcceptedConnectionCallback callback) {
if (!IsAvailable()) {
MutexLock lock(&mutex_);
LogAndDisconnect(Role::kOfferer, service_id,
"WebRTC is not available for data transfer.");
return false;
}
if (IsAcceptingConnections(service_id)) {
NEARBY_LOG(WARNING, "Already accepting WebRTC connections.");
return false;
}
{
MutexLock lock(&mutex_);
NEARBY_LOGS(WARNING) << "StartAcceptingConnections: "
<< InternalStatesToString();
accepting_map_.emplace(service_id,
ConnectionInfo{.socket = WebRtcSocketWrapper()});
ConnectionInfo* connection_info = &accepting_map_[service_id];
if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint, service_id))
return false;
connection_info->restart_receive_messages_alarm = CancelableAlarm(
"restart_receiving_messages_webrtc",
std::bind(&WebRtc::RestartReceiveMessages, this, location_hint,
service_id),
kRestartReceiveMessagesDuration, &restart_receive_messages_executor_);
SessionDescriptionWrapper offer =
connection_info->connection_flow->CreateOffer();
connection_info->pending_local_offer =
webrtc_frames::EncodeOffer(self_id, offer.GetSdp());
if (!SetLocalSessionDescription(std::move(offer), Role::kOfferer,
service_id)) {
NEARBY_LOG(WARNING, "Failed to set local session description.");
return false;
}
// There is no timeout set for the future returned since we do not know how
// much time it will take for the two devices to discover each other before
// the actual transport can begin.
ListenForWebRtcSocketFuture(
Role::kOfferer, service_id,
connection_info->connection_flow->GetDataChannel(),
std::move(callback));
NEARBY_LOG(WARNING, "Started listening for WebRtc connections as %s",
self_id.GetId().c_str());
}
return true;
}
WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
const LocationHint& location_hint) {
if (!IsAvailable()) {
MutexLock lock(&mutex_);
LogAndDisconnect(Role::kAnswerer, peer_id.GetId(),
"WebRTC is not available for data transfer.");
return WebRtcSocketWrapper();
}
{
MutexLock lock(&mutex_);
NEARBY_LOGS(WARNING) << "Start Connecting to " << peer_id.GetId() << ":\n"
<< InternalStatesToString();
if (connecting_map_.contains(peer_id.GetId())) {
NEARBY_LOG(
ERROR,
"Cannot connect with WebRtc because we are already connecting.");
return WebRtcSocketWrapper();
}
connecting_map_.emplace(peer_id.GetId(),
ConnectionInfo{.socket = WebRtcSocketWrapper()});
ConnectionInfo* connection_info = &connecting_map_[peer_id.GetId()];
connection_info->peer_id = peer_id;
if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom(), location_hint,
peer_id.GetId())) {
return WebRtcSocketWrapper();
}
}
NEARBY_LOG(WARNING, "Attempting to make a WebRTC connection to %s.",
peer_id.GetId().c_str());
Future<WebRtcSocketWrapper> socket_future;
{
MutexLock lock(&mutex_);
socket_future = ListenForWebRtcSocketFuture(
Role::kAnswerer, peer_id.GetId(),
connecting_map_[peer_id.GetId()].connection_flow->GetDataChannel(),
AcceptedConnectionCallback());
}
// The two devices have discovered each other, hence we have a timeout for
// establishing the transport channel.
// NOTE - We should not hold |mutex_| while waiting for the data channel since
// it would block incoming signaling messages from being processed, resulting
// in a timeout in creating the socket.
ExceptionOr<WebRtcSocketWrapper> result =
socket_future.Get(kDataChannelTimeout);
if (result.ok()) {
NEARBY_LOGS(WARNING) << "Succeeded to make WebRTC connection to "
<< peer_id.GetId();
return result.result();
}
NEARBY_LOGS(WARNING) << "Failed to make WebRTC connection to "
<< peer_id.GetId();
Disconnect(Role::kAnswerer, peer_id.GetId());
return WebRtcSocketWrapper();
}
bool WebRtc::SetLocalSessionDescription(SessionDescriptionWrapper sdp,
Role role,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return false;
if (!connection_info->connection_flow->SetLocalSessionDescription(
std::move(sdp))) {
LogAndDisconnect(role, connection_id,
"Unable to set local session description");
return false;
}
return true;
}
void WebRtc::StopAcceptingConnections(const std::string& service_id) {
if (!IsAcceptingConnections(service_id)) {
NEARBY_LOG(WARNING,
"Skipped StopAcceptingConnections since we are not currently "
"accepting WebRTC connections for %s",
service_id.c_str());
return;
}
{
MutexLock lock(&mutex_);
LogAndShutdownSignaling(Role::kOfferer, service_id,
"Invoked by StopAcceptingConnections.");
}
NEARBY_LOG(WARNING, "Stopped accepting WebRTC connections for %s",
service_id.c_str());
}
Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
const Role& role, const std::string& connection_id,
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
data_channel_future,
AcceptedConnectionCallback callback) {
Future<WebRtcSocketWrapper> socket_future;
auto data_channel_runnable = [this, role, connection_id, socket_future,
data_channel_future,
callback{std::move(callback)}]() mutable {
// The overall timeout of creating the socket and data channel is controlled
// by the caller of this function.
ExceptionOr<rtc::scoped_refptr<webrtc::DataChannelInterface>> res =
data_channel_future.Get();
if (res.ok()) {
WebRtcSocketWrapper wrapper =
CreateWebRtcSocketWrapper(role, connection_id, res.result());
callback.accepted_cb(wrapper);
{
MutexLock lock(&mutex_);
ConnectionInfo* connection_info =
GetConnectionInfo(role, connection_id);
if (connection_info) {
connection_info->socket = wrapper;
}
}
socket_future.Set(wrapper);
} else {
NEARBY_LOG(WARNING, "Failed to get WebRtcSocket.");
socket_future.Set(WebRtcSocketWrapper());
}
};
data_channel_future.AddListener(std::move(data_channel_runnable),
&single_thread_executor_);
return socket_future;
}
WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper(
const Role& role, const std::string& connection_id,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
if (data_channel == nullptr) {
return WebRtcSocketWrapper();
}
auto socket = std::make_unique<WebRtcSocket>("WebRtcSocket", data_channel);
socket->SetOnSocketClosedListener({[this, role, connection_id]() {
OffloadFromSignalingThread(
[this, role, connection_id]() { Disconnect(role, connection_id); });
}});
return WebRtcSocketWrapper(std::move(socket));
}
bool WebRtc::InitWebRtcFlow(const Role& role, const PeerId& self_id,
const LocationHint& location_hint,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) {
NEARBY_LOGS(WARNING) << "Can not find matching connection info.";
return false;
}
connection_info->self_id = self_id;
if (connection_info->connection_flow) {
LogAndShutdownSignaling(
role, connection_id,
"Tried to initialize WebRTC without shutting down the previous "
"connection");
return false;
}
if (connection_info->signaling_messenger) {
LogAndShutdownSignaling(
role, connection_id,
"Tried to initialize WebRTC without shutting down signaling messenger");
return false;
}
connection_info->signaling_messenger =
medium_.GetSignalingMessenger(self_id.GetId(), location_hint);
auto signaling_message_callback = std::bind(
[this](ByteArray message, Role role, const std::string& connection_id) {
OffloadFromSignalingThread([this, message{std::move(message)},
role{role},
connection_id{connection_id}]() {
ProcessSignalingMessage(role, connection_id, message);
});
},
std::placeholders::_1, role, connection_id);
if (!connection_info->signaling_messenger->IsValid() ||
!connection_info->signaling_messenger->StartReceivingMessages(
signaling_message_callback)) {
LogAndDisconnect(role, connection_id,
"Could not receive from signaling messenger.");
return false;
}
if (role == Role::kAnswerer &&
!connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(),
webrtc_frames::EncodeReadyForSignalingPoke(self_id))) {
LogAndDisconnect(Role::kAnswerer, connection_info->peer_id.GetId(),
absl::StrCat("Could not send signaling poke to peer ",
connection_info->peer_id.GetId()));
return false;
}
connection_info->connection_flow = ConnectionFlow::Create(
GetLocalIceCandidateListener(role, connection_id),
GetDataChannelListener(role, connection_id), medium_);
if (!connection_info->connection_flow) {
LogAndDisconnect(role, connection_id, "Failed to create connection flow");
return false;
}
NEARBY_LOGS(WARNING) << "Succeeded to create connection flow for role:"
<< role_names_[role]
<< ", connection_id: " << connection_id;
return true;
}
void WebRtc::OnLocalIceCandidate(
const Role& role, const std::string& connection_id,
const webrtc::IceCandidateInterface* local_ice_candidate) {
::location::nearby::mediums::IceCandidate ice_candidate =
webrtc_frames::EncodeIceCandidate(*local_ice_candidate);
OffloadFromSignalingThread([this, ice_candidate{std::move(ice_candidate)},
role{role}, connection_id{connection_id}]() {
MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (IsSignaling(role, connection_id)) {
if (connection_info && connection_info->signaling_messenger) {
NEARBY_LOG(WARNING, "Sending local ice candidates to %s",
connection_info->peer_id.GetId().c_str());
connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(),
webrtc_frames::EncodeIceCandidates(connection_info->self_id,
{std::move(ice_candidate)}));
} else {
connection_info->pending_local_ice_candidates.push_back(
std::move(ice_candidate));
}
} else {
connection_info->pending_local_ice_candidates.push_back(
std::move(ice_candidate));
}
});
}
LocalIceCandidateListener WebRtc::GetLocalIceCandidateListener(
const Role& role, const std::string& connection_id) {
return {std::bind(&WebRtc::OnLocalIceCandidate, this, role, connection_id,
std::placeholders::_1)};
}
void WebRtc::OnDataChannelClosed(const Role& role,
const std::string& connection_id) {
OffloadFromSignalingThread([this, role, connection_id]() {
MutexLock lock(&mutex_);
LogAndDisconnect(role, connection_id, "WebRTC data channel closed");
});
}
void WebRtc::OnDataChannelMessageReceived(const Role& role,
const std::string& connection_id,
const ByteArray& message) {
OffloadFromSignalingThread([this, role, connection_id, message]() {
{
MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return;
if (!connection_info->socket.IsValid()) {
LogAndDisconnect(role, connection_id,
"Received a data channel message without a socket");
return;
}
connection_info->socket.NotifyDataChannelMsgReceived(message);
}
});
}
void WebRtc::OnDataChannelBufferedAmountChanged(
const Role& role, const std::string& connection_id) {
OffloadFromSignalingThread([this, role, connection_id]() {
{
MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return;
if (!connection_info->socket.IsValid()) {
LogAndDisconnect(role, connection_id,
"Data channel buffer changed without a socket");
return;
}
connection_info->socket.NotifyDataChannelBufferedAmountChanged();
}
});
}
DataChannelListener WebRtc::GetDataChannelListener(
const Role& role, const std::string& connection_id) {
return {
.data_channel_closed_cb =
std::bind(&WebRtc::OnDataChannelClosed, this, role, connection_id),
.data_channel_message_received_cb =
std::bind(&WebRtc::OnDataChannelMessageReceived, this, role,
connection_id, std::placeholders::_1),
.data_channel_buffered_amount_changed_cb =
std::bind(&WebRtc::OnDataChannelBufferedAmountChanged, this, role,
connection_id),
};
}
bool WebRtc::IsSignaling(const Role& role, const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return false;
return (connection_info->self_id.IsValid() &&
connection_info->peer_id.IsValid());
}
void WebRtc::ProcessSignalingMessage(const Role& role,
const std::string& connection_id,
const ByteArray& message) {
MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) {
NEARBY_LOG(ERROR,
"Could not find connection info for role: %s, connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
return;
}
if (!connection_info->connection_flow) {
LogAndDisconnect(role, connection_id,
"Received WebRTC frame before signaling was started");
return;
}
location::nearby::mediums::WebRtcSignalingFrame frame;
if (!frame.ParseFromString(std::string(message))) {
LogAndDisconnect(role, connection_id, "Failed to parse signaling message");
return;
}
if (!frame.has_sender_id()) {
LogAndDisconnect(role, connection_id,
"Invalid WebRTC frame: Sender ID is missing");
return;
}
if (frame.has_ready_for_signaling_poke() &&
!connection_info->peer_id.IsValid()) {
connection_info->peer_id = PeerId(frame.sender_id().id());
NEARBY_LOG(WARNING, "Peer %s is ready for signaling",
connection_info->peer_id.GetId().c_str());
}
if (!IsSignaling(role, connection_id)) {
NEARBY_LOG(WARNING,
"Ignoring WebRTC frame: we are not currently listening for "
"signaling messages");
return;
}
if (frame.sender_id().id() != connection_info->peer_id.GetId()) {
NEARBY_LOG(
WARNING,
"Ignoring WebRTC frame: we are only listening for another peer.");
return;
}
if (frame.has_ready_for_signaling_poke()) {
NEARBY_LOG(WARNING,
"Received ready-for-poke for role: %s connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
SendOfferAndIceCandidatesToPeer(connection_id);
} else if (frame.has_offer()) {
NEARBY_LOG(WARNING, "Received offer for role: %s connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
DCHECK(role == Role::kAnswerer);
connection_info->connection_flow->OnOfferReceived(
SessionDescriptionWrapper(webrtc_frames::DecodeOffer(frame).release()));
SendAnswerToPeer(connection_id);
} else if (frame.has_answer()) {
NEARBY_LOG(WARNING, "Received answer for role: %s connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
DCHECK(role == Role::kOfferer);
connection_info->connection_flow->OnAnswerReceived(
SessionDescriptionWrapper(
webrtc_frames::DecodeAnswer(frame).release()));
} else if (frame.has_ice_candidates()) {
NEARBY_LOG(WARNING,
"Received ice candidates for role: %s connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
if (!connection_info->connection_flow->OnRemoteIceCandidatesReceived(
webrtc_frames::DecodeIceCandidates(frame))) {
LogAndDisconnect(role, connection_id,
"Could not add remote ice candidates.");
}
} else {
NEARBY_LOG(WARNING,
"Received unknown frame type for role: %s connection_id: %s",
role_names_[role].c_str(), connection_id.c_str());
}
}
void WebRtc::SendOfferAndIceCandidatesToPeer(const std::string& service_id) {
ConnectionInfo* connection_info =
GetConnectionInfo(Role::kOfferer, service_id);
if (!connection_info) return;
if (connection_info->pending_local_offer.Empty()) {
LogAndDisconnect(
Role::kOfferer, service_id,
"Unable to send pending offer to remote peer: local offer not set");
return;
}
NEARBY_LOG(WARNING, "Sending offer from %s", service_id.c_str());
if (!connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(),
connection_info->pending_local_offer)) {
LogAndDisconnect(Role::kOfferer, service_id,
"Failed to send local offer via signaling messenger");
return;
}
connection_info->pending_local_offer = ByteArray();
if (!connection_info->pending_local_ice_candidates.empty()) {
NEARBY_LOG(WARNING, "Sending local pending ice candidates from %s",
service_id.c_str());
connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(),
webrtc_frames::EncodeIceCandidates(
connection_info->self_id,
std::move(connection_info->pending_local_ice_candidates)));
}
}
void WebRtc::SendAnswerToPeer(const std::string& peer_id) {
ConnectionInfo* connection_info = GetConnectionInfo(Role::kAnswerer, peer_id);
if (!connection_info) return;
SessionDescriptionWrapper answer =
connection_info->connection_flow->CreateAnswer();
ByteArray answer_message(
webrtc_frames::EncodeAnswer(connection_info->self_id, answer.GetSdp()));
if (!SetLocalSessionDescription(std::move(answer), Role::kAnswerer, peer_id))
return;
NEARBY_LOGS(WARNING) << "Sending answer to peer " << peer_id;
if (!connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(), answer_message)) {
LogAndDisconnect(Role::kAnswerer, peer_id,
"Failed to send local answer via signaling messenger");
return;
}
}
void WebRtc::LogAndDisconnect(const Role& role,
const std::string& connection_id,
const std::string& error_message) {
NEARBY_LOG(WARNING,
"Disconnecting WebRTC role: %d, connection id: %s, msg: %s", role,
connection_id.c_str(), error_message.c_str());
DisconnectLocked(role, connection_id);
}
void WebRtc::LogAndShutdownSignaling(const Role& role,
const std::string& connection_id,
const std::string& error_message) {
NEARBY_LOG(WARNING,
"Stopping WebRTC role: %s, connection id: %s, msg: %s:\n%s",
role_names_[role].c_str(), connection_id.c_str(),
error_message.c_str(), InternalStatesToString().c_str());
ShutdownSignaling(role, connection_id);
}
void WebRtc::ShutdownSignaling(const Role& role,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) {
return;
}
connection_info->self_id = PeerId();
connection_info->peer_id = PeerId();
connection_info->pending_local_offer = ByteArray();
connection_info->pending_local_ice_candidates.clear();
if (connection_info->restart_receive_messages_alarm.IsValid()) {
connection_info->restart_receive_messages_alarm.Cancel();
connection_info->restart_receive_messages_alarm = CancelableAlarm();
}
if (connection_info->signaling_messenger) {
connection_info->signaling_messenger->StopReceivingMessages();
connection_info->signaling_messenger.reset();
}
if (!connection_info->socket.IsValid())
ShutdownIceCandidateCollection(role, connection_id);
}
void WebRtc::Disconnect(const Role& role, const std::string& connection_id) {
MutexLock lock(&mutex_);
DisconnectLocked(role, connection_id);
}
void WebRtc::DisconnectLocked(const Role& role,
const std::string& connection_id) {
NEARBY_LOGS(WARNING) << "Disconnecting role: " << role_names_[role]
<< " connection_id: " << connection_id << ":\n"
<< InternalStatesToString();
ShutdownSignaling(role, connection_id);
ShutdownWebRtcSocket(role, connection_id);
ShutdownIceCandidateCollection(role, connection_id);
if (role == Role::kOfferer && accepting_map_.contains(connection_id)) {
accepting_map_.erase(connection_id);
} else if (role == Role::kAnswerer &&
connecting_map_.contains(connection_id)) {
connecting_map_.erase(connection_id);
}
}
void WebRtc::ShutdownWebRtcSocket(const Role& role,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (connection_info && connection_info->socket.IsValid()) {
connection_info->socket.Close();
connection_info->socket = WebRtcSocketWrapper();
}
}
void WebRtc::ShutdownIceCandidateCollection(const Role& role,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (connection_info && connection_info->connection_flow) {
connection_info->connection_flow->Close();
connection_info->connection_flow.reset();
}
}
void WebRtc::OffloadFromSignalingThread(Runnable runnable) {
single_thread_executor_.Execute(std::move(runnable));
}
void WebRtc::RestartReceiveMessages(const LocationHint& location_hint,
const std::string& service_id) {
if (!IsAcceptingConnections(service_id)) {
NEARBY_LOG(WARNING,
"Skipping restart since we are not accepting connections.");
return;
}
NEARBY_LOG(WARNING, "Restarting listening for receiving signaling messages.");
{
MutexLock lock(&mutex_);
ConnectionInfo* connection_info =
GetConnectionInfo(Role::kOfferer, service_id);
if (!connection_info) {
NEARBY_LOG(ERROR,
"Can't find connection info in RestartReceiveMessages for %s",
service_id.c_str());
return;
}
connection_info->signaling_messenger->StopReceivingMessages();
connection_info->signaling_messenger = medium_.GetSignalingMessenger(
connection_info->self_id.GetId(), location_hint);
auto signaling_message_callback = std::bind(
[this](ByteArray message, const Role& role,
const std::string& connection_id) {
OffloadFromSignalingThread([this, message{std::move(message)},
role{role},
connection_id{connection_id}]() {
ProcessSignalingMessage(role, connection_id, message);
});
},
std::placeholders::_1, Role::kOfferer, service_id);
if (!connection_info->signaling_messenger->IsValid() ||
!connection_info->signaling_messenger->StartReceivingMessages(
signaling_message_callback)) {
DisconnectLocked(Role::kOfferer, service_id);
}
}
}
WebRtc::ConnectionInfo* WebRtc::GetConnectionInfo(
const Role& role, const std::string& connection_id) {
if (role == Role::kOfferer && accepting_map_.contains(connection_id)) {
return &accepting_map_[connection_id];
} else if (role == Role::kAnswerer &&
connecting_map_.contains(connection_id)) {
return &connecting_map_[connection_id];
}
return nullptr;
}
std::string WebRtc::ConnectionInfo::ToString() const {
std::ostringstream result;
result << (connection_flow == nullptr ? "connection_flow is null, "
: "connection_flow is valid, ");
result << (signaling_messenger == nullptr ? "signaling_messenger is null, "
: "signaling_messenger is valid, ");
result << (socket.IsValid() ? "socket is valid, " : "socket is not valid, ");
result << "remote peer_id: " << peer_id.GetId() << ", ";
result << "self peer_id: " << self_id.GetId();
return result.str();
}
std::string WebRtc::InternalStatesToString() {
std::ostringstream map_values;
map_values << "connecting map size: " << connecting_map_.size()
<< ", accepting map size: " << accepting_map_.size() << "\n";
for (auto& item : connecting_map_) {
map_values << "connecting " << item.first << ": " << item.second.ToString()
<< "\n";
}
for (auto& item : accepting_map_) {
map_values << "accepting " << item.first << ": " << item.second.ToString()
<< "\n";
}
return map_values.str();
}
} // namespace mediums
} // namespace connections
} // namespace nearby
} // namespace location