blob: bf6a6827b03071cf6648b7a1f2948bf48156514b [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
Karl Wiberg918f50c2018-07-05 11:40:33 +020015#include "absl/memory/memory.h"
Qiang Chen51e20462017-12-05 11:11:21 -080016#include "api/audio_codecs/builtin_audio_decoder_factory.h"
17#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010018#include "api/create_peerconnection_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/videosourceproxy.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080020#include "media/engine/internaldecoderfactory.h"
21#include "media/engine/internalencoderfactory.h"
Anders Carlssondd8c1652018-01-30 10:32:13 +010022#include "media/engine/multiplexcodecfactory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "media/engine/webrtcvideocapturerfactory.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080024#include "media/engine/webrtcvideodecoderfactory.h"
25#include "media/engine/webrtcvideoencoderfactory.h"
26#include "modules/audio_device/include/audio_device.h"
27#include "modules/audio_processing/include/audio_processing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "modules/video_capture/video_capture_factory.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__; }
Harald Alvestrand73771a82018-05-24 10:53:49 +020079 virtual void OnFailure(webrtc::RTCError error) {
80 RTC_LOG(INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": "
81 << error.message();
gyzhouad7cad82017-05-11 16:10:03 -070082 }
83
84 protected:
85 DummySetSessionDescriptionObserver() {}
86 ~DummySetSessionDescriptionObserver() {}
87};
88
89} // namespace
90
gyzhoub38f3862017-07-25 16:04:31 -070091bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls,
92 const int no_of_urls,
93 const char* username,
94 const char* credential,
95 bool is_receiver) {
gyzhouad7cad82017-05-11 16:10:03 -070096 RTC_DCHECK(peer_connection_.get() == nullptr);
97
98 if (g_peer_connection_factory == nullptr) {
99 g_worker_thread.reset(new rtc::Thread());
100 g_worker_thread->Start();
101 g_signaling_thread.reset(new rtc::Thread());
102 g_signaling_thread->Start();
103
104 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
105 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
Qiang Chen51e20462017-12-05 11:11:21 -0800106 nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
Qiang Chen43fb9122017-12-20 10:47:36 -0800107 webrtc::CreateBuiltinAudioDecoderFactory(),
108 std::unique_ptr<webrtc::VideoEncoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100109 new webrtc::MultiplexEncoderFactory(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200110 absl::make_unique<webrtc::InternalEncoderFactory>())),
Qiang Chen43fb9122017-12-20 10:47:36 -0800111 std::unique_ptr<webrtc::VideoDecoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100112 new webrtc::MultiplexDecoderFactory(
Karl Wiberg918f50c2018-07-05 11:40:33 +0200113 absl::make_unique<webrtc::InternalDecoderFactory>())),
Qiang Chen43fb9122017-12-20 10:47:36 -0800114 nullptr, nullptr);
gyzhouad7cad82017-05-11 16:10:03 -0700115 }
116 if (!g_peer_connection_factory.get()) {
117 DeletePeerConnection();
118 return false;
119 }
120
121 g_peer_count++;
Qiang Chen51e20462017-12-05 11:11:21 -0800122 if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) {
gyzhouad7cad82017-05-11 16:10:03 -0700123 DeletePeerConnection();
124 return false;
125 }
Qiang Chen51e20462017-12-05 11:11:21 -0800126
127 mandatory_receive_ = is_receiver;
gyzhouad7cad82017-05-11 16:10:03 -0700128 return peer_connection_.get() != nullptr;
129}
130
gyzhoub38f3862017-07-25 16:04:31 -0700131bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls,
132 const int no_of_urls,
133 const char* username,
Qiang Chen51e20462017-12-05 11:11:21 -0800134 const char* credential) {
gyzhouad7cad82017-05-11 16:10:03 -0700135 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
136 RTC_DCHECK(peer_connection_.get() == nullptr);
137
gyzhoub38f3862017-07-25 16:04:31 -0700138 local_video_observer_.reset(new VideoObserver());
139 remote_video_observer_.reset(new VideoObserver());
140
141 // Add the turn server.
142 if (turn_urls != nullptr) {
143 if (no_of_urls > 0) {
144 webrtc::PeerConnectionInterface::IceServer turn_server;
145 for (int i = 0; i < no_of_urls; i++) {
146 std::string url(turn_urls[i]);
147 if (url.length() > 0)
148 turn_server.urls.push_back(turn_urls[i]);
149 }
150
151 std::string user_name(username);
152 if (user_name.length() > 0)
153 turn_server.username = username;
154
155 std::string password(credential);
156 if (password.length() > 0)
157 turn_server.password = credential;
158
159 config_.servers.push_back(turn_server);
160 }
161 }
162
163 // Add the stun server.
164 webrtc::PeerConnectionInterface::IceServer stun_server;
165 stun_server.uri = GetPeerConnectionString();
166 config_.servers.push_back(stun_server);
Niels Möllerf06f9232018-08-07 12:32:18 +0200167 config_.enable_rtp_data_channel = true;
168 config_.enable_dtls_srtp = false;
gyzhouad7cad82017-05-11 16:10:03 -0700169
gyzhouad7cad82017-05-11 16:10:03 -0700170 peer_connection_ = g_peer_connection_factory->CreatePeerConnection(
Niels Möllerf06f9232018-08-07 12:32:18 +0200171 config_, 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
Niels Möllerf06f9232018-08-07 12:32:18 +0200209 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
Qiang Chen51e20462017-12-05 11:11:21 -0800210 if (mandatory_receive_) {
Niels Möllerf06f9232018-08-07 12:32:18 +0200211 options.offer_to_receive_audio = true;
212 options.offer_to_receive_video = true;
Qiang Chen51e20462017-12-05 11:11:21 -0800213 }
Niels Möllerf06f9232018-08-07 12:32:18 +0200214 peer_connection_->CreateOffer(this, options);
gyzhouad7cad82017-05-11 16:10:03 -0700215 return true;
216}
217
218bool SimplePeerConnection::CreateAnswer() {
219 if (!peer_connection_.get())
220 return false;
221
Niels Möllerf06f9232018-08-07 12:32:18 +0200222 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
Qiang Chen51e20462017-12-05 11:11:21 -0800223 if (mandatory_receive_) {
Niels Möllerf06f9232018-08-07 12:32:18 +0200224 options.offer_to_receive_audio = true;
225 options.offer_to_receive_video = true;
Qiang Chen51e20462017-12-05 11:11:21 -0800226 }
Niels Möllerf06f9232018-08-07 12:32:18 +0200227 peer_connection_->CreateAnswer(this, options);
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
Harald Alvestrand73771a82018-05-24 10:53:49 +0200243void SimplePeerConnection::OnFailure(webrtc::RTCError error) {
244 RTC_LOG(LERROR) << ToString(error.type()) << ": " << error.message();
gyzhouad7cad82017-05-11 16:10:03 -0700245
Harald Alvestrand73771a82018-05-24 10:53:49 +0200246 // TODO(hta): include error.type in the message
gyzhouad7cad82017-05-11 16:10:03 -0700247 if (OnFailureMessage)
Harald Alvestrand73771a82018-05-24 10:53:49 +0200248 OnFailureMessage(error.message());
gyzhouad7cad82017-05-11 16:10:03 -0700249}
250
251void SimplePeerConnection::OnIceCandidate(
252 const webrtc::IceCandidateInterface* candidate) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100253 RTC_LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
gyzhouad7cad82017-05-11 16:10:03 -0700254
gyzhouad7cad82017-05-11 16:10:03 -0700255 std::string sdp;
256 if (!candidate->ToString(&sdp)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100257 RTC_LOG(LS_ERROR) << "Failed to serialize candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700258 return;
259 }
gyzhouad7cad82017-05-11 16:10:03 -0700260
261 if (OnIceCandiateReady)
gyzhoub38f3862017-07-25 16:04:31 -0700262 OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(),
263 candidate->sdp_mid().c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700264}
265
gyzhoub38f3862017-07-25 16:04:31 -0700266void SimplePeerConnection::RegisterOnLocalI420FrameReady(
267 I420FRAMEREADY_CALLBACK callback) {
268 if (local_video_observer_)
269 local_video_observer_->SetVideoCallback(callback);
270}
271
272void SimplePeerConnection::RegisterOnRemoteI420FrameReady(
273 I420FRAMEREADY_CALLBACK callback) {
274 if (remote_video_observer_)
275 remote_video_observer_->SetVideoCallback(callback);
gyzhouad7cad82017-05-11 16:10:03 -0700276}
277
278void SimplePeerConnection::RegisterOnLocalDataChannelReady(
279 LOCALDATACHANNELREADY_CALLBACK callback) {
280 OnLocalDataChannelReady = callback;
281}
282
283void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
284 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
285 OnDataFromDataChannelReady = callback;
286}
287
288void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
289 OnFailureMessage = callback;
290}
291
292void SimplePeerConnection::RegisterOnAudioBusReady(
293 AUDIOBUSREADY_CALLBACK callback) {
294 OnAudioReady = callback;
295}
296
297void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
298 LOCALSDPREADYTOSEND_CALLBACK callback) {
299 OnLocalSdpReady = callback;
300}
301
302void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
303 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
304 OnIceCandiateReady = callback;
305}
306
gyzhoub38f3862017-07-25 16:04:31 -0700307bool SimplePeerConnection::SetRemoteDescription(const char* type,
308 const char* sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700309 if (!peer_connection_)
310 return false;
311
gyzhoub38f3862017-07-25 16:04:31 -0700312 std::string remote_desc(sdp);
313 std::string sdp_type(type);
gyzhouad7cad82017-05-11 16:10:03 -0700314 webrtc::SdpParseError error;
315 webrtc::SessionDescriptionInterface* session_description(
gyzhoub38f3862017-07-25 16:04:31 -0700316 webrtc::CreateSessionDescription(sdp_type, remote_desc, &error));
gyzhouad7cad82017-05-11 16:10:03 -0700317 if (!session_description) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100318 RTC_LOG(WARNING) << "Can't parse received session description message. "
319 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700320 return false;
321 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100322 RTC_LOG(INFO) << " Received session description :" << remote_desc;
gyzhouad7cad82017-05-11 16:10:03 -0700323 peer_connection_->SetRemoteDescription(
324 DummySetSessionDescriptionObserver::Create(), session_description);
325
326 return true;
327}
328
gyzhoub38f3862017-07-25 16:04:31 -0700329bool SimplePeerConnection::AddIceCandidate(const char* candidate,
330 const int sdp_mlineindex,
331 const char* sdp_mid) {
gyzhouad7cad82017-05-11 16:10:03 -0700332 if (!peer_connection_)
333 return false;
334
gyzhouad7cad82017-05-11 16:10:03 -0700335 webrtc::SdpParseError error;
gyzhoub38f3862017-07-25 16:04:31 -0700336 std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate(
337 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error));
338 if (!ice_candidate.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100339 RTC_LOG(WARNING) << "Can't parse received candidate message. "
340 << "SdpParseError was: " << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700341 return false;
342 }
gyzhoub38f3862017-07-25 16:04:31 -0700343 if (!peer_connection_->AddIceCandidate(ice_candidate.get())) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100344 RTC_LOG(WARNING) << "Failed to apply the received candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700345 return false;
346 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100347 RTC_LOG(INFO) << " Received candidate :" << candidate;
gyzhouad7cad82017-05-11 16:10:03 -0700348 return true;
349}
350
351void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
352 is_mute_audio_ = is_mute;
353 is_record_audio_ = is_record;
354
355 SetAudioControl();
356}
357
358void SimplePeerConnection::SetAudioControl() {
359 if (!remote_stream_)
360 return;
361 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
362 if (tracks.empty())
363 return;
364
365 webrtc::AudioTrackInterface* audio_track = tracks[0];
366 std::string id = audio_track->id();
367 if (is_record_audio_)
368 audio_track->AddSink(this);
369 else
370 audio_track->RemoveSink(this);
371
372 for (auto& track : tracks) {
373 if (is_mute_audio_)
374 track->set_enabled(false);
375 else
376 track->set_enabled(true);
377 }
378}
379
380void SimplePeerConnection::OnAddStream(
381 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
Seth Hampson13b8bad2018-03-13 16:05:28 -0700382 RTC_LOG(INFO) << __FUNCTION__ << " " << stream->id();
gyzhouad7cad82017-05-11 16:10:03 -0700383 remote_stream_ = stream;
gyzhoub38f3862017-07-25 16:04:31 -0700384 if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) {
385 remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink(
386 remote_video_observer_.get(), rtc::VideoSinkWants());
387 }
gyzhouad7cad82017-05-11 16:10:03 -0700388 SetAudioControl();
389}
390
391std::unique_ptr<cricket::VideoCapturer>
392SimplePeerConnection::OpenVideoCaptureDevice() {
393 std::vector<std::string> device_names;
394 {
395 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
396 webrtc::VideoCaptureFactory::CreateDeviceInfo());
397 if (!info) {
398 return nullptr;
399 }
400 int num_devices = info->NumberOfDevices();
401 for (int i = 0; i < num_devices; ++i) {
402 const uint32_t kSize = 256;
403 char name[kSize] = {0};
404 char id[kSize] = {0};
405 if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
406 device_names.push_back(name);
407 }
408 }
409 }
410
411 cricket::WebRtcVideoDeviceCapturerFactory factory;
412 std::unique_ptr<cricket::VideoCapturer> capturer;
413 for (const auto& name : device_names) {
414 capturer = factory.Create(cricket::Device(name, 0));
415 if (capturer) {
416 break;
417 }
418 }
419 return capturer;
420}
421
422void SimplePeerConnection::AddStreams(bool audio_only) {
Seth Hampson513449e2018-03-06 09:35:56 -0800423 if (active_streams_.find(kStreamId) != active_streams_.end())
gyzhouad7cad82017-05-11 16:10:03 -0700424 return; // Already added.
425
426 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
Seth Hampson513449e2018-03-06 09:35:56 -0800427 g_peer_connection_factory->CreateLocalMediaStream(kStreamId);
gyzhouad7cad82017-05-11 16:10:03 -0700428
429 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
430 g_peer_connection_factory->CreateAudioTrack(
Niels Möller2d02e082018-05-21 11:23:35 +0200431 kAudioLabel, g_peer_connection_factory->CreateAudioSource(
432 cricket::AudioOptions())));
gyzhouad7cad82017-05-11 16:10:03 -0700433 std::string id = audio_track->id();
434 stream->AddTrack(audio_track);
435
436 if (!audio_only) {
qiangchen42f96d52017-08-08 17:08:03 -0700437#if defined(WEBRTC_ANDROID)
magjeda3d4f682017-08-28 16:24:06 -0700438 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700439 jclass pc_factory_class =
440 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
George Zhou2770c3d2018-03-07 09:58:54 -0800441 jmethodID load_texture_helper_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700442 env, pc_factory_class, "LoadSurfaceTextureHelper",
443 "()Lorg/webrtc/SurfaceTextureHelper;");
444 jobject texture_helper = env->CallStaticObjectMethod(
445 pc_factory_class, load_texture_helper_method);
446 CHECK_EXCEPTION(env);
447 RTC_DCHECK(texture_helper != nullptr)
448 << "Cannot get the Surface Texture Helper.";
449
Qiang Chen51e20462017-12-05 11:11:21 -0800450 rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source(
451 new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>(
Magnus Jedvert95140712018-11-15 12:07:32 +0100452 g_signaling_thread.get(), env, /* is_screencast= */ false,
453 /* align_timestamps= */ true));
qiangchen42f96d52017-08-08 17:08:03 -0700454 rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source =
455 webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(),
456 g_worker_thread.get(), source);
457
458 // link with VideoCapturer (Camera);
George Zhou2770c3d2018-03-07 09:58:54 -0800459 jmethodID link_camera_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700460 env, pc_factory_class, "LinkCamera",
461 "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;");
462 jobject camera_tmp =
463 env->CallStaticObjectMethod(pc_factory_class, link_camera_method,
464 (jlong)proxy_source.get(), texture_helper);
465 CHECK_EXCEPTION(env);
466 g_camera = (jobject)env->NewGlobalRef(camera_tmp);
467
468 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
469 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
470 proxy_source.release()));
471 stream->AddTrack(video_track);
472#else
gyzhouad7cad82017-05-11 16:10:03 -0700473 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
474 if (capture) {
475 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
476 g_peer_connection_factory->CreateVideoTrack(
477 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
gyzhoub38f3862017-07-25 16:04:31 -0700478 std::move(capture), nullptr)));
gyzhouad7cad82017-05-11 16:10:03 -0700479
480 stream->AddTrack(video_track);
qiangchen42f96d52017-08-08 17:08:03 -0700481 }
482#endif
483 if (local_video_observer_ && !stream->GetVideoTracks().empty()) {
484 stream->GetVideoTracks()[0]->AddOrUpdateSink(local_video_observer_.get(),
485 rtc::VideoSinkWants());
gyzhouad7cad82017-05-11 16:10:03 -0700486 }
487 }
488
489 if (!peer_connection_->AddStream(stream)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100490 RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
gyzhouad7cad82017-05-11 16:10:03 -0700491 }
492
493 typedef std::pair<std::string,
494 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
495 MediaStreamPair;
Seth Hampson13b8bad2018-03-13 16:05:28 -0700496 active_streams_.insert(MediaStreamPair(stream->id(), stream));
gyzhouad7cad82017-05-11 16:10:03 -0700497}
498
499bool SimplePeerConnection::CreateDataChannel() {
500 struct webrtc::DataChannelInit init;
501 init.ordered = true;
502 init.reliable = true;
503 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
504 if (data_channel_.get()) {
505 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100506 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700507 return true;
508 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100509 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700510 return false;
511 }
512}
513
514void SimplePeerConnection::CloseDataChannel() {
515 if (data_channel_.get()) {
516 data_channel_->UnregisterObserver();
517 data_channel_->Close();
518 }
519 data_channel_ = nullptr;
520}
521
522bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
523 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100524 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700525 return false;
526 }
527 webrtc::DataBuffer buffer(data);
528 data_channel_->Send(buffer);
529 return true;
530}
531
532// Peerconnection observer
533void SimplePeerConnection::OnDataChannel(
534 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
535 channel->RegisterObserver(this);
536}
537
538void SimplePeerConnection::OnStateChange() {
539 if (data_channel_) {
540 webrtc::DataChannelInterface::DataState state = data_channel_->state();
541 if (state == webrtc::DataChannelInterface::kOpen) {
542 if (OnLocalDataChannelReady)
543 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100544 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700545 }
546 }
547}
548
549// A data buffer was successfully received.
550void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
551 size_t size = buffer.data.size();
552 char* msg = new char[size + 1];
553 memcpy(msg, buffer.data.data(), size);
554 msg[size] = 0;
555 if (OnDataFromDataChannelReady)
556 OnDataFromDataChannelReady(msg);
557 delete[] msg;
558}
559
560// AudioTrackSinkInterface implementation.
561void SimplePeerConnection::OnData(const void* audio_data,
562 int bits_per_sample,
563 int sample_rate,
564 size_t number_of_channels,
565 size_t number_of_frames) {
566 if (OnAudioReady)
567 OnAudioReady(audio_data, bits_per_sample, sample_rate,
568 static_cast<int>(number_of_channels),
569 static_cast<int>(number_of_frames));
570}
571
572std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
573 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
574 peer_connection_->GetReceivers();
575
576 std::vector<uint32_t> ssrcs;
577 for (const auto& receiver : receivers) {
578 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
579 continue;
580
581 std::vector<webrtc::RtpEncodingParameters> params =
582 receiver->GetParameters().encodings;
583
584 for (const auto& param : params) {
585 uint32_t ssrc = param.ssrc.value_or(0);
586 if (ssrc > 0)
587 ssrcs.push_back(ssrc);
588 }
589 }
590
591 return ssrcs;
592}