From 9d456d5d17aebe0c3aae988f6450f9af51573c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 11 Jun 2020 11:27:58 +0200 Subject: [PATCH] Use data channel ids --- components/script/dom/bindings/trace.rs | 3 +- components/script/dom/rtcdatachannel.rs | 199 ++++++++------------- components/script/dom/rtcpeerconnection.rs | 90 ++++++++-- 3 files changed, 148 insertions(+), 144 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 40ec44a62d5..6208a7bc1ba 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -128,7 +128,7 @@ use servo_media::player::video::VideoFrame; use servo_media::player::Player; use servo_media::streams::registry::MediaStreamId; use servo_media::streams::MediaStreamType; -use servo_media::webrtc::{WebRtcController, WebRtcDataChannelBackend}; +use servo_media::webrtc::WebRtcController; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use smallvec::SmallVec; use std::borrow::Cow; @@ -607,7 +607,6 @@ unsafe_no_jsmanaged_fields!(NodeId); unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamType); unsafe_no_jsmanaged_fields!(Arc>); unsafe_no_jsmanaged_fields!(WebRtcController); -unsafe_no_jsmanaged_fields!(Box); unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType); unsafe_no_jsmanaged_fields!(Mutex); unsafe_no_jsmanaged_fields!(ResourceFetchTiming); diff --git a/components/script/dom/rtcdatachannel.rs b/components/script/dom/rtcdatachannel.rs index 24475c22323..4b5aa8eeed2 100644 --- a/components/script/dom/rtcdatachannel.rs +++ b/components/script/dom/rtcdatachannel.rs @@ -2,39 +2,32 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelInit; use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods; use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit}; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::refcounted::Trusted; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::{DOMString, USVString}; -use crate::dom::blob::Blob; use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::messageevent::MessageEvent; use crate::dom::rtcerror::RTCError; use crate::dom::rtcerrorevent::RTCErrorEvent; -use crate::task_source::TaskSource; +use crate::dom::rtcpeerconnection::RTCPeerConnection; use dom_struct::dom_struct; use js::conversions::ToJSValConvertible; use js::jsapi::JSAutoRealm; use js::jsval::UndefinedValue; -use js::rust::CustomAutoRooterGuard; -use js::typedarray::{ArrayBuffer, ArrayBufferView}; -use servo_media::webrtc::{ - WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError, -}; -use std::sync::mpsc; +use servo_media::webrtc::{DataChannelId, DataChannelInit, DataChannelMessage, WebRtcError}; #[dom_struct] pub struct RTCDataChannel { eventtarget: EventTarget, #[ignore_malloc_size_of = "defined in servo-media"] - channel: Box, + servo_media_id: DataChannelId, + peer_connection: Dom, label: USVString, ordered: bool, max_packet_life_time: Option, @@ -45,30 +38,29 @@ pub struct RTCDataChannel { } impl RTCDataChannel { + #[allow(unrooted_must_root)] pub fn new_inherited( - webrtc_controller: &DomRefCell>, + peer_connection: &RTCPeerConnection, label: USVString, options: &RTCDataChannelInit, - channel: Option>, + servo_media_id: Option, ) -> RTCDataChannel { - let webrtc = webrtc_controller.borrow(); - let webrtc = webrtc.as_ref().unwrap(); - - let (sender, receiver) = mpsc::channel::>(); - - let mut init: WebRtcDataChannelInit = options.into(); + let mut init: DataChannelInit = options.into(); init.label = label.to_string(); - let channel = if channel.is_none() { - webrtc.create_data_channel(init, sender); - receiver.recv().unwrap() - } else { - channel.unwrap() - }; + let controller = peer_connection.get_webrtc_controller().borrow(); + let servo_media_id = servo_media_id.unwrap_or( + controller + .as_ref() + .unwrap() + .create_data_channel(init) + .expect("Expected data channel id"), + ); - RTCDataChannel { + let channel = RTCDataChannel { eventtarget: EventTarget::new_inherited(), - channel, + servo_media_id, + peer_connection: Dom::from_ref(&peer_connection), label, ordered: options.ordered, max_packet_life_time: options.maxPacketLifeTime, @@ -76,96 +68,34 @@ impl RTCDataChannel { protocol: options.protocol.clone(), negotiated: options.negotiated, id: options.id, - } + }; + + peer_connection.register_data_channel(servo_media_id, &channel); + + channel } pub fn new( global: &GlobalScope, - webrtc_controller: &DomRefCell>, + peer_connection: &RTCPeerConnection, label: USVString, options: &RTCDataChannelInit, - channel: Option>, + servo_media_id: Option, ) -> DomRoot { let rtc_data_channel = reflect_dom_object( Box::new(RTCDataChannel::new_inherited( - webrtc_controller, + peer_connection, label, options, - channel, + servo_media_id, )), global, ); - let trusted = Trusted::new(&*rtc_data_channel); - let (task_source, canceller) = global - .as_window() - .task_manager() - .networking_task_source_with_canceller(); - - let this = trusted.clone(); - rtc_data_channel.channel.set_on_open(Box::new(move || { - let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(on_open: move || { - this.root().on_open(); - }), - &canceller, - ); - })); - - let this = trusted.clone(); - let (task_source, canceller) = global - .as_window() - .task_manager() - .networking_task_source_with_canceller(); - rtc_data_channel.channel.set_on_close(Box::new(move || { - let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(on_close: move || { - this.root().on_close(); - }), - &canceller, - ); - })); - - let this = trusted.clone(); - let (task_source, canceller) = global - .as_window() - .task_manager() - .networking_task_source_with_canceller(); - rtc_data_channel - .channel - .set_on_error(Box::new(move |error| { - let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(on_error: move || { - this.root().on_error(error); - }), - &canceller, - ); - })); - - let this = trusted.clone(); - let (task_source, canceller) = global - .as_window() - .task_manager() - .networking_task_source_with_canceller(); - rtc_data_channel - .channel - .set_on_message(Box::new(move |message| { - let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(on_message: move || { - this.root().on_message(message); - }), - &canceller, - ); - })); - rtc_data_channel } - fn on_open(&self) { + pub fn on_open(&self) { let event = Event::new( &self.global(), atom!("open"), @@ -175,7 +105,7 @@ impl RTCDataChannel { event.upcast::().fire(self.upcast()); } - fn on_close(&self) { + pub fn on_close(&self) { let event = Event::new( &self.global(), atom!("close"), @@ -183,9 +113,12 @@ impl RTCDataChannel { EventCancelable::NotCancelable, ); event.upcast::().fire(self.upcast()); + + self.peer_connection + .unregister_data_channel(&self.servo_media_id); } - fn on_error(&self, error: WebRtcError) { + pub fn on_error(&self, error: WebRtcError) { let init = RTCErrorInit { errorDetail: RTCErrorDetailType::Data_channel_failure, httpRequestStatusCode: None, @@ -203,27 +136,37 @@ impl RTCDataChannel { } #[allow(unsafe_code)] - fn on_message(&self, text: String) { + pub fn on_message(&self, message: DataChannelMessage) { // XXX(ferjm) Support binary messages - unsafe { - let global = self.global(); - let cx = global.get_cx(); - let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get()); - rooted!(in(*cx) let mut message = UndefinedValue()); - text.to_jsval(*cx, message.handle_mut()); + match message { + DataChannelMessage::Text(text) => unsafe { + let global = self.global(); + let cx = global.get_cx(); + let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get()); + rooted!(in(*cx) let mut message = UndefinedValue()); + text.to_jsval(*cx, message.handle_mut()); - MessageEvent::dispatch_jsval( - self.upcast(), - &global, - message.handle(), - Some(&global.origin().immutable().ascii_serialization()), - None, - vec![], - ); + MessageEvent::dispatch_jsval( + self.upcast(), + &global, + message.handle(), + Some(&global.origin().immutable().ascii_serialization()), + None, + vec![], + ); + }, + DataChannelMessage::Binary(_) => {}, } } } +impl Drop for RTCDataChannel { + fn drop(&mut self) { + self.peer_connection + .unregister_data_channel(&self.servo_media_id); + } +} + impl RTCDataChannelMethods for RTCDataChannel { // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen event_handler!(open, GetOnopen, SetOnopen); @@ -282,16 +225,24 @@ impl RTCDataChannelMethods for RTCDataChannel { // fn SetBufferedAmountLowThreshold(&self, value: u32) -> (); // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close - fn Close(&self) {} + fn Close(&self) { + let controller = self.peer_connection.get_webrtc_controller().borrow(); + controller + .as_ref() + .unwrap() + .close_data_channel(&self.servo_media_id); + } // fn BinaryType(&self) -> DOMString; // fn SetBinaryType(&self, value: DOMString) -> (); // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send fn Send(&self, data: USVString) { - if let Err(error) = self.channel.send(&data.0) { - warn!("Could not send data channel message. Error: {:?}", error); - } + let controller = self.peer_connection.get_webrtc_controller().borrow(); + controller + .as_ref() + .unwrap() + .send_data_channel_message(&self.servo_media_id, DataChannelMessage::Text(data.0)); } // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1 @@ -304,9 +255,9 @@ impl RTCDataChannelMethods for RTCDataChannel { // fn Send___(&self, data: CustomAutoRooterGuard) -> () {} } -impl From<&RTCDataChannelInit> for WebRtcDataChannelInit { - fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit { - WebRtcDataChannelInit { +impl From<&RTCDataChannelInit> for DataChannelInit { + fn from(init: &RTCDataChannelInit) -> DataChannelInit { + DataChannelInit { label: String::new(), id: init.id, max_packet_life_time: init.maxPacketLifeTime, diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs index 2e568c7a971..1ec1cc4e337 100644 --- a/components/script/dom/rtcpeerconnection.rs +++ b/components/script/dom/rtcpeerconnection.rs @@ -20,7 +20,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::reflector::DomObject; -use crate::dom::bindings::root::{DomRoot, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::str::USVString; use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; @@ -44,12 +44,14 @@ use dom_struct::dom_struct; use servo_media::streams::registry::MediaStreamId; use servo_media::streams::MediaStreamType; use servo_media::webrtc::{ - BundlePolicy, GatheringState, IceCandidate, IceConnectionState, SdpType, SessionDescription, - SignalingState, WebRtcController, WebRtcDataChannelBackend, WebRtcSignaller, + BundlePolicy, DataChannelEvent, DataChannelId, GatheringState, IceCandidate, + IceConnectionState, SdpType, SessionDescription, SignalingState, WebRtcController, + WebRtcSignaller, }; use servo_media::ServoMedia; use std::cell::Cell; +use std::collections::HashMap; use std::rc::Rc; #[dom_struct] @@ -70,6 +72,8 @@ pub struct RTCPeerConnection { gathering_state: Cell, ice_connection_state: Cell, signaling_state: Cell, + #[ignore_malloc_size_of = "defined in servo-media"] + data_channels: DomRefCell>>, } struct RTCSignaller { @@ -146,13 +150,18 @@ impl WebRtcSignaller for RTCSignaller { ); } - fn on_data_channel(&self, channel: Box) { + fn on_data_channel_event( + &self, + channel: DataChannelId, + event: DataChannelEvent, + _: &WebRtcController, + ) { // XXX(ferjm) get label and options from channel properties. let this = self.trusted.clone(); let _ = self.task_source.queue_with_canceller( - task!(on_data_channel: move || { + task!(on_data_channel_event: move || { let this = this.root(); - this.on_data_channel(channel); + this.on_data_channel_event(channel, event); }), &self.canceller, ); @@ -160,6 +169,7 @@ impl WebRtcSignaller for RTCSignaller { fn close(&self) { // do nothing + // XXX(ferjm) close all data channels. } } @@ -177,6 +187,7 @@ impl RTCPeerConnection { gathering_state: Cell::new(RTCIceGatheringState::New), ice_connection_state: Cell::new(RTCIceConnectionState::New), signaling_state: Cell::new(RTCSignalingState::Stable), + data_channels: DomRefCell::new(HashMap::new()), } } @@ -215,6 +226,10 @@ impl RTCPeerConnection { Ok(RTCPeerConnection::new(&window.global(), config)) } + pub fn get_webrtc_controller(&self) -> &DomRefCell> { + &self.controller + } + fn make_signaller(&self) -> Box { let trusted = Trusted::new(self); let (task_source, canceller) = self @@ -272,22 +287,61 @@ impl RTCPeerConnection { event.upcast::().fire(self.upcast()); } - fn on_data_channel(&self, channel: Box) { + fn on_data_channel_event(&self, channel_id: DataChannelId, event: DataChannelEvent) { if self.closed.get() { return; } - let channel = RTCDataChannel::new( - &self.global(), - &self.controller, - USVString::from("".to_owned()), - &RTCDataChannelInit::empty(), - Some(channel), - ); + match event { + DataChannelEvent::NewChannel => { + let channel = RTCDataChannel::new( + &self.global(), + &self, + USVString::from("".to_owned()), + &RTCDataChannelInit::empty(), + Some(channel_id), + ); - let event = - RTCDataChannelEvent::new(&self.global(), atom!("datachannel"), false, false, &channel); - event.upcast::().fire(self.upcast()); + self.register_data_channel(channel_id, &channel); + + let event = RTCDataChannelEvent::new( + &self.global(), + atom!("datachannel"), + false, + false, + &channel, + ); + event.upcast::().fire(self.upcast()); + }, + _ => { + if let Some(ref channel) = self.data_channels.borrow().get(&channel_id) { + match event { + DataChannelEvent::Open => channel.on_open(), + DataChannelEvent::Close => channel.on_close(), + DataChannelEvent::Error(error) => channel.on_error(error), + DataChannelEvent::OnMessage(message) => channel.on_message(message), + _ => unreachable!(), + } + } else { + debug_assert!(false, "Got an event for an unregistered data channel"); + } + }, + }; + } + + pub fn register_data_channel(&self, id: DataChannelId, channel: &RTCDataChannel) { + if self + .data_channels + .borrow_mut() + .insert(id, Dom::from_ref(channel)) + .is_none() + { + debug_assert!(false, "Could not register data channel"); + } + } + + pub fn unregister_data_channel(&self, id: &DataChannelId) { + self.data_channels.borrow_mut().remove(&id); } /// https://www.w3.org/TR/webrtc/#update-ice-gathering-state @@ -677,7 +731,7 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { label: USVString, init: &RTCDataChannelInit, ) -> DomRoot { - RTCDataChannel::new(&self.global(), &self.controller, label, init, None) + RTCDataChannel::new(&self.global(), &self, label, init, None) } }