mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #26752 - ferjm:datachannel, r=Manishearth
WebRTC data channels support - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #26212 This depends on https://github.com/servo/media/pull/350 and contains the basic pieces to make a simple test like https://ferjm.github.io/samples/src/content/datachannel/basic/ work
This commit is contained in:
commit
4b034ede46
22 changed files with 930 additions and 34 deletions
|
@ -16,6 +16,7 @@ characteristicvaluechanged
|
|||
checkbox
|
||||
click
|
||||
close
|
||||
closing
|
||||
color
|
||||
complete
|
||||
compositionend
|
||||
|
@ -23,6 +24,7 @@ compositionstart
|
|||
compositionupdate
|
||||
controllerchange
|
||||
cursive
|
||||
datachannel
|
||||
date
|
||||
datetime-local
|
||||
dir
|
||||
|
|
|
@ -487,6 +487,10 @@ pub mod raredata;
|
|||
pub mod readablestream;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
pub mod rtcdatachannel;
|
||||
pub mod rtcdatachannelevent;
|
||||
pub mod rtcerror;
|
||||
pub mod rtcerrorevent;
|
||||
pub mod rtcicecandidate;
|
||||
pub mod rtcpeerconnection;
|
||||
pub mod rtcpeerconnectioniceevent;
|
||||
|
|
387
components/script/dom/rtcdatachannel.rs
Normal file
387
components/script/dom/rtcdatachannel.rs
Normal file
|
@ -0,0 +1,387 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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::RTCDataChannelBinding::RTCDataChannelState;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
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::dom::rtcpeerconnection::RTCPeerConnection;
|
||||
use dom_struct::dom_struct;
|
||||
use js::conversions::ToJSValConvertible;
|
||||
use js::jsapi::{JSAutoRealm, JSObject};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::CustomAutoRooterGuard;
|
||||
use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
|
||||
use script_traits::serializable::BlobImpl;
|
||||
use servo_media::webrtc::{
|
||||
DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
|
||||
};
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct RTCDataChannel {
|
||||
eventtarget: EventTarget,
|
||||
#[ignore_malloc_size_of = "defined in servo-media"]
|
||||
servo_media_id: DataChannelId,
|
||||
peer_connection: Dom<RTCPeerConnection>,
|
||||
label: USVString,
|
||||
ordered: bool,
|
||||
max_packet_life_time: Option<u16>,
|
||||
max_retransmits: Option<u16>,
|
||||
protocol: USVString,
|
||||
negotiated: bool,
|
||||
id: Option<u16>,
|
||||
ready_state: Cell<RTCDataChannelState>,
|
||||
binary_type: DomRefCell<DOMString>,
|
||||
}
|
||||
|
||||
impl RTCDataChannel {
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new_inherited(
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
) -> RTCDataChannel {
|
||||
let mut init: DataChannelInit = options.into();
|
||||
init.label = label.to_string();
|
||||
|
||||
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"),
|
||||
);
|
||||
|
||||
let channel = RTCDataChannel {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
servo_media_id,
|
||||
peer_connection: Dom::from_ref(&peer_connection),
|
||||
label,
|
||||
ordered: options.ordered,
|
||||
max_packet_life_time: options.maxPacketLifeTime,
|
||||
max_retransmits: options.maxRetransmits,
|
||||
protocol: options.protocol.clone(),
|
||||
negotiated: options.negotiated,
|
||||
id: options.id,
|
||||
ready_state: Cell::new(RTCDataChannelState::Connecting),
|
||||
binary_type: DomRefCell::new(DOMString::from("blob")),
|
||||
};
|
||||
|
||||
channel
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
) -> DomRoot<RTCDataChannel> {
|
||||
let rtc_data_channel = reflect_dom_object(
|
||||
Box::new(RTCDataChannel::new_inherited(
|
||||
peer_connection,
|
||||
label,
|
||||
options,
|
||||
servo_media_id,
|
||||
)),
|
||||
global,
|
||||
);
|
||||
|
||||
peer_connection.register_data_channel(rtc_data_channel.servo_media_id, &*rtc_data_channel);
|
||||
|
||||
rtc_data_channel
|
||||
}
|
||||
|
||||
pub fn on_open(&self) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("open"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
|
||||
pub fn on_close(&self) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("close"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
|
||||
self.peer_connection
|
||||
.unregister_data_channel(&self.servo_media_id);
|
||||
}
|
||||
|
||||
pub fn on_error(&self, error: WebRtcError) {
|
||||
let global = self.global();
|
||||
let cx = global.get_cx();
|
||||
let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
|
||||
let init = RTCErrorInit {
|
||||
errorDetail: RTCErrorDetailType::Data_channel_failure,
|
||||
httpRequestStatusCode: None,
|
||||
receivedAlert: None,
|
||||
sctpCauseCode: None,
|
||||
sdpLineNumber: None,
|
||||
sentAlert: None,
|
||||
};
|
||||
let message = match error {
|
||||
WebRtcError::Backend(message) => DOMString::from(message),
|
||||
};
|
||||
let error = RTCError::new(&global, &init, message);
|
||||
let event = RTCErrorEvent::new(&global, atom!("error"), false, false, &error);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn on_message(&self, channel_message: DataChannelMessage) {
|
||||
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());
|
||||
|
||||
match channel_message {
|
||||
DataChannelMessage::Text(text) => {
|
||||
text.to_jsval(*cx, message.handle_mut());
|
||||
},
|
||||
DataChannelMessage::Binary(data) => match &**self.binary_type.borrow() {
|
||||
"blob" => {
|
||||
let blob =
|
||||
Blob::new(&global, BlobImpl::new_from_bytes(data, "".to_owned()));
|
||||
blob.to_jsval(*cx, message.handle_mut());
|
||||
},
|
||||
"arraybuffer" => {
|
||||
rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
|
||||
assert!(ArrayBuffer::create(
|
||||
*cx,
|
||||
CreateWith::Slice(&data),
|
||||
array_buffer.handle_mut()
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
(*array_buffer).to_jsval(*cx, message.handle_mut());
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
|
||||
MessageEvent::dispatch_jsval(
|
||||
self.upcast(),
|
||||
&global,
|
||||
message.handle(),
|
||||
Some(&global.origin().immutable().ascii_serialization()),
|
||||
None,
|
||||
vec![],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_state_change(&self, state: DataChannelState) {
|
||||
match state {
|
||||
DataChannelState::Closing => {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("closing"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
self.ready_state.set(state.into());
|
||||
}
|
||||
|
||||
fn send(&self, source: &SendSource) -> Fallible<()> {
|
||||
if self.ready_state.get() != RTCDataChannelState::Open {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
let message = match source {
|
||||
SendSource::String(string) => DataChannelMessage::Text(string.0.clone()),
|
||||
SendSource::Blob(blob) => {
|
||||
DataChannelMessage::Binary(blob.get_bytes().unwrap_or(vec![]))
|
||||
},
|
||||
SendSource::ArrayBuffer(array) => DataChannelMessage::Binary(array.to_vec()),
|
||||
SendSource::ArrayBufferView(array) => DataChannelMessage::Binary(array.to_vec()),
|
||||
};
|
||||
|
||||
let controller = self.peer_connection.get_webrtc_controller().borrow();
|
||||
controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_data_channel_message(&self.servo_media_id, message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RTCDataChannel {
|
||||
fn drop(&mut self) {
|
||||
self.peer_connection
|
||||
.unregister_data_channel(&self.servo_media_id);
|
||||
}
|
||||
}
|
||||
|
||||
enum SendSource<'a, 'b> {
|
||||
String(&'a USVString),
|
||||
Blob(&'a Blob),
|
||||
ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
|
||||
ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
|
||||
}
|
||||
|
||||
impl RTCDataChannelMethods for RTCDataChannel {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
|
||||
event_handler!(open, GetOnopen, SetOnopen);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
|
||||
event_handler!(
|
||||
bufferedamountlow,
|
||||
GetOnbufferedamountlow,
|
||||
SetOnbufferedamountlow
|
||||
);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
|
||||
event_handler!(error, GetOnerror, SetOnerror);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
|
||||
event_handler!(closing, GetOnclosing, SetOnclosing);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
|
||||
event_handler!(close, GetOnclose, SetOnclose);
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
|
||||
event_handler!(message, GetOnmessage, SetOnmessage);
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-label
|
||||
fn Label(&self) -> USVString {
|
||||
self.label.clone()
|
||||
}
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
|
||||
fn Ordered(&self) -> bool {
|
||||
self.ordered
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
|
||||
fn GetMaxPacketLifeTime(&self) -> Option<u16> {
|
||||
self.max_packet_life_time
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
|
||||
fn GetMaxRetransmits(&self) -> Option<u16> {
|
||||
self.max_retransmits
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
|
||||
fn Protocol(&self) -> USVString {
|
||||
self.protocol.clone()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
|
||||
fn Negotiated(&self) -> bool {
|
||||
self.negotiated
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
|
||||
fn GetId(&self) -> Option<u16> {
|
||||
self.id
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-readystate
|
||||
fn ReadyState(&self) -> RTCDataChannelState {
|
||||
self.ready_state.get()
|
||||
}
|
||||
|
||||
// XXX We need a way to know when the underlying data transport
|
||||
// actually sends data from its queue to decrease buffered amount.
|
||||
|
||||
// fn BufferedAmount(&self) -> u32;
|
||||
// fn BufferedAmountLowThreshold(&self) -> u32;
|
||||
// fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
|
||||
fn Close(&self) {
|
||||
let controller = self.peer_connection.get_webrtc_controller().borrow();
|
||||
controller
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.close_data_channel(&self.servo_media_id);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
|
||||
fn BinaryType(&self) -> DOMString {
|
||||
self.binary_type.borrow().clone()
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannel-binarytype
|
||||
fn SetBinaryType(&self, value: DOMString) -> Fallible<()> {
|
||||
if value != "blob" || value != "arraybuffer" {
|
||||
return Err(Error::Syntax);
|
||||
}
|
||||
*self.binary_type.borrow_mut() = value;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
|
||||
fn Send(&self, data: USVString) -> Fallible<()> {
|
||||
self.send(&SendSource::String(&data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
|
||||
fn Send_(&self, data: &Blob) -> Fallible<()> {
|
||||
self.send(&SendSource::Blob(data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
|
||||
fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> Fallible<()> {
|
||||
self.send(&SendSource::ArrayBuffer(data))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
|
||||
fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> Fallible<()> {
|
||||
self.send(&SendSource::ArrayBufferView(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RTCDataChannelInit> for DataChannelInit {
|
||||
fn from(init: &RTCDataChannelInit) -> DataChannelInit {
|
||||
DataChannelInit {
|
||||
label: String::new(),
|
||||
id: init.id,
|
||||
max_packet_life_time: init.maxPacketLifeTime,
|
||||
max_retransmits: init.maxRetransmits,
|
||||
negotiated: init.negotiated,
|
||||
ordered: init.ordered,
|
||||
protocol: init.protocol.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DataChannelState> for RTCDataChannelState {
|
||||
fn from(state: DataChannelState) -> RTCDataChannelState {
|
||||
match state {
|
||||
DataChannelState::New |
|
||||
DataChannelState::Connecting |
|
||||
DataChannelState::__Unknown(_) => RTCDataChannelState::Connecting,
|
||||
DataChannelState::Open => RTCDataChannelState::Open,
|
||||
DataChannelState::Closing => RTCDataChannelState::Closing,
|
||||
DataChannelState::Closed => RTCDataChannelState::Closed,
|
||||
}
|
||||
}
|
||||
}
|
77
components/script/dom/rtcdatachannelevent.rs
Normal file
77
components/script/dom/rtcdatachannelevent.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCDataChannelEventBinding::RTCDataChannelEventInit;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCDataChannelEventBinding::RTCDataChannelEventMethods;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::rtcdatachannel::RTCDataChannel;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_atoms::Atom;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct RTCDataChannelEvent {
|
||||
event: Event,
|
||||
channel: Dom<RTCDataChannel>,
|
||||
}
|
||||
|
||||
impl RTCDataChannelEvent {
|
||||
fn new_inherited(channel: &RTCDataChannel) -> RTCDataChannelEvent {
|
||||
RTCDataChannelEvent {
|
||||
event: Event::new_inherited(),
|
||||
channel: Dom::from_ref(channel),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
channel: &RTCDataChannel,
|
||||
) -> DomRoot<RTCDataChannelEvent> {
|
||||
let event = reflect_dom_object(
|
||||
Box::new(RTCDataChannelEvent::new_inherited(&channel)),
|
||||
global,
|
||||
);
|
||||
{
|
||||
let event = event.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
event
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &RTCDataChannelEventInit,
|
||||
) -> DomRoot<RTCDataChannelEvent> {
|
||||
RTCDataChannelEvent::new(
|
||||
&window.global(),
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.channel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCDataChannelEventMethods for RTCDataChannelEvent {
|
||||
// https://www.w3.org/TR/webrtc/#dom-datachannelevent-channel
|
||||
fn Channel(&self) -> DomRoot<RTCDataChannel> {
|
||||
DomRoot::from_ref(&*self.channel)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
90
components/script/dom/rtcerror.rs
Normal file
90
components/script/dom/rtcerror.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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::codegen::Bindings::RTCErrorBinding::RTCErrorDetailType;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::RTCErrorInit;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::RTCErrorMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::domexception::{DOMErrorName, DOMException};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct RTCError {
|
||||
exception: Dom<DOMException>,
|
||||
error_detail: RTCErrorDetailType,
|
||||
sdp_line_number: Option<i32>,
|
||||
http_request_status_code: Option<i32>,
|
||||
sctp_cause_code: Option<i32>,
|
||||
received_alert: Option<u32>,
|
||||
sent_alert: Option<u32>,
|
||||
}
|
||||
|
||||
impl RTCError {
|
||||
fn new_inherited(global: &GlobalScope, init: &RTCErrorInit, message: DOMString) -> RTCError {
|
||||
RTCError {
|
||||
exception: Dom::from_ref(&*DOMException::new(
|
||||
global,
|
||||
DOMErrorName::from(&message).unwrap(),
|
||||
)),
|
||||
error_detail: init.errorDetail,
|
||||
sdp_line_number: init.sdpLineNumber,
|
||||
http_request_status_code: init.httpRequestStatusCode,
|
||||
sctp_cause_code: init.sctpCauseCode,
|
||||
received_alert: init.receivedAlert,
|
||||
sent_alert: init.sentAlert,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, init: &RTCErrorInit, message: DOMString) -> DomRoot<RTCError> {
|
||||
reflect_dom_object(
|
||||
Box::new(RTCError::new_inherited(global, init, message)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
init: &RTCErrorInit,
|
||||
message: DOMString,
|
||||
) -> DomRoot<RTCError> {
|
||||
RTCError::new(&window.global(), init, message)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCErrorMethods for RTCError {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-errordetail
|
||||
fn ErrorDetail(&self) -> RTCErrorDetailType {
|
||||
self.error_detail
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-sdplinenumber
|
||||
fn GetSdpLineNumber(&self) -> Option<i32> {
|
||||
self.sdp_line_number
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror
|
||||
fn GetHttpRequestStatusCode(&self) -> Option<i32> {
|
||||
self.http_request_status_code
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-sctpcausecode
|
||||
fn GetSctpCauseCode(&self) -> Option<i32> {
|
||||
self.sctp_cause_code
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-receivedalert
|
||||
fn GetReceivedAlert(&self) -> Option<u32> {
|
||||
self.received_alert
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-sentalert
|
||||
fn GetSentAlert(&self) -> Option<u32> {
|
||||
self.sent_alert
|
||||
}
|
||||
}
|
74
components/script/dom/rtcerrorevent.rs
Normal file
74
components/script/dom/rtcerrorevent.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorEventBinding::RTCErrorEventInit;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorEventBinding::RTCErrorEventMethods;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::rtcerror::RTCError;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_atoms::Atom;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct RTCErrorEvent {
|
||||
event: Event,
|
||||
error: Dom<RTCError>,
|
||||
}
|
||||
|
||||
impl RTCErrorEvent {
|
||||
fn new_inherited(error: &RTCError) -> RTCErrorEvent {
|
||||
RTCErrorEvent {
|
||||
event: Event::new_inherited(),
|
||||
error: Dom::from_ref(error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
error: &RTCError,
|
||||
) -> DomRoot<RTCErrorEvent> {
|
||||
let event = reflect_dom_object(Box::new(RTCErrorEvent::new_inherited(&error)), global);
|
||||
{
|
||||
let event = event.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
event
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &RTCErrorEventInit,
|
||||
) -> DomRoot<RTCErrorEvent> {
|
||||
RTCErrorEvent::new(
|
||||
&window.global(),
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCErrorEventMethods for RTCErrorEvent {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerrorevent-error
|
||||
fn Error(&self) -> DomRoot<RTCError> {
|
||||
DomRoot::from_ref(&*self.error)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
* 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::RTCIceCandidateBinding::RTCIceCandidateInit;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCPeerConnectionBinding::RTCPeerConnectionMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCPeerConnectionBinding::{
|
||||
|
@ -19,19 +20,22 @@ 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;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::mediastream::MediaStream;
|
||||
use crate::dom::mediastreamtrack::MediaStreamTrack;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::rtcdatachannel::RTCDataChannel;
|
||||
use crate::dom::rtcdatachannelevent::RTCDataChannelEvent;
|
||||
use crate::dom::rtcicecandidate::RTCIceCandidate;
|
||||
use crate::dom::rtcpeerconnectioniceevent::RTCPeerConnectionIceEvent;
|
||||
use crate::dom::rtcsessiondescription::RTCSessionDescription;
|
||||
use crate::dom::rtctrackevent::RTCTrackEvent;
|
||||
use crate::dom::window::Window;
|
||||
use crate::realms::InRealm;
|
||||
use crate::realms::{enter_realm, InRealm};
|
||||
use crate::task::TaskCanceller;
|
||||
use crate::task_source::networking::NetworkingTaskSource;
|
||||
use crate::task_source::TaskSource;
|
||||
|
@ -40,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, WebRtcSignaller,
|
||||
BundlePolicy, DataChannelEvent, DataChannelId, DataChannelState, 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]
|
||||
|
@ -66,6 +72,8 @@ pub struct RTCPeerConnection {
|
|||
gathering_state: Cell<RTCIceGatheringState>,
|
||||
ice_connection_state: Cell<RTCIceConnectionState>,
|
||||
signaling_state: Cell<RTCSignalingState>,
|
||||
#[ignore_malloc_size_of = "defined in servo-media"]
|
||||
data_channels: DomRefCell<HashMap<DataChannelId, Dom<RTCDataChannel>>>,
|
||||
}
|
||||
|
||||
struct RTCSignaller {
|
||||
|
@ -142,6 +150,25 @@ impl WebRtcSignaller for RTCSignaller {
|
|||
);
|
||||
}
|
||||
|
||||
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_event: move || {
|
||||
let this = this.root();
|
||||
let global = this.global();
|
||||
let _ac = enter_realm(&*global);
|
||||
this.on_data_channel_event(channel, event);
|
||||
}),
|
||||
&self.canceller,
|
||||
);
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
// do nothing
|
||||
}
|
||||
|
@ -161,6 +188,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()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +227,10 @@ impl RTCPeerConnection {
|
|||
Ok(RTCPeerConnection::new(&window.global(), config))
|
||||
}
|
||||
|
||||
pub fn get_webrtc_controller(&self) -> &DomRefCell<Option<WebRtcController>> {
|
||||
&self.controller
|
||||
}
|
||||
|
||||
fn make_signaller(&self) -> Box<dyn WebRtcSignaller> {
|
||||
let trusted = Trusted::new(self);
|
||||
let (task_source, canceller) = self
|
||||
|
@ -256,6 +288,68 @@ impl RTCPeerConnection {
|
|||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
|
||||
fn on_data_channel_event(&self, channel_id: DataChannelId, event: DataChannelEvent) {
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
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::<Event>().fire(self.upcast());
|
||||
},
|
||||
_ => {
|
||||
let channel = if let Some(channel) = self.data_channels.borrow().get(&channel_id) {
|
||||
DomRoot::from_ref(&**channel)
|
||||
} else {
|
||||
warn!(
|
||||
"Got an event for an unregistered data channel {:?}",
|
||||
channel_id
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
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),
|
||||
DataChannelEvent::StateChange(state) => channel.on_state_change(state),
|
||||
DataChannelEvent::NewChannel => unreachable!(),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn register_data_channel(&self, id: DataChannelId, channel: &RTCDataChannel) {
|
||||
if self
|
||||
.data_channels
|
||||
.borrow_mut()
|
||||
.insert(id, Dom::from_ref(channel))
|
||||
.is_some()
|
||||
{
|
||||
warn!("Data channel already registered {:?}", id);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
fn update_gathering_state(&self, state: GatheringState) {
|
||||
// step 1
|
||||
|
@ -448,6 +542,9 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
|
|||
SetOnsignalingstatechange
|
||||
);
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ondatachannel
|
||||
event_handler!(datachannel, GetOndatachannel, SetOndatachannel);
|
||||
|
||||
/// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addicecandidate
|
||||
fn AddIceCandidate(&self, candidate: &RTCIceCandidateInit, comp: InRealm) -> Rc<Promise> {
|
||||
let p = Promise::new_in_current_realm(&self.global(), comp);
|
||||
|
@ -624,8 +721,13 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
|
|||
// Step 5 handled by backend
|
||||
self.controller.borrow_mut().as_ref().unwrap().quit();
|
||||
|
||||
// Step 6-10
|
||||
// (no current support for data channels, transports, etc)
|
||||
// Step 6
|
||||
for (_, val) in self.data_channels.borrow().iter() {
|
||||
val.on_state_change(DataChannelState::Closed);
|
||||
}
|
||||
|
||||
// Step 7-10
|
||||
// (no current support for transports, etc)
|
||||
|
||||
// Step 11
|
||||
self.ice_connection_state.set(RTCIceConnectionState::Closed);
|
||||
|
@ -633,6 +735,15 @@ impl RTCPeerConnectionMethods for RTCPeerConnection {
|
|||
// Step 11
|
||||
// (no current support for connection state)
|
||||
}
|
||||
|
||||
/// https://www.w3.org/TR/webrtc/#dom-peerconnection-createdatachannel
|
||||
fn CreateDataChannel(
|
||||
&self,
|
||||
label: USVString,
|
||||
init: &RTCDataChannelInit,
|
||||
) -> DomRoot<RTCDataChannel> {
|
||||
RTCDataChannel::new(&self.global(), &self, label, init, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SessionDescription> for RTCSessionDescriptionInit {
|
||||
|
|
49
components/script/dom/webidls/RTCDataChannel.webidl
Normal file
49
components/script/dom/webidls/RTCDataChannel.webidl
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcdatachannel
|
||||
|
||||
[Exposed=Window, Pref="dom.webrtc.enabled"]
|
||||
interface RTCDataChannel : EventTarget {
|
||||
readonly attribute USVString label;
|
||||
readonly attribute boolean ordered;
|
||||
readonly attribute unsigned short? maxPacketLifeTime;
|
||||
readonly attribute unsigned short? maxRetransmits;
|
||||
readonly attribute USVString protocol;
|
||||
readonly attribute boolean negotiated;
|
||||
readonly attribute unsigned short? id;
|
||||
readonly attribute RTCDataChannelState readyState;
|
||||
//readonly attribute unsigned long bufferedAmount;
|
||||
//attribute unsigned long bufferedAmountLowThreshold;
|
||||
attribute EventHandler onopen;
|
||||
attribute EventHandler onbufferedamountlow;
|
||||
attribute EventHandler onerror;
|
||||
attribute EventHandler onclosing;
|
||||
attribute EventHandler onclose;
|
||||
void close();
|
||||
attribute EventHandler onmessage;
|
||||
[SetterThrows] attribute DOMString binaryType;
|
||||
[Throws] void send(USVString data);
|
||||
[Throws] void send(Blob data);
|
||||
[Throws] void send(ArrayBuffer data);
|
||||
[Throws] void send(ArrayBufferView data);
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannelinit
|
||||
dictionary RTCDataChannelInit {
|
||||
boolean ordered = true;
|
||||
unsigned short maxPacketLifeTime;
|
||||
unsigned short maxRetransmits;
|
||||
USVString protocol = "";
|
||||
boolean negotiated = false;
|
||||
unsigned short id;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannelstate
|
||||
enum RTCDataChannelState {
|
||||
"connecting",
|
||||
"open",
|
||||
"closing",
|
||||
"closed"
|
||||
};
|
15
components/script/dom/webidls/RTCDataChannelEvent.webidl
Normal file
15
components/script/dom/webidls/RTCDataChannelEvent.webidl
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcdatachannelevent
|
||||
|
||||
[Exposed=Window, Pref="dom.webrtc.enabled"]
|
||||
interface RTCDataChannelEvent : Event {
|
||||
constructor(DOMString type, RTCDataChannelEventInit eventInitDict);
|
||||
readonly attribute RTCDataChannel channel;
|
||||
};
|
||||
|
||||
dictionary RTCDataChannelEventInit : EventInit {
|
||||
required RTCDataChannel channel;
|
||||
};
|
35
components/script/dom/webidls/RTCError.webidl
Normal file
35
components/script/dom/webidls/RTCError.webidl
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcerror
|
||||
|
||||
[Exposed=Window, Pref="dom.webrtc.enabled"]
|
||||
interface RTCError : DOMException {
|
||||
constructor(RTCErrorInit init, optional DOMString message = "");
|
||||
readonly attribute RTCErrorDetailType errorDetail;
|
||||
readonly attribute long? sdpLineNumber;
|
||||
readonly attribute long? httpRequestStatusCode;
|
||||
readonly attribute long? sctpCauseCode;
|
||||
readonly attribute unsigned long? receivedAlert;
|
||||
readonly attribute unsigned long? sentAlert;
|
||||
};
|
||||
|
||||
dictionary RTCErrorInit {
|
||||
required RTCErrorDetailType errorDetail;
|
||||
long sdpLineNumber;
|
||||
long httpRequestStatusCode;
|
||||
long sctpCauseCode;
|
||||
unsigned long receivedAlert;
|
||||
unsigned long sentAlert;
|
||||
};
|
||||
|
||||
enum RTCErrorDetailType {
|
||||
"data-channel-failure",
|
||||
"dtls-failure",
|
||||
"fingerprint-failure",
|
||||
"sctp-failure",
|
||||
"sdp-syntax-error",
|
||||
"hardware-encoder-not-available",
|
||||
"hardware-encoder-error"
|
||||
};
|
15
components/script/dom/webidls/RTCErrorEvent.webidl
Normal file
15
components/script/dom/webidls/RTCErrorEvent.webidl
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcerrorevent
|
||||
|
||||
[Exposed=Window, Pref="dom.webrtc.enabled"]
|
||||
interface RTCErrorEvent : Event {
|
||||
constructor(DOMString type, RTCErrorEventInit eventInitDict);
|
||||
[SameObject] readonly attribute RTCError error;
|
||||
};
|
||||
|
||||
dictionary RTCErrorEventInit : EventInit {
|
||||
required RTCError error;
|
||||
};
|
|
@ -126,3 +126,11 @@ partial interface RTCPeerConnection {
|
|||
// optional RTCRtpTransceiverInit init);
|
||||
attribute EventHandler ontrack;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#rtcpeerconnection-interface-extensions-0
|
||||
partial interface RTCPeerConnection {
|
||||
// readonly attribute RTCSctpTransport? sctp;
|
||||
RTCDataChannel createDataChannel(USVString label,
|
||||
optional RTCDataChannelInit dataChannelDict = {});
|
||||
attribute EventHandler ondatachannel;
|
||||
};
|
||||
|
|
|
@ -55,7 +55,7 @@ euclid = "0.20"
|
|||
gfx = { path = "../gfx" }
|
||||
gfx_traits = { path = "../gfx_traits" }
|
||||
gleam = "0.11"
|
||||
gstreamer = { version = "0.15", optional = true }
|
||||
gstreamer = { version = "0.15", features = ["v1_16"], optional = true }
|
||||
ipc-channel = "0.14"
|
||||
keyboard-types = "0.5"
|
||||
layout_thread_2013 = { path = "../layout_thread", optional = true }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue