blob: a830f91b373ab9f20dd44a38279f523e14bbe2b6 [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) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100381 RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label();
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>(
George Zhou2770c3d2018-03-07 09:58:54 -0800450 g_signaling_thread.get(), env,
451 webrtc::JavaParamRef<jobject>(texture_helper), false));
qiangchen42f96d52017-08-08 17:08:03 -0700452 rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source =
453 webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(),
454 g_worker_thread.get(), source);
455
456 // link with VideoCapturer (Camera);
George Zhou2770c3d2018-03-07 09:58:54 -0800457 jmethodID link_camera_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700458 env, pc_factory_class, "LinkCamera",
459 "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;");
460 jobject camera_tmp =
461 env->CallStaticObjectMethod(pc_factory_class, link_camera_method,
462 (jlong)proxy_source.get(), texture_helper);
463 CHECK_EXCEPTION(env);
464 g_camera = (jobject)env->NewGlobalRef(camera_tmp);
465
466 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
467 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
468 proxy_source.release()));
469 stream->AddTrack(video_track);
470#else
gyzhouad7cad82017-05-11 16:10:03 -0700471 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
472 if (capture) {
473 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
474 g_peer_connection_factory->CreateVideoTrack(
475 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
gyzhoub38f3862017-07-25 16:04:31 -0700476 std::move(capture), nullptr)));
gyzhouad7cad82017-05-11 16:10:03 -0700477
478 stream->AddTrack(video_track);
qiangchen42f96d52017-08-08 17:08:03 -0700479 }
480#endif
481 if (local_video_observer_ && !stream->GetVideoTracks().empty()) {
482 stream->GetVideoTracks()[0]->AddOrUpdateSink(local_video_observer_.get(),
483 rtc::VideoSinkWants());
gyzhouad7cad82017-05-11 16:10:03 -0700484 }
485 }
486
487 if (!peer_connection_->AddStream(stream)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100488 RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
gyzhouad7cad82017-05-11 16:10:03 -0700489 }
490
491 typedef std::pair<std::string,
492 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
493 MediaStreamPair;
494 active_streams_.insert(MediaStreamPair(stream->label(), stream));
495}
496
497bool SimplePeerConnection::CreateDataChannel() {
498 struct webrtc::DataChannelInit init;
499 init.ordered = true;
500 init.reliable = true;
501 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
502 if (data_channel_.get()) {
503 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100504 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700505 return true;
506 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100507 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700508 return false;
509 }
510}
511
512void SimplePeerConnection::CloseDataChannel() {
513 if (data_channel_.get()) {
514 data_channel_->UnregisterObserver();
515 data_channel_->Close();
516 }
517 data_channel_ = nullptr;
518}
519
520bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
521 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100522 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700523 return false;
524 }
525 webrtc::DataBuffer buffer(data);
526 data_channel_->Send(buffer);
527 return true;
528}
529
530// Peerconnection observer
531void SimplePeerConnection::OnDataChannel(
532 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
533 channel->RegisterObserver(this);
534}
535
536void SimplePeerConnection::OnStateChange() {
537 if (data_channel_) {
538 webrtc::DataChannelInterface::DataState state = data_channel_->state();
539 if (state == webrtc::DataChannelInterface::kOpen) {
540 if (OnLocalDataChannelReady)
541 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100542 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700543 }
544 }
545}
546
547// A data buffer was successfully received.
548void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
549 size_t size = buffer.data.size();
550 char* msg = new char[size + 1];
551 memcpy(msg, buffer.data.data(), size);
552 msg[size] = 0;
553 if (OnDataFromDataChannelReady)
554 OnDataFromDataChannelReady(msg);
555 delete[] msg;
556}
557
558// AudioTrackSinkInterface implementation.
559void SimplePeerConnection::OnData(const void* audio_data,
560 int bits_per_sample,
561 int sample_rate,
562 size_t number_of_channels,
563 size_t number_of_frames) {
564 if (OnAudioReady)
565 OnAudioReady(audio_data, bits_per_sample, sample_rate,
566 static_cast<int>(number_of_channels),
567 static_cast<int>(number_of_frames));
568}
569
570std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
571 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
572 peer_connection_->GetReceivers();
573
574 std::vector<uint32_t> ssrcs;
575 for (const auto& receiver : receivers) {
576 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
577 continue;
578
579 std::vector<webrtc::RtpEncodingParameters> params =
580 receiver->GetParameters().encodings;
581
582 for (const auto& param : params) {
583 uint32_t ssrc = param.ssrc.value_or(0);
584 if (ssrc > 0)
585 ssrcs.push_back(ssrc);
586 }
587 }
588
589 return ssrcs;
590}