blob: 34abbe294e2faf481f96ce0607317b475b3c3438 [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"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/engine/internal_decoder_factory.h"
20#include "media/engine/internal_encoder_factory.h"
21#include "media/engine/multiplex_codec_factory.h"
Qiang Chen43fb9122017-12-20 10:47:36 -080022#include "modules/audio_device/include/audio_device.h"
23#include "modules/audio_processing/include/audio_processing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_capture/video_capture_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "pc/video_track_source.h"
Niels Möller0a595352019-01-02 15:12:38 +010026#include "test/vcm_capturer.h"
gyzhouad7cad82017-05-11 16:10:03 -070027
qiangchen42f96d52017-08-08 17:08:03 -070028#if defined(WEBRTC_ANDROID)
Steve Anton10542f22019-01-11 09:11:00 -080029#include "examples/unityplugin/class_reference_holder.h"
George Zhou2770c3d2018-03-07 09:58:54 -080030#include "modules/utility/include/helpers_android.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "sdk/android/src/jni/android_video_track_source.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "sdk/android/src/jni/jni_helpers.h"
qiangchen42f96d52017-08-08 17:08:03 -070033#endif
34
Seth Hampson513449e2018-03-06 09:35:56 -080035// Names used for media stream ids.
gyzhouad7cad82017-05-11 16:10:03 -070036const char kAudioLabel[] = "audio_label";
37const char kVideoLabel[] = "video_label";
Seth Hampson513449e2018-03-06 09:35:56 -080038const char kStreamId[] = "stream_id";
gyzhouad7cad82017-05-11 16:10:03 -070039
40namespace {
41static int g_peer_count = 0;
42static std::unique_ptr<rtc::Thread> g_worker_thread;
43static std::unique_ptr<rtc::Thread> g_signaling_thread;
44static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
45 g_peer_connection_factory;
qiangchen42f96d52017-08-08 17:08:03 -070046#if defined(WEBRTC_ANDROID)
47// Android case: the video track does not own the capturer, and it
48// relies on the app to dispose the capturer when the peerconnection
49// shuts down.
50static jobject g_camera = nullptr;
Niels Möller0a595352019-01-02 15:12:38 +010051#else
52class CapturerTrackSource : public webrtc::VideoTrackSource {
53 public:
54 static rtc::scoped_refptr<CapturerTrackSource> Create() {
55 const size_t kWidth = 640;
56 const size_t kHeight = 480;
57 const size_t kFps = 30;
58 const size_t kDeviceIndex = 0;
59 std::unique_ptr<webrtc::test::VcmCapturer> capturer = absl::WrapUnique(
60 webrtc::test::VcmCapturer::Create(kWidth, kHeight, kFps, kDeviceIndex));
61 if (!capturer) {
62 return nullptr;
63 }
Niels Möllerac0d1832022-01-17 15:26:54 +010064 return rtc::make_ref_counted<CapturerTrackSource>(std::move(capturer));
Niels Möller0a595352019-01-02 15:12:38 +010065 }
66
67 protected:
68 explicit CapturerTrackSource(
69 std::unique_ptr<webrtc::test::VcmCapturer> capturer)
70 : VideoTrackSource(/*remote=*/false), capturer_(std::move(capturer)) {}
71
72 private:
73 rtc::VideoSourceInterface<webrtc::VideoFrame>* source() override {
74 return capturer_.get();
75 }
76 std::unique_ptr<webrtc::test::VcmCapturer> capturer_;
77};
78
qiangchen42f96d52017-08-08 17:08:03 -070079#endif
gyzhouad7cad82017-05-11 16:10:03 -070080
81std::string GetEnvVarOrDefault(const char* env_var_name,
82 const char* default_value) {
83 std::string value;
84 const char* env_var = getenv(env_var_name);
85 if (env_var)
86 value = env_var;
87
88 if (value.empty())
89 value = default_value;
90
91 return value;
92}
93
94std::string GetPeerConnectionString() {
95 return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
96}
97
98class DummySetSessionDescriptionObserver
99 : public webrtc::SetSessionDescriptionObserver {
100 public:
101 static DummySetSessionDescriptionObserver* Create() {
102 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
103 }
Harald Alvestrand97597c02021-11-04 12:01:23 +0000104 virtual void OnSuccess() { RTC_LOG(LS_INFO) << __FUNCTION__; }
Harald Alvestrand73771a82018-05-24 10:53:49 +0200105 virtual void OnFailure(webrtc::RTCError error) {
Harald Alvestrand97597c02021-11-04 12:01:23 +0000106 RTC_LOG(LS_INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": "
107 << error.message();
gyzhouad7cad82017-05-11 16:10:03 -0700108 }
109
110 protected:
111 DummySetSessionDescriptionObserver() {}
112 ~DummySetSessionDescriptionObserver() {}
113};
114
115} // namespace
116
gyzhoub38f3862017-07-25 16:04:31 -0700117bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls,
118 const int no_of_urls,
119 const char* username,
120 const char* credential,
121 bool is_receiver) {
gyzhouad7cad82017-05-11 16:10:03 -0700122 RTC_DCHECK(peer_connection_.get() == nullptr);
123
124 if (g_peer_connection_factory == nullptr) {
Niels Möller5a96a0e2019-04-30 11:45:58 +0200125 g_worker_thread = rtc::Thread::Create();
gyzhouad7cad82017-05-11 16:10:03 -0700126 g_worker_thread->Start();
Niels Möller5a96a0e2019-04-30 11:45:58 +0200127 g_signaling_thread = rtc::Thread::Create();
gyzhouad7cad82017-05-11 16:10:03 -0700128 g_signaling_thread->Start();
129
130 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
131 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
Qiang Chen51e20462017-12-05 11:11:21 -0800132 nullptr, webrtc::CreateBuiltinAudioEncoderFactory(),
Qiang Chen43fb9122017-12-20 10:47:36 -0800133 webrtc::CreateBuiltinAudioDecoderFactory(),
134 std::unique_ptr<webrtc::VideoEncoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100135 new webrtc::MultiplexEncoderFactory(
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200136 std::make_unique<webrtc::InternalEncoderFactory>())),
Qiang Chen43fb9122017-12-20 10:47:36 -0800137 std::unique_ptr<webrtc::VideoDecoderFactory>(
Anders Carlssondd8c1652018-01-30 10:32:13 +0100138 new webrtc::MultiplexDecoderFactory(
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200139 std::make_unique<webrtc::InternalDecoderFactory>())),
Qiang Chen43fb9122017-12-20 10:47:36 -0800140 nullptr, nullptr);
gyzhouad7cad82017-05-11 16:10:03 -0700141 }
142 if (!g_peer_connection_factory.get()) {
143 DeletePeerConnection();
144 return false;
145 }
146
147 g_peer_count++;
Qiang Chen51e20462017-12-05 11:11:21 -0800148 if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) {
gyzhouad7cad82017-05-11 16:10:03 -0700149 DeletePeerConnection();
150 return false;
151 }
Qiang Chen51e20462017-12-05 11:11:21 -0800152
153 mandatory_receive_ = is_receiver;
gyzhouad7cad82017-05-11 16:10:03 -0700154 return peer_connection_.get() != nullptr;
155}
156
gyzhoub38f3862017-07-25 16:04:31 -0700157bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls,
158 const int no_of_urls,
159 const char* username,
Qiang Chen51e20462017-12-05 11:11:21 -0800160 const char* credential) {
gyzhouad7cad82017-05-11 16:10:03 -0700161 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
162 RTC_DCHECK(peer_connection_.get() == nullptr);
163
gyzhoub38f3862017-07-25 16:04:31 -0700164 local_video_observer_.reset(new VideoObserver());
165 remote_video_observer_.reset(new VideoObserver());
166
167 // Add the turn server.
168 if (turn_urls != nullptr) {
169 if (no_of_urls > 0) {
170 webrtc::PeerConnectionInterface::IceServer turn_server;
171 for (int i = 0; i < no_of_urls; i++) {
172 std::string url(turn_urls[i]);
173 if (url.length() > 0)
174 turn_server.urls.push_back(turn_urls[i]);
175 }
176
177 std::string user_name(username);
178 if (user_name.length() > 0)
179 turn_server.username = username;
180
181 std::string password(credential);
182 if (password.length() > 0)
183 turn_server.password = credential;
184
185 config_.servers.push_back(turn_server);
186 }
187 }
188
189 // Add the stun server.
190 webrtc::PeerConnectionInterface::IceServer stun_server;
191 stun_server.uri = GetPeerConnectionString();
192 config_.servers.push_back(stun_server);
gyzhouad7cad82017-05-11 16:10:03 -0700193
Harald Alvestrandf33f7a22021-05-09 14:58:57 +0000194 auto result = g_peer_connection_factory->CreatePeerConnectionOrError(
195 config_, webrtc::PeerConnectionDependencies(this));
196 if (!result.ok()) {
197 peer_connection_ = nullptr;
198 return false;
199 }
200 peer_connection_ = result.MoveValue();
201 return true;
gyzhouad7cad82017-05-11 16:10:03 -0700202}
203
204void SimplePeerConnection::DeletePeerConnection() {
205 g_peer_count--;
206
qiangchen42f96d52017-08-08 17:08:03 -0700207#if defined(WEBRTC_ANDROID)
208 if (g_camera) {
magjeda3d4f682017-08-28 16:24:06 -0700209 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700210 jclass pc_factory_class =
211 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
George Zhou2770c3d2018-03-07 09:58:54 -0800212 jmethodID stop_camera_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700213 env, pc_factory_class, "StopCamera", "(Lorg/webrtc/VideoCapturer;)V");
214
215 env->CallStaticVoidMethod(pc_factory_class, stop_camera_method, g_camera);
216 CHECK_EXCEPTION(env);
217
218 g_camera = nullptr;
219 }
220#endif
221
gyzhouad7cad82017-05-11 16:10:03 -0700222 CloseDataChannel();
223 peer_connection_ = nullptr;
224 active_streams_.clear();
225
226 if (g_peer_count == 0) {
227 g_peer_connection_factory = nullptr;
228 g_signaling_thread.reset();
229 g_worker_thread.reset();
230 }
231}
232
233bool SimplePeerConnection::CreateOffer() {
234 if (!peer_connection_.get())
235 return false;
236
Niels Möllerf06f9232018-08-07 12:32:18 +0200237 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
Qiang Chen51e20462017-12-05 11:11:21 -0800238 if (mandatory_receive_) {
Niels Möllerf06f9232018-08-07 12:32:18 +0200239 options.offer_to_receive_audio = true;
240 options.offer_to_receive_video = true;
Qiang Chen51e20462017-12-05 11:11:21 -0800241 }
Niels Möllerf06f9232018-08-07 12:32:18 +0200242 peer_connection_->CreateOffer(this, options);
gyzhouad7cad82017-05-11 16:10:03 -0700243 return true;
244}
245
246bool SimplePeerConnection::CreateAnswer() {
247 if (!peer_connection_.get())
248 return false;
249
Niels Möllerf06f9232018-08-07 12:32:18 +0200250 webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
Qiang Chen51e20462017-12-05 11:11:21 -0800251 if (mandatory_receive_) {
Niels Möllerf06f9232018-08-07 12:32:18 +0200252 options.offer_to_receive_audio = true;
253 options.offer_to_receive_video = true;
Qiang Chen51e20462017-12-05 11:11:21 -0800254 }
Niels Möllerf06f9232018-08-07 12:32:18 +0200255 peer_connection_->CreateAnswer(this, options);
gyzhouad7cad82017-05-11 16:10:03 -0700256 return true;
257}
258
259void SimplePeerConnection::OnSuccess(
260 webrtc::SessionDescriptionInterface* desc) {
261 peer_connection_->SetLocalDescription(
262 DummySetSessionDescriptionObserver::Create(), desc);
263
264 std::string sdp;
265 desc->ToString(&sdp);
266
gyzhouad7cad82017-05-11 16:10:03 -0700267 if (OnLocalSdpReady)
gyzhoub38f3862017-07-25 16:04:31 -0700268 OnLocalSdpReady(desc->type().c_str(), sdp.c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700269}
270
Harald Alvestrand73771a82018-05-24 10:53:49 +0200271void SimplePeerConnection::OnFailure(webrtc::RTCError error) {
Harald Alvestrand5f341302021-11-24 10:01:32 +0000272 RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
gyzhouad7cad82017-05-11 16:10:03 -0700273
Harald Alvestrand73771a82018-05-24 10:53:49 +0200274 // TODO(hta): include error.type in the message
gyzhouad7cad82017-05-11 16:10:03 -0700275 if (OnFailureMessage)
Harald Alvestrand73771a82018-05-24 10:53:49 +0200276 OnFailureMessage(error.message());
gyzhouad7cad82017-05-11 16:10:03 -0700277}
278
279void SimplePeerConnection::OnIceCandidate(
280 const webrtc::IceCandidateInterface* candidate) {
Harald Alvestrand97597c02021-11-04 12:01:23 +0000281 RTC_LOG(LS_INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
gyzhouad7cad82017-05-11 16:10:03 -0700282
gyzhouad7cad82017-05-11 16:10:03 -0700283 std::string sdp;
284 if (!candidate->ToString(&sdp)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100285 RTC_LOG(LS_ERROR) << "Failed to serialize candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700286 return;
287 }
gyzhouad7cad82017-05-11 16:10:03 -0700288
289 if (OnIceCandiateReady)
gyzhoub38f3862017-07-25 16:04:31 -0700290 OnIceCandiateReady(sdp.c_str(), candidate->sdp_mline_index(),
291 candidate->sdp_mid().c_str());
gyzhouad7cad82017-05-11 16:10:03 -0700292}
293
gyzhoub38f3862017-07-25 16:04:31 -0700294void SimplePeerConnection::RegisterOnLocalI420FrameReady(
295 I420FRAMEREADY_CALLBACK callback) {
296 if (local_video_observer_)
297 local_video_observer_->SetVideoCallback(callback);
298}
299
300void SimplePeerConnection::RegisterOnRemoteI420FrameReady(
301 I420FRAMEREADY_CALLBACK callback) {
302 if (remote_video_observer_)
303 remote_video_observer_->SetVideoCallback(callback);
gyzhouad7cad82017-05-11 16:10:03 -0700304}
305
306void SimplePeerConnection::RegisterOnLocalDataChannelReady(
307 LOCALDATACHANNELREADY_CALLBACK callback) {
308 OnLocalDataChannelReady = callback;
309}
310
311void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
312 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
313 OnDataFromDataChannelReady = callback;
314}
315
316void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
317 OnFailureMessage = callback;
318}
319
320void SimplePeerConnection::RegisterOnAudioBusReady(
321 AUDIOBUSREADY_CALLBACK callback) {
322 OnAudioReady = callback;
323}
324
325void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
326 LOCALSDPREADYTOSEND_CALLBACK callback) {
327 OnLocalSdpReady = callback;
328}
329
330void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
331 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
332 OnIceCandiateReady = callback;
333}
334
gyzhoub38f3862017-07-25 16:04:31 -0700335bool SimplePeerConnection::SetRemoteDescription(const char* type,
336 const char* sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700337 if (!peer_connection_)
338 return false;
339
gyzhoub38f3862017-07-25 16:04:31 -0700340 std::string remote_desc(sdp);
Philipp Hanckedd680632020-09-10 17:22:16 +0200341 std::string desc_type(type);
gyzhouad7cad82017-05-11 16:10:03 -0700342 webrtc::SdpParseError error;
343 webrtc::SessionDescriptionInterface* session_description(
Philipp Hanckedd680632020-09-10 17:22:16 +0200344 webrtc::CreateSessionDescription(desc_type, remote_desc, &error));
gyzhouad7cad82017-05-11 16:10:03 -0700345 if (!session_description) {
Harald Alvestrandef5b21e2021-11-27 21:31:08 +0000346 RTC_LOG(LS_WARNING) << "Can't parse received session description message. "
347 "SdpParseError was: "
348 << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700349 return false;
350 }
Harald Alvestrand97597c02021-11-04 12:01:23 +0000351 RTC_LOG(LS_INFO) << " Received session description :" << remote_desc;
gyzhouad7cad82017-05-11 16:10:03 -0700352 peer_connection_->SetRemoteDescription(
353 DummySetSessionDescriptionObserver::Create(), session_description);
354
355 return true;
356}
357
gyzhoub38f3862017-07-25 16:04:31 -0700358bool SimplePeerConnection::AddIceCandidate(const char* candidate,
359 const int sdp_mlineindex,
360 const char* sdp_mid) {
gyzhouad7cad82017-05-11 16:10:03 -0700361 if (!peer_connection_)
362 return false;
363
gyzhouad7cad82017-05-11 16:10:03 -0700364 webrtc::SdpParseError error;
gyzhoub38f3862017-07-25 16:04:31 -0700365 std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate(
366 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate, &error));
367 if (!ice_candidate.get()) {
Harald Alvestrandef5b21e2021-11-27 21:31:08 +0000368 RTC_LOG(LS_WARNING) << "Can't parse received candidate message. "
369 "SdpParseError was: "
370 << error.description;
gyzhouad7cad82017-05-11 16:10:03 -0700371 return false;
372 }
gyzhoub38f3862017-07-25 16:04:31 -0700373 if (!peer_connection_->AddIceCandidate(ice_candidate.get())) {
Harald Alvestrandef5b21e2021-11-27 21:31:08 +0000374 RTC_LOG(LS_WARNING) << "Failed to apply the received candidate";
gyzhouad7cad82017-05-11 16:10:03 -0700375 return false;
376 }
Harald Alvestrand97597c02021-11-04 12:01:23 +0000377 RTC_LOG(LS_INFO) << " Received candidate :" << candidate;
gyzhouad7cad82017-05-11 16:10:03 -0700378 return true;
379}
380
381void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
382 is_mute_audio_ = is_mute;
383 is_record_audio_ = is_record;
384
385 SetAudioControl();
386}
387
388void SimplePeerConnection::SetAudioControl() {
389 if (!remote_stream_)
390 return;
391 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
392 if (tracks.empty())
393 return;
394
395 webrtc::AudioTrackInterface* audio_track = tracks[0];
396 std::string id = audio_track->id();
397 if (is_record_audio_)
398 audio_track->AddSink(this);
399 else
400 audio_track->RemoveSink(this);
401
402 for (auto& track : tracks) {
403 if (is_mute_audio_)
404 track->set_enabled(false);
405 else
406 track->set_enabled(true);
407 }
408}
409
410void SimplePeerConnection::OnAddStream(
411 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
Harald Alvestrand97597c02021-11-04 12:01:23 +0000412 RTC_LOG(LS_INFO) << __FUNCTION__ << " " << stream->id();
gyzhouad7cad82017-05-11 16:10:03 -0700413 remote_stream_ = stream;
gyzhoub38f3862017-07-25 16:04:31 -0700414 if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) {
415 remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink(
416 remote_video_observer_.get(), rtc::VideoSinkWants());
417 }
gyzhouad7cad82017-05-11 16:10:03 -0700418 SetAudioControl();
419}
420
gyzhouad7cad82017-05-11 16:10:03 -0700421void 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(
Niels Möller2d02e082018-05-21 11:23:35 +0200430 kAudioLabel, g_peer_connection_factory->CreateAudioSource(
431 cricket::AudioOptions())));
gyzhouad7cad82017-05-11 16:10:03 -0700432 std::string id = audio_track->id();
433 stream->AddTrack(audio_track);
434
435 if (!audio_only) {
qiangchen42f96d52017-08-08 17:08:03 -0700436#if defined(WEBRTC_ANDROID)
magjeda3d4f682017-08-28 16:24:06 -0700437 JNIEnv* env = webrtc::jni::GetEnv();
qiangchen42f96d52017-08-08 17:08:03 -0700438 jclass pc_factory_class =
439 unity_plugin::FindClass(env, "org/webrtc/UnityUtility");
George Zhou2770c3d2018-03-07 09:58:54 -0800440 jmethodID load_texture_helper_method = webrtc::GetStaticMethodID(
qiangchen42f96d52017-08-08 17:08:03 -0700441 env, pc_factory_class, "LoadSurfaceTextureHelper",
442 "()Lorg/webrtc/SurfaceTextureHelper;");
443 jobject texture_helper = env->CallStaticObjectMethod(
444 pc_factory_class, load_texture_helper_method);
445 CHECK_EXCEPTION(env);
446 RTC_DCHECK(texture_helper != nullptr)
447 << "Cannot get the Surface Texture Helper.";
448
Qiang Chen51e20462017-12-05 11:11:21 -0800449 rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source(
450 new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>(
Magnus Jedvert95140712018-11-15 12:07:32 +0100451 g_signaling_thread.get(), env, /* is_screencast= */ false,
452 /* align_timestamps= */ true));
qiangchen42f96d52017-08-08 17:08:03 -0700453
454 // link with VideoCapturer (Camera);
George Zhou2770c3d2018-03-07 09:58:54 -0800455 jmethodID link_camera_method = webrtc::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,
Magnus Jedvert167316b2019-01-31 13:23:46 +0100460 (jlong)source.get(), texture_helper);
qiangchen42f96d52017-08-08 17:08:03 -0700461 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,
Magnus Jedvert167316b2019-01-31 13:23:46 +0100466 source.release()));
qiangchen42f96d52017-08-08 17:08:03 -0700467 stream->AddTrack(video_track);
468#else
Niels Möller0a595352019-01-02 15:12:38 +0100469 rtc::scoped_refptr<CapturerTrackSource> video_device =
470 CapturerTrackSource::Create();
471 if (video_device) {
gyzhouad7cad82017-05-11 16:10:03 -0700472 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
Niels Möller0a595352019-01-02 15:12:38 +0100473 g_peer_connection_factory->CreateVideoTrack(kVideoLabel,
474 video_device));
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;
Seth Hampson13b8bad2018-03-13 16:05:28 -0700492 active_streams_.insert(MediaStreamPair(stream->id(), stream));
gyzhouad7cad82017-05-11 16:10:03 -0700493}
494
495bool SimplePeerConnection::CreateDataChannel() {
496 struct webrtc::DataChannelInit init;
497 init.ordered = true;
498 init.reliable = true;
Harald Alvestranda9af50f2021-05-21 13:33:51 +0000499 auto result = peer_connection_->CreateDataChannelOrError("Hello", &init);
500 if (result.ok()) {
501 data_channel_ = result.MoveValue();
gyzhouad7cad82017-05-11 16:10:03 -0700502 data_channel_->RegisterObserver(this);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100503 RTC_LOG(LS_INFO) << "Succeeds to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700504 return true;
505 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100506 RTC_LOG(LS_INFO) << "Fails to create data channel";
gyzhouad7cad82017-05-11 16:10:03 -0700507 return false;
508 }
509}
510
511void SimplePeerConnection::CloseDataChannel() {
512 if (data_channel_.get()) {
513 data_channel_->UnregisterObserver();
514 data_channel_->Close();
515 }
516 data_channel_ = nullptr;
517}
518
519bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
520 if (!data_channel_.get()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100521 RTC_LOG(LS_INFO) << "Data channel is not established";
gyzhouad7cad82017-05-11 16:10:03 -0700522 return false;
523 }
524 webrtc::DataBuffer buffer(data);
525 data_channel_->Send(buffer);
526 return true;
527}
528
529// Peerconnection observer
530void SimplePeerConnection::OnDataChannel(
531 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
532 channel->RegisterObserver(this);
533}
534
535void SimplePeerConnection::OnStateChange() {
536 if (data_channel_) {
537 webrtc::DataChannelInterface::DataState state = data_channel_->state();
538 if (state == webrtc::DataChannelInterface::kOpen) {
539 if (OnLocalDataChannelReady)
540 OnLocalDataChannelReady();
Mirko Bonadei675513b2017-11-09 11:09:25 +0100541 RTC_LOG(LS_INFO) << "Data channel is open";
gyzhouad7cad82017-05-11 16:10:03 -0700542 }
543 }
544}
545
546// A data buffer was successfully received.
547void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
548 size_t size = buffer.data.size();
549 char* msg = new char[size + 1];
550 memcpy(msg, buffer.data.data(), size);
551 msg[size] = 0;
552 if (OnDataFromDataChannelReady)
553 OnDataFromDataChannelReady(msg);
554 delete[] msg;
555}
556
557// AudioTrackSinkInterface implementation.
558void SimplePeerConnection::OnData(const void* audio_data,
559 int bits_per_sample,
560 int sample_rate,
561 size_t number_of_channels,
562 size_t number_of_frames) {
563 if (OnAudioReady)
564 OnAudioReady(audio_data, bits_per_sample, sample_rate,
565 static_cast<int>(number_of_channels),
566 static_cast<int>(number_of_frames));
567}
568
569std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
570 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
571 peer_connection_->GetReceivers();
572
573 std::vector<uint32_t> ssrcs;
574 for (const auto& receiver : receivers) {
575 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
576 continue;
577
578 std::vector<webrtc::RtpEncodingParameters> params =
579 receiver->GetParameters().encodings;
580
581 for (const auto& param : params) {
582 uint32_t ssrc = param.ssrc.value_or(0);
583 if (ssrc > 0)
584 ssrcs.push_back(ssrc);
585 }
586 }
587
588 return ssrcs;
589}