blob: 02911f6cd9661b22d8bbc063b18b71fea8864c90 [file] [log] [blame]
gyzhouad7cad82017-05-11 16:10:03 -07001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "examples/unityplugin/simple_peer_connection.h"
gyzhouad7cad82017-05-11 16:10:03 -070012
13#include <utility>
14
Qiang Chen51e20462017-12-05 11:11:21 -080015#include "api/audio_codecs/builtin_audio_decoder_factory.h"
16#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "api/test/fakeconstraints.h"
18#include "api/videosourceproxy.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080019#include "media/engine/internaldecoderfactory.h"
20#include "media/engine/internalencoderfactory.h"
Anders Carlssondd8c1652018-01-30 10:32:13 +010021#include "media/engine/multiplexcodecfactory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "media/engine/webrtcvideocapturerfactory.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080023#include "media/engine/webrtcvideodecoderfactory.h"
24#include "media/engine/webrtcvideoencoderfactory.h"
25#include "modules/audio_device/include/audio_device.h"
26#include "modules/audio_processing/include/audio_processing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "modules/video_capture/video_capture_factory.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080028#include "rtc_base/ptr_util.h"
gyzhouad7cad82017-05-11 16:10:03 -070029
qiangchen42f96d52017-08-08 17:08:03 -070030#if defined(WEBRTC_ANDROID)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "examples/unityplugin/classreferenceholder.h"
George Zhou2770c3d2018-03-07 09:58:54 -080032#include "modules/utility/include/helpers_android.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "sdk/android/src/jni/androidvideotracksource.h"
34#include "sdk/android/src/jni/jni_helpers.h"
qiangchen42f96d52017-08-08 17:08:03 -070035#endif
36
Seth Hampson513449e2018-03-06 09:35:56 -080037// Names used for media stream ids.
gyzhouad7cad82017-05-11 16:10:03 -070038const char kAudioLabel[] = "audio_label";
39const char kVideoLabel[] = "video_label";
Seth Hampson513449e2018-03-06 09:35:56 -080040const char kStreamId[] = "stream_id";
gyzhouad7cad82017-05-11 16:10:03 -070041
42namespace {
43static int g_peer_count = 0;
44static std::unique_ptr<rtc::Thread> g_worker_thread;
45static std::unique_ptr<rtc::Thread> g_signaling_thread;
46static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
47 g_peer_connection_factory;
qiangchen42f96d52017-08-08 17:08:03 -070048#if defined(WEBRTC_ANDROID)
49// Android case: the video track does not own the capturer, and it
50// relies on the app to dispose the capturer when the peerconnection
51// shuts down.
52static jobject g_camera = nullptr;
53#endif
gyzhouad7cad82017-05-11 16:10:03 -070054
55std::string GetEnvVarOrDefault(const char* env_var_name,
56 const char* default_value) {
57 std::string value;
58 const char* env_var = getenv(env_var_name);
59 if (env_var)
60 value = env_var;
61
62 if (value.empty())
63 value = default_value;
64
65 return value;
66}
67
68std::string GetPeerConnectionString() {
69 return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
70}
71
72class DummySetSessionDescriptionObserver
73 : public webrtc::SetSessionDescriptionObserver {
74 public:
75 static DummySetSessionDescriptionObserver* Create() {
76 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
77 }
Mirko Bonadei675513b2017-11-09 11:09:25 +010078 virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; }
gyzhouad7cad82017-05-11 16:10:03 -070079 virtual void OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010080 RTC_LOG(INFO) << __FUNCTION__ << " " << error;
gyzhouad7cad82017-05-11 16:10:03 -070081 }
82
83 protected:
84 DummySetSessionDescriptionObserver() {}
85 ~DummySetSessionDescriptionObserver() {}
86};
87
88} // namespace
89
gyzhoub38f3862017-07-25 16:04:31 -070090bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls,
91 const int no_of_urls,
92 const char* username,
93 const char* credential,
94 bool is_receiver) {
gyzhouad7cad82017-05-11 16:10:03 -070095 RTC_DCHECK(peer_connection_.get() == nullptr);
96
97 if (g_peer_connection_factory == nullptr) {
98 g_worker_thread.reset(new rtc::Thread());
99 g_worker_thread->Start();
100 g_signaling_thread.reset(new rtc::Thread());
101 g_signaling_thread->Start();
102
103 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
104 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
Qiang Chen51e20462017-12-05 11:11:21 -0800105 nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
Qiang Chen43fb9122017-12-20 10:47:36 -0800106 webrtc::CreateBuiltinAudioDecoderFactory(),
107 std::unique_ptr<webrtc::VideoEncoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100108 new webrtc::MultiplexEncoderFactory(
Qiang Chen43fb9122017-12-20 10:47:36 -0800109 rtc::MakeUnique<webrtc::InternalEncoderFactory>())),
110 std::unique_ptr<webrtc::VideoDecoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100111 new webrtc::MultiplexDecoderFactory(
Qiang Chen43fb9122017-12-20 10:47:36 -0800112 rtc::MakeUnique<webrtc::InternalDecoderFactory>())),
113 nullptr, nullptr);
gyzhouad7cad82017-05-11 16:10:03 -0700114 }
115 if (!g_peer_connection_factory.get()) {
116 DeletePeerConnection();
117 return false;
118 }
119
120 g_peer_count++;
Qiang Chen51e20462017-12-05 11:11:21 -0800121 if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) {
gyzhouad7cad82017-05-11 16:10:03 -0700122 DeletePeerConnection();
123 return false;
124 }
Qiang Chen51e20462017-12-05 11:11:21 -0800125
126 mandatory_receive_ = is_receiver;
gyzhouad7cad82017-05-11 16:10:03 -0700127 return peer_connection_.get() != nullptr;
128}
129
gyzhoub38f3862017-07-25 16:04:31 -0700130bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls,
131 const int no_of_urls,
132 const char* username,
Qiang Chen51e20462017-12-05 11:11:21 -0800133 const char* credential) {
gyzhouad7cad82017-05-11 16:10:03 -0700134 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
135 RTC_DCHECK(peer_connection_.get() == nullptr);
136
gyzhoub38f3862017-07-25 16:04:31 -0700137 local_video_observer_.reset(new VideoObserver());
138 remote_video_observer_.reset(new VideoObserver());
139
140 // Add the turn server.
141 if (turn_urls != nullptr) {
142 if (no_of_urls > 0) {
143 webrtc::PeerConnectionInterface::IceServer turn_server;
144 for (int i = 0; i < no_of_urls; i++) {
145 std::string url(turn_urls[i]);
146 if (url.length() > 0)
147 turn_server.urls.push_back(turn_urls[i]);
148 }
149
150 std::string user_name(username);
151 if (user_name.length() > 0)
152 turn_server.username = username;
153
154 std::string password(credential);
155 if (password.length() > 0)
156 turn_server.password = credential;
157
158 config_.servers.push_back(turn_server);
159 }
160 }
161
162 // Add the stun server.
163 webrtc::PeerConnectionInterface::IceServer stun_server;
164 stun_server.uri = GetPeerConnectionString();
165 config_.servers.push_back(stun_server);
gyzhouad7cad82017-05-11 16:10:03 -0700166
167 webrtc::FakeConstraints constraints;
168 constraints.SetAllowDtlsSctpDataChannels();
169
gyzhouad7cad82017-05-11 16:10:03 -0700170 peer_connection_ = g_peer_connection_factory->CreatePeerConnection(
gyzhoub38f3862017-07-25 16:04:31 -0700171 config_, &constraints, nullptr, nullptr, this);
gyzhouad7cad82017-05-11 16:10:03 -0700172
173 return peer_connection_.get() != nullptr;
174}
175
176void SimplePeerConnection::DeletePeerConnection() {
177 g_peer_count--;
178
qiangchen42f96d52017-08-08 17:08:03 -0700179#if defined(WEBRTC_ANDROID)
180 if (g_camera) {
magjeda3d4f682017-08-28 16:24:06 -0700181 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700182 jclass pc_factory_class =
183 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
George Zhou2770c3d2018-03-07 09:58:54 -0800184 jmethodID stop_camera_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700185 env, pc_factory_class, "StopCamera", "(Lorg/webrtc/VideoCapturer;)V");
186
187 env->CallStaticVoidMethod(pc_factory_class, stop_camera_method, g_camera);
188 CHECK_EXCEPTION(env);
189
190 g_camera = nullptr;
191 }
192#endif
193
gyzhouad7cad82017-05-11 16:10:03 -0700194 CloseDataChannel();
195 peer_connection_ = nullptr;
196 active_streams_.clear();
197
198 if (g_peer_count == 0) {
199 g_peer_connection_factory = nullptr;
200 g_signaling_thread.reset();
201 g_worker_thread.reset();
202 }
203}
204
205bool SimplePeerConnection::CreateOffer() {
206 if (!peer_connection_.get())
207 return false;
208
Qiang Chen51e20462017-12-05 11:11:21 -0800209 webrtc::FakeConstraints constraints;
210 if (mandatory_receive_) {
211 constraints.SetMandatoryReceiveAudio(true);
212 constraints.SetMandatoryReceiveVideo(true);
213 }
214 peer_connection_->CreateOffer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700215 return true;
216}
217
218bool SimplePeerConnection::CreateAnswer() {
219 if (!peer_connection_.get())
220 return false;
221
Qiang Chen51e20462017-12-05 11:11:21 -0800222 webrtc::FakeConstraints constraints;
223 if (mandatory_receive_) {
224 constraints.SetMandatoryReceiveAudio(true);
225 constraints.SetMandatoryReceiveVideo(true);
226 }
227 peer_connection_->CreateAnswer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700228 return true;
229}
230
231void SimplePeerConnection::OnSuccess(
232 webrtc::SessionDescriptionInterface* desc) {
233 peer_connection_->SetLocalDescription(
234 DummySetSessionDescriptionObserver::Create(), desc);
235
236 std::string sdp;
237 desc->ToString(&sdp);
238
gyzhouad7cad82017-05-11 16:10:03 -0700239 if (OnLocalSdpReady)
gyzhoub38f3862017-07-25 16:04:31 -0700240 OnLocalSdpReady(desc->type().c_str(), sdp.c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700241}
242
243void SimplePeerConnection::OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100244 RTC_LOG(LERROR) << error;
gyzhouad7cad82017-05-11 16:10:03 -0700245
246 if (OnFailureMessage)
247 OnFailureMessage(error.c_str());
248}
249
250void SimplePeerConnection::OnIceCandidate(
251 const webrtc::IceCandidateInterface* candidate) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100252 RTC_LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
gyzhouad7cad82017-05-11 16:10:03 -0700253
gyzhouad7cad82017-05-11 16:10:03 -0700254 std::string sdp;
255 if (!candidate->ToString(&sdp)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100256 RTC_LOG(LS_ERROR) << "Failed to serialize candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700257 return;
258 }
gyzhouad7cad82017-05-11 16:10:03 -0700259
260 if (OnIceCandiateReady)
gyzhoub38f3862017-07-25 16:04:31 -0700261 OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(),
262 candidate->sdp_mid().c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700263}
264
gyzhoub38f3862017-07-25 16:04:31 -0700265void SimplePeerConnection::RegisterOnLocalI420FrameReady(
266 I420FRAMEREADY_CALLBACK callback) {
267 if (local_video_observer_)
268 local_video_observer_->SetVideoCallback(callback);
269}
270
271void SimplePeerConnection::RegisterOnRemoteI420FrameReady(
272 I420FRAMEREADY_CALLBACK callback) {
273 if (remote_video_observer_)
274 remote_video_observer_->SetVideoCallback(callback);
gyzhouad7cad82017-05-11 16:10:03 -0700275}
276
277void SimplePeerConnection::RegisterOnLocalDataChannelReady(
278 LOCALDATACHANNELREADY_CALLBACK callback) {
279 OnLocalDataChannelReady = callback;
280}
281
282void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
283 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
284 OnDataFromDataChannelReady = callback;
285}
286
287void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
288 OnFailureMessage = callback;
289}
290
291void SimplePeerConnection::RegisterOnAudioBusReady(
292 AUDIOBUSREADY_CALLBACK callback) {
293 OnAudioReady = callback;
294}
295
296void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
297 LOCALSDPREADYTOSEND_CALLBACK callback) {
298 OnLocalSdpReady = callback;
299}
300
301void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
302 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
303 OnIceCandiateReady = callback;
304}
305
gyzhoub38f3862017-07-25 16:04:31 -0700306bool SimplePeerConnection::SetRemoteDescription(const char* type,
307 const char* sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700308 if (!peer_connection_)
309 return false;
310
gyzhoub38f3862017-07-25 16:04:31 -0700311 std::string remote_desc(sdp);
312 std::string sdp_type(type);
gyzhouad7cad82017-05-11 16:10:03 -0700313 webrtc::SdpParseError error;
314 webrtc::SessionDescriptionInterface* session_description(
gyzhoub38f3862017-07-25 16:04:31 -0700315 webrtc::CreateSessionDescription(sdp_type, remote_desc, &error));
gyzhouad7cad82017-05-11 16:10:03 -0700316 if (!session_description) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100317 RTC_LOG(WARNING) << "Can't parse received session description message. "
318 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700319 return false;
320 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100321 RTC_LOG(INFO) << " Received session description :" << remote_desc;
gyzhouad7cad82017-05-11 16:10:03 -0700322 peer_connection_->SetRemoteDescription(
323 DummySetSessionDescriptionObserver::Create(), session_description);
324
325 return true;
326}
327
gyzhoub38f3862017-07-25 16:04:31 -0700328bool SimplePeerConnection::AddIceCandidate(const char* candidate,
329 const int sdp_mlineindex,
330 const char* sdp_mid) {
gyzhouad7cad82017-05-11 16:10:03 -0700331 if (!peer_connection_)
332 return false;
333
gyzhouad7cad82017-05-11 16:10:03 -0700334 webrtc::SdpParseError error;
gyzhoub38f3862017-07-25 16:04:31 -0700335 std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate(
336 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error));
337 if (!ice_candidate.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100338 RTC_LOG(WARNING) << "Can't parse received candidate message. "
339 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700340 return false;
341 }
gyzhoub38f3862017-07-25 16:04:31 -0700342 if (!peer_connection_->AddIceCandidate(ice_candidate.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100343 RTC_LOG(WARNING) << "Failed to apply the received candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700344 return false;
345 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100346 RTC_LOG(INFO) << " Received candidate :" << candidate;
gyzhouad7cad82017-05-11 16:10:03 -0700347 return true;
348}
349
350void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
351 is_mute_audio_ = is_mute;
352 is_record_audio_ = is_record;
353
354 SetAudioControl();
355}
356
357void SimplePeerConnection::SetAudioControl() {
358 if (!remote_stream_)
359 return;
360 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
361 if (tracks.empty())
362 return;
363
364 webrtc::AudioTrackInterface* audio_track = tracks[0];
365 std::string id = audio_track->id();
366 if (is_record_audio_)
367 audio_track->AddSink(this);
368 else
369 audio_track->RemoveSink(this);
370
371 for (auto& track : tracks) {
372 if (is_mute_audio_)
373 track->set_enabled(false);
374 else
375 track->set_enabled(true);
376 }
377}
378
379void SimplePeerConnection::OnAddStream(
380 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
Seth Hampson13b8bad2018-03-13 16:05:28 -0700381 RTC_LOG(INFO) << __FUNCTION__ << " " << stream->id();
gyzhouad7cad82017-05-11 16:10:03 -0700382 remote_stream_ = stream;
gyzhoub38f3862017-07-25 16:04:31 -0700383 if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) {
384 remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink(
385 remote_video_observer_.get(), rtc::VideoSinkWants());
386 }
gyzhouad7cad82017-05-11 16:10:03 -0700387 SetAudioControl();
388}
389
390std::unique_ptr<cricket::VideoCapturer>
391SimplePeerConnection::OpenVideoCaptureDevice() {
392 std::vector<std::string> device_names;
393 {
394 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
395 webrtc::VideoCaptureFactory::CreateDeviceInfo());
396 if (!info) {
397 return nullptr;
398 }
399 int num_devices = info->NumberOfDevices();
400 for (int i = 0; i < num_devices; ++i) {
401 const uint32_t kSize = 256;
402 char name[kSize] = {0};
403 char id[kSize] = {0};
404 if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
405 device_names.push_back(name);
406 }
407 }
408 }
409
410 cricket::WebRtcVideoDeviceCapturerFactory factory;
411 std::unique_ptr<cricket::VideoCapturer> capturer;
412 for (const auto& name : device_names) {
413 capturer = factory.Create(cricket::Device(name, 0));
414 if (capturer) {
415 break;
416 }
417 }
418 return capturer;
419}
420
421void SimplePeerConnection::AddStreams(bool audio_only) {
Seth Hampson513449e2018-03-06 09:35:56 -0800422 if (active_streams_.find(kStreamId) != active_streams_.end())
gyzhouad7cad82017-05-11 16:10:03 -0700423 return; // Already added.
424
425 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
Seth Hampson513449e2018-03-06 09:35:56 -0800426 g_peer_connection_factory->CreateLocalMediaStream(kStreamId);
gyzhouad7cad82017-05-11 16:10:03 -0700427
428 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
429 g_peer_connection_factory->CreateAudioTrack(
430 kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr)));
431 std::string id = audio_track->id();
432 stream->AddTrack(audio_track);
433
434 if (!audio_only) {
qiangchen42f96d52017-08-08 17:08:03 -0700435#if defined(WEBRTC_ANDROID)
magjeda3d4f682017-08-28 16:24:06 -0700436 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700437 jclass pc_factory_class =
438 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
George Zhou2770c3d2018-03-07 09:58:54 -0800439 jmethodID load_texture_helper_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700440 env, pc_factory_class, "LoadSurfaceTextureHelper",
441 "()Lorg/webrtc/SurfaceTextureHelper;");
442 jobject texture_helper = env->CallStaticObjectMethod(
443 pc_factory_class, load_texture_helper_method);
444 CHECK_EXCEPTION(env);
445 RTC_DCHECK(texture_helper != nullptr)
446 << "Cannot get the Surface Texture Helper.";
447
Qiang Chen51e20462017-12-05 11:11:21 -0800448 rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source(
449 new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>(
Magnus Jedvert1a759c62018-04-24 15:11:02 +0200450 g_signaling_thread.get(), env, false));
qiangchen42f96d52017-08-08 17:08:03 -0700451 rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source =
452 webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(),
453 g_worker_thread.get(), source);
454
455 // link with VideoCapturer (Camera);
George Zhou2770c3d2018-03-07 09:58:54 -0800456 jmethodID link_camera_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700457 env, pc_factory_class, "LinkCamera",
458 "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;");
459 jobject camera_tmp =
460 env->CallStaticObjectMethod(pc_factory_class, link_camera_method,
461 (jlong)proxy_source.get(), texture_helper);
462 CHECK_EXCEPTION(env);
463 g_camera = (jobject)env->NewGlobalRef(camera_tmp);
464
465 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
466 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
467 proxy_source.release()));
468 stream->AddTrack(video_track);
469#else
gyzhouad7cad82017-05-11 16:10:03 -0700470 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
471 if (capture) {
472 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
473 g_peer_connection_factory->CreateVideoTrack(
474 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
gyzhoub38f3862017-07-25 16:04:31 -0700475 std::move(capture), nullptr)));
gyzhouad7cad82017-05-11 16:10:03 -0700476
477 stream->AddTrack(video_track);
qiangchen42f96d52017-08-08 17:08:03 -0700478 }
479#endif
480 if (local_video_observer_ && !stream->GetVideoTracks().empty()) {
481 stream->GetVideoTracks()[0]->AddOrUpdateSink(local_video_observer_.get(),
482 rtc::VideoSinkWants());
gyzhouad7cad82017-05-11 16:10:03 -0700483 }
484 }
485
486 if (!peer_connection_->AddStream(stream)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100487 RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
gyzhouad7cad82017-05-11 16:10:03 -0700488 }
489
490 typedef std::pair<std::string,
491 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
492 MediaStreamPair;
Seth Hampson13b8bad2018-03-13 16:05:28 -0700493 active_streams_.insert(MediaStreamPair(stream->id(), stream));
gyzhouad7cad82017-05-11 16:10:03 -0700494}
495
496bool SimplePeerConnection::CreateDataChannel() {
497 struct webrtc::DataChannelInit init;
498 init.ordered = true;
499 init.reliable = true;
500 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
501 if (data_channel_.get()) {
502 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100503 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700504 return true;
505 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100506 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700507 return false;
508 }
509}
510
511void SimplePeerConnection::CloseDataChannel() {
512 if (data_channel_.get()) {
513 data_channel_->UnregisterObserver();
514 data_channel_->Close();
515 }
516 data_channel_ = nullptr;
517}
518
519bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
520 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100521 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700522 return false;
523 }
524 webrtc::DataBuffer buffer(data);
525 data_channel_->Send(buffer);
526 return true;
527}
528
529// Peerconnection observer
530void SimplePeerConnection::OnDataChannel(
531 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
532 channel->RegisterObserver(this);
533}
534
535void SimplePeerConnection::OnStateChange() {
536 if (data_channel_) {
537 webrtc::DataChannelInterface::DataState state = data_channel_->state();
538 if (state == webrtc::DataChannelInterface::kOpen) {
539 if (OnLocalDataChannelReady)
540 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100541 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700542 }
543 }
544}
545
546// A data buffer was successfully received.
547void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
548 size_t size = buffer.data.size();
549 char* msg = new char[size + 1];
550 memcpy(msg, buffer.data.data(), size);
551 msg[size] = 0;
552 if (OnDataFromDataChannelReady)
553 OnDataFromDataChannelReady(msg);
554 delete[] msg;
555}
556
557// AudioTrackSinkInterface implementation.
558void SimplePeerConnection::OnData(const void* audio_data,
559 int bits_per_sample,
560 int sample_rate,
561 size_t number_of_channels,
562 size_t number_of_frames) {
563 if (OnAudioReady)
564 OnAudioReady(audio_data, bits_per_sample, sample_rate,
565 static_cast<int>(number_of_channels),
566 static_cast<int>(number_of_frames));
567}
568
569std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
570 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
571 peer_connection_->GetReceivers();
572
573 std::vector<uint32_t> ssrcs;
574 for (const auto& receiver : receivers) {
575 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
576 continue;
577
578 std::vector<webrtc::RtpEncodingParameters> params =
579 receiver->GetParameters().encodings;
580
581 for (const auto& param : params) {
582 uint32_t ssrc = param.ssrc.value_or(0);
583 if (ssrc > 0)
584 ssrcs.push_back(ssrc);
585 }
586 }
587
588 return ssrcs;
589}