mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Release based on cl/313536507.
Signed-off-by: Alexey Polyudov <apolyudov@google.com> Change-Id: I83ec7dee1a7ef6f4bdfd47482c94d03910525b7e
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# 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.
|
||||
|
||||
cc_library(
|
||||
name = "webrtc",
|
||||
hdrs = [
|
||||
"webrtc_socket.cc",
|
||||
"webrtc_socket.h",
|
||||
],
|
||||
deps = [
|
||||
"//platform:utils",
|
||||
"//platform/api",
|
||||
"//webrtc/api:libjingle_peerconnection_api",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "webrtc_test",
|
||||
srcs = ["webrtc_socket_test.cc"],
|
||||
deps = [
|
||||
":webrtc",
|
||||
"//platform:types",
|
||||
"//platform/api",
|
||||
"//platform/impl/g3", # buildcleaner: keep
|
||||
"//testing/base/public:gunit_main",
|
||||
"//webrtc/api:libjingle_peerconnection_api",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "peer_id",
|
||||
srcs = ["peer_id.cc"],
|
||||
hdrs = ["peer_id.h"],
|
||||
deps = [
|
||||
"//core/internal/mediums:utils",
|
||||
"//platform:types",
|
||||
"//platform/api",
|
||||
"//platform/port:string",
|
||||
"//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "signaling_frames",
|
||||
srcs = ["signaling_frames.cc"],
|
||||
hdrs = ["signaling_frames.h"],
|
||||
deps = [
|
||||
":peer_id",
|
||||
"//platform:types",
|
||||
"//location/nearby/mediums/proto:web_rtc_signaling_frames_cc_proto",
|
||||
"//webrtc/api:libjingle_peerconnection_api",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "peer_id_test",
|
||||
srcs = ["peer_id_test.cc"],
|
||||
deps = [
|
||||
":peer_id",
|
||||
"//platform:types",
|
||||
"//platform/api",
|
||||
"//platform/impl/g3", # buildcleaner: keep
|
||||
"//testing/base/public:gunit_main",
|
||||
"//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "signaling_frames_test",
|
||||
srcs = ["signaling_frames_test.cc"],
|
||||
deps = [
|
||||
":peer_id",
|
||||
":signaling_frames",
|
||||
"//platform:types",
|
||||
"//platform/impl/g3", # buildcleaner: keep
|
||||
"//net/proto2/public:proto2",
|
||||
"//testing/base/public:gunit_main",
|
||||
"//webrtc/pc:peerconnection", # buildcleaner: keep
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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/peer_id.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "core/internal/mediums/utils.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
namespace {
|
||||
constexpr int kPeerIdLength = 64;
|
||||
|
||||
std::string BytesToStringUppercase(ConstPtr<ByteArray> bytes) {
|
||||
std::string hex_string(
|
||||
absl::BytesToHexString(std::string(bytes->getData(), bytes->size())));
|
||||
absl::AsciiStrToUpper(&hex_string);
|
||||
return hex_string;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ConstPtr<PeerId> PeerId::FromRandom(Ptr<HashUtils> hash_utils) {
|
||||
return FromSeed(Utils::generateRandomBytes(kPeerIdLength), hash_utils);
|
||||
}
|
||||
|
||||
ConstPtr<PeerId> PeerId::FromSeed(ConstPtr<ByteArray> seed,
|
||||
Ptr<HashUtils> hash_utils) {
|
||||
ScopedPtr<ConstPtr<ByteArray>> full_hash(
|
||||
Utils::sha256Hash(hash_utils, seed, kPeerIdLength));
|
||||
ScopedPtr<ConstPtr<ByteArray>> hashedSeed(
|
||||
MakeConstPtr(new ByteArray(full_hash->getData(), kPeerIdLength / 2)));
|
||||
return MakeConstPtr(new PeerId(BytesToStringUppercase(hashedSeed.get())));
|
||||
}
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
|
||||
#define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
|
||||
|
||||
#include "platform/api/hash_utils.h"
|
||||
#include "platform/byte_array.h"
|
||||
#include "platform/port/string.h"
|
||||
#include "platform/ptr.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
// PeerId is used as an identifier to exchange SDP messages to establish WebRTC
|
||||
// p2p connection.
|
||||
class PeerId {
|
||||
public:
|
||||
explicit PeerId(const string& id) : id_(id) {}
|
||||
~PeerId() = default;
|
||||
|
||||
static ConstPtr<PeerId> FromRandom(Ptr<HashUtils> hash_utils);
|
||||
static ConstPtr<PeerId> FromSeed(ConstPtr<ByteArray> seed,
|
||||
Ptr<HashUtils> hash_utils);
|
||||
|
||||
const string& GetId() const { return id_; }
|
||||
|
||||
private:
|
||||
const string id_;
|
||||
};
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_
|
||||
@@ -0,0 +1,90 @@
|
||||
// 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/peer_id.h"
|
||||
|
||||
#include "platform/api/hash_utils.h"
|
||||
#include "platform/byte_array.h"
|
||||
#include "platform/ptr.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
namespace {
|
||||
|
||||
class MockHashUtils : public HashUtils {
|
||||
public:
|
||||
MOCK_METHOD(ConstPtr<ByteArray>, md5, (const std::string& input), (override));
|
||||
MOCK_METHOD(ConstPtr<ByteArray>, sha256, (const std::string& input),
|
||||
(override));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(PeerIdTest, GenerateRandomPeerId) {
|
||||
// These are actual SHA-256 values for |seed| = "seed".
|
||||
std::string hashed_output =
|
||||
"19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b";
|
||||
std::string expected_peer_id =
|
||||
"19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B";
|
||||
|
||||
Ptr<testing::NiceMock<MockHashUtils>> mock_hash_utils(
|
||||
MakePtr(new MockHashUtils()));
|
||||
ON_CALL(*mock_hash_utils.get(), sha256(testing::_))
|
||||
.WillByDefault(testing::Return(
|
||||
MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output)))));
|
||||
EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::_));
|
||||
|
||||
ConstPtr<PeerId> peer_id = PeerId::FromRandom(mock_hash_utils);
|
||||
ASSERT_EQ(64, peer_id->GetId().size());
|
||||
ASSERT_EQ(expected_peer_id, peer_id->GetId());
|
||||
}
|
||||
|
||||
TEST(PeerIdTest, GenerateFromSeed) {
|
||||
// Values calculated by running actual SHA-256 hash on |seed|.
|
||||
std::string seed = "sesdfed";
|
||||
std::string hashed_output =
|
||||
"19b25856e1c150ca834cffc8b59b23adbd0ec0389e58eb22b3b64768098d002b";
|
||||
std::string expected_peer_id =
|
||||
"19B25856E1C150CA834CFFC8B59B23ADBD0EC0389E58EB22B3B64768098D002B";
|
||||
|
||||
Ptr<testing::NiceMock<MockHashUtils>> mock_hash_utils(
|
||||
MakePtr(new MockHashUtils()));
|
||||
ON_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed)))
|
||||
.WillByDefault(testing::Return(
|
||||
MakeConstPtr(new ByteArray(absl::HexStringToBytes(hashed_output)))));
|
||||
EXPECT_CALL(*mock_hash_utils.get(), sha256(testing::Eq(seed)));
|
||||
|
||||
ConstPtr<PeerId> peer_id =
|
||||
PeerId::FromSeed(MakeConstPtr(new ByteArray(seed)), mock_hash_utils);
|
||||
|
||||
ASSERT_EQ(64, peer_id->GetId().size());
|
||||
ASSERT_EQ(expected_peer_id, peer_id->GetId());
|
||||
}
|
||||
|
||||
TEST(PeerIdTest, GetId) {
|
||||
const std::string id = "this_is_a_test";
|
||||
PeerId peer_id(id);
|
||||
ASSERT_EQ(id, peer_id.GetId());
|
||||
}
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,139 @@
|
||||
// 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/signaling_frames.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
namespace webrtc_frames {
|
||||
using WebRtcSignalingFrame = location::nearby::mediums::WebRtcSignalingFrame;
|
||||
|
||||
namespace {
|
||||
|
||||
ConstPtr<ByteArray> FrameToByteArray(
|
||||
const WebRtcSignalingFrame& signaling_frame) {
|
||||
std::string message;
|
||||
signaling_frame.SerializeToString(&message);
|
||||
return MakeConstPtr(new ByteArray(message.c_str(), message.size()));
|
||||
}
|
||||
|
||||
void SetSenderId(ConstPtr<PeerId> sender_id, WebRtcSignalingFrame& frame) {
|
||||
frame.mutable_sender_id()->set_id(sender_id->GetId());
|
||||
}
|
||||
|
||||
ConstPtr<webrtc::IceCandidateInterface> DecodeIceCandidate(
|
||||
const location::nearby::mediums::IceCandidate& ice_candidate_proto) {
|
||||
webrtc::SdpParseError error;
|
||||
return ConstPtr<webrtc::IceCandidateInterface>(webrtc::CreateIceCandidate(
|
||||
ice_candidate_proto.sdp_mid(), ice_candidate_proto.sdp_m_line_index(),
|
||||
ice_candidate_proto.sdp(), &error));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ConstPtr<ByteArray> EncodeReadyForSignalingPoke(ConstPtr<PeerId> sender_id) {
|
||||
WebRtcSignalingFrame signaling_frame;
|
||||
signaling_frame.set_type(WebRtcSignalingFrame::READY_FOR_SIGNALING_POKE_TYPE);
|
||||
SetSenderId(sender_id, signaling_frame);
|
||||
signaling_frame.mutable_ready_for_signaling_poke();
|
||||
return FrameToByteArray(std::move(signaling_frame));
|
||||
}
|
||||
|
||||
ConstPtr<ByteArray> EncodeOffer(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const webrtc::SessionDescriptionInterface& offer) {
|
||||
WebRtcSignalingFrame signaling_frame;
|
||||
signaling_frame.set_type(WebRtcSignalingFrame::OFFER_TYPE);
|
||||
SetSenderId(sender_id, signaling_frame);
|
||||
std::string offer_str;
|
||||
offer.ToString(&offer_str);
|
||||
signaling_frame.mutable_offer()
|
||||
->mutable_session_description()
|
||||
->set_description(offer_str);
|
||||
return FrameToByteArray(std::move(signaling_frame));
|
||||
}
|
||||
|
||||
ConstPtr<ByteArray> EncodeAnswer(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const webrtc::SessionDescriptionInterface& answer) {
|
||||
WebRtcSignalingFrame signaling_frame;
|
||||
signaling_frame.set_type(WebRtcSignalingFrame::ANSWER_TYPE);
|
||||
SetSenderId(sender_id, signaling_frame);
|
||||
std::string answer_str;
|
||||
answer.ToString(&answer_str);
|
||||
signaling_frame.mutable_answer()
|
||||
->mutable_session_description()
|
||||
->set_description(answer_str);
|
||||
return FrameToByteArray(std::move(signaling_frame));
|
||||
}
|
||||
|
||||
ConstPtr<ByteArray> EncodeIceCandidates(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const std::vector<location::nearby::mediums::IceCandidate>&
|
||||
ice_candidates) {
|
||||
WebRtcSignalingFrame signaling_frame;
|
||||
signaling_frame.set_type(WebRtcSignalingFrame::ICE_CANDIDATES_TYPE);
|
||||
SetSenderId(sender_id, signaling_frame);
|
||||
for (const auto& ice_candidate : ice_candidates) {
|
||||
*signaling_frame.mutable_ice_candidates()->add_ice_candidates() =
|
||||
ice_candidate;
|
||||
}
|
||||
return FrameToByteArray(std::move(signaling_frame));
|
||||
}
|
||||
|
||||
Ptr<webrtc::SessionDescriptionInterface> DecodeOffer(
|
||||
const WebRtcSignalingFrame& frame) {
|
||||
return MakePtr(webrtc::CreateSessionDescription(
|
||||
webrtc::SdpType::kOffer,
|
||||
frame.offer().session_description().description())
|
||||
.release());
|
||||
}
|
||||
|
||||
Ptr<webrtc::SessionDescriptionInterface> DecodeAnswer(
|
||||
const WebRtcSignalingFrame& frame) {
|
||||
return MakePtr(webrtc::CreateSessionDescription(
|
||||
webrtc::SdpType::kAnswer,
|
||||
frame.answer().session_description().description())
|
||||
.release());
|
||||
}
|
||||
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> DecodeIceCandidates(
|
||||
const WebRtcSignalingFrame& frame) {
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
|
||||
for (const auto& candidate : frame.ice_candidates().ice_candidates()) {
|
||||
ice_candidates.push_back(DecodeIceCandidate(candidate));
|
||||
}
|
||||
return ice_candidates;
|
||||
}
|
||||
|
||||
location::nearby::mediums::IceCandidate EncodeIceCandidate(
|
||||
const webrtc::IceCandidateInterface& ice_candidate) {
|
||||
std::string sdp;
|
||||
ice_candidate.ToString(&sdp);
|
||||
location::nearby::mediums::IceCandidate ice_candidate_proto;
|
||||
ice_candidate_proto.set_sdp(sdp);
|
||||
ice_candidate_proto.set_sdp_mid(ice_candidate.sdp_mid());
|
||||
ice_candidate_proto.set_sdp_m_line_index(ice_candidate.sdp_mline_index());
|
||||
return ice_candidate_proto;
|
||||
}
|
||||
|
||||
} // namespace webrtc_frames
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,63 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
|
||||
#define CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "core/internal/mediums/webrtc/peer_id.h"
|
||||
#include "platform/byte_array.h"
|
||||
#include "platform/ptr.h"
|
||||
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
|
||||
#include "webrtc/api/peer_connection_interface.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
namespace webrtc_frames {
|
||||
|
||||
ConstPtr<ByteArray> EncodeReadyForSignalingPoke(ConstPtr<PeerId> sender_id);
|
||||
|
||||
ConstPtr<ByteArray> EncodeOffer(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const webrtc::SessionDescriptionInterface& offer);
|
||||
ConstPtr<ByteArray> EncodeAnswer(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const webrtc::SessionDescriptionInterface& answer);
|
||||
|
||||
ConstPtr<ByteArray> EncodeIceCandidates(
|
||||
ConstPtr<PeerId> sender_id,
|
||||
const std::vector<location::nearby::mediums::IceCandidate>& ice_candidates);
|
||||
location::nearby::mediums::IceCandidate EncodeIceCandidate(
|
||||
const webrtc::IceCandidateInterface& ice_candidate);
|
||||
|
||||
Ptr<webrtc::SessionDescriptionInterface> DecodeOffer(
|
||||
const location::nearby::mediums::WebRtcSignalingFrame& frame);
|
||||
Ptr<webrtc::SessionDescriptionInterface> DecodeAnswer(
|
||||
const location::nearby::mediums::WebRtcSignalingFrame& frame);
|
||||
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> DecodeIceCandidates(
|
||||
const location::nearby::mediums::WebRtcSignalingFrame& frame);
|
||||
|
||||
} // namespace webrtc_frames
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_
|
||||
@@ -0,0 +1,198 @@
|
||||
// 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/signaling_frames.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/internal/mediums/webrtc/peer_id.h"
|
||||
#include "platform/ptr.h"
|
||||
#include "net/proto2/public/text_format.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
namespace webrtc_frames {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kSampleSdp[] =
|
||||
"v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 "
|
||||
"0\r\na=msid-semantic: WMS\r\n";
|
||||
|
||||
const char kIceCandidateSdp1[] =
|
||||
"a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host";
|
||||
const char kIceCandidateSdp2[] =
|
||||
"a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr";
|
||||
|
||||
const char kIceSdpMid[] = "data";
|
||||
const int kIceSdpMLineIndex = 0;
|
||||
|
||||
const char kOfferProto[] = R"(
|
||||
sender_id { id: "abc" }
|
||||
type: OFFER_TYPE
|
||||
offer {
|
||||
session_description {
|
||||
description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n"
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
const char kAnswerProto[] = R"(
|
||||
sender_id { id: "abc" }
|
||||
type: ANSWER_TYPE
|
||||
answer {
|
||||
session_description {
|
||||
description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n"
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
const char kIceCandidatesProto[] = R"(
|
||||
sender_id { id: "abc" }
|
||||
type: ICE_CANDIDATES_TYPE
|
||||
ice_candidates {
|
||||
ice_candidates {
|
||||
sdp: "candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0"
|
||||
sdp_mid: "data"
|
||||
sdp_m_line_index: 0
|
||||
}
|
||||
ice_candidates {
|
||||
sdp: "candidate:2 1 udp 1694498815 192.0.2.3 45664 typ srflx generation 0"
|
||||
sdp_mid: "data"
|
||||
sdp_m_line_index: 0
|
||||
}
|
||||
}
|
||||
)";
|
||||
} // namespace
|
||||
|
||||
TEST(SignalingFramesTest, SignalingPoke) {
|
||||
ConstPtr<PeerId> sender_id(new PeerId("abc"));
|
||||
ConstPtr<ByteArray> encoded_poke = EncodeReadyForSignalingPoke(sender_id);
|
||||
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
frame.ParseFromString(
|
||||
std::string(encoded_poke->getData(), encoded_poke->size()));
|
||||
|
||||
EXPECT_THAT(frame, testing::EqualsProto(R"(
|
||||
sender_id { id: "abc" }
|
||||
type: READY_FOR_SIGNALING_POKE_TYPE
|
||||
ready_for_signaling_poke {}
|
||||
)"));
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, EncodeValidOffer) {
|
||||
ConstPtr<PeerId> sender_id(new PeerId("abc"));
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> offer =
|
||||
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, kSampleSdp);
|
||||
ConstPtr<ByteArray> encoded_offer = EncodeOffer(sender_id, *offer);
|
||||
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
frame.ParseFromString(
|
||||
std::string(encoded_offer->getData(), encoded_offer->size()));
|
||||
|
||||
EXPECT_THAT(frame, testing::EqualsProto(kOfferProto));
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, DecodeValidOffer) {
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
proto2::TextFormat::ParseFromString(kOfferProto, &frame);
|
||||
Ptr<webrtc::SessionDescriptionInterface> decoded_offer = DecodeOffer(frame);
|
||||
|
||||
EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType());
|
||||
std::string description;
|
||||
decoded_offer->ToString(&description);
|
||||
EXPECT_EQ(kSampleSdp, description);
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, EncodeValidAnswer) {
|
||||
ConstPtr<PeerId> sender_id(new PeerId("abc"));
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> answer =
|
||||
webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp);
|
||||
ConstPtr<ByteArray> encoded_answer = EncodeAnswer(sender_id, *answer);
|
||||
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
frame.ParseFromString(
|
||||
std::string(encoded_answer->getData(), encoded_answer->size()));
|
||||
|
||||
EXPECT_THAT(frame, testing::EqualsProto(kAnswerProto));
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, DecodeValidAnswer) {
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
proto2::TextFormat::ParseFromString(kAnswerProto, &frame);
|
||||
Ptr<webrtc::SessionDescriptionInterface> decoded_answer = DecodeAnswer(frame);
|
||||
|
||||
EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType());
|
||||
std::string description;
|
||||
decoded_answer->ToString(&description);
|
||||
EXPECT_EQ(kSampleSdp, description);
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, EncodeValidIceCandidates) {
|
||||
ConstPtr<PeerId> sender_id(new PeerId("abc"));
|
||||
webrtc::SdpParseError error;
|
||||
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
|
||||
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
|
||||
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error));
|
||||
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
|
||||
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error));
|
||||
std::vector<location::nearby::mediums::IceCandidate> encoded_candidates_vec;
|
||||
for (const auto& ice_candidate : ice_candidates) {
|
||||
encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate.get()));
|
||||
}
|
||||
ConstPtr<ByteArray> encoded_candidates =
|
||||
EncodeIceCandidates(sender_id, encoded_candidates_vec);
|
||||
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
frame.ParseFromString(
|
||||
std::string(encoded_candidates->getData(), encoded_candidates->size()));
|
||||
|
||||
EXPECT_THAT(frame, testing::EqualsProto(kIceCandidatesProto));
|
||||
}
|
||||
|
||||
TEST(SignalingFramesTest, DecodeValidIceCandidates) {
|
||||
webrtc::SdpParseError error;
|
||||
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> ice_candidates;
|
||||
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
|
||||
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error));
|
||||
ice_candidates.emplace_back(webrtc::CreateIceCandidate(
|
||||
kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error));
|
||||
std::vector<location::nearby::mediums::IceCandidate> encoded_candidates_vec;
|
||||
|
||||
location::nearby::mediums::WebRtcSignalingFrame frame;
|
||||
proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame);
|
||||
std::vector<ConstPtr<webrtc::IceCandidateInterface>> decoded_candidates =
|
||||
DecodeIceCandidates(frame);
|
||||
|
||||
ASSERT_EQ(2u, decoded_candidates.size());
|
||||
for (int i = 0; i < static_cast<int>(decoded_candidates.size()); i++) {
|
||||
EXPECT_TRUE(ice_candidates[i]->candidate().IsEquivalent(
|
||||
decoded_candidates[i]->candidate()));
|
||||
EXPECT_EQ(ice_candidates[i]->sdp_mid(), decoded_candidates[i]->sdp_mid());
|
||||
EXPECT_EQ(ice_candidates[i]->sdp_mline_index(),
|
||||
decoded_candidates[i]->sdp_mline_index());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc_frames
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,153 @@
|
||||
// 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/webrtc_socket.h"
|
||||
|
||||
#include "platform/synchronized.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
// OutputStreamImpl
|
||||
template <typename Platform>
|
||||
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::write(
|
||||
ConstPtr<ByteArray> data) {
|
||||
ScopedPtr<ConstPtr<ByteArray>> scoped_data(data);
|
||||
|
||||
if (scoped_data->size() > kMaxDataSize) {
|
||||
NEARBY_LOG(WARNING, "Sending data larger than 1MB");
|
||||
return Exception::IO;
|
||||
}
|
||||
|
||||
socket_->BlockUntilSufficientSpaceInBuffer(scoped_data->size());
|
||||
|
||||
if (socket_->IsClosed()) {
|
||||
NEARBY_LOG(WARNING, "Tried sending message while socket is closed");
|
||||
return Exception::IO;
|
||||
}
|
||||
|
||||
if (!socket_->SendMessage(scoped_data.release())) {
|
||||
return Exception::IO;
|
||||
}
|
||||
return Exception::NONE;
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::flush() {
|
||||
// Java implementation is empty.
|
||||
return Exception::NONE;
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
Exception::Value WebRtcSocket<Platform>::OutputStreamImpl::close() {
|
||||
socket_->close();
|
||||
return Exception::NONE;
|
||||
}
|
||||
|
||||
// WebRtcSocket
|
||||
template <typename Platform>
|
||||
WebRtcSocket<Platform>::WebRtcSocket(
|
||||
const string& name,
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel)
|
||||
: name_(name),
|
||||
data_channel_(std::move(data_channel)),
|
||||
pipe_(MakeRefCountedPtr(new Pipe())),
|
||||
incoming_data_piped_input_stream_(Pipe::createInputStream(pipe_)),
|
||||
incoming_data_piped_output_stream_(Pipe::createOutputStream(pipe_)),
|
||||
output_stream_(MakePtr(new OutputStreamImpl(this))),
|
||||
closed_(Platform::createAtomicBoolean(false)),
|
||||
backpressure_lock_(Platform::createLock()),
|
||||
buffer_variable_(
|
||||
Platform::createConditionVariable(backpressure_lock_.get())) {}
|
||||
|
||||
template <typename Platform>
|
||||
Ptr<InputStream> WebRtcSocket<Platform>::getInputStream() {
|
||||
return incoming_data_piped_input_stream_.get();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
Ptr<OutputStream> WebRtcSocket<Platform>::getOutputStream() {
|
||||
return output_stream_.get();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::close() {
|
||||
if (IsClosed()) return;
|
||||
|
||||
closed_->set(true);
|
||||
incoming_data_piped_output_stream_->close();
|
||||
incoming_data_piped_input_stream_->close();
|
||||
data_channel_->Close();
|
||||
WakeUpWriter();
|
||||
if (!socket_closed_listener_.isNull()) {
|
||||
socket_closed_listener_->OnSocketClosed();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::NotifyDataChannelMsgReceived(
|
||||
ConstPtr<ByteArray> message) {
|
||||
Exception::Value exception =
|
||||
incoming_data_piped_output_stream_->write(message);
|
||||
if (exception != Exception::NONE) close();
|
||||
|
||||
exception = incoming_data_piped_output_stream_->flush();
|
||||
if (exception != Exception::NONE) close();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::NotifyDataChannelBufferedAmountChanged() {
|
||||
WakeUpWriter();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
bool WebRtcSocket<Platform>::SendMessage(ConstPtr<ByteArray> data) {
|
||||
ScopedPtr<ConstPtr<ByteArray>> scoped_data(data);
|
||||
return data_channel_->Send(webrtc::DataBuffer(
|
||||
std::string(scoped_data->getData(), scoped_data->size())));
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
bool WebRtcSocket<Platform>::IsClosed() {
|
||||
return closed_->get();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::WakeUpWriter() {
|
||||
Synchronized s(backpressure_lock_.get());
|
||||
buffer_variable_->notify();
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::SetOnSocketClosedListener(
|
||||
Ptr<SocketClosedListener> listener) {
|
||||
socket_closed_listener_ = listener;
|
||||
}
|
||||
|
||||
template <typename Platform>
|
||||
void WebRtcSocket<Platform>::BlockUntilSufficientSpaceInBuffer(int length) {
|
||||
Synchronized s(backpressure_lock_.get());
|
||||
while (!IsClosed() &&
|
||||
(data_channel_->buffered_amount() + length > kMaxDataSize)) {
|
||||
// TODO(himanshujaju): Add wait with timeout.
|
||||
buffer_variable_->wait();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,118 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
|
||||
#define CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
|
||||
|
||||
#include "platform/api/atomic_boolean.h"
|
||||
#include "platform/api/input_stream.h"
|
||||
#include "platform/api/output_stream.h"
|
||||
#include "platform/api/socket.h"
|
||||
#include "platform/pipe.h"
|
||||
#include "webrtc/api/data_channel_interface.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
// Maximum data size: 1 MB
|
||||
constexpr int kMaxDataSize = 1 * 1024 * 1024;
|
||||
|
||||
// Defines the Socket implementation specific to WebRTC, which uses the WebRTC
|
||||
// data channel to send and receive messages.
|
||||
//
|
||||
// Messages are buffered here to prevent the data channel from overflowing,
|
||||
// which could lead to data loss.
|
||||
template <typename Platform>
|
||||
class WebRtcSocket : public Socket {
|
||||
public:
|
||||
WebRtcSocket(const string& name,
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
||||
~WebRtcSocket() override = default;
|
||||
|
||||
WebRtcSocket(const WebRtcSocket& other) = delete;
|
||||
WebRtcSocket& operator=(const WebRtcSocket& other) = delete;
|
||||
|
||||
// Overrides for location::nearby::Socket:
|
||||
Ptr<InputStream> getInputStream() override;
|
||||
Ptr<OutputStream> getOutputStream() override;
|
||||
void close() override;
|
||||
|
||||
// Callback from WebRTC data channel when new message has been received from
|
||||
// the remote.
|
||||
void NotifyDataChannelMsgReceived(ConstPtr<ByteArray> message);
|
||||
|
||||
// Callback from WebRTC data channel that the buffered data amount has
|
||||
// changed.
|
||||
void NotifyDataChannelBufferedAmountChanged();
|
||||
|
||||
// Listener class the gets called when the socket is closed.
|
||||
class SocketClosedListener {
|
||||
public:
|
||||
virtual ~SocketClosedListener() = default;
|
||||
virtual void OnSocketClosed() = 0;
|
||||
};
|
||||
void SetOnSocketClosedListener(Ptr<SocketClosedListener> listener);
|
||||
|
||||
private:
|
||||
class OutputStreamImpl : public OutputStream {
|
||||
public:
|
||||
explicit OutputStreamImpl(WebRtcSocket<Platform>* const socket)
|
||||
: socket_(socket) {}
|
||||
~OutputStreamImpl() override = default;
|
||||
|
||||
OutputStreamImpl(const OutputStreamImpl& other) = delete;
|
||||
OutputStreamImpl& operator=(const OutputStreamImpl& other) = delete;
|
||||
|
||||
// OutputStream:
|
||||
Exception::Value write(ConstPtr<ByteArray> data) override;
|
||||
Exception::Value flush() override;
|
||||
Exception::Value close() override;
|
||||
|
||||
private:
|
||||
// |this| OutputStreamImpl is owned by |socket_|.
|
||||
WebRtcSocket<Platform>* const socket_;
|
||||
};
|
||||
|
||||
void WakeUpWriter();
|
||||
bool IsClosed();
|
||||
bool SendMessage(ConstPtr<ByteArray> data);
|
||||
void BlockUntilSufficientSpaceInBuffer(int length);
|
||||
|
||||
string name_;
|
||||
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
|
||||
|
||||
Ptr<Pipe> pipe_;
|
||||
ScopedPtr<Ptr<InputStream>> incoming_data_piped_input_stream_;
|
||||
ScopedPtr<Ptr<OutputStream>> incoming_data_piped_output_stream_;
|
||||
|
||||
ScopedPtr<Ptr<OutputStream>> output_stream_;
|
||||
|
||||
ScopedPtr<Ptr<AtomicBoolean>> closed_;
|
||||
|
||||
Ptr<SocketClosedListener> socket_closed_listener_;
|
||||
|
||||
ScopedPtr<Ptr<Lock>> backpressure_lock_;
|
||||
ScopedPtr<Ptr<ConditionVariable>> buffer_variable_;
|
||||
};
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#include "core/internal/mediums/webrtc/webrtc_socket.cc"
|
||||
|
||||
#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_
|
||||
@@ -0,0 +1,169 @@
|
||||
// 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/webrtc_socket.h"
|
||||
|
||||
#include "platform/api/platform.h"
|
||||
#include "platform/byte_array.h"
|
||||
#include "platform/ptr.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "webrtc/api/data_channel_interface.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace connections {
|
||||
namespace mediums {
|
||||
|
||||
namespace {
|
||||
|
||||
using TestPlatform = platform::ImplementationPlatform;
|
||||
|
||||
const char kSocketName[] = "TestSocket";
|
||||
|
||||
class MockDataChannel
|
||||
: public rtc::RefCountedObject<webrtc::DataChannelInterface> {
|
||||
public:
|
||||
MOCK_METHOD(void, RegisterObserver, (webrtc::DataChannelObserver*));
|
||||
MOCK_METHOD(void, UnregisterObserver, ());
|
||||
|
||||
MOCK_METHOD(std::string, label, (), (const));
|
||||
|
||||
MOCK_METHOD(bool, reliable, (), (const));
|
||||
MOCK_METHOD(int, id, (), (const));
|
||||
MOCK_METHOD(DataState, state, (), (const));
|
||||
MOCK_METHOD(uint32_t, messages_sent, (), (const));
|
||||
MOCK_METHOD(uint64_t, bytes_sent, (), (const));
|
||||
MOCK_METHOD(uint32_t, messages_received, (), (const));
|
||||
MOCK_METHOD(uint64_t, bytes_received, (), (const));
|
||||
|
||||
MOCK_METHOD(uint64_t, buffered_amount, (), (const));
|
||||
|
||||
MOCK_METHOD(void, Close, ());
|
||||
|
||||
MOCK_METHOD(bool, Send, (const webrtc::DataBuffer&));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class MockSocketClosedListener
|
||||
: public WebRtcSocket<TestPlatform>::SocketClosedListener {
|
||||
public:
|
||||
MOCK_METHOD(void, OnSocketClosed, ());
|
||||
};
|
||||
|
||||
TEST(WebRtcSocketTest, ReadFromSocket) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
|
||||
webrtc_socket.NotifyDataChannelMsgReceived(kMessage);
|
||||
ExceptionOr<ConstPtr<ByteArray>> result =
|
||||
webrtc_socket.getInputStream()->read();
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.result(), kMessage);
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, ReadMultipleMessages) {
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
|
||||
webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("Me")));
|
||||
webrtc_socket.NotifyDataChannelMsgReceived(
|
||||
MakeConstPtr(new ByteArray("ssa")));
|
||||
webrtc_socket.NotifyDataChannelMsgReceived(MakeConstPtr(new ByteArray("ge")));
|
||||
ExceptionOr<ConstPtr<ByteArray>> result;
|
||||
|
||||
// This behaviour is different from the Java code
|
||||
result = webrtc_socket.getInputStream()->read();
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.result()->asString(), "Me");
|
||||
|
||||
result = webrtc_socket.getInputStream()->read();
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.result()->asString(), "ssa");
|
||||
|
||||
result = webrtc_socket.getInputStream()->read();
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_EQ(result.result()->asString(), "ge");
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, WriteToSocket) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
|
||||
EXPECT_CALL(*mock_data_channel, Send(testing::_))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::NONE);
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, SendDataBiggerThanMax) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray(kMaxDataSize + 1));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
|
||||
EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0);
|
||||
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, WriteToDataChannelFails) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
|
||||
ON_CALL(*mock_data_channel, Send(testing::_))
|
||||
.WillByDefault(testing::Return(false));
|
||||
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, Close) {
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
ScopedPtr<Ptr<MockSocketClosedListener>> mock_listener(
|
||||
MakePtr(new MockSocketClosedListener()));
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
webrtc_socket.SetOnSocketClosedListener(mock_listener.get());
|
||||
|
||||
EXPECT_CALL(*mock_listener, OnSocketClosed());
|
||||
EXPECT_CALL(*mock_data_channel, Close());
|
||||
webrtc_socket.close();
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, WriteOnClosedChannel) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
webrtc_socket.close();
|
||||
|
||||
EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0);
|
||||
EXPECT_EQ(webrtc_socket.getOutputStream()->write(kMessage), Exception::IO);
|
||||
}
|
||||
|
||||
TEST(WebRtcSocketTest, ReadFromClosedChannel) {
|
||||
ConstPtr<ByteArray> kMessage = MakeConstPtr(new ByteArray("Message"));
|
||||
rtc::scoped_refptr<MockDataChannel> mock_data_channel = new MockDataChannel();
|
||||
WebRtcSocket<TestPlatform> webrtc_socket(kSocketName, mock_data_channel);
|
||||
ON_CALL(*mock_data_channel, Send(testing::_))
|
||||
.WillByDefault(testing::Return(true));
|
||||
|
||||
webrtc_socket.getOutputStream()->write(kMessage);
|
||||
webrtc_socket.close();
|
||||
|
||||
EXPECT_EQ(webrtc_socket.getInputStream()->read().exception(), Exception::IO);
|
||||
}
|
||||
|
||||
} // namespace mediums
|
||||
} // namespace connections
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Reference in New Issue
Block a user