Index: webrtc/examples/unityplugin/simple_peer_connection.cc |
diff --git a/webrtc/examples/unityplugin/simple_peer_connection.cc b/webrtc/examples/unityplugin/simple_peer_connection.cc |
index c302e9c433df9cd50df16b6b43b8daa558269b1d..60ee709ad0773f4fbbcb34d85b53e96027590d0b 100644 |
--- a/webrtc/examples/unityplugin/simple_peer_connection.cc |
+++ b/webrtc/examples/unityplugin/simple_peer_connection.cc |
@@ -1,514 +1,501 @@ |
-/* |
- * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
- * |
- * Use of this source code is governed by a BSD-style license |
- * that can be found in the LICENSE file in the root of the source |
- * tree. An additional intellectual property rights grant can be found |
- * in the file PATENTS. All contributing project authors may |
- * be found in the AUTHORS file in the root of the source tree. |
- */ |
- |
-#include "webrtc/examples/unityplugin/simple_peer_connection.h" |
- |
-#include <utility> |
- |
-#include "webrtc/api/test/fakeconstraints.h" |
-#include "webrtc/media/engine/webrtcvideocapturerfactory.h" |
-#include "webrtc/modules/video_capture/video_capture_factory.h" |
-#include "webrtc/rtc_base/json.h" |
- |
-// Names used for a IceCandidate JSON object. |
-const char kCandidateSdpMidName[] = "sdpMid"; |
-const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex"; |
-const char kCandidateSdpName[] = "candidate"; |
- |
-// Names used for a SessionDescription JSON object. |
-const char kSessionDescriptionTypeName[] = "type"; |
-const char kSessionDescriptionSdpName[] = "sdp"; |
- |
-// Names used for media stream labels. |
-const char kAudioLabel[] = "audio_label"; |
-const char kVideoLabel[] = "video_label"; |
-const char kStreamLabel[] = "stream_label"; |
- |
-namespace { |
-static int g_peer_count = 0; |
-static std::unique_ptr<rtc::Thread> g_worker_thread; |
-static std::unique_ptr<rtc::Thread> g_signaling_thread; |
-static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> |
- g_peer_connection_factory; |
- |
-std::string GetEnvVarOrDefault(const char* env_var_name, |
- const char* default_value) { |
- std::string value; |
- const char* env_var = getenv(env_var_name); |
- if (env_var) |
- value = env_var; |
- |
- if (value.empty()) |
- value = default_value; |
- |
- return value; |
-} |
- |
-std::string GetPeerConnectionString() { |
- return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302"); |
-} |
- |
-class DummySetSessionDescriptionObserver |
- : public webrtc::SetSessionDescriptionObserver { |
- public: |
- static DummySetSessionDescriptionObserver* Create() { |
- return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); |
- } |
- virtual void OnSuccess() { LOG(INFO) << __FUNCTION__; } |
- virtual void OnFailure(const std::string& error) { |
- LOG(INFO) << __FUNCTION__ << " " << error; |
- } |
- |
- protected: |
- DummySetSessionDescriptionObserver() {} |
- ~DummySetSessionDescriptionObserver() {} |
-}; |
- |
-} // namespace |
- |
-bool SimplePeerConnection::InitializePeerConnection(bool is_receiver) { |
- RTC_DCHECK(peer_connection_.get() == nullptr); |
- |
- if (g_peer_connection_factory == nullptr) { |
- g_worker_thread.reset(new rtc::Thread()); |
- g_worker_thread->Start(); |
- g_signaling_thread.reset(new rtc::Thread()); |
- g_signaling_thread->Start(); |
- |
- g_peer_connection_factory = webrtc::CreatePeerConnectionFactory( |
- g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(), |
- nullptr, nullptr, nullptr); |
- } |
- if (!g_peer_connection_factory.get()) { |
- DeletePeerConnection(); |
- return false; |
- } |
- |
- g_peer_count++; |
- if (!CreatePeerConnection(is_receiver)) { |
- DeletePeerConnection(); |
- return false; |
- } |
- return peer_connection_.get() != nullptr; |
-} |
- |
-bool SimplePeerConnection::CreatePeerConnection(bool is_receiver) { |
- RTC_DCHECK(g_peer_connection_factory.get() != nullptr); |
- RTC_DCHECK(peer_connection_.get() == nullptr); |
- |
- webrtc::PeerConnectionInterface::RTCConfiguration config; |
- webrtc::PeerConnectionInterface::IceServer server; |
- server.uri = GetPeerConnectionString(); |
- config.servers.push_back(server); |
- |
- webrtc::FakeConstraints constraints; |
- constraints.SetAllowDtlsSctpDataChannels(); |
- |
- if (is_receiver) { |
- constraints.SetMandatoryReceiveAudio(true); |
- constraints.SetMandatoryReceiveVideo(true); |
- } |
- |
- peer_connection_ = g_peer_connection_factory->CreatePeerConnection( |
- config, &constraints, nullptr, nullptr, this); |
- |
- return peer_connection_.get() != nullptr; |
-} |
- |
-void SimplePeerConnection::DeletePeerConnection() { |
- g_peer_count--; |
- |
- CloseDataChannel(); |
- peer_connection_ = nullptr; |
- active_streams_.clear(); |
- |
- if (g_peer_count == 0) { |
- g_peer_connection_factory = nullptr; |
- g_signaling_thread.reset(); |
- g_worker_thread.reset(); |
- } |
-} |
- |
-bool SimplePeerConnection::CreateOffer() { |
- if (!peer_connection_.get()) |
- return false; |
- |
- peer_connection_->CreateOffer(this, nullptr); |
- return true; |
-} |
- |
-bool SimplePeerConnection::CreateAnswer() { |
- if (!peer_connection_.get()) |
- return false; |
- |
- peer_connection_->CreateAnswer(this, nullptr); |
- return true; |
-} |
- |
-void SimplePeerConnection::OnSuccess( |
- webrtc::SessionDescriptionInterface* desc) { |
- peer_connection_->SetLocalDescription( |
- DummySetSessionDescriptionObserver::Create(), desc); |
- |
- std::string sdp; |
- desc->ToString(&sdp); |
- |
- Json::StyledWriter writer; |
- Json::Value jmessage; |
- jmessage[kSessionDescriptionTypeName] = desc->type(); |
- jmessage[kSessionDescriptionSdpName] = sdp; |
- |
- if (OnLocalSdpReady) |
- OnLocalSdpReady(writer.write(jmessage).c_str()); |
-} |
- |
-void SimplePeerConnection::OnFailure(const std::string& error) { |
- LOG(LERROR) << error; |
- |
- if (OnFailureMessage) |
- OnFailureMessage(error.c_str()); |
-} |
- |
-void SimplePeerConnection::OnIceCandidate( |
- const webrtc::IceCandidateInterface* candidate) { |
- LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index(); |
- |
- Json::StyledWriter writer; |
- Json::Value jmessage; |
- |
- jmessage[kCandidateSdpMidName] = candidate->sdp_mid(); |
- jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index(); |
- std::string sdp; |
- if (!candidate->ToString(&sdp)) { |
- LOG(LS_ERROR) << "Failed to serialize candidate"; |
- return; |
- } |
- jmessage[kCandidateSdpName] = sdp; |
- |
- if (OnIceCandiateReady) |
- OnIceCandiateReady(writer.write(jmessage).c_str()); |
-} |
- |
-void SimplePeerConnection::RegisterOnVideoFramReady( |
- VIDEOFRAMEREADY_CALLBACK callback) { |
- OnVideoFrameReady = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnLocalDataChannelReady( |
- LOCALDATACHANNELREADY_CALLBACK callback) { |
- OnLocalDataChannelReady = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnDataFromDataChannelReady( |
- DATAFROMEDATECHANNELREADY_CALLBACK callback) { |
- OnDataFromDataChannelReady = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) { |
- OnFailureMessage = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnAudioBusReady( |
- AUDIOBUSREADY_CALLBACK callback) { |
- OnAudioReady = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnLocalSdpReadytoSend( |
- LOCALSDPREADYTOSEND_CALLBACK callback) { |
- OnLocalSdpReady = callback; |
-} |
- |
-void SimplePeerConnection::RegisterOnIceCandiateReadytoSend( |
- ICECANDIDATEREADYTOSEND_CALLBACK callback) { |
- OnIceCandiateReady = callback; |
-} |
- |
-bool SimplePeerConnection::ReceivedSdp(const char* msg) { |
- if (!peer_connection_) |
- return false; |
- |
- std::string message(msg); |
- |
- Json::Reader reader; |
- Json::Value jmessage; |
- if (!reader.parse(message, jmessage)) { |
- LOG(WARNING) << "Received unknown message. " << message; |
- return false; |
- } |
- std::string type; |
- std::string json_object; |
- |
- rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type); |
- if (type.empty()) |
- return false; |
- |
- std::string sdp; |
- if (!rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName, |
- &sdp)) { |
- LOG(WARNING) << "Can't parse received session description message."; |
- return false; |
- } |
- webrtc::SdpParseError error; |
- webrtc::SessionDescriptionInterface* session_description( |
- webrtc::CreateSessionDescription(type, sdp, &error)); |
- if (!session_description) { |
- LOG(WARNING) << "Can't parse received session description message. " |
- << "SdpParseError was: " << error.description; |
- return false; |
- } |
- LOG(INFO) << " Received session description :" << message; |
- peer_connection_->SetRemoteDescription( |
- DummySetSessionDescriptionObserver::Create(), session_description); |
- |
- return true; |
-} |
- |
-bool SimplePeerConnection::ReceivedIceCandidate(const char* ice_candidate) { |
- if (!peer_connection_) |
- return false; |
- |
- std::string message(ice_candidate); |
- |
- Json::Reader reader; |
- Json::Value jmessage; |
- if (!reader.parse(message, jmessage)) { |
- LOG(WARNING) << "Received unknown message. " << message; |
- return false; |
- } |
- std::string type; |
- std::string json_object; |
- |
- rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type); |
- if (!type.empty()) |
- return false; |
- |
- std::string sdp_mid; |
- int sdp_mlineindex = 0; |
- std::string sdp; |
- if (!rtc::GetStringFromJsonObject(jmessage, kCandidateSdpMidName, &sdp_mid) || |
- !rtc::GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName, |
- &sdp_mlineindex) || |
- !rtc::GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) { |
- LOG(WARNING) << "Can't parse received message."; |
- return false; |
- } |
- webrtc::SdpParseError error; |
- std::unique_ptr<webrtc::IceCandidateInterface> candidate( |
- webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error)); |
- if (!candidate.get()) { |
- LOG(WARNING) << "Can't parse received candidate message. " |
- << "SdpParseError was: " << error.description; |
- return false; |
- } |
- if (!peer_connection_->AddIceCandidate(candidate.get())) { |
- LOG(WARNING) << "Failed to apply the received candidate"; |
- return false; |
- } |
- LOG(INFO) << " Received candidate :" << message; |
- return true; |
-} |
- |
-void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) { |
- is_mute_audio_ = is_mute; |
- is_record_audio_ = is_record; |
- |
- SetAudioControl(); |
-} |
- |
-void SimplePeerConnection::SetAudioControl() { |
- if (!remote_stream_) |
- return; |
- webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks(); |
- if (tracks.empty()) |
- return; |
- |
- webrtc::AudioTrackInterface* audio_track = tracks[0]; |
- std::string id = audio_track->id(); |
- if (is_record_audio_) |
- audio_track->AddSink(this); |
- else |
- audio_track->RemoveSink(this); |
- |
- for (auto& track : tracks) { |
- if (is_mute_audio_) |
- track->set_enabled(false); |
- else |
- track->set_enabled(true); |
- } |
-} |
- |
-void SimplePeerConnection::OnAddStream( |
- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
- LOG(INFO) << __FUNCTION__ << " " << stream->label(); |
- remote_stream_ = stream; |
- |
- SetAudioControl(); |
-} |
- |
-std::unique_ptr<cricket::VideoCapturer> |
-SimplePeerConnection::OpenVideoCaptureDevice() { |
- std::vector<std::string> device_names; |
- { |
- std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info( |
- webrtc::VideoCaptureFactory::CreateDeviceInfo()); |
- if (!info) { |
- return nullptr; |
- } |
- int num_devices = info->NumberOfDevices(); |
- for (int i = 0; i < num_devices; ++i) { |
- const uint32_t kSize = 256; |
- char name[kSize] = {0}; |
- char id[kSize] = {0}; |
- if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) { |
- device_names.push_back(name); |
- } |
- } |
- } |
- |
- cricket::WebRtcVideoDeviceCapturerFactory factory; |
- std::unique_ptr<cricket::VideoCapturer> capturer; |
- for (const auto& name : device_names) { |
- capturer = factory.Create(cricket::Device(name, 0)); |
- if (capturer) { |
- break; |
- } |
- } |
- return capturer; |
-} |
- |
-void SimplePeerConnection::AddStreams(bool audio_only) { |
- if (active_streams_.find(kStreamLabel) != active_streams_.end()) |
- return; // Already added. |
- |
- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = |
- g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel); |
- |
- rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( |
- g_peer_connection_factory->CreateAudioTrack( |
- kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr))); |
- std::string id = audio_track->id(); |
- stream->AddTrack(audio_track); |
- |
- if (!audio_only) { |
- std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice(); |
- if (capture) { |
- rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( |
- g_peer_connection_factory->CreateVideoTrack( |
- kVideoLabel, g_peer_connection_factory->CreateVideoSource( |
- OpenVideoCaptureDevice(), nullptr))); |
- |
- stream->AddTrack(video_track); |
- } |
- } |
- |
- if (!peer_connection_->AddStream(stream)) { |
- LOG(LS_ERROR) << "Adding stream to PeerConnection failed"; |
- } |
- |
- typedef std::pair<std::string, |
- rtc::scoped_refptr<webrtc::MediaStreamInterface>> |
- MediaStreamPair; |
- active_streams_.insert(MediaStreamPair(stream->label(), stream)); |
-} |
- |
-bool SimplePeerConnection::CreateDataChannel() { |
- struct webrtc::DataChannelInit init; |
- init.ordered = true; |
- init.reliable = true; |
- data_channel_ = peer_connection_->CreateDataChannel("Hello", &init); |
- if (data_channel_.get()) { |
- data_channel_->RegisterObserver(this); |
- LOG(LS_INFO) << "Succeeds to create data channel"; |
- return true; |
- } else { |
- LOG(LS_INFO) << "Fails to create data channel"; |
- return false; |
- } |
-} |
- |
-void SimplePeerConnection::CloseDataChannel() { |
- if (data_channel_.get()) { |
- data_channel_->UnregisterObserver(); |
- data_channel_->Close(); |
- } |
- data_channel_ = nullptr; |
-} |
- |
-bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) { |
- if (!data_channel_.get()) { |
- LOG(LS_INFO) << "Data channel is not established"; |
- return false; |
- } |
- webrtc::DataBuffer buffer(data); |
- data_channel_->Send(buffer); |
- return true; |
-} |
- |
-// Peerconnection observer |
-void SimplePeerConnection::OnDataChannel( |
- rtc::scoped_refptr<webrtc::DataChannelInterface> channel) { |
- channel->RegisterObserver(this); |
-} |
- |
-void SimplePeerConnection::OnStateChange() { |
- if (data_channel_) { |
- webrtc::DataChannelInterface::DataState state = data_channel_->state(); |
- if (state == webrtc::DataChannelInterface::kOpen) { |
- if (OnLocalDataChannelReady) |
- OnLocalDataChannelReady(); |
- LOG(LS_INFO) << "Data channel is open"; |
- } |
- } |
-} |
- |
-// A data buffer was successfully received. |
-void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) { |
- size_t size = buffer.data.size(); |
- char* msg = new char[size + 1]; |
- memcpy(msg, buffer.data.data(), size); |
- msg[size] = 0; |
- if (OnDataFromDataChannelReady) |
- OnDataFromDataChannelReady(msg); |
- delete[] msg; |
-} |
- |
-// AudioTrackSinkInterface implementation. |
-void SimplePeerConnection::OnData(const void* audio_data, |
- int bits_per_sample, |
- int sample_rate, |
- size_t number_of_channels, |
- size_t number_of_frames) { |
- if (OnAudioReady) |
- OnAudioReady(audio_data, bits_per_sample, sample_rate, |
- static_cast<int>(number_of_channels), |
- static_cast<int>(number_of_frames)); |
-} |
- |
-std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() { |
- std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers = |
- peer_connection_->GetReceivers(); |
- |
- std::vector<uint32_t> ssrcs; |
- for (const auto& receiver : receivers) { |
- if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO) |
- continue; |
- |
- std::vector<webrtc::RtpEncodingParameters> params = |
- receiver->GetParameters().encodings; |
- |
- for (const auto& param : params) { |
- uint32_t ssrc = param.ssrc.value_or(0); |
- if (ssrc > 0) |
- ssrcs.push_back(ssrc); |
- } |
- } |
- |
- return ssrcs; |
-} |
+/* |
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/examples/unityplugin/simple_peer_connection.h" |
+ |
+#include <utility> |
+ |
+#include "webrtc/api/test/fakeconstraints.h" |
+#include "webrtc/media/engine/webrtcvideocapturerfactory.h" |
+#include "webrtc/modules/video_capture/video_capture_factory.h" |
+ |
+// Names used for media stream labels. |
+const char kAudioLabel[] = "audio_label"; |
+const char kVideoLabel[] = "video_label"; |
+const char kStreamLabel[] = "stream_label"; |
+ |
+namespace { |
+static int g_peer_count = 0; |
+static std::unique_ptr<rtc::Thread> g_worker_thread; |
+static std::unique_ptr<rtc::Thread> g_signaling_thread; |
+static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> |
+ g_peer_connection_factory; |
+ |
+std::string GetEnvVarOrDefault(const char* env_var_name, |
+ const char* default_value) { |
+ std::string value; |
+ const char* env_var = getenv(env_var_name); |
+ if (env_var) |
+ value = env_var; |
+ |
+ if (value.empty()) |
+ value = default_value; |
+ |
+ return value; |
+} |
+ |
+std::string GetPeerConnectionString() { |
+ return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302"); |
+} |
+ |
+class DummySetSessionDescriptionObserver |
+ : public webrtc::SetSessionDescriptionObserver { |
+ public: |
+ static DummySetSessionDescriptionObserver* Create() { |
+ return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); |
+ } |
+ virtual void OnSuccess() { LOG(INFO) << __FUNCTION__; } |
+ virtual void OnFailure(const std::string& error) { |
+ LOG(INFO) << __FUNCTION__ << " " << error; |
+ } |
+ |
+ protected: |
+ DummySetSessionDescriptionObserver() {} |
+ ~DummySetSessionDescriptionObserver() {} |
+}; |
+ |
+} // namespace |
+ |
+bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls, |
+ const int no_of_urls, |
+ const char* username, |
+ const char* credential, |
+ bool is_receiver) { |
+ RTC_DCHECK(peer_connection_.get() == nullptr); |
+ |
+ if (g_peer_connection_factory == nullptr) { |
+ g_worker_thread.reset(new rtc::Thread()); |
+ g_worker_thread->Start(); |
+ g_signaling_thread.reset(new rtc::Thread()); |
+ g_signaling_thread->Start(); |
+ |
+ g_peer_connection_factory = webrtc::CreatePeerConnectionFactory( |
+ g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(), |
+ nullptr, nullptr, nullptr); |
+ } |
+ if (!g_peer_connection_factory.get()) { |
+ DeletePeerConnection(); |
+ return false; |
+ } |
+ |
+ g_peer_count++; |
+ if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential, |
+ is_receiver)) { |
+ DeletePeerConnection(); |
+ return false; |
+ } |
+ return peer_connection_.get() != nullptr; |
+} |
+ |
+bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls, |
+ const int no_of_urls, |
+ const char* username, |
+ const char* credential, |
+ bool is_receiver) { |
+ RTC_DCHECK(g_peer_connection_factory.get() != nullptr); |
+ RTC_DCHECK(peer_connection_.get() == nullptr); |
+ |
+ local_video_observer_.reset(new VideoObserver()); |
+ remote_video_observer_.reset(new VideoObserver()); |
+ |
+ // Add the turn server. |
+ if (turn_urls != nullptr) { |
+ if (no_of_urls > 0) { |
+ webrtc::PeerConnectionInterface::IceServer turn_server; |
+ for (int i = 0; i < no_of_urls; i++) { |
+ std::string url(turn_urls[i]); |
+ if (url.length() > 0) |
+ turn_server.urls.push_back(turn_urls[i]); |
+ } |
+ |
+ std::string user_name(username); |
+ if (user_name.length() > 0) |
+ turn_server.username = username; |
+ |
+ std::string password(credential); |
+ if (password.length() > 0) |
+ turn_server.password = credential; |
+ |
+ config_.servers.push_back(turn_server); |
+ } |
+ } |
+ |
+ // Add the stun server. |
+ webrtc::PeerConnectionInterface::IceServer stun_server; |
+ stun_server.uri = GetPeerConnectionString(); |
+ config_.servers.push_back(stun_server); |
+ |
+ webrtc::FakeConstraints constraints; |
+ constraints.SetAllowDtlsSctpDataChannels(); |
+ |
+ if (is_receiver) { |
+ constraints.SetMandatoryReceiveAudio(true); |
+ constraints.SetMandatoryReceiveVideo(true); |
+ } |
+ |
+ peer_connection_ = g_peer_connection_factory->CreatePeerConnection( |
+ config_, &constraints, nullptr, nullptr, this); |
+ |
+ return peer_connection_.get() != nullptr; |
+} |
+ |
+void SimplePeerConnection::DeletePeerConnection() { |
+ g_peer_count--; |
+ |
+ CloseDataChannel(); |
+ peer_connection_ = nullptr; |
+ active_streams_.clear(); |
+ |
+ if (g_peer_count == 0) { |
+ g_peer_connection_factory = nullptr; |
+ g_signaling_thread.reset(); |
+ g_worker_thread.reset(); |
+ } |
+} |
+ |
+bool SimplePeerConnection::CreateOffer() { |
+ if (!peer_connection_.get()) |
+ return false; |
+ |
+ peer_connection_->CreateOffer(this, nullptr); |
+ return true; |
+} |
+ |
+bool SimplePeerConnection::CreateAnswer() { |
+ if (!peer_connection_.get()) |
+ return false; |
+ |
+ peer_connection_->CreateAnswer(this, nullptr); |
+ return true; |
+} |
+ |
+void SimplePeerConnection::OnSuccess( |
+ webrtc::SessionDescriptionInterface* desc) { |
+ peer_connection_->SetLocalDescription( |
+ DummySetSessionDescriptionObserver::Create(), desc); |
+ |
+ std::string sdp; |
+ desc->ToString(&sdp); |
+ |
+ if (OnLocalSdpReady) |
+ OnLocalSdpReady(desc->type().c_str(), sdp.c_str()); |
+} |
+ |
+void SimplePeerConnection::OnFailure(const std::string& error) { |
+ LOG(LERROR) << error; |
+ |
+ if (OnFailureMessage) |
+ OnFailureMessage(error.c_str()); |
+} |
+ |
+void SimplePeerConnection::OnIceCandidate( |
+ const webrtc::IceCandidateInterface* candidate) { |
+ LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index(); |
+ |
+ std::string sdp; |
+ if (!candidate->ToString(&sdp)) { |
+ LOG(LS_ERROR) << "Failed to serialize candidate"; |
+ return; |
+ } |
+ |
+ if (OnIceCandiateReady) |
+ OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(), |
+ candidate->sdp_mid().c_str()); |
+} |
+ |
+void SimplePeerConnection::RegisterOnLocalI420FrameReady( |
+ I420FRAMEREADY_CALLBACK callback) { |
+ if (local_video_observer_) |
+ local_video_observer_->SetVideoCallback(callback); |
+} |
+ |
+void SimplePeerConnection::RegisterOnRemoteI420FrameReady( |
+ I420FRAMEREADY_CALLBACK callback) { |
+ if (remote_video_observer_) |
+ remote_video_observer_->SetVideoCallback(callback); |
+} |
+ |
+void SimplePeerConnection::RegisterOnLocalDataChannelReady( |
+ LOCALDATACHANNELREADY_CALLBACK callback) { |
+ OnLocalDataChannelReady = callback; |
+} |
+ |
+void SimplePeerConnection::RegisterOnDataFromDataChannelReady( |
+ DATAFROMEDATECHANNELREADY_CALLBACK callback) { |
+ OnDataFromDataChannelReady = callback; |
+} |
+ |
+void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) { |
+ OnFailureMessage = callback; |
+} |
+ |
+void SimplePeerConnection::RegisterOnAudioBusReady( |
+ AUDIOBUSREADY_CALLBACK callback) { |
+ OnAudioReady = callback; |
+} |
+ |
+void SimplePeerConnection::RegisterOnLocalSdpReadytoSend( |
+ LOCALSDPREADYTOSEND_CALLBACK callback) { |
+ OnLocalSdpReady = callback; |
+} |
+ |
+void SimplePeerConnection::RegisterOnIceCandiateReadytoSend( |
+ ICECANDIDATEREADYTOSEND_CALLBACK callback) { |
+ OnIceCandiateReady = callback; |
+} |
+ |
+bool SimplePeerConnection::SetRemoteDescription(const char* type, |
+ const char* sdp) { |
+ if (!peer_connection_) |
+ return false; |
+ |
+ std::string remote_desc(sdp); |
+ std::string sdp_type(type); |
+ webrtc::SdpParseError error; |
+ webrtc::SessionDescriptionInterface* session_description( |
+ webrtc::CreateSessionDescription(sdp_type, remote_desc, &error)); |
+ if (!session_description) { |
+ LOG(WARNING) << "Can't parse received session description message. " |
+ << "SdpParseError was: " << error.description; |
+ return false; |
+ } |
+ LOG(INFO) << " Received session description :" << remote_desc; |
+ peer_connection_->SetRemoteDescription( |
+ DummySetSessionDescriptionObserver::Create(), session_description); |
+ |
+ return true; |
+} |
+ |
+bool SimplePeerConnection::AddIceCandidate(const char* candidate, |
+ const int sdp_mlineindex, |
+ const char* sdp_mid) { |
+ if (!peer_connection_) |
+ return false; |
+ |
+ webrtc::SdpParseError error; |
+ std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate( |
+ webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error)); |
+ if (!ice_candidate.get()) { |
+ LOG(WARNING) << "Can't parse received candidate message. " |
+ << "SdpParseError was: " << error.description; |
+ return false; |
+ } |
+ if (!peer_connection_->AddIceCandidate(ice_candidate.get())) { |
+ LOG(WARNING) << "Failed to apply the received candidate"; |
+ return false; |
+ } |
+ LOG(INFO) << " Received candidate :" << candidate; |
+ return true; |
+} |
+ |
+void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) { |
+ is_mute_audio_ = is_mute; |
+ is_record_audio_ = is_record; |
+ |
+ SetAudioControl(); |
+} |
+ |
+void SimplePeerConnection::SetAudioControl() { |
+ if (!remote_stream_) |
+ return; |
+ webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks(); |
+ if (tracks.empty()) |
+ return; |
+ |
+ webrtc::AudioTrackInterface* audio_track = tracks[0]; |
+ std::string id = audio_track->id(); |
+ if (is_record_audio_) |
+ audio_track->AddSink(this); |
+ else |
+ audio_track->RemoveSink(this); |
+ |
+ for (auto& track : tracks) { |
+ if (is_mute_audio_) |
+ track->set_enabled(false); |
+ else |
+ track->set_enabled(true); |
+ } |
+} |
+ |
+void SimplePeerConnection::OnAddStream( |
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
+ LOG(INFO) << __FUNCTION__ << " " << stream->label(); |
+ remote_stream_ = stream; |
+ if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) { |
+ remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink( |
+ remote_video_observer_.get(), rtc::VideoSinkWants()); |
+ } |
+ SetAudioControl(); |
+} |
+ |
+std::unique_ptr<cricket::VideoCapturer> |
+SimplePeerConnection::OpenVideoCaptureDevice() { |
+ std::vector<std::string> device_names; |
+ { |
+ std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info( |
+ webrtc::VideoCaptureFactory::CreateDeviceInfo()); |
+ if (!info) { |
+ return nullptr; |
+ } |
+ int num_devices = info->NumberOfDevices(); |
+ for (int i = 0; i < num_devices; ++i) { |
+ const uint32_t kSize = 256; |
+ char name[kSize] = {0}; |
+ char id[kSize] = {0}; |
+ if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) { |
+ device_names.push_back(name); |
+ } |
+ } |
+ } |
+ |
+ cricket::WebRtcVideoDeviceCapturerFactory factory; |
+ std::unique_ptr<cricket::VideoCapturer> capturer; |
+ for (const auto& name : device_names) { |
+ capturer = factory.Create(cricket::Device(name, 0)); |
+ if (capturer) { |
+ break; |
+ } |
+ } |
+ return capturer; |
+} |
+ |
+void SimplePeerConnection::AddStreams(bool audio_only) { |
+ if (active_streams_.find(kStreamLabel) != active_streams_.end()) |
+ return; // Already added. |
+ |
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = |
+ g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel); |
+ |
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( |
+ g_peer_connection_factory->CreateAudioTrack( |
+ kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr))); |
+ std::string id = audio_track->id(); |
+ stream->AddTrack(audio_track); |
+ |
+ if (!audio_only) { |
+ std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice(); |
+ if (capture) { |
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( |
+ g_peer_connection_factory->CreateVideoTrack( |
+ kVideoLabel, g_peer_connection_factory->CreateVideoSource( |
+ std::move(capture), nullptr))); |
+ |
+ stream->AddTrack(video_track); |
+ if (local_video_observer_ && !stream->GetVideoTracks().empty()) { |
+ stream->GetVideoTracks()[0]->AddOrUpdateSink( |
+ local_video_observer_.get(), rtc::VideoSinkWants()); |
+ } |
+ } |
+ } |
+ |
+ if (!peer_connection_->AddStream(stream)) { |
+ LOG(LS_ERROR) << "Adding stream to PeerConnection failed"; |
+ } |
+ |
+ typedef std::pair<std::string, |
+ rtc::scoped_refptr<webrtc::MediaStreamInterface>> |
+ MediaStreamPair; |
+ active_streams_.insert(MediaStreamPair(stream->label(), stream)); |
+} |
+ |
+bool SimplePeerConnection::CreateDataChannel() { |
+ struct webrtc::DataChannelInit init; |
+ init.ordered = true; |
+ init.reliable = true; |
+ data_channel_ = peer_connection_->CreateDataChannel("Hello", &init); |
+ if (data_channel_.get()) { |
+ data_channel_->RegisterObserver(this); |
+ LOG(LS_INFO) << "Succeeds to create data channel"; |
+ return true; |
+ } else { |
+ LOG(LS_INFO) << "Fails to create data channel"; |
+ return false; |
+ } |
+} |
+ |
+void SimplePeerConnection::CloseDataChannel() { |
+ if (data_channel_.get()) { |
+ data_channel_->UnregisterObserver(); |
+ data_channel_->Close(); |
+ } |
+ data_channel_ = nullptr; |
+} |
+ |
+bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) { |
+ if (!data_channel_.get()) { |
+ LOG(LS_INFO) << "Data channel is not established"; |
+ return false; |
+ } |
+ webrtc::DataBuffer buffer(data); |
+ data_channel_->Send(buffer); |
+ return true; |
+} |
+ |
+// Peerconnection observer |
+void SimplePeerConnection::OnDataChannel( |
+ rtc::scoped_refptr<webrtc::DataChannelInterface> channel) { |
+ channel->RegisterObserver(this); |
+} |
+ |
+void SimplePeerConnection::OnStateChange() { |
+ if (data_channel_) { |
+ webrtc::DataChannelInterface::DataState state = data_channel_->state(); |
+ if (state == webrtc::DataChannelInterface::kOpen) { |
+ if (OnLocalDataChannelReady) |
+ OnLocalDataChannelReady(); |
+ LOG(LS_INFO) << "Data channel is open"; |
+ } |
+ } |
+} |
+ |
+// A data buffer was successfully received. |
+void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) { |
+ size_t size = buffer.data.size(); |
+ char* msg = new char[size + 1]; |
+ memcpy(msg, buffer.data.data(), size); |
+ msg[size] = 0; |
+ if (OnDataFromDataChannelReady) |
+ OnDataFromDataChannelReady(msg); |
+ delete[] msg; |
+} |
+ |
+// AudioTrackSinkInterface implementation. |
+void SimplePeerConnection::OnData(const void* audio_data, |
+ int bits_per_sample, |
+ int sample_rate, |
+ size_t number_of_channels, |
+ size_t number_of_frames) { |
+ if (OnAudioReady) |
+ OnAudioReady(audio_data, bits_per_sample, sample_rate, |
+ static_cast<int>(number_of_channels), |
+ static_cast<int>(number_of_frames)); |
+} |
+ |
+std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() { |
+ std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers = |
+ peer_connection_->GetReceivers(); |
+ |
+ std::vector<uint32_t> ssrcs; |
+ for (const auto& receiver : receivers) { |
+ if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO) |
+ continue; |
+ |
+ std::vector<webrtc::RtpEncodingParameters> params = |
+ receiver->GetParameters().encodings; |
+ |
+ for (const auto& param : params) { |
+ uint32_t ssrc = param.ssrc.value_or(0); |
+ if (ssrc > 0) |
+ ssrcs.push_back(ssrc); |
+ } |
+ } |
+ |
+ return ssrcs; |
+} |