Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: webrtc/examples/unityplugin/simple_peer_connection.cc

Issue 2823783002: An example of Unity native plugin of webrtc for Windows OS (Closed)
Patch Set: Sync to head Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
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
11 #include "webrtc/examples/unityplugin/simple_peer_connection.h"
12
13 #include <utility>
14
15 #include "webrtc/api/test/fakeconstraints.h"
16 #include "webrtc/base/json.h"
17 #include "webrtc/media/engine/webrtcvideocapturerfactory.h"
18 #include "webrtc/modules/video_capture/video_capture_factory.h"
19
20 // Names used for a IceCandidate JSON object.
21 const char kCandidateSdpMidName[] = "sdpMid";
22 const char kCandidateSdpMlineIndexName[] = "sdpMLineIndex";
23 const char kCandidateSdpName[] = "candidate";
24
25 // Names used for a SessionDescription JSON object.
26 const char kSessionDescriptionTypeName[] = "type";
27 const char kSessionDescriptionSdpName[] = "sdp";
28
29 // Names used for media stream labels.
30 const char kAudioLabel[] = "audio_label";
31 const char kVideoLabel[] = "video_label";
32 const char kStreamLabel[] = "stream_label";
33
34 namespace {
35 static int g_peer_count = 0;
36 static std::unique_ptr<rtc::Thread> g_worker_thread;
37 static std::unique_ptr<rtc::Thread> g_signaling_thread;
38 static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
39 g_peer_connection_factory;
40
41 std::string GetEnvVarOrDefault(const char* env_var_name,
42 const char* default_value) {
43 std::string value;
44 const char* env_var = getenv(env_var_name);
45 if (env_var)
46 value = env_var;
47
48 if (value.empty())
49 value = default_value;
50
51 return value;
52 }
53
54 std::string GetPeerConnectionString() {
55 return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302");
56 }
57
58 class DummySetSessionDescriptionObserver
59 : public webrtc::SetSessionDescriptionObserver {
60 public:
61 static DummySetSessionDescriptionObserver* Create() {
62 return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>();
63 }
64 virtual void OnSuccess() { LOG(INFO) << __FUNCTION__; }
65 virtual void OnFailure(const std::string& error) {
66 LOG(INFO) << __FUNCTION__ << " " << error;
67 }
68
69 protected:
70 DummySetSessionDescriptionObserver() {}
71 ~DummySetSessionDescriptionObserver() {}
72 };
73
74 } // namespace
75
76 bool SimplePeerConnection::InitializePeerConnection(bool is_receiver) {
77 RTC_DCHECK(peer_connection_.get() == nullptr);
78
79 if (g_peer_connection_factory == nullptr) {
80 g_worker_thread.reset(new rtc::Thread());
81 g_worker_thread->Start();
82 g_signaling_thread.reset(new rtc::Thread());
83 g_signaling_thread->Start();
84
85 g_peer_connection_factory = webrtc::CreatePeerConnectionFactory(
86 g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(),
87 nullptr, nullptr, nullptr);
88 }
89 if (!g_peer_connection_factory.get()) {
90 DeletePeerConnection();
91 return false;
92 }
93
94 g_peer_count++;
95 if (!CreatePeerConnection(is_receiver)) {
96 DeletePeerConnection();
97 return false;
98 }
99 return peer_connection_.get() != nullptr;
100 }
101
102 bool SimplePeerConnection::CreatePeerConnection(bool is_receiver) {
103 RTC_DCHECK(g_peer_connection_factory.get() != nullptr);
104 RTC_DCHECK(peer_connection_.get() == nullptr);
105
106 webrtc::PeerConnectionInterface::RTCConfiguration config;
107 webrtc::PeerConnectionInterface::IceServer server;
108 server.uri = GetPeerConnectionString();
109 config.servers.push_back(server);
110
111 webrtc::FakeConstraints constraints;
112 constraints.SetAllowDtlsSctpDataChannels();
113
114 if (is_receiver) {
115 constraints.SetMandatoryReceiveAudio(true);
116 constraints.SetMandatoryReceiveVideo(true);
117 }
118
119 peer_connection_ = g_peer_connection_factory->CreatePeerConnection(
120 config, &constraints, nullptr, nullptr, this);
121
122 return peer_connection_.get() != nullptr;
123 }
124
125 void SimplePeerConnection::DeletePeerConnection() {
126 g_peer_count--;
127
128 CloseDataChannel();
129 peer_connection_ = nullptr;
130 active_streams_.clear();
131
132 if (g_peer_count == 0) {
133 g_peer_connection_factory = nullptr;
134 g_signaling_thread.reset();
135 g_worker_thread.reset();
136 }
137 }
138
139 bool SimplePeerConnection::CreateOffer() {
140 if (!peer_connection_.get())
141 return false;
142
143 peer_connection_->CreateOffer(this, nullptr);
144 return true;
145 }
146
147 bool SimplePeerConnection::CreateAnswer() {
148 if (!peer_connection_.get())
149 return false;
150
151 peer_connection_->CreateAnswer(this, nullptr);
152 return true;
153 }
154
155 void SimplePeerConnection::OnSuccess(
156 webrtc::SessionDescriptionInterface* desc) {
157 peer_connection_->SetLocalDescription(
158 DummySetSessionDescriptionObserver::Create(), desc);
159
160 std::string sdp;
161 desc->ToString(&sdp);
162
163 Json::StyledWriter writer;
164 Json::Value jmessage;
165 jmessage[kSessionDescriptionTypeName] = desc->type();
166 jmessage[kSessionDescriptionSdpName] = sdp;
167
168 if (OnLocalSdpReady)
169 OnLocalSdpReady(writer.write(jmessage).c_str());
170 }
171
172 void SimplePeerConnection::OnFailure(const std::string& error) {
173 LOG(LERROR) << error;
174
175 if (OnFailureMessage)
176 OnFailureMessage(error.c_str());
177 }
178
179 void SimplePeerConnection::OnIceCandidate(
180 const webrtc::IceCandidateInterface* candidate) {
181 LOG(INFO) << __FUNCTION__ << " " << candidate->sdp_mline_index();
182
183 Json::StyledWriter writer;
184 Json::Value jmessage;
185
186 jmessage[kCandidateSdpMidName] = candidate->sdp_mid();
187 jmessage[kCandidateSdpMlineIndexName] = candidate->sdp_mline_index();
188 std::string sdp;
189 if (!candidate->ToString(&sdp)) {
190 LOG(LS_ERROR) << "Failed to serialize candidate";
191 return;
192 }
193 jmessage[kCandidateSdpName] = sdp;
194
195 if (OnIceCandiateReady)
196 OnIceCandiateReady(writer.write(jmessage).c_str());
197 }
198
199 void SimplePeerConnection::RegisterOnVideoFramReady(
200 VIDEOFRAMEREADY_CALLBACK callback) {
201 OnVideoFrameReady = callback;
202 }
203
204 void SimplePeerConnection::RegisterOnLocalDataChannelReady(
205 LOCALDATACHANNELREADY_CALLBACK callback) {
206 OnLocalDataChannelReady = callback;
207 }
208
209 void SimplePeerConnection::RegisterOnDataFromDataChannelReady(
210 DATAFROMEDATECHANNELREADY_CALLBACK callback) {
211 OnDataFromDataChannelReady = callback;
212 }
213
214 void SimplePeerConnection::RegisterOnFailure(FAILURE_CALLBACK callback) {
215 OnFailureMessage = callback;
216 }
217
218 void SimplePeerConnection::RegisterOnAudioBusReady(
219 AUDIOBUSREADY_CALLBACK callback) {
220 OnAudioReady = callback;
221 }
222
223 void SimplePeerConnection::RegisterOnLocalSdpReadytoSend(
224 LOCALSDPREADYTOSEND_CALLBACK callback) {
225 OnLocalSdpReady = callback;
226 }
227
228 void SimplePeerConnection::RegisterOnIceCandiateReadytoSend(
229 ICECANDIDATEREADYTOSEND_CALLBACK callback) {
230 OnIceCandiateReady = callback;
231 }
232
233 bool SimplePeerConnection::ReceivedSdp(const char* msg) {
234 if (!peer_connection_)
235 return false;
236
237 std::string message(msg);
238
239 Json::Reader reader;
240 Json::Value jmessage;
241 if (!reader.parse(message, jmessage)) {
242 LOG(WARNING) << "Received unknown message. " << message;
243 return false;
244 }
245 std::string type;
246 std::string json_object;
247
248 rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type);
249 if (type.empty())
250 return false;
251
252 std::string sdp;
253 if (!rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName,
254 &sdp)) {
255 LOG(WARNING) << "Can't parse received session description message.";
256 return false;
257 }
258 webrtc::SdpParseError error;
259 webrtc::SessionDescriptionInterface* session_description(
260 webrtc::CreateSessionDescription(type, sdp, &error));
261 if (!session_description) {
262 LOG(WARNING) << "Can't parse received session description message. "
263 << "SdpParseError was: " << error.description;
264 return false;
265 }
266 LOG(INFO) << " Received session description :" << message;
267 peer_connection_->SetRemoteDescription(
268 DummySetSessionDescriptionObserver::Create(), session_description);
269
270 return true;
271 }
272
273 bool SimplePeerConnection::ReceivedIceCandidate(const char* ice_candidate) {
274 if (!peer_connection_)
275 return false;
276
277 std::string message(ice_candidate);
278
279 Json::Reader reader;
280 Json::Value jmessage;
281 if (!reader.parse(message, jmessage)) {
282 LOG(WARNING) << "Received unknown message. " << message;
283 return false;
284 }
285 std::string type;
286 std::string json_object;
287
288 rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type);
289 if (!type.empty())
290 return false;
291
292 std::string sdp_mid;
293 int sdp_mlineindex = 0;
294 std::string sdp;
295 if (!rtc::GetStringFromJsonObject(jmessage, kCandidateSdpMidName, &sdp_mid) ||
296 !rtc::GetIntFromJsonObject(jmessage, kCandidateSdpMlineIndexName,
297 &sdp_mlineindex) ||
298 !rtc::GetStringFromJsonObject(jmessage, kCandidateSdpName, &sdp)) {
299 LOG(WARNING) << "Can't parse received message.";
300 return false;
301 }
302 webrtc::SdpParseError error;
303 std::unique_ptr<webrtc::IceCandidateInterface> candidate(
304 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
305 if (!candidate.get()) {
306 LOG(WARNING) << "Can't parse received candidate message. "
307 << "SdpParseError was: " << error.description;
308 return false;
309 }
310 if (!peer_connection_->AddIceCandidate(candidate.get())) {
311 LOG(WARNING) << "Failed to apply the received candidate";
312 return false;
313 }
314 LOG(INFO) << " Received candidate :" << message;
315 return true;
316 }
317
318 void SimplePeerConnection::SetAudioControl(bool is_mute, bool is_record) {
319 is_mute_audio_ = is_mute;
320 is_record_audio_ = is_record;
321
322 SetAudioControl();
323 }
324
325 void SimplePeerConnection::SetAudioControl() {
326 if (!remote_stream_)
327 return;
328 webrtc::AudioTrackVector tracks = remote_stream_->GetAudioTracks();
329 if (tracks.empty())
330 return;
331
332 webrtc::AudioTrackInterface* audio_track = tracks[0];
333 std::string id = audio_track->id();
334 if (is_record_audio_)
335 audio_track->AddSink(this);
336 else
337 audio_track->RemoveSink(this);
338
339 for (auto& track : tracks) {
340 if (is_mute_audio_)
341 track->set_enabled(false);
342 else
343 track->set_enabled(true);
344 }
345 }
346
347 void SimplePeerConnection::OnAddStream(
348 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
349 LOG(INFO) << __FUNCTION__ << " " << stream->label();
350 remote_stream_ = stream;
351
352 SetAudioControl();
353 }
354
355 std::unique_ptr<cricket::VideoCapturer>
356 SimplePeerConnection::OpenVideoCaptureDevice() {
357 std::vector<std::string> device_names;
358 {
359 std::unique_ptr<webrtc::VideoCaptureModule::DeviceInfo> info(
360 webrtc::VideoCaptureFactory::CreateDeviceInfo());
361 if (!info) {
362 return nullptr;
363 }
364 int num_devices = info->NumberOfDevices();
365 for (int i = 0; i < num_devices; ++i) {
366 const uint32_t kSize = 256;
367 char name[kSize] = {0};
368 char id[kSize] = {0};
369 if (info->GetDeviceName(i, name, kSize, id, kSize) != -1) {
370 device_names.push_back(name);
371 }
372 }
373 }
374
375 cricket::WebRtcVideoDeviceCapturerFactory factory;
376 std::unique_ptr<cricket::VideoCapturer> capturer;
377 for (const auto& name : device_names) {
378 capturer = factory.Create(cricket::Device(name, 0));
379 if (capturer) {
380 break;
381 }
382 }
383 return capturer;
384 }
385
386 void SimplePeerConnection::AddStreams(bool audio_only) {
387 if (active_streams_.find(kStreamLabel) != active_streams_.end())
388 return; // Already added.
389
390 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
391 g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel);
392
393 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
394 g_peer_connection_factory->CreateAudioTrack(
395 kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr)));
396 std::string id = audio_track->id();
397 stream->AddTrack(audio_track);
398
399 if (!audio_only) {
400 std::unique_ptr<cricket::VideoCapturer> capture = OpenVideoCaptureDevice();
401 if (capture) {
402 rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
403 g_peer_connection_factory->CreateVideoTrack(
404 kVideoLabel, g_peer_connection_factory->CreateVideoSource(
405 OpenVideoCaptureDevice(), nullptr)));
406
407 stream->AddTrack(video_track);
408 }
409 }
410
411 if (!peer_connection_->AddStream(stream)) {
412 LOG(LS_ERROR) << "Adding stream to PeerConnection failed";
413 }
414
415 typedef std::pair<std::string,
416 rtc::scoped_refptr<webrtc::MediaStreamInterface>>
417 MediaStreamPair;
418 active_streams_.insert(MediaStreamPair(stream->label(), stream));
419 }
420
421 bool SimplePeerConnection::CreateDataChannel() {
422 struct webrtc::DataChannelInit init;
423 init.ordered = true;
424 init.reliable = true;
425 data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
426 if (data_channel_.get()) {
427 data_channel_->RegisterObserver(this);
428 LOG(LS_INFO) << "Succeeds to create data channel";
429 return true;
430 } else {
431 LOG(LS_INFO) << "Fails to create data channel";
432 return false;
433 }
434 }
435
436 void SimplePeerConnection::CloseDataChannel() {
437 if (data_channel_.get()) {
438 data_channel_->UnregisterObserver();
439 data_channel_->Close();
440 }
441 data_channel_ = nullptr;
442 }
443
444 bool SimplePeerConnection::SendDataViaDataChannel(const std::string& data) {
445 if (!data_channel_.get()) {
446 LOG(LS_INFO) << "Data channel is not established";
447 return false;
448 }
449 webrtc::DataBuffer buffer(data);
450 data_channel_->Send(buffer);
451 return true;
452 }
453
454 // Peerconnection observer
455 void SimplePeerConnection::OnDataChannel(
456 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
457 channel->RegisterObserver(this);
458 }
459
460 void SimplePeerConnection::OnStateChange() {
461 if (data_channel_) {
462 webrtc::DataChannelInterface::DataState state = data_channel_->state();
463 if (state == webrtc::DataChannelInterface::kOpen) {
464 if (OnLocalDataChannelReady)
465 OnLocalDataChannelReady();
466 LOG(LS_INFO) << "Data channel is open";
467 }
468 }
469 }
470
471 // A data buffer was successfully received.
472 void SimplePeerConnection::OnMessage(const webrtc::DataBuffer& buffer) {
473 size_t size = buffer.data.size();
474 char* msg = new char[size + 1];
475 memcpy(msg, buffer.data.data(), size);
476 msg[size] = 0;
477 if (OnDataFromDataChannelReady)
478 OnDataFromDataChannelReady(msg);
479 delete[] msg;
480 }
481
482 // AudioTrackSinkInterface implementation.
483 void SimplePeerConnection::OnData(const void* audio_data,
484 int bits_per_sample,
485 int sample_rate,
486 size_t number_of_channels,
487 size_t number_of_frames) {
488 if (OnAudioReady)
489 OnAudioReady(audio_data, bits_per_sample, sample_rate,
490 static_cast<int>(number_of_channels),
491 static_cast<int>(number_of_frames));
492 }
493
494 std::vector<uint32_t> SimplePeerConnection::GetRemoteAudioTrackSsrcs() {
495 std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers =
496 peer_connection_->GetReceivers();
497
498 std::vector<uint32_t> ssrcs;
499 for (const auto& receiver : receivers) {
500 if (receiver->media_type() != cricket::MEDIA_TYPE_AUDIO)
501 continue;
502
503 std::vector<webrtc::RtpEncodingParameters> params =
504 receiver->GetParameters().encodings;
505
506 for (const auto& param : params) {
507 uint32_t ssrc = param.ssrc.value_or(0);
508 if (ssrc > 0)
509 ssrcs.push_back(ssrc);
510 }
511 }
512
513 return ssrcs;
514 }
OLDNEW
« no previous file with comments | « webrtc/examples/unityplugin/simple_peer_connection.h ('k') | webrtc/examples/unityplugin/unity_plugin_apis.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698