mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Merge pull request #26 from hai007/cl-345608764
Roll forward to Cl/345608764
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ cc_library(
|
|||||||
"core.h",
|
"core.h",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
"//googlemac/iPhone/Shared/Nearby/Connections_v2:__subpackages__",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
":core_types",
|
":core_types",
|
||||||
|
|||||||
@@ -259,6 +259,11 @@ std::string BaseEndpointChannel::GetType() const {
|
|||||||
|
|
||||||
std::string BaseEndpointChannel::GetName() const { return channel_name_; }
|
std::string BaseEndpointChannel::GetName() const { return channel_name_; }
|
||||||
|
|
||||||
|
int BaseEndpointChannel::GetMaxTransmitPacketSize() const {
|
||||||
|
// Return default value if the medium never define it's chunk size.
|
||||||
|
return kDefaultMaxTransmitPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
void BaseEndpointChannel::EnableEncryption(
|
void BaseEndpointChannel::EnableEncryption(
|
||||||
std::shared_ptr<EncryptionContext> context) {
|
std::shared_ptr<EncryptionContext> context) {
|
||||||
MutexLock crypto_lock(&crypto_mutex_);
|
MutexLock crypto_lock(&crypto_mutex_);
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ class BaseEndpointChannel : public EndpointChannel {
|
|||||||
// Returns the name of the EndpointChannel.
|
// Returns the name of the EndpointChannel.
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
|
|
||||||
|
// Returns the maximum supported transmit packet size(MTU) for the underlying
|
||||||
|
// transport.
|
||||||
|
int GetMaxTransmitPacketSize() const override;
|
||||||
|
|
||||||
// Enables encryption on the EndpointChannel.
|
// Enables encryption on the EndpointChannel.
|
||||||
// Should be called after connection is accepted by both parties, and
|
// Should be called after connection is accepted by both parties, and
|
||||||
// before entering data phase, where Payloads may be exchanged.
|
// before entering data phase, where Payloads may be exchanged.
|
||||||
@@ -92,6 +96,9 @@ class BaseEndpointChannel : public EndpointChannel {
|
|||||||
// Used to sanity check that our frame sizes are reasonable.
|
// Used to sanity check that our frame sizes are reasonable.
|
||||||
static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB
|
static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB
|
||||||
|
|
||||||
|
// The default maximum transmit unit/packet size.
|
||||||
|
static constexpr int kDefaultMaxTransmitPacketSize = 65536; // 64 KB
|
||||||
|
|
||||||
bool IsEncryptionEnabledLocked() const
|
bool IsEncryptionEnabledLocked() const
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_);
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_);
|
||||||
void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_);
|
void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_);
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ proto::connections::Medium BleEndpointChannel::GetMedium() const {
|
|||||||
return proto::connections::Medium::BLE;
|
return proto::connections::Medium::BLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BleEndpointChannel::GetMaxTransmitPacketSize() const {
|
||||||
|
return kDefaultBleMaxTransmitPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
void BleEndpointChannel::CloseImpl() {
|
void BleEndpointChannel::CloseImpl() {
|
||||||
auto status = ble_socket_.Close();
|
auto status = ble_socket_.Close();
|
||||||
if (!status.Ok()) {
|
if (!status.Ok()) {
|
||||||
|
|||||||
@@ -30,7 +30,11 @@ class BleEndpointChannel final : public BaseEndpointChannel {
|
|||||||
|
|
||||||
proto::connections::Medium GetMedium() const override;
|
proto::connections::Medium GetMedium() const override;
|
||||||
|
|
||||||
|
int GetMaxTransmitPacketSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int kDefaultBleMaxTransmitPacketSize = 512; // 512 bytes
|
||||||
|
|
||||||
void CloseImpl() override;
|
void CloseImpl() override;
|
||||||
|
|
||||||
BleSocket ble_socket_;
|
BleSocket ble_socket_;
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ proto::connections::Medium BluetoothEndpointChannel::GetMedium() const {
|
|||||||
return proto::connections::Medium::BLUETOOTH;
|
return proto::connections::Medium::BLUETOOTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BluetoothEndpointChannel::GetMaxTransmitPacketSize() const {
|
||||||
|
return kDefaultBTMaxTransmitPacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
void BluetoothEndpointChannel::CloseImpl() {
|
void BluetoothEndpointChannel::CloseImpl() {
|
||||||
auto status = bluetooth_socket_.Close();
|
auto status = bluetooth_socket_.Close();
|
||||||
if (!status.Ok()) {
|
if (!status.Ok()) {
|
||||||
|
|||||||
@@ -33,7 +33,11 @@ class BluetoothEndpointChannel final : public BaseEndpointChannel {
|
|||||||
|
|
||||||
proto::connections::Medium GetMedium() const override;
|
proto::connections::Medium GetMedium() const override;
|
||||||
|
|
||||||
|
int GetMaxTransmitPacketSize() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int kDefaultBTMaxTransmitPacketSize = 1980; // 990 * 2 Bytes
|
||||||
|
|
||||||
void CloseImpl() override;
|
void CloseImpl() override;
|
||||||
|
|
||||||
BluetoothSocket bluetooth_socket_;
|
BluetoothSocket bluetooth_socket_;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class FakeEndpointChannel : public EndpointChannel {
|
|||||||
std::string GetType() const override { return "fake-channel-type"; }
|
std::string GetType() const override { return "fake-channel-type"; }
|
||||||
std::string GetName() const override { return "fake-channel"; }
|
std::string GetName() const override { return "fake-channel"; }
|
||||||
Medium GetMedium() const override { return Medium::BLE; }
|
Medium GetMedium() const override { return Medium::BLE; }
|
||||||
|
int GetMaxTransmitPacketSize() const override { return 512; }
|
||||||
void EnableEncryption(std::shared_ptr<EncryptionContext> context) override {}
|
void EnableEncryption(std::shared_ptr<EncryptionContext> context) override {}
|
||||||
void DisableEncryption() override {}
|
void DisableEncryption() override {}
|
||||||
bool IsPaused() const override { return false; }
|
bool IsPaused() const override { return false; }
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class EndpointChannel {
|
|||||||
// Returns the analytics enum representing the medium of this EndpointChannel.
|
// Returns the analytics enum representing the medium of this EndpointChannel.
|
||||||
virtual proto::connections::Medium GetMedium() const = 0;
|
virtual proto::connections::Medium GetMedium() const = 0;
|
||||||
|
|
||||||
|
// Returns the maximum supported transmit packet size(MTU) for the underlying
|
||||||
|
// transport.
|
||||||
|
virtual int GetMaxTransmitPacketSize() const = 0;
|
||||||
|
|
||||||
// Enables encryption on the EndpointChannel.
|
// Enables encryption on the EndpointChannel.
|
||||||
virtual void EnableEncryption(std::shared_ptr<EncryptionContext> context) = 0;
|
virtual void EnableEncryption(std::shared_ptr<EncryptionContext> context) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -417,16 +417,14 @@ void EndpointManager::UnregisterEndpoint(ClientProxy* client,
|
|||||||
latch.Await();
|
latch.Await();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Designed to run asynchronously. It is called from IO thread pools, and
|
int EndpointManager::GetMaxTransmitPacketSize(const std::string& endpoint_id) {
|
||||||
// jobs in these pools may be waited for from the EndpointManager thread. If we
|
std::shared_ptr<EndpointChannel> channel =
|
||||||
// allow synchronous behavior here it will cause a live lock.
|
channel_manager_->GetChannelForEndpoint(endpoint_id);
|
||||||
void EndpointManager::DiscardEndpoint(ClientProxy* client,
|
if (channel == nullptr) {
|
||||||
const std::string& endpoint_id) {
|
return 0;
|
||||||
RunOnEndpointManagerThread([this, client, endpoint_id]() {
|
}
|
||||||
RemoveEndpoint(client, endpoint_id,
|
|
||||||
/*notify=*/
|
return channel->GetMaxTransmitPacketSize();
|
||||||
client->IsConnectedToEndpoint(endpoint_id));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> EndpointManager::SendPayloadChunk(
|
std::vector<std::string> EndpointManager::SendPayloadChunk(
|
||||||
@@ -441,6 +439,18 @@ std::vector<std::string> EndpointManager::SendPayloadChunk(
|
|||||||
/*packet_type=*/"DATA");
|
/*packet_type=*/"DATA");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Designed to run asynchronously. It is called from IO thread pools, and
|
||||||
|
// jobs in these pools may be waited for from the EndpointManager thread. If we
|
||||||
|
// allow synchronous behavior here it will cause a live lock.
|
||||||
|
void EndpointManager::DiscardEndpoint(ClientProxy* client,
|
||||||
|
const std::string& endpoint_id) {
|
||||||
|
RunOnEndpointManagerThread([this, client, endpoint_id]() {
|
||||||
|
RemoveEndpoint(client, endpoint_id,
|
||||||
|
/*notify=*/
|
||||||
|
client->IsConnectedToEndpoint(endpoint_id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> EndpointManager::SendControlMessage(
|
std::vector<std::string> EndpointManager::SendControlMessage(
|
||||||
const PayloadTransferFrame::PayloadHeader& header,
|
const PayloadTransferFrame::PayloadHeader& header,
|
||||||
const PayloadTransferFrame::ControlMessage& control,
|
const PayloadTransferFrame::ControlMessage& control,
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ class EndpointManager {
|
|||||||
// this case, we do not notify the client of onDisconnected().
|
// this case, we do not notify the client of onDisconnected().
|
||||||
void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id);
|
void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id);
|
||||||
|
|
||||||
|
// Returns the maximum supported transmit packet size(MTU) for the underlying
|
||||||
|
// transport.
|
||||||
|
int GetMaxTransmitPacketSize(const std::string& endpoint_id);
|
||||||
|
|
||||||
// Returns the list of endpoints to which sending this chunk failed.
|
// Returns the list of endpoints to which sending this chunk failed.
|
||||||
//
|
//
|
||||||
// Invoked from the PayloadManager's sendPayload() method.
|
// Invoked from the PayloadManager's sendPayload() method.
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ class MockEndpointChannel : public EndpointChannel {
|
|||||||
MOCK_METHOD(std::string, GetType, (), (const override));
|
MOCK_METHOD(std::string, GetType, (), (const override));
|
||||||
MOCK_METHOD(std::string, GetName, (), (const override));
|
MOCK_METHOD(std::string, GetName, (), (const override));
|
||||||
MOCK_METHOD(Medium, GetMedium, (), (const override));
|
MOCK_METHOD(Medium, GetMedium, (), (const override));
|
||||||
|
MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const override));
|
||||||
MOCK_METHOD(void, EnableEncryption,
|
MOCK_METHOD(void, EnableEncryption,
|
||||||
(std::shared_ptr<EncryptionContext> context), (override));
|
(std::shared_ptr<EncryptionContext> context), (override));
|
||||||
MOCK_METHOD(void, DisableEncryption, (), (override));
|
MOCK_METHOD(void, DisableEncryption, (), (override));
|
||||||
|
|||||||
@@ -63,8 +63,10 @@ class InternalPayload {
|
|||||||
// byte blobs for sending across a hard boundary (like the other side of
|
// byte blobs for sending across a hard boundary (like the other side of
|
||||||
// a Binder, or another device altogether).
|
// a Binder, or another device altogether).
|
||||||
//
|
//
|
||||||
|
// @param chunk_size The preferred size of the next chunk. Depending on
|
||||||
|
// payload type, the provided size may be ignored.
|
||||||
// @return The next chunk from the Payload, or null if we've reached the end.
|
// @return The next chunk from the Payload, or null if we've reached the end.
|
||||||
virtual ByteArray DetachNextChunk() = 0;
|
virtual ByteArray DetachNextChunk(int chunk_size) = 0;
|
||||||
|
|
||||||
// Adds the next chunk that comprises the Payload to which this object is
|
// Adds the next chunk that comprises the Payload to which this object is
|
||||||
// bound.
|
// bound.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "platform/base/exception.h"
|
#include "platform/base/exception.h"
|
||||||
#include "platform/public/condition_variable.h"
|
#include "platform/public/condition_variable.h"
|
||||||
#include "platform/public/file.h"
|
#include "platform/public/file.h"
|
||||||
|
#include "platform/public/logging.h"
|
||||||
#include "platform/public/mutex.h"
|
#include "platform/public/mutex.h"
|
||||||
#include "platform/public/pipe.h"
|
#include "platform/public/pipe.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
@@ -47,7 +48,7 @@ class BytesInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
// Relinquishes ownership of the payload_; retrieves and returns the stored
|
// Relinquishes ownership of the payload_; retrieves and returns the stored
|
||||||
// ByteArray.
|
// ByteArray.
|
||||||
ByteArray DetachNextChunk() override {
|
ByteArray DetachNextChunk(int chunk_size) override {
|
||||||
if (detached_only_chunk_) {
|
if (detached_only_chunk_) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -80,11 +81,11 @@ class OutgoingStreamInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
std::int64_t GetTotalSize() const override { return -1; }
|
std::int64_t GetTotalSize() const override { return -1; }
|
||||||
|
|
||||||
ByteArray DetachNextChunk() override {
|
ByteArray DetachNextChunk(int chunk_size) override {
|
||||||
InputStream* input_stream = payload_.AsStream();
|
InputStream* input_stream = payload_.AsStream();
|
||||||
if (!input_stream) return {};
|
if (!input_stream) return {};
|
||||||
|
|
||||||
ExceptionOr<ByteArray> bytes_read = input_stream->Read(kChunkSize);
|
ExceptionOr<ByteArray> bytes_read = input_stream->Read(chunk_size);
|
||||||
if (!bytes_read.ok()) {
|
if (!bytes_read.ok()) {
|
||||||
input_stream->Close();
|
input_stream->Close();
|
||||||
return {};
|
return {};
|
||||||
@@ -93,8 +94,8 @@ class OutgoingStreamInternalPayload : public InternalPayload {
|
|||||||
ByteArray scoped_bytes_read = std::move(bytes_read.result());
|
ByteArray scoped_bytes_read = std::move(bytes_read.result());
|
||||||
|
|
||||||
if (scoped_bytes_read.Empty()) {
|
if (scoped_bytes_read.Empty()) {
|
||||||
// TODO(reznor): logger.atVerbose().log("No more data for outgoing payload
|
NEARBY_LOGS(INFO) << "No more data for outgoing payload " << this
|
||||||
// %s, closing InputStream.", this);
|
<< ", closing InputStream.";
|
||||||
|
|
||||||
input_stream->Close();
|
input_stream->Close();
|
||||||
return {};
|
return {};
|
||||||
@@ -113,9 +114,6 @@ class OutgoingStreamInternalPayload : public InternalPayload {
|
|||||||
InputStream* stream = payload_.AsStream();
|
InputStream* stream = payload_.AsStream();
|
||||||
if (stream) stream->Close();
|
if (stream) stream->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::int64_t kChunkSize = Pipe::kChunkSize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IncomingStreamInternalPayload : public InternalPayload {
|
class IncomingStreamInternalPayload : public InternalPayload {
|
||||||
@@ -129,7 +127,7 @@ class IncomingStreamInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
std::int64_t GetTotalSize() const override { return -1; }
|
std::int64_t GetTotalSize() const override { return -1; }
|
||||||
|
|
||||||
ByteArray DetachNextChunk() override { return {}; }
|
ByteArray DetachNextChunk(int chunk_size) override { return {}; }
|
||||||
|
|
||||||
Exception AttachNextChunk(const ByteArray& chunk) override {
|
Exception AttachNextChunk(const ByteArray& chunk) override {
|
||||||
if (chunk.Empty()) {
|
if (chunk.Empty()) {
|
||||||
@@ -158,11 +156,11 @@ class OutgoingFileInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
std::int64_t GetTotalSize() const override { return total_size_; }
|
std::int64_t GetTotalSize() const override { return total_size_; }
|
||||||
|
|
||||||
ByteArray DetachNextChunk() override {
|
ByteArray DetachNextChunk(int chunk_size) override {
|
||||||
InputFile* file = payload_.AsFile();
|
InputFile* file = payload_.AsFile();
|
||||||
if (!file) return {};
|
if (!file) return {};
|
||||||
|
|
||||||
ExceptionOr<ByteArray> bytes_read = file->Read(kChunkSize);
|
ExceptionOr<ByteArray> bytes_read = file->Read(chunk_size);
|
||||||
if (!bytes_read.ok()) {
|
if (!bytes_read.ok()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -190,7 +188,6 @@ class OutgoingFileInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::int64_t total_size_;
|
std::int64_t total_size_;
|
||||||
static constexpr std::int64_t kChunkSize = 64 * 1024;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IncomingFileInternalPayload : public InternalPayload {
|
class IncomingFileInternalPayload : public InternalPayload {
|
||||||
@@ -207,7 +204,7 @@ class IncomingFileInternalPayload : public InternalPayload {
|
|||||||
|
|
||||||
std::int64_t GetTotalSize() const override { return total_size_; }
|
std::int64_t GetTotalSize() const override { return total_size_; }
|
||||||
|
|
||||||
ByteArray DetachNextChunk() override { return {}; }
|
ByteArray DetachNextChunk(int chunk_size) override { return {}; }
|
||||||
|
|
||||||
Exception AttachNextChunk(const ByteArray& chunk) override {
|
Exception AttachNextChunk(const ByteArray& chunk) override {
|
||||||
if (chunk.Empty()) {
|
if (chunk.Empty()) {
|
||||||
|
|||||||
+339
-181
@@ -26,6 +26,7 @@
|
|||||||
#include "platform/public/logging.h"
|
#include "platform/public/logging.h"
|
||||||
#include "platform/public/mutex_lock.h"
|
#include "platform/public/mutex_lock.h"
|
||||||
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.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/strings/str_cat.h"
|
||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
#include "webrtc/api/jsep.h"
|
#include "webrtc/api/jsep.h"
|
||||||
@@ -53,7 +54,23 @@ WebRtc::~WebRtc() {
|
|||||||
restart_receive_messages_executor_.Shutdown();
|
restart_receive_messages_executor_.Shutdown();
|
||||||
single_thread_executor_.Shutdown();
|
single_thread_executor_.Shutdown();
|
||||||
|
|
||||||
Disconnect();
|
// 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() {
|
const std::string WebRtc::GetDefaultCountryCode() {
|
||||||
@@ -64,8 +81,9 @@ bool WebRtc::IsAvailable() { return medium_.IsValid(); }
|
|||||||
|
|
||||||
bool WebRtc::IsAcceptingConnections(const std::string& service_id) {
|
bool WebRtc::IsAcceptingConnections(const std::string& service_id) {
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
// TODO(hais): refractor the implementation with maps.
|
ConnectionInfo* connection_info =
|
||||||
return role_ == Role::kOfferer;
|
GetConnectionInfo(Role::kOfferer, service_id);
|
||||||
|
return connection_info && connection_info->self_id.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtc::StartAcceptingConnections(const std::string& service_id,
|
bool WebRtc::StartAcceptingConnections(const std::string& service_id,
|
||||||
@@ -73,10 +91,9 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
|
|||||||
const LocationHint& location_hint,
|
const LocationHint& location_hint,
|
||||||
AcceptedConnectionCallback callback) {
|
AcceptedConnectionCallback callback) {
|
||||||
if (!IsAvailable()) {
|
if (!IsAvailable()) {
|
||||||
{
|
MutexLock lock(&mutex_);
|
||||||
MutexLock lock(&mutex_);
|
LogAndDisconnect(Role::kOfferer, service_id,
|
||||||
LogAndDisconnect("WebRTC is not available for data transfer.");
|
"WebRTC is not available for data transfer.");
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,35 +101,36 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
|
|||||||
NEARBY_LOG(WARNING, "Already accepting WebRTC connections.");
|
NEARBY_LOG(WARNING, "Already accepting WebRTC connections.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
if (role_ != Role::kNone) {
|
accepting_map_.emplace(service_id,
|
||||||
NEARBY_LOG(WARNING,
|
ConnectionInfo{.socket = WebRtcSocketWrapper()});
|
||||||
"Cannot start accepting WebRTC connections, current role %d",
|
ConnectionInfo* connection_info = &accepting_map_[service_id];
|
||||||
role_);
|
if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint, service_id))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint)) return false;
|
connection_info->restart_receive_messages_alarm = CancelableAlarm(
|
||||||
|
|
||||||
restart_receive_messages_alarm_ = CancelableAlarm(
|
|
||||||
"restart_receiving_messages_webrtc",
|
"restart_receiving_messages_webrtc",
|
||||||
std::bind(&WebRtc::RestartReceiveMessages, this, location_hint,
|
std::bind(&WebRtc::RestartReceiveMessages, this, location_hint,
|
||||||
service_id),
|
service_id),
|
||||||
kRestartReceiveMessagesDuration, &restart_receive_messages_executor_);
|
kRestartReceiveMessagesDuration, &restart_receive_messages_executor_);
|
||||||
|
|
||||||
SessionDescriptionWrapper offer = connection_flow_->CreateOffer();
|
SessionDescriptionWrapper offer =
|
||||||
pending_local_offer_ = webrtc_frames::EncodeOffer(self_id, offer.GetSdp());
|
connection_info->connection_flow->CreateOffer();
|
||||||
if (!SetLocalSessionDescription(std::move(offer))) {
|
connection_info->pending_local_offer =
|
||||||
|
webrtc_frames::EncodeOffer(self_id, offer.GetSdp());
|
||||||
|
if (!SetLocalSessionDescription(std::move(offer), Role::kOfferer,
|
||||||
|
service_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no timeout set for the future returned since we do not know how
|
// 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
|
// much time it will take for the two devices to discover each other before
|
||||||
// the actual transport can begin.
|
// the actual transport can begin.
|
||||||
ListenForWebRtcSocketFuture(connection_flow_->GetDataChannel(),
|
ListenForWebRtcSocketFuture(
|
||||||
std::move(callback));
|
Role::kOfferer, service_id,
|
||||||
|
connection_info->connection_flow->GetDataChannel(),
|
||||||
|
std::move(callback));
|
||||||
NEARBY_LOG(INFO, "Started listening for WebRtc connections as %s",
|
NEARBY_LOG(INFO, "Started listening for WebRtc connections as %s",
|
||||||
self_id.GetId().c_str());
|
self_id.GetId().c_str());
|
||||||
}
|
}
|
||||||
@@ -123,31 +141,38 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
|
|||||||
WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
|
WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
|
||||||
const LocationHint& location_hint) {
|
const LocationHint& location_hint) {
|
||||||
if (!IsAvailable()) {
|
if (!IsAvailable()) {
|
||||||
Disconnect();
|
Disconnect(Role::kAnswerer, peer_id.GetId());
|
||||||
return WebRtcSocketWrapper();
|
return WebRtcSocketWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
if (role_ != Role::kNone) {
|
if (connecting_map_.contains(peer_id.GetId())) {
|
||||||
NEARBY_LOG(
|
NEARBY_LOG(
|
||||||
WARNING,
|
ERROR,
|
||||||
"Cannot connect with WebRtc because we are already acting as %d",
|
"Cannot connect with WebRtc because we are already connecting.");
|
||||||
role_);
|
|
||||||
return WebRtcSocketWrapper();
|
return WebRtcSocketWrapper();
|
||||||
}
|
}
|
||||||
|
connecting_map_.emplace(peer_id.GetId(),
|
||||||
peer_id_ = peer_id;
|
ConnectionInfo{.socket = WebRtcSocketWrapper()});
|
||||||
if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom(), location_hint)) {
|
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();
|
return WebRtcSocketWrapper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NEARBY_LOG(INFO, "Attempting to make a WebRTC connection to %s.",
|
NEARBY_LOG(ERROR, "Attempting to make a WebRTC connection to %s.",
|
||||||
peer_id.GetId().c_str());
|
peer_id.GetId().c_str());
|
||||||
|
Future<WebRtcSocketWrapper> socket_future;
|
||||||
Future<WebRtcSocketWrapper> socket_future = ListenForWebRtcSocketFuture(
|
{
|
||||||
connection_flow_->GetDataChannel(), AcceptedConnectionCallback());
|
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
|
// The two devices have discovered each other, hence we have a timeout for
|
||||||
// establishing the transport channel.
|
// establishing the transport channel.
|
||||||
@@ -158,13 +183,19 @@ WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
|
|||||||
socket_future.Get(kDataChannelTimeout);
|
socket_future.Get(kDataChannelTimeout);
|
||||||
if (result.ok()) return result.result();
|
if (result.ok()) return result.result();
|
||||||
|
|
||||||
Disconnect();
|
Disconnect(Role::kAnswerer, peer_id.GetId());
|
||||||
return WebRtcSocketWrapper();
|
return WebRtcSocketWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtc::SetLocalSessionDescription(SessionDescriptionWrapper sdp) {
|
bool WebRtc::SetLocalSessionDescription(SessionDescriptionWrapper sdp,
|
||||||
if (!connection_flow_->SetLocalSessionDescription(std::move(sdp))) {
|
Role role,
|
||||||
LogAndDisconnect("Unable to set local session description");
|
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 false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,28 +213,35 @@ void WebRtc::StopAcceptingConnections(const std::string& service_id) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
ShutdownSignaling();
|
ShutdownSignaling(Role::kOfferer, service_id);
|
||||||
}
|
}
|
||||||
NEARBY_LOG(INFO, "Stopped accepting WebRTC connections");
|
NEARBY_LOG(INFO, "Stopped accepting WebRTC connections");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
|
Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
|
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
|
||||||
data_channel_future,
|
data_channel_future,
|
||||||
AcceptedConnectionCallback callback) {
|
AcceptedConnectionCallback callback) {
|
||||||
Future<WebRtcSocketWrapper> socket_future;
|
Future<WebRtcSocketWrapper> socket_future;
|
||||||
auto data_channel_runnable = [this, socket_future, data_channel_future,
|
auto data_channel_runnable = [this, role, connection_id, socket_future,
|
||||||
|
data_channel_future,
|
||||||
callback{std::move(callback)}]() mutable {
|
callback{std::move(callback)}]() mutable {
|
||||||
// The overall timeout of creating the socket and data channel is controlled
|
// The overall timeout of creating the socket and data channel is controlled
|
||||||
// by the caller of this function.
|
// by the caller of this function.
|
||||||
ExceptionOr<rtc::scoped_refptr<webrtc::DataChannelInterface>> res =
|
ExceptionOr<rtc::scoped_refptr<webrtc::DataChannelInterface>> res =
|
||||||
data_channel_future.Get();
|
data_channel_future.Get();
|
||||||
if (res.ok()) {
|
if (res.ok()) {
|
||||||
WebRtcSocketWrapper wrapper = CreateWebRtcSocketWrapper(res.result());
|
WebRtcSocketWrapper wrapper =
|
||||||
|
CreateWebRtcSocketWrapper(role, connection_id, res.result());
|
||||||
callback.accepted_cb(wrapper);
|
callback.accepted_cb(wrapper);
|
||||||
{
|
{
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
socket_ = wrapper;
|
ConnectionInfo* connection_info =
|
||||||
|
GetConnectionInfo(role, connection_id);
|
||||||
|
if (connection_info) {
|
||||||
|
connection_info->socket = wrapper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
socket_future.Set(wrapper);
|
socket_future.Set(wrapper);
|
||||||
} else {
|
} else {
|
||||||
@@ -219,274 +257,370 @@ Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper(
|
WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
||||||
if (data_channel == nullptr) {
|
if (data_channel == nullptr) {
|
||||||
return WebRtcSocketWrapper();
|
return WebRtcSocketWrapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto socket = std::make_unique<WebRtcSocket>("WebRtcSocket", data_channel);
|
auto socket = std::make_unique<WebRtcSocket>("WebRtcSocket", data_channel);
|
||||||
socket->SetOnSocketClosedListener(
|
socket->SetOnSocketClosedListener({[this, role, connection_id]() {
|
||||||
{[this]() { OffloadFromSignalingThread([this]() { Disconnect(); }); }});
|
OffloadFromSignalingThread(
|
||||||
|
[this, role, connection_id]() { Disconnect(role, connection_id); });
|
||||||
|
}});
|
||||||
return WebRtcSocketWrapper(std::move(socket));
|
return WebRtcSocketWrapper(std::move(socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id,
|
bool WebRtc::InitWebRtcFlow(const Role& role, const PeerId& self_id,
|
||||||
const LocationHint& location_hint) {
|
const LocationHint& location_hint,
|
||||||
role_ = role;
|
const std::string& connection_id) {
|
||||||
self_id_ = self_id;
|
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
|
||||||
|
if (!connection_info) return false;
|
||||||
|
connection_info->self_id = self_id;
|
||||||
|
|
||||||
if (connection_flow_) {
|
if (connection_info->connection_flow) {
|
||||||
LogAndShutdownSignaling(
|
LogAndShutdownSignaling(
|
||||||
|
role, connection_id,
|
||||||
"Tried to initialize WebRTC without shutting down the previous "
|
"Tried to initialize WebRTC without shutting down the previous "
|
||||||
"connection");
|
"connection");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signaling_messenger_) {
|
if (connection_info->signaling_messenger) {
|
||||||
LogAndShutdownSignaling(
|
LogAndShutdownSignaling(
|
||||||
|
role, connection_id,
|
||||||
"Tried to initialize WebRTC without shutting down signaling messenger");
|
"Tried to initialize WebRTC without shutting down signaling messenger");
|
||||||
return false;
|
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);
|
||||||
|
|
||||||
signaling_messenger_ =
|
if (!connection_info->signaling_messenger->IsValid() ||
|
||||||
medium_.GetSignalingMessenger(self_id_.GetId(), location_hint);
|
!connection_info->signaling_messenger->StartReceivingMessages(
|
||||||
auto signaling_message_callback = [this](ByteArray message) {
|
|
||||||
OffloadFromSignalingThread([this, message{std::move(message)}]() {
|
|
||||||
ProcessSignalingMessage(message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!signaling_messenger_->IsValid() ||
|
|
||||||
!signaling_messenger_->StartReceivingMessages(
|
|
||||||
signaling_message_callback)) {
|
signaling_message_callback)) {
|
||||||
DisconnectLocked();
|
LogAndDisconnect(role, connection_id,
|
||||||
|
"Could not receive from signaling messenger.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role_ == Role::kAnswerer &&
|
if (role == Role::kAnswerer &&
|
||||||
!signaling_messenger_->SendMessage(
|
!connection_info->signaling_messenger->SendMessage(
|
||||||
peer_id_.GetId(),
|
connection_info->peer_id.GetId(),
|
||||||
webrtc_frames::EncodeReadyForSignalingPoke(self_id))) {
|
webrtc_frames::EncodeReadyForSignalingPoke(self_id))) {
|
||||||
LogAndDisconnect(absl::StrCat("Could not send signaling poke to peer ",
|
LogAndDisconnect(Role::kAnswerer, connection_info->peer_id.GetId(),
|
||||||
peer_id_.GetId()));
|
absl::StrCat("Could not send signaling poke to peer ",
|
||||||
|
connection_info->peer_id.GetId()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_flow_ = ConnectionFlow::Create(GetLocalIceCandidateListener(),
|
connection_info->connection_flow = ConnectionFlow::Create(
|
||||||
GetDataChannelListener(), medium_);
|
GetLocalIceCandidateListener(role, connection_id),
|
||||||
if (!connection_flow_) return false;
|
GetDataChannelListener(role, connection_id), medium_);
|
||||||
|
if (!connection_info->connection_flow) {
|
||||||
|
LogAndDisconnect(role, connection_id, "Failed to create connection flow");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::OnLocalIceCandidate(
|
void WebRtc::OnLocalIceCandidate(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
const webrtc::IceCandidateInterface* local_ice_candidate) {
|
const webrtc::IceCandidateInterface* local_ice_candidate) {
|
||||||
::location::nearby::mediums::IceCandidate ice_candidate =
|
::location::nearby::mediums::IceCandidate ice_candidate =
|
||||||
webrtc_frames::EncodeIceCandidate(*local_ice_candidate);
|
webrtc_frames::EncodeIceCandidate(*local_ice_candidate);
|
||||||
|
|
||||||
OffloadFromSignalingThread([this, ice_candidate{std::move(ice_candidate)}]() {
|
OffloadFromSignalingThread([this, ice_candidate{std::move(ice_candidate)},
|
||||||
|
role{role}, connection_id{connection_id}]() {
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
if (IsSignaling()) {
|
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
|
||||||
signaling_messenger_->SendMessage(
|
if (IsSignaling(role, connection_id)) {
|
||||||
peer_id_.GetId(), webrtc_frames::EncodeIceCandidates(
|
if (connection_info && connection_info->signaling_messenger) {
|
||||||
self_id_, {std::move(ice_candidate)}));
|
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 {
|
} else {
|
||||||
pending_local_ice_candidates_.push_back(std::move(ice_candidate));
|
connection_info->pending_local_ice_candidates.push_back(
|
||||||
|
std::move(ice_candidate));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalIceCandidateListener WebRtc::GetLocalIceCandidateListener() {
|
LocalIceCandidateListener WebRtc::GetLocalIceCandidateListener(
|
||||||
return {std::bind(&WebRtc::OnLocalIceCandidate, this, std::placeholders::_1)};
|
const Role& role, const std::string& connection_id) {
|
||||||
|
return {std::bind(&WebRtc::OnLocalIceCandidate, this, role, connection_id,
|
||||||
|
std::placeholders::_1)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::OnDataChannelClosed() {
|
void WebRtc::OnDataChannelClosed(const Role& role,
|
||||||
OffloadFromSignalingThread([this]() {
|
const std::string& connection_id) {
|
||||||
|
OffloadFromSignalingThread([this, role, connection_id]() {
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
LogAndDisconnect("WebRTC data channel closed");
|
LogAndDisconnect(role, connection_id, "WebRTC data channel closed");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::OnDataChannelMessageReceived(const ByteArray& message) {
|
void WebRtc::OnDataChannelMessageReceived(const Role& role,
|
||||||
OffloadFromSignalingThread([this, message]() {
|
const std::string& connection_id,
|
||||||
MutexLock lock(&mutex_);
|
const ByteArray& message) {
|
||||||
if (!socket_.IsValid()) {
|
OffloadFromSignalingThread([this, role, connection_id, message]() {
|
||||||
LogAndDisconnect("Received a data channel message without a socket");
|
{
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_.NotifyDataChannelMsgReceived(message);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::OnDataChannelBufferedAmountChanged() {
|
void WebRtc::OnDataChannelBufferedAmountChanged(
|
||||||
OffloadFromSignalingThread([this]() {
|
const Role& role, const std::string& connection_id) {
|
||||||
MutexLock lock(&mutex_);
|
OffloadFromSignalingThread([this, role, connection_id]() {
|
||||||
if (!socket_.IsValid()) {
|
{
|
||||||
LogAndDisconnect("Data channel buffer changed without a socket");
|
MutexLock lock(&mutex_);
|
||||||
return;
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_.NotifyDataChannelBufferedAmountChanged();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DataChannelListener WebRtc::GetDataChannelListener() {
|
DataChannelListener WebRtc::GetDataChannelListener(
|
||||||
|
const Role& role, const std::string& connection_id) {
|
||||||
return {
|
return {
|
||||||
.data_channel_closed_cb = std::bind(&WebRtc::OnDataChannelClosed, this),
|
.data_channel_closed_cb =
|
||||||
.data_channel_message_received_cb = std::bind(
|
std::bind(&WebRtc::OnDataChannelClosed, this, role, connection_id),
|
||||||
&WebRtc::OnDataChannelMessageReceived, this, std::placeholders::_1),
|
.data_channel_message_received_cb =
|
||||||
|
std::bind(&WebRtc::OnDataChannelMessageReceived, this, role,
|
||||||
|
connection_id, std::placeholders::_1),
|
||||||
.data_channel_buffered_amount_changed_cb =
|
.data_channel_buffered_amount_changed_cb =
|
||||||
std::bind(&WebRtc::OnDataChannelBufferedAmountChanged, this),
|
std::bind(&WebRtc::OnDataChannelBufferedAmountChanged, this, role,
|
||||||
|
connection_id),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebRtc::IsSignaling() {
|
bool WebRtc::IsSignaling(const Role& role, const std::string& connection_id) {
|
||||||
return (role_ != Role::kNone && self_id_.IsValid() && peer_id_.IsValid());
|
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 ByteArray& message) {
|
void WebRtc::ProcessSignalingMessage(const Role& role,
|
||||||
|
const std::string& connection_id,
|
||||||
|
const ByteArray& message) {
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
|
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
|
||||||
|
if (!connection_info) return;
|
||||||
|
|
||||||
if (!connection_flow_) {
|
if (!connection_info->connection_flow) {
|
||||||
LogAndDisconnect("Received WebRTC frame before signaling was started");
|
LogAndDisconnect(role, connection_id,
|
||||||
|
"Received WebRTC frame before signaling was started");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||||
if (!frame.ParseFromString(std::string(message))) {
|
if (!frame.ParseFromString(std::string(message))) {
|
||||||
LogAndDisconnect("Failed to parse signaling message");
|
LogAndDisconnect(role, connection_id, "Failed to parse signaling message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frame.has_sender_id()) {
|
if (!frame.has_sender_id()) {
|
||||||
LogAndDisconnect("Invalid WebRTC frame: Sender ID is missing");
|
LogAndDisconnect(role, connection_id,
|
||||||
|
"Invalid WebRTC frame: Sender ID is missing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.has_ready_for_signaling_poke() && !peer_id_.IsValid()) {
|
if (frame.has_ready_for_signaling_poke() &&
|
||||||
peer_id_ = PeerId(frame.sender_id().id());
|
!connection_info->peer_id.IsValid()) {
|
||||||
|
connection_info->peer_id = PeerId(frame.sender_id().id());
|
||||||
NEARBY_LOG(INFO, "Peer %s is ready for signaling",
|
NEARBY_LOG(INFO, "Peer %s is ready for signaling",
|
||||||
peer_id_.GetId().c_str());
|
connection_info->peer_id.GetId().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSignaling()) {
|
if (!IsSignaling(role, connection_id)) {
|
||||||
NEARBY_LOG(INFO,
|
NEARBY_LOG(INFO,
|
||||||
"Ignoring WebRTC frame: we are not currently listening for "
|
"Ignoring WebRTC frame: we are not currently listening for "
|
||||||
"signaling messages");
|
"signaling messages");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.sender_id().id() != peer_id_.GetId()) {
|
if (frame.sender_id().id() != connection_info->peer_id.GetId()) {
|
||||||
NEARBY_LOG(
|
NEARBY_LOG(
|
||||||
INFO, "Ignoring WebRTC frame: we are only listening for another peer.");
|
INFO, "Ignoring WebRTC frame: we are only listening for another peer.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.has_ready_for_signaling_poke()) {
|
if (frame.has_ready_for_signaling_poke()) {
|
||||||
SendOfferAndIceCandidatesToPeer();
|
SendOfferAndIceCandidatesToPeer(connection_id);
|
||||||
} else if (frame.has_offer()) {
|
} else if (frame.has_offer()) {
|
||||||
connection_flow_->OnOfferReceived(
|
DCHECK(role == Role::kAnswerer);
|
||||||
|
connection_info->connection_flow->OnOfferReceived(
|
||||||
SessionDescriptionWrapper(webrtc_frames::DecodeOffer(frame).release()));
|
SessionDescriptionWrapper(webrtc_frames::DecodeOffer(frame).release()));
|
||||||
SendAnswerToPeer();
|
SendAnswerToPeer(connection_id);
|
||||||
} else if (frame.has_answer()) {
|
} else if (frame.has_answer()) {
|
||||||
connection_flow_->OnAnswerReceived(SessionDescriptionWrapper(
|
DCHECK(role == Role::kOfferer);
|
||||||
webrtc_frames::DecodeAnswer(frame).release()));
|
connection_info->connection_flow->OnAnswerReceived(
|
||||||
|
SessionDescriptionWrapper(
|
||||||
|
webrtc_frames::DecodeAnswer(frame).release()));
|
||||||
} else if (frame.has_ice_candidates()) {
|
} else if (frame.has_ice_candidates()) {
|
||||||
if (!connection_flow_->OnRemoteIceCandidatesReceived(
|
if (!connection_info->connection_flow->OnRemoteIceCandidatesReceived(
|
||||||
webrtc_frames::DecodeIceCandidates(frame))) {
|
webrtc_frames::DecodeIceCandidates(frame))) {
|
||||||
LogAndDisconnect("Could not add remote ice candidates.");
|
LogAndDisconnect(role, connection_id,
|
||||||
|
"Could not add remote ice candidates.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::SendOfferAndIceCandidatesToPeer() {
|
void WebRtc::SendOfferAndIceCandidatesToPeer(const std::string& service_id) {
|
||||||
if (pending_local_offer_.Empty()) {
|
ConnectionInfo* connection_info =
|
||||||
|
GetConnectionInfo(Role::kOfferer, service_id);
|
||||||
|
if (!connection_info) return;
|
||||||
|
if (connection_info->pending_local_offer.Empty()) {
|
||||||
LogAndDisconnect(
|
LogAndDisconnect(
|
||||||
|
Role::kOfferer, service_id,
|
||||||
"Unable to send pending offer to remote peer: local offer not set");
|
"Unable to send pending offer to remote peer: local offer not set");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!signaling_messenger_->SendMessage(peer_id_.GetId(),
|
if (!connection_info->signaling_messenger->SendMessage(
|
||||||
pending_local_offer_)) {
|
connection_info->peer_id.GetId(),
|
||||||
LogAndDisconnect("Failed to send local offer via signaling messenger");
|
connection_info->pending_local_offer)) {
|
||||||
|
LogAndDisconnect(Role::kOfferer, service_id,
|
||||||
|
"Failed to send local offer via signaling messenger");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pending_local_offer_ = ByteArray();
|
connection_info->pending_local_offer = ByteArray();
|
||||||
|
|
||||||
if (!pending_local_ice_candidates_.empty()) {
|
if (!connection_info->pending_local_ice_candidates.empty()) {
|
||||||
signaling_messenger_->SendMessage(
|
connection_info->signaling_messenger->SendMessage(
|
||||||
peer_id_.GetId(),
|
connection_info->peer_id.GetId(),
|
||||||
webrtc_frames::EncodeIceCandidates(
|
webrtc_frames::EncodeIceCandidates(
|
||||||
self_id_, std::move(pending_local_ice_candidates_)));
|
connection_info->self_id,
|
||||||
|
std::move(connection_info->pending_local_ice_candidates)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::SendAnswerToPeer() {
|
void WebRtc::SendAnswerToPeer(const std::string& peer_id) {
|
||||||
SessionDescriptionWrapper answer = connection_flow_->CreateAnswer();
|
ConnectionInfo* connection_info = GetConnectionInfo(Role::kAnswerer, peer_id);
|
||||||
|
if (!connection_info) return;
|
||||||
|
SessionDescriptionWrapper answer =
|
||||||
|
connection_info->connection_flow->CreateAnswer();
|
||||||
ByteArray answer_message(
|
ByteArray answer_message(
|
||||||
webrtc_frames::EncodeAnswer(self_id_, answer.GetSdp()));
|
webrtc_frames::EncodeAnswer(connection_info->self_id, answer.GetSdp()));
|
||||||
|
|
||||||
if (!SetLocalSessionDescription(std::move(answer))) return;
|
if (!SetLocalSessionDescription(std::move(answer), Role::kAnswerer, peer_id))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!signaling_messenger_->SendMessage(peer_id_.GetId(), answer_message)) {
|
if (!connection_info->signaling_messenger->SendMessage(
|
||||||
LogAndDisconnect("Failed to send local answer via signaling messenger");
|
connection_info->peer_id.GetId(), answer_message)) {
|
||||||
|
LogAndDisconnect(Role::kAnswerer, peer_id,
|
||||||
|
"Failed to send local answer via signaling messenger");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::LogAndDisconnect(const std::string& error_message) {
|
void WebRtc::LogAndDisconnect(const Role& role,
|
||||||
NEARBY_LOG(WARNING, "Disconnecting WebRTC : %s", error_message.c_str());
|
const std::string& connection_id,
|
||||||
DisconnectLocked();
|
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 std::string& error_message) {
|
void WebRtc::LogAndShutdownSignaling(const Role& role,
|
||||||
NEARBY_LOG(WARNING, "Stopping WebRTC signaling : %s", error_message.c_str());
|
const std::string& connection_id,
|
||||||
ShutdownSignaling();
|
const std::string& error_message) {
|
||||||
|
NEARBY_LOG(WARNING, "Stopping WebRTC role: %d, connection id: %s, msg: %s",
|
||||||
|
role, connection_id.c_str(), error_message.c_str());
|
||||||
|
ShutdownSignaling(role, connection_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::ShutdownSignaling() {
|
void WebRtc::ShutdownSignaling(const Role& role,
|
||||||
role_ = Role::kNone;
|
const std::string& connection_id) {
|
||||||
self_id_ = PeerId();
|
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
|
||||||
peer_id_ = PeerId();
|
if (!connection_info) {
|
||||||
pending_local_offer_ = ByteArray();
|
return;
|
||||||
pending_local_ice_candidates_.clear();
|
|
||||||
|
|
||||||
if (restart_receive_messages_alarm_.IsValid()) {
|
|
||||||
restart_receive_messages_alarm_.Cancel();
|
|
||||||
restart_receive_messages_alarm_ = CancelableAlarm();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signaling_messenger_) {
|
connection_info->self_id = PeerId();
|
||||||
signaling_messenger_->StopReceivingMessages();
|
connection_info->peer_id = PeerId();
|
||||||
signaling_messenger_.reset();
|
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 (!socket_.IsValid()) ShutdownIceCandidateCollection();
|
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() {
|
void WebRtc::Disconnect(const Role& role, const std::string& connection_id) {
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
DisconnectLocked();
|
DisconnectLocked(role, connection_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::DisconnectLocked() {
|
void WebRtc::DisconnectLocked(const Role& role,
|
||||||
ShutdownSignaling();
|
const std::string& connection_id) {
|
||||||
ShutdownWebRtcSocket();
|
ShutdownSignaling(role, connection_id);
|
||||||
ShutdownIceCandidateCollection();
|
ShutdownWebRtcSocket(role, connection_id);
|
||||||
}
|
ShutdownIceCandidateCollection(role, connection_id);
|
||||||
|
|
||||||
void WebRtc::ShutdownWebRtcSocket() {
|
if (role == Role::kOfferer && accepting_map_.contains(connection_id)) {
|
||||||
if (socket_.IsValid()) {
|
accepting_map_.erase(connection_id);
|
||||||
socket_.Close();
|
} else if (role == Role::kAnswerer &&
|
||||||
socket_ = WebRtcSocketWrapper();
|
connecting_map_.contains(connection_id)) {
|
||||||
|
connecting_map_.erase(connection_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtc::ShutdownIceCandidateCollection() {
|
void WebRtc::ShutdownWebRtcSocket(const Role& role,
|
||||||
if (connection_flow_) {
|
const std::string& connection_id) {
|
||||||
connection_flow_->Close();
|
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
|
||||||
connection_flow_.reset();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,25 +639,49 @@ void WebRtc::RestartReceiveMessages(const LocationHint& location_hint,
|
|||||||
NEARBY_LOG(INFO, "Restarting listening for receiving signaling messages.");
|
NEARBY_LOG(INFO, "Restarting listening for receiving signaling messages.");
|
||||||
{
|
{
|
||||||
MutexLock lock(&mutex_);
|
MutexLock lock(&mutex_);
|
||||||
signaling_messenger_->StopReceivingMessages();
|
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();
|
||||||
|
|
||||||
signaling_messenger_ =
|
connection_info->signaling_messenger = medium_.GetSignalingMessenger(
|
||||||
medium_.GetSignalingMessenger(self_id_.GetId(), location_hint);
|
connection_info->self_id.GetId(), location_hint);
|
||||||
|
|
||||||
auto signaling_message_callback = [this](ByteArray message) {
|
auto signaling_message_callback = std::bind(
|
||||||
OffloadFromSignalingThread([this, message{std::move(message)}]() {
|
[this](ByteArray message, const Role& role,
|
||||||
ProcessSignalingMessage(message);
|
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 (!signaling_messenger_->IsValid() ||
|
if (!connection_info->signaling_messenger->IsValid() ||
|
||||||
!signaling_messenger_->StartReceivingMessages(
|
!connection_info->signaling_messenger->StartReceivingMessages(
|
||||||
signaling_message_callback)) {
|
signaling_message_callback)) {
|
||||||
DisconnectLocked();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mediums
|
} // namespace mediums
|
||||||
} // namespace connections
|
} // namespace connections
|
||||||
} // namespace nearby
|
} // namespace nearby
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "platform/public/single_thread_executor.h"
|
#include "platform/public/single_thread_executor.h"
|
||||||
#include "platform/public/webrtc.h"
|
#include "platform/public/webrtc.h"
|
||||||
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
|
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
|
||||||
|
#include "absl/container/flat_hash_map.h"
|
||||||
#include "absl/container/flat_hash_set.h"
|
#include "absl/container/flat_hash_set.h"
|
||||||
#include "webrtc/api/data_channel_interface.h"
|
#include "webrtc/api/data_channel_interface.h"
|
||||||
#include "webrtc/api/jsep.h"
|
#include "webrtc/api/jsep.h"
|
||||||
@@ -99,65 +100,102 @@ class WebRtc {
|
|||||||
kAnswerer = 2,
|
kAnswerer = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool InitWebRtcFlow(Role role, const PeerId& self_id,
|
struct ConnectionInfo {
|
||||||
const LocationHint& location_hint)
|
std::unique_ptr<ConnectionFlow> connection_flow;
|
||||||
|
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger;
|
||||||
|
WebRtcSocketWrapper socket;
|
||||||
|
CancelableAlarm restart_receive_messages_alarm;
|
||||||
|
|
||||||
|
PeerId self_id;
|
||||||
|
PeerId peer_id;
|
||||||
|
ByteArray pending_local_offer;
|
||||||
|
std::vector<::location::nearby::mediums::IceCandidate>
|
||||||
|
pending_local_ice_candidates;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool InitWebRtcFlow(const Role& role, const PeerId& self_id,
|
||||||
|
const LocationHint& location_hint,
|
||||||
|
const std::string& connection_id)
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
Future<WebRtcSocketWrapper> ListenForWebRtcSocketFuture(
|
Future<WebRtcSocketWrapper> ListenForWebRtcSocketFuture(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
|
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
|
||||||
data_channel_future,
|
data_channel_future,
|
||||||
AcceptedConnectionCallback callback);
|
AcceptedConnectionCallback callback);
|
||||||
|
|
||||||
WebRtcSocketWrapper CreateWebRtcSocketWrapper(
|
WebRtcSocketWrapper CreateWebRtcSocketWrapper(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
||||||
|
|
||||||
LocalIceCandidateListener GetLocalIceCandidateListener();
|
LocalIceCandidateListener GetLocalIceCandidateListener(
|
||||||
|
const Role& role, const std::string& connection_id);
|
||||||
void OnLocalIceCandidate(
|
void OnLocalIceCandidate(
|
||||||
|
const Role& role, const std::string& connection_id,
|
||||||
const webrtc::IceCandidateInterface* local_ice_candidate);
|
const webrtc::IceCandidateInterface* local_ice_candidate);
|
||||||
|
|
||||||
DataChannelListener GetDataChannelListener();
|
DataChannelListener GetDataChannelListener(const Role& role,
|
||||||
void OnDataChannelClosed();
|
const std::string& connection_id);
|
||||||
void OnDataChannelMessageReceived(const ByteArray& message);
|
void OnDataChannelClosed(const Role& role, const std::string& connection_id);
|
||||||
void OnDataChannelBufferedAmountChanged();
|
void OnDataChannelMessageReceived(const Role& role,
|
||||||
|
const std::string& connection_id,
|
||||||
|
const ByteArray& message);
|
||||||
|
void OnDataChannelBufferedAmountChanged(const Role& role,
|
||||||
|
const std::string& connection_id);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
bool SetLocalSessionDescription(SessionDescriptionWrapper sdp)
|
bool SetLocalSessionDescription(SessionDescriptionWrapper sdp, Role role,
|
||||||
|
const std::string& connection_id)
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on |single_thread_executor_|.
|
// Runs on |single_thread_executor_|.
|
||||||
bool IsSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
bool IsSignaling(const Role& role, const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on |single_thread_executor_|.
|
// Runs on |single_thread_executor_|.
|
||||||
void ProcessSignalingMessage(const ByteArray& message)
|
void ProcessSignalingMessage(const Role& role,
|
||||||
|
const std::string& connection_id,
|
||||||
|
const ByteArray& message)
|
||||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||||
|
|
||||||
// Runs on |single_thread_executor_|.
|
// Runs on |single_thread_executor_|.
|
||||||
void SendOfferAndIceCandidatesToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
void SendOfferAndIceCandidatesToPeer(const std::string& service_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on |single_thread_executor_|.
|
// Runs on |single_thread_executor_|.
|
||||||
void SendAnswerToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
void SendAnswerToPeer(const std::string& peer_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
void LogAndDisconnect(const std::string& error_message)
|
void LogAndDisconnect(const Role& role, const std::string& connection_id,
|
||||||
|
const std::string& error_message)
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread.
|
// Runs on @MainThread.
|
||||||
void Disconnect() ABSL_LOCKS_EXCLUDED(mutex_);
|
void Disconnect(const Role& role, const std::string& connection_id)
|
||||||
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
void DisconnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
void DisconnectLocked(const Role& role, const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
void LogAndShutdownSignaling(const std::string& error_message)
|
void LogAndShutdownSignaling(const Role& role,
|
||||||
|
const std::string& connection_id,
|
||||||
|
const std::string& error_message)
|
||||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
void ShutdownSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
void ShutdownSignaling(const Role& role, const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
void ShutdownWebRtcSocket() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
void ShutdownWebRtcSocket(const Role& role, const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
// Runs on @MainThread and |single_thread_executor_|.
|
// Runs on @MainThread and |single_thread_executor_|.
|
||||||
void ShutdownIceCandidateCollection();
|
void ShutdownIceCandidateCollection(const Role& role,
|
||||||
|
const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
void OffloadFromSignalingThread(Runnable runnable);
|
void OffloadFromSignalingThread(Runnable runnable);
|
||||||
|
|
||||||
@@ -166,26 +204,27 @@ class WebRtc {
|
|||||||
const std::string& service_id)
|
const std::string& service_id)
|
||||||
ABSL_LOCKS_EXCLUDED(mutex_);
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
||||||
|
|
||||||
|
void PrintStatus(const std::string& func);
|
||||||
|
|
||||||
|
ConnectionInfo* GetConnectionInfo(const Role& role,
|
||||||
|
const std::string& connection_id)
|
||||||
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||||
|
|
||||||
Mutex mutex_;
|
Mutex mutex_;
|
||||||
|
|
||||||
Role role_ ABSL_GUARDED_BY(mutex_) = Role::kNone;
|
|
||||||
PeerId self_id_ ABSL_GUARDED_BY(mutex_);
|
|
||||||
PeerId peer_id_ ABSL_GUARDED_BY(mutex_);
|
|
||||||
ByteArray pending_local_offer_ ABSL_GUARDED_BY(mutex_);
|
|
||||||
std::vector<::location::nearby::mediums::IceCandidate>
|
|
||||||
pending_local_ice_candidates_ ABSL_GUARDED_BY(mutex_);
|
|
||||||
|
|
||||||
WebRtcMedium medium_;
|
WebRtcMedium medium_;
|
||||||
std::unique_ptr<ConnectionFlow> connection_flow_;
|
|
||||||
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger_
|
|
||||||
ABSL_GUARDED_BY(mutex_);
|
|
||||||
WebRtcSocketWrapper socket_ ABSL_GUARDED_BY(mutex_);
|
|
||||||
|
|
||||||
SingleThreadExecutor single_thread_executor_;
|
SingleThreadExecutor single_thread_executor_;
|
||||||
|
|
||||||
// Restarts the signaling messenger for receiving messages.
|
// Restarts the signaling messenger for receiving messages.
|
||||||
ScheduledExecutor restart_receive_messages_executor_;
|
ScheduledExecutor restart_receive_messages_executor_;
|
||||||
CancelableAlarm restart_receive_messages_alarm_;
|
|
||||||
|
// Use service_id as key for accepting connections.
|
||||||
|
absl::flat_hash_map<std::string, ConnectionInfo> accepting_map_
|
||||||
|
ABSL_GUARDED_BY(mutex_);
|
||||||
|
// Use remote peer_id as key for connecting connections.
|
||||||
|
absl::flat_hash_map<std::string, ConnectionInfo> connecting_map_
|
||||||
|
ABSL_GUARDED_BY(mutex_);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mediums
|
} // namespace mediums
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ TEST_F(WebRtcTest, StartAcceptingConnectionTwice) {
|
|||||||
EXPECT_FALSE(webrtc.StartAcceptingConnections(
|
EXPECT_FALSE(webrtc.StartAcceptingConnections(
|
||||||
service_id, self_id, location_hint,
|
service_id, self_id, location_hint,
|
||||||
{mock_accepted_callback_.AsStdFunction()}));
|
{mock_accepted_callback_.AsStdFunction()}));
|
||||||
EXPECT_TRUE(webrtc.IsAcceptingConnections(std::string{}));
|
EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
|
||||||
|
EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the flow when the device tries to connect but the data channel times
|
// Tests the flow when the device tries to connect but the data channel times
|
||||||
@@ -99,7 +100,7 @@ TEST_F(WebRtcTest, StartAcceptingConnection_ThenConnect) {
|
|||||||
{mock_accepted_callback_.AsStdFunction()}));
|
{mock_accepted_callback_.AsStdFunction()}));
|
||||||
WebRtcSocketWrapper wrapper =
|
WebRtcSocketWrapper wrapper =
|
||||||
webrtc.Connect(PeerId("random_peer_id"), location_hint);
|
webrtc.Connect(PeerId("random_peer_id"), location_hint);
|
||||||
EXPECT_TRUE(webrtc.IsAcceptingConnections(std::string{}));
|
EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
|
||||||
EXPECT_FALSE(wrapper.IsValid());
|
EXPECT_FALSE(wrapper.IsValid());
|
||||||
EXPECT_FALSE(webrtc.StartAcceptingConnections(
|
EXPECT_FALSE(webrtc.StartAcceptingConnections(
|
||||||
service_id, self_id, location_hint,
|
service_id, self_id, location_hint,
|
||||||
@@ -122,8 +123,9 @@ TEST_F(WebRtcTest, StartAndStopAcceptingConnections) {
|
|||||||
ASSERT_TRUE(webrtc.StartAcceptingConnections(
|
ASSERT_TRUE(webrtc.StartAcceptingConnections(
|
||||||
service_id, self_id, location_hint,
|
service_id, self_id, location_hint,
|
||||||
{mock_accepted_callback_.AsStdFunction()}));
|
{mock_accepted_callback_.AsStdFunction()}));
|
||||||
|
EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
|
||||||
webrtc.StopAcceptingConnections(service_id);
|
webrtc.StopAcceptingConnections(service_id);
|
||||||
EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{}));
|
EXPECT_FALSE(webrtc.IsAcceptingConnections(service_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the flow when the device tries to connect to two different peers
|
// Tests the flow when the device tries to connect to two different peers
|
||||||
@@ -144,11 +146,8 @@ TEST_F(WebRtcTest, ConnectTwice) {
|
|||||||
connected.Set(receiver_socket.IsValid());
|
connected.Set(receiver_socket.IsValid());
|
||||||
}});
|
}});
|
||||||
|
|
||||||
using MockAcceptedCallback =
|
|
||||||
testing::MockFunction<void(WebRtcSocketWrapper socket)>;
|
|
||||||
testing::StrictMock<MockAcceptedCallback> mock_accepted_callback_;
|
|
||||||
device_c.StartAcceptingConnections(service_id, other_id, location_hint,
|
device_c.StartAcceptingConnections(service_id, other_id, location_hint,
|
||||||
{mock_accepted_callback_.AsStdFunction()});
|
{[](WebRtcSocketWrapper wrapper) {}});
|
||||||
|
|
||||||
sender_socket = sender.Connect(self_id, location_hint);
|
sender_socket = sender.Connect(self_id, location_hint);
|
||||||
EXPECT_TRUE(sender_socket.IsValid());
|
EXPECT_TRUE(sender_socket.IsValid());
|
||||||
@@ -157,8 +156,11 @@ TEST_F(WebRtcTest, ConnectTwice) {
|
|||||||
ASSERT_TRUE(devices_connected.ok());
|
ASSERT_TRUE(devices_connected.ok());
|
||||||
EXPECT_TRUE(devices_connected.result());
|
EXPECT_TRUE(devices_connected.result());
|
||||||
|
|
||||||
WebRtcSocketWrapper socket = sender.Connect(other_id, location_hint);
|
WebRtcSocketWrapper socket =
|
||||||
EXPECT_FALSE(socket.IsValid());
|
sender.Connect(other_id, location_hint);
|
||||||
|
EXPECT_TRUE(socket.IsValid());
|
||||||
|
socket.Close();
|
||||||
|
|
||||||
|
|
||||||
EXPECT_TRUE(receiver_socket.IsValid());
|
EXPECT_TRUE(receiver_socket.IsValid());
|
||||||
EXPECT_TRUE(sender_socket.IsValid());
|
EXPECT_TRUE(sender_socket.IsValid());
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -89,8 +90,9 @@ bool PayloadManager::SendPayloadLoop(
|
|||||||
|
|
||||||
// This will block if there is no data to transfer.
|
// This will block if there is no data to transfer.
|
||||||
// It will resume when new data arrives, or if Close() is called.
|
// It will resume when new data arrives, or if Close() is called.
|
||||||
|
int chunk_size = GetOptimalChunkSize(available_endpoint_ids);
|
||||||
ByteArray next_chunk =
|
ByteArray next_chunk =
|
||||||
pending_payload.GetInternalPayload()->DetachNextChunk();
|
pending_payload.GetInternalPayload()->DetachNextChunk(chunk_size);
|
||||||
if (shutdown_.Get()) return false;
|
if (shutdown_.Get()) return false;
|
||||||
// Save chunk size. We'll need it after we move next_chunk.
|
// Save chunk size. We'll need it after we move next_chunk.
|
||||||
auto next_chunk_size = next_chunk.size();
|
auto next_chunk_size = next_chunk.size();
|
||||||
@@ -497,6 +499,15 @@ SingleThreadExecutor* PayloadManager::GetOutgoingPayloadExecutor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PayloadManager::GetOptimalChunkSize(EndpointIds endpoint_ids) {
|
||||||
|
int minChunkSize = std::numeric_limits<int>::max();
|
||||||
|
for (const auto& endpoint_id : endpoint_ids) {
|
||||||
|
minChunkSize = std::min(
|
||||||
|
minChunkSize, endpoint_manager_->GetMaxTransmitPacketSize(endpoint_id));
|
||||||
|
}
|
||||||
|
return minChunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader(
|
PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader(
|
||||||
const InternalPayload& internal_payload) {
|
const InternalPayload& internal_payload) {
|
||||||
PayloadTransferFrame::PayloadHeader payload_header;
|
PayloadTransferFrame::PayloadHeader payload_header;
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ class PayloadManager : public EndpointManager::FrameProcessor {
|
|||||||
static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus(
|
static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus(
|
||||||
proto::connections::PayloadStatus status);
|
proto::connections::PayloadStatus status);
|
||||||
|
|
||||||
|
int GetOptimalChunkSize(EndpointIds endpoint_ids);
|
||||||
|
|
||||||
PayloadTransferFrame::PayloadHeader CreatePayloadHeader(
|
PayloadTransferFrame::PayloadHeader CreatePayloadHeader(
|
||||||
const InternalPayload& payload);
|
const InternalPayload& payload);
|
||||||
PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset,
|
PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset,
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ cc_library(
|
|||||||
"platform.h",
|
"platform.h",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
|
"//googlemac/iPhone/Shared/Nearby/Connections_v2:__subpackages__",
|
||||||
"//platform/base:__pkg__",
|
"//platform/base:__pkg__",
|
||||||
"//platform/impl:__subpackages__",
|
"//platform/impl:__subpackages__",
|
||||||
"//platform/public:__pkg__",
|
"//platform/public:__pkg__",
|
||||||
|
|||||||
@@ -61,14 +61,14 @@ void WebRtcMedium::CreatePeerConnection(
|
|||||||
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
|
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
|
||||||
webrtc::PeerConnectionDependencies dependencies(observer);
|
webrtc::PeerConnectionDependencies dependencies(observer);
|
||||||
|
|
||||||
signaling_thread_ = rtc::Thread::Create();
|
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
|
||||||
signaling_thread_->SetName("signaling_thread", nullptr);
|
signaling_thread->SetName("signaling_thread", nullptr);
|
||||||
RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread";
|
RTC_CHECK(signaling_thread->Start()) << "Failed to start thread";
|
||||||
|
|
||||||
webrtc::PeerConnectionFactoryDependencies factory_dependencies;
|
webrtc::PeerConnectionFactoryDependencies factory_dependencies;
|
||||||
factory_dependencies.task_queue_factory =
|
factory_dependencies.task_queue_factory =
|
||||||
webrtc::CreateDefaultTaskQueueFactory();
|
webrtc::CreateDefaultTaskQueueFactory();
|
||||||
factory_dependencies.signaling_thread = signaling_thread_.get();
|
factory_dependencies.signaling_thread = signaling_thread.release();
|
||||||
|
|
||||||
callback(webrtc::CreateModularPeerConnectionFactory(
|
callback(webrtc::CreateModularPeerConnectionFactory(
|
||||||
std::move(factory_dependencies))
|
std::move(factory_dependencies))
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ class WebRtcMedium : public api::WebRtcMedium {
|
|||||||
const connections::LocationHint& location_hint) override;
|
const connections::LocationHint& location_hint) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<rtc::Thread> signaling_thread_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace g3
|
} // namespace g3
|
||||||
|
|||||||
Reference in New Issue
Block a user