Use data channel ids

This commit is contained in:
Fernando Jiménez Moreno 2020-06-11 11:27:58 +02:00
parent 960b010d30
commit 9d456d5d17
3 changed files with 148 additions and 144 deletions

View file

@ -128,7 +128,7 @@ use servo_media::player::video::VideoFrame;
use servo_media::player::Player; use servo_media::player::Player;
use servo_media::streams::registry::MediaStreamId; use servo_media::streams::registry::MediaStreamId;
use servo_media::streams::MediaStreamType; use servo_media::streams::MediaStreamType;
use servo_media::webrtc::{WebRtcController, WebRtcDataChannelBackend}; use servo_media::webrtc::WebRtcController;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::Cow; 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!(AnalysisEngine, DistanceModel, PanningModel, ParamType);
unsafe_no_jsmanaged_fields!(Arc<Mutex<dyn Player>>); unsafe_no_jsmanaged_fields!(Arc<Mutex<dyn Player>>);
unsafe_no_jsmanaged_fields!(WebRtcController); unsafe_no_jsmanaged_fields!(WebRtcController);
unsafe_no_jsmanaged_fields!(Box<dyn WebRtcDataChannelBackend>);
unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType); unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType);
unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>); unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
unsafe_no_jsmanaged_fields!(ResourceFetchTiming); unsafe_no_jsmanaged_fields!(ResourceFetchTiming);

View file

@ -2,39 +2,32 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::RTCDataChannelInit;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods; use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods;
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit}; use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
use crate::dom::bindings::inheritance::Castable; 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::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::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
use crate::dom::rtcerror::RTCError; use crate::dom::rtcerror::RTCError;
use crate::dom::rtcerrorevent::RTCErrorEvent; use crate::dom::rtcerrorevent::RTCErrorEvent;
use crate::task_source::TaskSource; use crate::dom::rtcpeerconnection::RTCPeerConnection;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible; use js::conversions::ToJSValConvertible;
use js::jsapi::JSAutoRealm; use js::jsapi::JSAutoRealm;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use js::rust::CustomAutoRooterGuard; use servo_media::webrtc::{DataChannelId, DataChannelInit, DataChannelMessage, WebRtcError};
use js::typedarray::{ArrayBuffer, ArrayBufferView};
use servo_media::webrtc::{
WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError,
};
use std::sync::mpsc;
#[dom_struct] #[dom_struct]
pub struct RTCDataChannel { pub struct RTCDataChannel {
eventtarget: EventTarget, eventtarget: EventTarget,
#[ignore_malloc_size_of = "defined in servo-media"] #[ignore_malloc_size_of = "defined in servo-media"]
channel: Box<dyn WebRtcDataChannelBackend>, servo_media_id: DataChannelId,
peer_connection: Dom<RTCPeerConnection>,
label: USVString, label: USVString,
ordered: bool, ordered: bool,
max_packet_life_time: Option<u16>, max_packet_life_time: Option<u16>,
@ -45,30 +38,29 @@ pub struct RTCDataChannel {
} }
impl RTCDataChannel { impl RTCDataChannel {
#[allow(unrooted_must_root)]
pub fn new_inherited( pub fn new_inherited(
webrtc_controller: &DomRefCell<Option<WebRtcController>>, peer_connection: &RTCPeerConnection,
label: USVString, label: USVString,
options: &RTCDataChannelInit, options: &RTCDataChannelInit,
channel: Option<Box<dyn WebRtcDataChannelBackend>>, servo_media_id: Option<DataChannelId>,
) -> RTCDataChannel { ) -> RTCDataChannel {
let webrtc = webrtc_controller.borrow(); let mut init: DataChannelInit = options.into();
let webrtc = webrtc.as_ref().unwrap();
let (sender, receiver) = mpsc::channel::<Box<dyn WebRtcDataChannelBackend>>();
let mut init: WebRtcDataChannelInit = options.into();
init.label = label.to_string(); init.label = label.to_string();
let channel = if channel.is_none() { let controller = peer_connection.get_webrtc_controller().borrow();
webrtc.create_data_channel(init, sender); let servo_media_id = servo_media_id.unwrap_or(
receiver.recv().unwrap() controller
} else { .as_ref()
channel.unwrap() .unwrap()
}; .create_data_channel(init)
.expect("Expected data channel id"),
);
RTCDataChannel { let channel = RTCDataChannel {
eventtarget: EventTarget::new_inherited(), eventtarget: EventTarget::new_inherited(),
channel, servo_media_id,
peer_connection: Dom::from_ref(&peer_connection),
label, label,
ordered: options.ordered, ordered: options.ordered,
max_packet_life_time: options.maxPacketLifeTime, max_packet_life_time: options.maxPacketLifeTime,
@ -76,96 +68,34 @@ impl RTCDataChannel {
protocol: options.protocol.clone(), protocol: options.protocol.clone(),
negotiated: options.negotiated, negotiated: options.negotiated,
id: options.id, id: options.id,
} };
peer_connection.register_data_channel(servo_media_id, &channel);
channel
} }
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
webrtc_controller: &DomRefCell<Option<WebRtcController>>, peer_connection: &RTCPeerConnection,
label: USVString, label: USVString,
options: &RTCDataChannelInit, options: &RTCDataChannelInit,
channel: Option<Box<dyn WebRtcDataChannelBackend>>, servo_media_id: Option<DataChannelId>,
) -> DomRoot<RTCDataChannel> { ) -> DomRoot<RTCDataChannel> {
let rtc_data_channel = reflect_dom_object( let rtc_data_channel = reflect_dom_object(
Box::new(RTCDataChannel::new_inherited( Box::new(RTCDataChannel::new_inherited(
webrtc_controller, peer_connection,
label, label,
options, options,
channel, servo_media_id,
)), )),
global, 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 rtc_data_channel
} }
fn on_open(&self) { pub fn on_open(&self) {
let event = Event::new( let event = Event::new(
&self.global(), &self.global(),
atom!("open"), atom!("open"),
@ -175,7 +105,7 @@ impl RTCDataChannel {
event.upcast::<Event>().fire(self.upcast()); event.upcast::<Event>().fire(self.upcast());
} }
fn on_close(&self) { pub fn on_close(&self) {
let event = Event::new( let event = Event::new(
&self.global(), &self.global(),
atom!("close"), atom!("close"),
@ -183,9 +113,12 @@ impl RTCDataChannel {
EventCancelable::NotCancelable, EventCancelable::NotCancelable,
); );
event.upcast::<Event>().fire(self.upcast()); event.upcast::<Event>().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 { let init = RTCErrorInit {
errorDetail: RTCErrorDetailType::Data_channel_failure, errorDetail: RTCErrorDetailType::Data_channel_failure,
httpRequestStatusCode: None, httpRequestStatusCode: None,
@ -203,9 +136,10 @@ impl RTCDataChannel {
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn on_message(&self, text: String) { pub fn on_message(&self, message: DataChannelMessage) {
// XXX(ferjm) Support binary messages // XXX(ferjm) Support binary messages
unsafe { match message {
DataChannelMessage::Text(text) => unsafe {
let global = self.global(); let global = self.global();
let cx = global.get_cx(); let cx = global.get_cx();
let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get()); let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
@ -220,10 +154,19 @@ impl RTCDataChannel {
None, None,
vec![], 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 { impl RTCDataChannelMethods for RTCDataChannel {
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
event_handler!(open, GetOnopen, SetOnopen); event_handler!(open, GetOnopen, SetOnopen);
@ -282,16 +225,24 @@ impl RTCDataChannelMethods for RTCDataChannel {
// fn SetBufferedAmountLowThreshold(&self, value: u32) -> (); // fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close // 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 BinaryType(&self) -> DOMString;
// fn SetBinaryType(&self, value: DOMString) -> (); // fn SetBinaryType(&self, value: DOMString) -> ();
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
fn Send(&self, data: USVString) { fn Send(&self, data: USVString) {
if let Err(error) = self.channel.send(&data.0) { let controller = self.peer_connection.get_webrtc_controller().borrow();
warn!("Could not send data channel message. Error: {:?}", error); 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 // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
@ -304,9 +255,9 @@ impl RTCDataChannelMethods for RTCDataChannel {
// fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {} // fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {}
} }
impl From<&RTCDataChannelInit> for WebRtcDataChannelInit { impl From<&RTCDataChannelInit> for DataChannelInit {
fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit { fn from(init: &RTCDataChannelInit) -> DataChannelInit {
WebRtcDataChannelInit { DataChannelInit {
label: String::new(), label: String::new(),
id: init.id, id: init.id,
max_packet_life_time: init.maxPacketLifeTime, max_packet_life_time: init.maxPacketLifeTime,

View file

@ -20,7 +20,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::reflector::DomObject; 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::bindings::str::USVString;
use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
@ -44,12 +44,14 @@ use dom_struct::dom_struct;
use servo_media::streams::registry::MediaStreamId; use servo_media::streams::registry::MediaStreamId;
use servo_media::streams::MediaStreamType; use servo_media::streams::MediaStreamType;
use servo_media::webrtc::{ use servo_media::webrtc::{
BundlePolicy, GatheringState, IceCandidate, IceConnectionState, SdpType, SessionDescription, BundlePolicy, DataChannelEvent, DataChannelId, GatheringState, IceCandidate,
SignalingState, WebRtcController, WebRtcDataChannelBackend, WebRtcSignaller, IceConnectionState, SdpType, SessionDescription, SignalingState, WebRtcController,
WebRtcSignaller,
}; };
use servo_media::ServoMedia; use servo_media::ServoMedia;
use std::cell::Cell; use std::cell::Cell;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
#[dom_struct] #[dom_struct]
@ -70,6 +72,8 @@ pub struct RTCPeerConnection {
gathering_state: Cell<RTCIceGatheringState>, gathering_state: Cell<RTCIceGatheringState>,
ice_connection_state: Cell<RTCIceConnectionState>, ice_connection_state: Cell<RTCIceConnectionState>,
signaling_state: Cell<RTCSignalingState>, signaling_state: Cell<RTCSignalingState>,
#[ignore_malloc_size_of = "defined in servo-media"]
data_channels: DomRefCell<HashMap<DataChannelId, Dom<RTCDataChannel>>>,
} }
struct RTCSignaller { struct RTCSignaller {
@ -146,13 +150,18 @@ impl WebRtcSignaller for RTCSignaller {
); );
} }
fn on_data_channel(&self, channel: Box<dyn WebRtcDataChannelBackend>) { fn on_data_channel_event(
&self,
channel: DataChannelId,
event: DataChannelEvent,
_: &WebRtcController,
) {
// XXX(ferjm) get label and options from channel properties. // XXX(ferjm) get label and options from channel properties.
let this = self.trusted.clone(); let this = self.trusted.clone();
let _ = self.task_source.queue_with_canceller( let _ = self.task_source.queue_with_canceller(
task!(on_data_channel: move || { task!(on_data_channel_event: move || {
let this = this.root(); let this = this.root();
this.on_data_channel(channel); this.on_data_channel_event(channel, event);
}), }),
&self.canceller, &self.canceller,
); );
@ -160,6 +169,7 @@ impl WebRtcSignaller for RTCSignaller {
fn close(&self) { fn close(&self) {
// do nothing // do nothing
// XXX(ferjm) close all data channels.
} }
} }
@ -177,6 +187,7 @@ impl RTCPeerConnection {
gathering_state: Cell::new(RTCIceGatheringState::New), gathering_state: Cell::new(RTCIceGatheringState::New),
ice_connection_state: Cell::new(RTCIceConnectionState::New), ice_connection_state: Cell::new(RTCIceConnectionState::New),
signaling_state: Cell::new(RTCSignalingState::Stable), signaling_state: Cell::new(RTCSignalingState::Stable),
data_channels: DomRefCell::new(HashMap::new()),
} }
} }
@ -215,6 +226,10 @@ impl RTCPeerConnection {
Ok(RTCPeerConnection::new(&window.global(), config)) Ok(RTCPeerConnection::new(&window.global(), config))
} }
pub fn get_webrtc_controller(&self) -> &DomRefCell<Option<WebRtcController>> {
&self.controller
}
fn make_signaller(&self) -> Box<dyn WebRtcSignaller> { fn make_signaller(&self) -> Box<dyn WebRtcSignaller> {
let trusted = Trusted::new(self); let trusted = Trusted::new(self);
let (task_source, canceller) = self let (task_source, canceller) = self
@ -272,22 +287,61 @@ impl RTCPeerConnection {
event.upcast::<Event>().fire(self.upcast()); event.upcast::<Event>().fire(self.upcast());
} }
fn on_data_channel(&self, channel: Box<dyn WebRtcDataChannelBackend>) { fn on_data_channel_event(&self, channel_id: DataChannelId, event: DataChannelEvent) {
if self.closed.get() { if self.closed.get() {
return; return;
} }
match event {
DataChannelEvent::NewChannel => {
let channel = RTCDataChannel::new( let channel = RTCDataChannel::new(
&self.global(), &self.global(),
&self.controller, &self,
USVString::from("".to_owned()), USVString::from("".to_owned()),
&RTCDataChannelInit::empty(), &RTCDataChannelInit::empty(),
Some(channel), Some(channel_id),
); );
let event = self.register_data_channel(channel_id, &channel);
RTCDataChannelEvent::new(&self.global(), atom!("datachannel"), false, false, &channel);
let event = RTCDataChannelEvent::new(
&self.global(),
atom!("datachannel"),
false,
false,
&channel,
);
event.upcast::<Event>().fire(self.upcast()); event.upcast::<Event>().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 /// https://www.w3.org/TR/webrtc/#update-ice-gathering-state
@ -677,7 +731,7 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
label: USVString, label: USVString,
init: &RTCDataChannelInit, init: &RTCDataChannelInit,
) -> DomRoot<RTCDataChannel> { ) -> DomRoot<RTCDataChannel> {
RTCDataChannel::new(&self.global(), &self.controller, label, init, None) RTCDataChannel::new(&self.global(), &self, label, init, None)
} }
} }