blob: 2ea8227b12e1f766db98c1b53f571921b8e5a6cb [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"
19#include "media/engine/webrtcvideocapturerfactory.h"
20#include "modules/video_capture/video_capture_factory.h"
gyzhouad7cad82017-05-11 16:10:03 -070021
qiangchen42f96d52017-08-08 17:08:03 -070022#if defined(WEBRTC_ANDROID)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "examples/unityplugin/classreferenceholder.h"
24#include "sdk/android/src/jni/androidvideotracksource.h"
25#include "sdk/android/src/jni/jni_helpers.h"
qiangchen42f96d52017-08-08 17:08:03 -070026#endif
27
gyzhouad7cad82017-05-11 16:10:03 -070028// Names used for media stream labels.
29const char kAudioLabel[] = "audio_label";
30const char kVideoLabel[] = "video_label";
31const char kStreamLabel[] = "stream_label";
32
33namespace {
34static int g_peer_count = 0;
35static std::unique_ptr<rtc::Thread> g_worker_thread;
36static std::unique_ptr<rtc::Thread> g_signaling_thread;
37static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
38 g_peer_connection_factory;
qiangchen42f96d52017-08-08 17:08:03 -070039#if defined(WEBRTC_ANDROID)
40// Android case: the video track does not own the capturer, and it
41// relies on the app to dispose the capturer when the peerconnection
42// shuts down.
43static jobject g_camera = nullptr;
44#endif
gyzhouad7cad82017-05-11 16:10:03 -070045
46std::string GetEnvVarOrDefault(const char* env_var_name,
47 const char* default_value) {
48 std::string value;
49 const char* env_var = getenv(env_var_name);
50 if (env_var)
51 value = env_var;
52
53 if (value.empty())
54 value = default_value;
55
56 return value;
57}
58
59std::string GetPeerConnectionString() {
60 return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
61}
62
63class DummySetSessionDescriptionObserver
64 : public webrtc::SetSessionDescriptionObserver {
65 public:
66 static DummySetSessionDescriptionObserver* Create() {
67 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
68 }
Mirko Bonadei675513b2017-11-09 11:09:25 +010069 virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; }
gyzhouad7cad82017-05-11 16:10:03 -070070 virtual void OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010071 RTC_LOG(INFO) << __FUNCTION__ << " " << error;
gyzhouad7cad82017-05-11 16:10:03 -070072 }
73
74 protected:
75 DummySetSessionDescriptionObserver() {}
76 ~DummySetSessionDescriptionObserver() {}
77};
78
79} // namespace
80
gyzhoub38f3862017-07-25 16:04:31 -070081bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls,
82 const int no_of_urls,
83 const char* username,
84 const char* credential,
85 bool is_receiver) {
gyzhouad7cad82017-05-11 16:10:03 -070086 RTC_DCHECK(peer_connection_.get() == nullptr);
87
88 if (g_peer_connection_factory == nullptr) {
89 g_worker_thread.reset(new rtc::Thread());
90 g_worker_thread->Start();
91 g_signaling_thread.reset(new rtc::Thread());
92 g_signaling_thread->Start();
93
94 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
95 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
Qiang Chen51e20462017-12-05 11:11:21 -080096 nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
Lu Liuec841072017-12-20 18:37:17 +000097 webrtc::CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
gyzhouad7cad82017-05-11 16:10:03 -070098 }
99 if (!g_peer_connection_factory.get()) {
100 DeletePeerConnection();
101 return false;
102 }
103
104 g_peer_count++;
Qiang Chen51e20462017-12-05 11:11:21 -0800105 if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) {
gyzhouad7cad82017-05-11 16:10:03 -0700106 DeletePeerConnection();
107 return false;
108 }
Qiang Chen51e20462017-12-05 11:11:21 -0800109
110 mandatory_receive_ = is_receiver;
gyzhouad7cad82017-05-11 16:10:03 -0700111 return peer_connection_.get() != nullptr;
112}
113
gyzhoub38f3862017-07-25 16:04:31 -0700114bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls,
115 const int no_of_urls,
116 const char* username,
Qiang Chen51e20462017-12-05 11:11:21 -0800117 const char* credential) {
gyzhouad7cad82017-05-11 16:10:03 -0700118 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
119 RTC_DCHECK(peer_connection_.get() == nullptr);
120
gyzhoub38f3862017-07-25 16:04:31 -0700121 local_video_observer_.reset(new VideoObserver());
122 remote_video_observer_.reset(new VideoObserver());
123
124 // Add the turn server.
125 if (turn_urls != nullptr) {
126 if (no_of_urls > 0) {
127 webrtc::PeerConnectionInterface::IceServer turn_server;
128 for (int i = 0; i < no_of_urls; i++) {
129 std::string url(turn_urls[i]);
130 if (url.length() > 0)
131 turn_server.urls.push_back(turn_urls[i]);
132 }
133
134 std::string user_name(username);
135 if (user_name.length() > 0)
136 turn_server.username = username;
137
138 std::string password(credential);
139 if (password.length() > 0)
140 turn_server.password = credential;
141
142 config_.servers.push_back(turn_server);
143 }
144 }
145
146 // Add the stun server.
147 webrtc::PeerConnectionInterface::IceServer stun_server;
148 stun_server.uri = GetPeerConnectionString();
149 config_.servers.push_back(stun_server);
gyzhouad7cad82017-05-11 16:10:03 -0700150
151 webrtc::FakeConstraints constraints;
152 constraints.SetAllowDtlsSctpDataChannels();
153
gyzhouad7cad82017-05-11 16:10:03 -0700154 peer_connection_ = g_peer_connection_factory->CreatePeerConnection(
gyzhoub38f3862017-07-25 16:04:31 -0700155 config_, &constraints, nullptr, nullptr, this);
gyzhouad7cad82017-05-11 16:10:03 -0700156
157 return peer_connection_.get() != nullptr;
158}
159
160void SimplePeerConnection::DeletePeerConnection() {
161 g_peer_count--;
162
qiangchen42f96d52017-08-08 17:08:03 -0700163#if defined(WEBRTC_ANDROID)
164 if (g_camera) {
magjeda3d4f682017-08-28 16:24:06 -0700165 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700166 jclass pc_factory_class =
167 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
magjeda3d4f682017-08-28 16:24:06 -0700168 jmethodID stop_camera_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700169 env, pc_factory_class, "StopCamera", "(Lorg/webrtc/VideoCapturer;)V");
170
171 env->CallStaticVoidMethod(pc_factory_class, stop_camera_method, g_camera);
172 CHECK_EXCEPTION(env);
173
174 g_camera = nullptr;
175 }
176#endif
177
gyzhouad7cad82017-05-11 16:10:03 -0700178 CloseDataChannel();
179 peer_connection_ = nullptr;
180 active_streams_.clear();
181
182 if (g_peer_count == 0) {
183 g_peer_connection_factory = nullptr;
184 g_signaling_thread.reset();
185 g_worker_thread.reset();
186 }
187}
188
189bool SimplePeerConnection::CreateOffer() {
190 if (!peer_connection_.get())
191 return false;
192
Qiang Chen51e20462017-12-05 11:11:21 -0800193 webrtc::FakeConstraints constraints;
194 if (mandatory_receive_) {
195 constraints.SetMandatoryReceiveAudio(true);
196 constraints.SetMandatoryReceiveVideo(true);
197 }
198 peer_connection_->CreateOffer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700199 return true;
200}
201
202bool SimplePeerConnection::CreateAnswer() {
203 if (!peer_connection_.get())
204 return false;
205
Qiang Chen51e20462017-12-05 11:11:21 -0800206 webrtc::FakeConstraints constraints;
207 if (mandatory_receive_) {
208 constraints.SetMandatoryReceiveAudio(true);
209 constraints.SetMandatoryReceiveVideo(true);
210 }
211 peer_connection_->CreateAnswer(this, &constraints);
gyzhouad7cad82017-05-11 16:10:03 -0700212 return true;
213}
214
215void SimplePeerConnection::OnSuccess(
216 webrtc::SessionDescriptionInterface* desc) {
217 peer_connection_->SetLocalDescription(
218 DummySetSessionDescriptionObserver::Create(), desc);
219
220 std::string sdp;
221 desc->ToString(&sdp);
222
gyzhouad7cad82017-05-11 16:10:03 -0700223 if (OnLocalSdpReady)
gyzhoub38f3862017-07-25 16:04:31 -0700224 OnLocalSdpReady(desc->type().c_str(), sdp.c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700225}
226
227void SimplePeerConnection::OnFailure(const std::string& error) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100228 RTC_LOG(LERROR) << error;
gyzhouad7cad82017-05-11 16:10:03 -0700229
230 if (OnFailureMessage)
231 OnFailureMessage(error.c_str());
232}
233
234void SimplePeerConnection::OnIceCandidate(
235 const webrtc::IceCandidateInterface* candidate) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100236 RTC_LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
gyzhouad7cad82017-05-11 16:10:03 -0700237
gyzhouad7cad82017-05-11 16:10:03 -0700238 std::string sdp;
239 if (!candidate->ToString(&sdp)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100240 RTC_LOG(LS_ERROR) << "Failed to serialize candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700241 return;
242 }
gyzhouad7cad82017-05-11 16:10:03 -0700243
244 if (OnIceCandiateReady)
gyzhoub38f3862017-07-25 16:04:31 -0700245 OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(),
246 candidate->sdp_mid().c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700247}
248
gyzhoub38f3862017-07-25 16:04:31 -0700249void SimplePeerConnection::RegisterOnLocalI420FrameReady(
250 I420FRAMEREADY_CALLBACK callback) {
251 if (local_video_observer_)
252 local_video_observer_->SetVideoCallback(callback);
253}
254
255void SimplePeerConnection::RegisterOnRemoteI420FrameReady(
256 I420FRAMEREADY_CALLBACK callback) {
257 if (remote_video_observer_)
258 remote_video_observer_->SetVideoCallback(callback);
gyzhouad7cad82017-05-11 16:10:03 -0700259}
260
261void SimplePeerConnection::RegisterOnLocalDataChannelReady(
262 LOCALDATACHANNELREADY_CALLBACK callback) {
263 OnLocalDataChannelReady = callback;
264}
265
266void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
267 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
268 OnDataFromDataChannelReady = callback;
269}
270
271void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
272 OnFailureMessage = callback;
273}
274
275void SimplePeerConnection::RegisterOnAudioBusReady(
276 AUDIOBUSREADY_CALLBACK callback) {
277 OnAudioReady = callback;
278}
279
280void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
281 LOCALSDPREADYTOSEND_CALLBACK callback) {
282 OnLocalSdpReady = callback;
283}
284
285void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
286 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
287 OnIceCandiateReady = callback;
288}
289
gyzhoub38f3862017-07-25 16:04:31 -0700290bool SimplePeerConnection::SetRemoteDescription(const char* type,
291 const char* sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700292 if (!peer_connection_)
293 return false;
294
gyzhoub38f3862017-07-25 16:04:31 -0700295 std::string remote_desc(sdp);
296 std::string sdp_type(type);
gyzhouad7cad82017-05-11 16:10:03 -0700297 webrtc::SdpParseError error;
298 webrtc::SessionDescriptionInterface* session_description(
gyzhoub38f3862017-07-25 16:04:31 -0700299 webrtc::CreateSessionDescription(sdp_type, remote_desc, &error));
gyzhouad7cad82017-05-11 16:10:03 -0700300 if (!session_description) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100301 RTC_LOG(WARNING) << "Can't parse received session description message. "
302 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700303 return false;
304 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100305 RTC_LOG(INFO) << " Received session description :" << remote_desc;
gyzhouad7cad82017-05-11 16:10:03 -0700306 peer_connection_->SetRemoteDescription(
307 DummySetSessionDescriptionObserver::Create(), session_description);
308
309 return true;
310}
311
gyzhoub38f3862017-07-25 16:04:31 -0700312bool SimplePeerConnection::AddIceCandidate(const char* candidate,
313 const int sdp_mlineindex,
314 const char* sdp_mid) {
gyzhouad7cad82017-05-11 16:10:03 -0700315 if (!peer_connection_)
316 return false;
317
gyzhouad7cad82017-05-11 16:10:03 -0700318 webrtc::SdpParseError error;
gyzhoub38f3862017-07-25 16:04:31 -0700319 std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate(
320 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error));
321 if (!ice_candidate.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100322 RTC_LOG(WARNING) << "Can't parse received candidate message. "
323 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700324 return false;
325 }
gyzhoub38f3862017-07-25 16:04:31 -0700326 if (!peer_connection_->AddIceCandidate(ice_candidate.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100327 RTC_LOG(WARNING) << "Failed to apply the received candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700328 return false;
329 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100330 RTC_LOG(INFO) << " Received candidate :" << candidate;
gyzhouad7cad82017-05-11 16:10:03 -0700331 return true;
332}
333
334void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
335 is_mute_audio_ = is_mute;
336 is_record_audio_ = is_record;
337
338 SetAudioControl();
339}
340
341void SimplePeerConnection::SetAudioControl() {
342 if (!remote_stream_)
343 return;
344 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
345 if (tracks.empty())
346 return;
347
348 webrtc::AudioTrackInterface* audio_track = tracks[0];
349 std::string id = audio_track->id();
350 if (is_record_audio_)
351 audio_track->AddSink(this);
352 else
353 audio_track->RemoveSink(this);
354
355 for (auto& track : tracks) {
356 if (is_mute_audio_)
357 track->set_enabled(false);
358 else
359 track->set_enabled(true);
360 }
361}
362
363void SimplePeerConnection::OnAddStream(
364 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100365 RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label();
gyzhouad7cad82017-05-11 16:10:03 -0700366 remote_stream_ = stream;
gyzhoub38f3862017-07-25 16:04:31 -0700367 if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) {
368 remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink(
369 remote_video_observer_.get(), rtc::VideoSinkWants());
370 }
gyzhouad7cad82017-05-11 16:10:03 -0700371 SetAudioControl();
372}
373
374std::unique_ptr<cricket::VideoCapturer>
375SimplePeerConnection::OpenVideoCaptureDevice() {
376 std::vector<std::string> device_names;
377 {
378 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
379 webrtc::VideoCaptureFactory::CreateDeviceInfo());
380 if (!info) {
381 return nullptr;
382 }
383 int num_devices = info->NumberOfDevices();
384 for (int i = 0; i < num_devices; ++i) {
385 const uint32_t kSize = 256;
386 char name[kSize] = {0};
387 char id[kSize] = {0};
388 if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
389 device_names.push_back(name);
390 }
391 }
392 }
393
394 cricket::WebRtcVideoDeviceCapturerFactory factory;
395 std::unique_ptr<cricket::VideoCapturer> capturer;
396 for (const auto& name : device_names) {
397 capturer = factory.Create(cricket::Device(name, 0));
398 if (capturer) {
399 break;
400 }
401 }
402 return capturer;
403}
404
405void SimplePeerConnection::AddStreams(bool audio_only) {
406 if (active_streams_.find(kStreamLabel) != active_streams_.end())
407 return; // Already added.
408
409 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
410 g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel);
411
412 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
413 g_peer_connection_factory->CreateAudioTrack(
414 kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr)));
415 std::string id = audio_track->id();
416 stream->AddTrack(audio_track);
417
418 if (!audio_only) {
qiangchen42f96d52017-08-08 17:08:03 -0700419#if defined(WEBRTC_ANDROID)
magjeda3d4f682017-08-28 16:24:06 -0700420 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700421 jclass pc_factory_class =
422 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
magjeda3d4f682017-08-28 16:24:06 -0700423 jmethodID load_texture_helper_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700424 env, pc_factory_class, "LoadSurfaceTextureHelper",
425 "()Lorg/webrtc/SurfaceTextureHelper;");
426 jobject texture_helper = env->CallStaticObjectMethod(
427 pc_factory_class, load_texture_helper_method);
428 CHECK_EXCEPTION(env);
429 RTC_DCHECK(texture_helper != nullptr)
430 << "Cannot get the Surface Texture Helper.";
431
Qiang Chen51e20462017-12-05 11:11:21 -0800432 rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source(
433 new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>(
qiangchen42f96d52017-08-08 17:08:03 -0700434 g_signaling_thread.get(), env, texture_helper, false));
435 rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source =
436 webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(),
437 g_worker_thread.get(), source);
438
439 // link with VideoCapturer (Camera);
magjeda3d4f682017-08-28 16:24:06 -0700440 jmethodID link_camera_method = webrtc::jni::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700441 env, pc_factory_class, "LinkCamera",
442 "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;");
443 jobject camera_tmp =
444 env->CallStaticObjectMethod(pc_factory_class, link_camera_method,
445 (jlong)proxy_source.get(), texture_helper);
446 CHECK_EXCEPTION(env);
447 g_camera = (jobject)env->NewGlobalRef(camera_tmp);
448
449 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
450 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
451 proxy_source.release()));
452 stream->AddTrack(video_track);
453#else
gyzhouad7cad82017-05-11 16:10:03 -0700454 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
455 if (capture) {
456 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
457 g_peer_connection_factory->CreateVideoTrack(
458 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
gyzhoub38f3862017-07-25 16:04:31 -0700459 std::move(capture), nullptr)));
gyzhouad7cad82017-05-11 16:10:03 -0700460
461 stream->AddTrack(video_track);
qiangchen42f96d52017-08-08 17:08:03 -0700462 }
463#endif
464 if (local_video_observer_ && !stream->GetVideoTracks().empty()) {
465 stream->GetVideoTracks()[0]->AddOrUpdateSink(local_video_observer_.get(),
466 rtc::VideoSinkWants());
gyzhouad7cad82017-05-11 16:10:03 -0700467 }
468 }
469
470 if (!peer_connection_->AddStream(stream)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100471 RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
gyzhouad7cad82017-05-11 16:10:03 -0700472 }
473
474 typedef std::pair<std::string,
475 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
476 MediaStreamPair;
477 active_streams_.insert(MediaStreamPair(stream->label(), stream));
478}
479
480bool SimplePeerConnection::CreateDataChannel() {
481 struct webrtc::DataChannelInit init;
482 init.ordered = true;
483 init.reliable = true;
484 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
485 if (data_channel_.get()) {
486 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100487 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700488 return true;
489 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100490 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700491 return false;
492 }
493}
494
495void SimplePeerConnection::CloseDataChannel() {
496 if (data_channel_.get()) {
497 data_channel_->UnregisterObserver();
498 data_channel_->Close();
499 }
500 data_channel_ = nullptr;
501}
502
503bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
504 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100505 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700506 return false;
507 }
508 webrtc::DataBuffer buffer(data);
509 data_channel_->Send(buffer);
510 return true;
511}
512
513// Peerconnection observer
514void SimplePeerConnection::OnDataChannel(
515 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
516 channel->RegisterObserver(this);
517}
518
519void SimplePeerConnection::OnStateChange() {
520 if (data_channel_) {
521 webrtc::DataChannelInterface::DataState state = data_channel_->state();
522 if (state == webrtc::DataChannelInterface::kOpen) {
523 if (OnLocalDataChannelReady)
524 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100525 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700526 }
527 }
528}
529
530// A data buffer was successfully received.
531void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
532 size_t size = buffer.data.size();
533 char* msg = new char[size + 1];
534 memcpy(msg, buffer.data.data(), size);
535 msg[size] = 0;
536 if (OnDataFromDataChannelReady)
537 OnDataFromDataChannelReady(msg);
538 delete[] msg;
539}
540
541// AudioTrackSinkInterface implementation.
542void SimplePeerConnection::OnData(const void* audio_data,
543 int bits_per_sample,
544 int sample_rate,
545 size_t number_of_channels,
546 size_t number_of_frames) {
547 if (OnAudioReady)
548 OnAudioReady(audio_data, bits_per_sample, sample_rate,
549 static_cast<int>(number_of_channels),
550 static_cast<int>(number_of_frames));
551}
552
553std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
554 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
555 peer_connection_->GetReceivers();
556
557 std::vector<uint32_t> ssrcs;
558 for (const auto& receiver : receivers) {
559 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
560 continue;
561
562 std::vector<webrtc::RtpEncodingParameters> params =
563 receiver->GetParameters().encodings;
564
565 for (const auto& param : params) {
566 uint32_t ssrc = param.ssrc.value_or(0);
567 if (ssrc > 0)
568 ssrcs.push_back(ssrc);
569 }
570 }
571
572 return ssrcs;
573}