blob: c5ea6f7db85a931cc71ccb637e526c71a3c10140 [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"
32#include "sdk/android/src/jni/androidvideotracksource.h"
33#include "sdk/android/src/jni/jni_helpers.h"
qiangchen42f96d52017-08-08 17:08:03 -070034#endif
35
gyzhouad7cad82017-05-11 16:10:03 -070036// Names used for media stream labels.
37const char kAudioLabel[] = "audio_label";
38const char kVideoLabel[] = "video_label";
39const char kStreamLabel[] = "stream_label";
40
41namespace {
42static int g_peer_count = 0;
43static std::unique_ptr<rtc::Thread> g_worker_thread;
44static std::unique_ptr<rtc::Thread> g_signaling_thread;
45static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
46 g_peer_connection_factory;
qiangchen42f96d52017-08-08 17:08:03 -070047#if defined(WEBRTC_ANDROID)
48// Android case: the video track does not own the capturer, and it
49// relies on the app to dispose the capturer when the peerconnection
50// shuts down.
51static jobject g_camera = nullptr;
52#endif
gyzhouad7cad82017-05-11 16:10:03 -070053
54std::string GetEnvVarOrDefault(const char* env_var_name,
55 const char* default_value) {
56 std::string value;
57 const char* env_var = getenv(env_var_name);
58 if (env_var)
59 value = env_var;
60
61 if (value.empty())
62 value = default_value;
63
64 return value;
65}
66
67std::string GetPeerConnectionString() {
68 return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
69}
70
71class DummySetSessionDescriptionObserver
72 : public webrtc::SetSessionDescriptionObserver {
73 public:
74 static DummySetSessionDescriptionObserver* Create() {
75 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
76 }
Mirko Bonadei675513b2017-11-09 11:09:25 +010077 virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; }
gyzhouad7cad82017-05-11 16:10:03 -070078 virtual void OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010079 RTC_LOG(INFO) << __FUNCTION__ << " " << error;
gyzhouad7cad82017-05-11 16:10:03 -070080 }
81
82 protected:
83 DummySetSessionDescriptionObserver() {}
84 ~DummySetSessionDescriptionObserver() {}
85};
86
87} // namespace
88
gyzhoub38f3862017-07-25 16:04:31 -070089bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls,
90 const int no_of_urls,
91 const char* username,
92 const char* credential,
93 bool is_receiver) {
gyzhouad7cad82017-05-11 16:10:03 -070094 RTC_DCHECK(peer_connection_.get() == nullptr);
95
96 if (g_peer_connection_factory == nullptr) {
97 g_worker_thread.reset(new rtc::Thread());
98 g_worker_thread->Start();
99 g_signaling_thread.reset(new rtc::Thread());
100 g_signaling_thread->Start();
101
102 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
103 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
Qiang Chen51e20462017-12-05 11:11:21 -0800104 nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
Qiang Chen43fb9122017-12-20 10:47:36 -0800105 webrtc::CreateBuiltinAudioDecoderFactory(),
106 std::unique_ptr<webrtc::VideoEncoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100107 new webrtc::MultiplexEncoderFactory(
Qiang Chen43fb9122017-12-20 10:47:36 -0800108 rtc::MakeUnique<webrtc::InternalEncoderFactory>())),
109 std::unique_ptr<webrtc::VideoDecoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100110 new webrtc::MultiplexDecoderFactory(
Qiang Chen43fb9122017-12-20 10:47:36 -0800111 rtc::MakeUnique<webrtc::InternalDecoderFactory>())),
112 nullptr, nullptr);
gyzhouad7cad82017-05-11 16:10:03 -0700113 }
114 if (!g_peer_connection_factory.get()) {
115 DeletePeerConnection();
116 return false;
117 }
118
119 g_peer_count++;
Qiang Chen51e20462017-12-05 11:11:21 -0800120 if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) {
gyzhouad7cad82017-05-11 16:10:03 -0700121 DeletePeerConnection();
122 return false;
123 }
Qiang Chen51e20462017-12-05 11:11:21 -0800124
125 mandatory_receive_ = is_receiver;
gyzhouad7cad82017-05-11 16:10:03 -0700126 return peer_connection_.get() != nullptr;
127}
128
gyzhoub38f3862017-07-25 16:04:31 -0700129bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls,
130 const int no_of_urls,
131 const char* username,
Qiang Chen51e20462017-12-05 11:11:21 -0800132 const char* credential) {
gyzhouad7cad82017-05-11 16:10:03 -0700133 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
134 RTC_DCHECK(peer_connection_.get() == nullptr);
135
gyzhoub38f3862017-07-25 16:04:31 -0700136 local_video_observer_.reset(new VideoObserver());
137 remote_video_observer_.reset(new VideoObserver());
138
139 // Add the turn server.
140 if (turn_urls != nullptr) {
141 if (no_of_urls > 0) {
142 webrtc::PeerConnectionInterface::IceServer turn_server;
143 for (int i = 0; i < no_of_urls; i++) {
144 std::string url(turn_urls[i]);
145 if (url.length() > 0)
146 turn_server.urls.push_back(turn_urls[i]);
147 }
148
149 std::string user_name(username);
150 if (user_name.length() > 0)
151 turn_server.username = username;
152
153 std::string password(credential);
154 if (password.length() > 0)
155 turn_server.password = credential;
156
157 config_.servers.push_back(turn_server);
158 }
159 }
160
161 // Add the stun server.
162 webrtc::PeerConnectionInterface::IceServer stun_server;
163 stun_server.uri = GetPeerConnectionString();
164 config_.servers.push_back(stun_server);
gyzhouad7cad82017-05-11 16:10:03 -0700165
166 webrtc::FakeConstraints constraints;
167 constraints.SetAllowDtlsSctpDataChannels();
168
gyzhouad7cad82017-05-11 16:10:03 -0700169 peer_connection_ = g_peer_connection_factory->CreatePeerConnection(
gyzhoub38f3862017-07-25 16:04:31 -0700170 config_, &constraints, nullptr, nullptr, this);
gyzhouad7cad82017-05-11 16:10:03 -0700171
172 return peer_connection_.get() != nullptr;
173}
174
175void SimplePeerConnection::DeletePeerConnection() {
176 g_peer_count--;
177
qiangchen42f96d52017-08-08 17:08:03 -0700178#if defined(WEBRTC_ANDROID)
179 if (g_camera) {
magjeda3d4f682017-08-28 16:24:06 -0700180 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700181 jclass pc_factory_class =
182 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
magjeda3d4f682017-08-28 16:24:06 -0700183 jmethodID stop_camera_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700184 env, pc_factory_class, "StopCamera", "(Lorg/webrtc/VideoCapturer;)V");
185
186 env->CallStaticVoidMethod(pc_factory_class, stop_camera_method, g_camera);
187 CHECK_EXCEPTION(env);
188
189 g_camera = nullptr;
190 }
191#endif
192
gyzhouad7cad82017-05-11 16:10:03 -0700193 CloseDataChannel();
194 peer_connection_ = nullptr;
195 active_streams_.clear();
196
197 if (g_peer_count == 0) {
198 g_peer_connection_factory = nullptr;
199 g_signaling_thread.reset();
200 g_worker_thread.reset();
201 }
202}
203
204bool SimplePeerConnection::CreateOffer() {
205 if (!peer_connection_.get())
206 return false;
207
Qiang Chen51e20462017-12-05 11:11:21 -0800208 webrtc::FakeConstraints constraints;
209 if (mandatory_receive_) {
210 constraints.SetMandatoryReceiveAudio(true);
211 constraints.SetMandatoryReceiveVideo(true);
212 }
213 peer_connection_->CreateOffer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700214 return true;
215}
216
217bool SimplePeerConnection::CreateAnswer() {
218 if (!peer_connection_.get())
219 return false;
220
Qiang Chen51e20462017-12-05 11:11:21 -0800221 webrtc::FakeConstraints constraints;
222 if (mandatory_receive_) {
223 constraints.SetMandatoryReceiveAudio(true);
224 constraints.SetMandatoryReceiveVideo(true);
225 }
226 peer_connection_->CreateAnswer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700227 return true;
228}
229
230void SimplePeerConnection::OnSuccess(
231 webrtc::SessionDescriptionInterface* desc) {
232 peer_connection_->SetLocalDescription(
233 DummySetSessionDescriptionObserver::Create(), desc);
234
235 std::string sdp;
236 desc->ToString(&sdp);
237
gyzhouad7cad82017-05-11 16:10:03 -0700238 if (OnLocalSdpReady)
gyzhoub38f3862017-07-25 16:04:31 -0700239 OnLocalSdpReady(desc->type().c_str(), sdp.c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700240}
241
242void SimplePeerConnection::OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100243 RTC_LOG(LERROR) << error;
gyzhouad7cad82017-05-11 16:10:03 -0700244
245 if (OnFailureMessage)
246 OnFailureMessage(error.c_str());
247}
248
249void SimplePeerConnection::OnIceCandidate(
250 const webrtc::IceCandidateInterface* candidate) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100251 RTC_LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
gyzhouad7cad82017-05-11 16:10:03 -0700252
gyzhouad7cad82017-05-11 16:10:03 -0700253 std::string sdp;
254 if (!candidate->ToString(&sdp)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100255 RTC_LOG(LS_ERROR) << "Failed to serialize candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700256 return;
257 }
gyzhouad7cad82017-05-11 16:10:03 -0700258
259 if (OnIceCandiateReady)
gyzhoub38f3862017-07-25 16:04:31 -0700260 OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(),
261 candidate->sdp_mid().c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700262}
263
gyzhoub38f3862017-07-25 16:04:31 -0700264void SimplePeerConnection::RegisterOnLocalI420FrameReady(
265 I420FRAMEREADY_CALLBACK callback) {
266 if (local_video_observer_)
267 local_video_observer_->SetVideoCallback(callback);
268}
269
270void SimplePeerConnection::RegisterOnRemoteI420FrameReady(
271 I420FRAMEREADY_CALLBACK callback) {
272 if (remote_video_observer_)
273 remote_video_observer_->SetVideoCallback(callback);
gyzhouad7cad82017-05-11 16:10:03 -0700274}
275
276void SimplePeerConnection::RegisterOnLocalDataChannelReady(
277 LOCALDATACHANNELREADY_CALLBACK callback) {
278 OnLocalDataChannelReady = callback;
279}
280
281void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
282 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
283 OnDataFromDataChannelReady = callback;
284}
285
286void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
287 OnFailureMessage = callback;
288}
289
290void SimplePeerConnection::RegisterOnAudioBusReady(
291 AUDIOBUSREADY_CALLBACK callback) {
292 OnAudioReady = callback;
293}
294
295void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
296 LOCALSDPREADYTOSEND_CALLBACK callback) {
297 OnLocalSdpReady = callback;
298}
299
300void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
301 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
302 OnIceCandiateReady = callback;
303}
304
gyzhoub38f3862017-07-25 16:04:31 -0700305bool SimplePeerConnection::SetRemoteDescription(const char* type,
306 const char* sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700307 if (!peer_connection_)
308 return false;
309
gyzhoub38f3862017-07-25 16:04:31 -0700310 std::string remote_desc(sdp);
311 std::string sdp_type(type);
gyzhouad7cad82017-05-11 16:10:03 -0700312 webrtc::SdpParseError error;
313 webrtc::SessionDescriptionInterface* session_description(
gyzhoub38f3862017-07-25 16:04:31 -0700314 webrtc::CreateSessionDescription(sdp_type, remote_desc, &error));
gyzhouad7cad82017-05-11 16:10:03 -0700315 if (!session_description) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100316 RTC_LOG(WARNING) << "Can't parse received session description message. "
317 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700318 return false;
319 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100320 RTC_LOG(INFO) << " Received session description :" << remote_desc;
gyzhouad7cad82017-05-11 16:10:03 -0700321 peer_connection_->SetRemoteDescription(
322 DummySetSessionDescriptionObserver::Create(), session_description);
323
324 return true;
325}
326
gyzhoub38f3862017-07-25 16:04:31 -0700327bool SimplePeerConnection::AddIceCandidate(const char* candidate,
328 const int sdp_mlineindex,
329 const char* sdp_mid) {
gyzhouad7cad82017-05-11 16:10:03 -0700330 if (!peer_connection_)
331 return false;
332
gyzhouad7cad82017-05-11 16:10:03 -0700333 webrtc::SdpParseError error;
gyzhoub38f3862017-07-25 16:04:31 -0700334 std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate(
335 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error));
336 if (!ice_candidate.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100337 RTC_LOG(WARNING) << "Can't parse received candidate message. "
338 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700339 return false;
340 }
gyzhoub38f3862017-07-25 16:04:31 -0700341 if (!peer_connection_->AddIceCandidate(ice_candidate.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100342 RTC_LOG(WARNING) << "Failed to apply the received candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700343 return false;
344 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100345 RTC_LOG(INFO) << " Received candidate :" << candidate;
gyzhouad7cad82017-05-11 16:10:03 -0700346 return true;
347}
348
349void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
350 is_mute_audio_ = is_mute;
351 is_record_audio_ = is_record;
352
353 SetAudioControl();
354}
355
356void SimplePeerConnection::SetAudioControl() {
357 if (!remote_stream_)
358 return;
359 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
360 if (tracks.empty())
361 return;
362
363 webrtc::AudioTrackInterface* audio_track = tracks[0];
364 std::string id = audio_track->id();
365 if (is_record_audio_)
366 audio_track->AddSink(this);
367 else
368 audio_track->RemoveSink(this);
369
370 for (auto& track : tracks) {
371 if (is_mute_audio_)
372 track->set_enabled(false);
373 else
374 track->set_enabled(true);
375 }
376}
377
378void SimplePeerConnection::OnAddStream(
379 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100380 RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label();
gyzhouad7cad82017-05-11 16:10:03 -0700381 remote_stream_ = stream;
gyzhoub38f3862017-07-25 16:04:31 -0700382 if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) {
383 remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink(
384 remote_video_observer_.get(), rtc::VideoSinkWants());
385 }
gyzhouad7cad82017-05-11 16:10:03 -0700386 SetAudioControl();
387}
388
389std::unique_ptr<cricket::VideoCapturer>
390SimplePeerConnection::OpenVideoCaptureDevice() {
391 std::vector<std::string> device_names;
392 {
393 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
394 webrtc::VideoCaptureFactory::CreateDeviceInfo());
395 if (!info) {
396 return nullptr;
397 }
398 int num_devices = info->NumberOfDevices();
399 for (int i = 0; i < num_devices; ++i) {
400 const uint32_t kSize = 256;
401 char name[kSize] = {0};
402 char id[kSize] = {0};
403 if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
404 device_names.push_back(name);
405 }
406 }
407 }
408
409 cricket::WebRtcVideoDeviceCapturerFactory factory;
410 std::unique_ptr<cricket::VideoCapturer> capturer;
411 for (const auto& name : device_names) {
412 capturer = factory.Create(cricket::Device(name, 0));
413 if (capturer) {
414 break;
415 }
416 }
417 return capturer;
418}
419
420void SimplePeerConnection::AddStreams(bool audio_only) {
421 if (active_streams_.find(kStreamLabel) != active_streams_.end())
422 return; // Already added.
423
424 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
425 g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel);
426
427 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
428 g_peer_connection_factory->CreateAudioTrack(
429 kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr)));
430 std::string id = audio_track->id();
431 stream->AddTrack(audio_track);
432
433 if (!audio_only) {
qiangchen42f96d52017-08-08 17:08:03 -0700434#if defined(WEBRTC_ANDROID)
magjeda3d4f682017-08-28 16:24:06 -0700435 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700436 jclass pc_factory_class =
437 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
magjeda3d4f682017-08-28 16:24:06 -0700438 jmethodID load_texture_helper_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700439 env, pc_factory_class, "LoadSurfaceTextureHelper",
440 "()Lorg/webrtc/SurfaceTextureHelper;");
441 jobject texture_helper = env->CallStaticObjectMethod(
442 pc_factory_class, load_texture_helper_method);
443 CHECK_EXCEPTION(env);
444 RTC_DCHECK(texture_helper != nullptr)
445 << "Cannot get the Surface Texture Helper.";
446
Qiang Chen51e20462017-12-05 11:11:21 -0800447 rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source(
448 new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>(
qiangchen42f96d52017-08-08 17:08:03 -0700449 g_signaling_thread.get(), env, texture_helper, false));
450 rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source =
451 webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(),
452 g_worker_thread.get(), source);
453
454 // link with VideoCapturer (Camera);
magjeda3d4f682017-08-28 16:24:06 -0700455 jmethodID link_camera_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700456 env, pc_factory_class, "LinkCamera",
457 "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;");
458 jobject camera_tmp =
459 env->CallStaticObjectMethod(pc_factory_class, link_camera_method,
460 (jlong)proxy_source.get(), texture_helper);
461 CHECK_EXCEPTION(env);
462 g_camera = (jobject)env->NewGlobalRef(camera_tmp);
463
464 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
465 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
466 proxy_source.release()));
467 stream->AddTrack(video_track);
468#else
gyzhouad7cad82017-05-11 16:10:03 -0700469 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
470 if (capture) {
471 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
472 g_peer_connection_factory->CreateVideoTrack(
473 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
gyzhoub38f3862017-07-25 16:04:31 -0700474 std::move(capture), nullptr)));
gyzhouad7cad82017-05-11 16:10:03 -0700475
476 stream->AddTrack(video_track);
qiangchen42f96d52017-08-08 17:08:03 -0700477 }
478#endif
479 if (local_video_observer_ && !stream->GetVideoTracks().empty()) {
480 stream->GetVideoTracks()[0]->AddOrUpdateSink(local_video_observer_.get(),
481 rtc::VideoSinkWants());
gyzhouad7cad82017-05-11 16:10:03 -0700482 }
483 }
484
485 if (!peer_connection_->AddStream(stream)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100486 RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
gyzhouad7cad82017-05-11 16:10:03 -0700487 }
488
489 typedef std::pair<std::string,
490 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
491 MediaStreamPair;
492 active_streams_.insert(MediaStreamPair(stream->label(), stream));
493}
494
495bool SimplePeerConnection::CreateDataChannel() {
496 struct webrtc::DataChannelInit init;
497 init.ordered = true;
498 init.reliable = true;
499 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
500 if (data_channel_.get()) {
501 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100502 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700503 return true;
504 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100505 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700506 return false;
507 }
508}
509
510void SimplePeerConnection::CloseDataChannel() {
511 if (data_channel_.get()) {
512 data_channel_->UnregisterObserver();
513 data_channel_->Close();
514 }
515 data_channel_ = nullptr;
516}
517
518bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
519 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100520 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700521 return false;
522 }
523 webrtc::DataBuffer buffer(data);
524 data_channel_->Send(buffer);
525 return true;
526}
527
528// Peerconnection observer
529void SimplePeerConnection::OnDataChannel(
530 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
531 channel->RegisterObserver(this);
532}
533
534void SimplePeerConnection::OnStateChange() {
535 if (data_channel_) {
536 webrtc::DataChannelInterface::DataState state = data_channel_->state();
537 if (state == webrtc::DataChannelInterface::kOpen) {
538 if (OnLocalDataChannelReady)
539 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100540 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700541 }
542 }
543}
544
545// A data buffer was successfully received.
546void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
547 size_t size = buffer.data.size();
548 char* msg = new char[size + 1];
549 memcpy(msg, buffer.data.data(), size);
550 msg[size] = 0;
551 if (OnDataFromDataChannelReady)
552 OnDataFromDataChannelReady(msg);
553 delete[] msg;
554}
555
556// AudioTrackSinkInterface implementation.
557void SimplePeerConnection::OnData(const void* audio_data,
558 int bits_per_sample,
559 int sample_rate,
560 size_t number_of_channels,
561 size_t number_of_frames) {
562 if (OnAudioReady)
563 OnAudioReady(audio_data, bits_per_sample, sample_rate,
564 static_cast<int>(number_of_channels),
565 static_cast<int>(number_of_frames));
566}
567
568std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
569 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
570 peer_connection_->GetReceivers();
571
572 std::vector<uint32_t> ssrcs;
573 for (const auto& receiver : receivers) {
574 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
575 continue;
576
577 std::vector<webrtc::RtpEncodingParameters> params =
578 receiver->GetParameters().encodings;
579
580 for (const auto& param : params) {
581 uint32_t ssrc = param.ssrc.value_or(0);
582 if (ssrc > 0)
583 ssrcs.push_back(ssrc);
584 }
585 }
586
587 return ssrcs;
588}