mirror of
https://github.com/servo/servo.git
synced 2025-09-30 00:29:14 +01:00
script: Move WebRTC DOM interfaces to script/dom/webrtc/ (#39023)
Move interfaces defined by the WebRTC specification to the `script/dom/webrtc/` module from `script/dom/`. `script/dom/rtc*.rs -> script/dom/webrtc/` Testing: No changes, just a refactoring Fixes (partially): #38901 Signed-off-by: Andrei Volykhin <volykhin.andrei@huawei.com> Co-authored-by: Andrei Volykhin <volykhin.andrei@huawei.com>
This commit is contained in:
parent
66d9f957e6
commit
00d0783471
13 changed files with 17 additions and 11 deletions
15
components/script/dom/webrtc/mod.rs
Normal file
15
components/script/dom/webrtc/mod.rs
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/. */
|
||||
|
||||
pub(crate) mod rtcdatachannel;
|
||||
pub(crate) mod rtcdatachannelevent;
|
||||
pub(crate) mod rtcerror;
|
||||
pub(crate) mod rtcerrorevent;
|
||||
pub(crate) mod rtcicecandidate;
|
||||
pub(crate) mod rtcpeerconnection;
|
||||
pub(crate) mod rtcpeerconnectioniceevent;
|
||||
pub(crate) mod rtcrtpsender;
|
||||
pub(crate) mod rtcrtptransceiver;
|
||||
pub(crate) mod rtcsessiondescription;
|
||||
pub(crate) mod rtctrackevent;
|
424
components/script/dom/webrtc/rtcdatachannel.rs
Normal file
424
components/script/dom/webrtc/rtcdatachannel.rs
Normal file
|
@ -0,0 +1,424 @@
|
|||
/* 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 std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
use constellation_traits::BlobImpl;
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::{JSAutoRealm, JSObject};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::CustomAutoRooterGuard;
|
||||
use js::typedarray::{ArrayBuffer, ArrayBufferView, CreateWith};
|
||||
use script_bindings::conversions::SafeToJSValConvertible;
|
||||
use script_bindings::weakref::WeakRef;
|
||||
use servo_media::webrtc::{
|
||||
DataChannelId, DataChannelInit, DataChannelMessage, DataChannelState, WebRtcError,
|
||||
};
|
||||
|
||||
use crate::conversions::Convert;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::{
|
||||
RTCDataChannelInit, RTCDataChannelMethods, 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::{DomGlobal, DomObject, reflect_dom_object};
|
||||
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 crate::script_runtime::CanGc;
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
struct DroppableRTCDataChannel {
|
||||
#[ignore_malloc_size_of = "defined in servo-media"]
|
||||
servo_media_id: DataChannelId,
|
||||
peer_connection: WeakRef<RTCPeerConnection>,
|
||||
}
|
||||
|
||||
impl DroppableRTCDataChannel {
|
||||
fn new(peer_connection: WeakRef<RTCPeerConnection>, servo_media_id: DataChannelId) -> Self {
|
||||
DroppableRTCDataChannel {
|
||||
servo_media_id,
|
||||
peer_connection,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
|
||||
self.servo_media_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DroppableRTCDataChannel {
|
||||
fn drop(&mut self) {
|
||||
if let Some(root) = self.peer_connection.root() {
|
||||
root.unregister_data_channel(&self.get_servo_media_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCDataChannel {
|
||||
eventtarget: EventTarget,
|
||||
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>,
|
||||
peer_connection: Dom<RTCPeerConnection>,
|
||||
droppable: DroppableRTCDataChannel,
|
||||
}
|
||||
|
||||
impl RTCDataChannel {
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
pub(crate) fn new_inherited(
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
) -> RTCDataChannel {
|
||||
let mut init: DataChannelInit = options.convert();
|
||||
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"),
|
||||
);
|
||||
|
||||
RTCDataChannel {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
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")),
|
||||
peer_connection: Dom::from_ref(peer_connection),
|
||||
droppable: DroppableRTCDataChannel::new(WeakRef::new(peer_connection), servo_media_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
global: &GlobalScope,
|
||||
peer_connection: &RTCPeerConnection,
|
||||
label: USVString,
|
||||
options: &RTCDataChannelInit,
|
||||
servo_media_id: Option<DataChannelId>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCDataChannel> {
|
||||
let rtc_data_channel = reflect_dom_object(
|
||||
Box::new(RTCDataChannel::new_inherited(
|
||||
peer_connection,
|
||||
label,
|
||||
options,
|
||||
servo_media_id,
|
||||
)),
|
||||
global,
|
||||
can_gc,
|
||||
);
|
||||
|
||||
peer_connection
|
||||
.register_data_channel(rtc_data_channel.get_servo_media_id(), &rtc_data_channel);
|
||||
|
||||
rtc_data_channel
|
||||
}
|
||||
|
||||
pub(crate) fn get_servo_media_id(&self) -> DataChannelId {
|
||||
self.droppable.get_servo_media_id()
|
||||
}
|
||||
|
||||
pub(crate) fn on_open(&self, can_gc: CanGc) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("open"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
pub(crate) fn on_close(&self, can_gc: CanGc) {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("close"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
|
||||
self.peer_connection
|
||||
.unregister_data_channel(&self.get_servo_media_id());
|
||||
}
|
||||
|
||||
pub(crate) fn on_error(&self, error: WebRtcError, can_gc: CanGc) {
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
let cx = GlobalScope::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(window, &init, message, can_gc);
|
||||
let event = RTCErrorEvent::new(window, atom!("error"), false, false, &error, can_gc);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn on_message(&self, channel_message: DataChannelMessage, can_gc: CanGc) {
|
||||
let global = self.global();
|
||||
let cx = GlobalScope::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.safe_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()),
|
||||
can_gc,
|
||||
);
|
||||
blob.safe_to_jsval(cx, message.handle_mut());
|
||||
},
|
||||
"arraybuffer" => {
|
||||
rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
assert!(
|
||||
ArrayBuffer::create(
|
||||
*cx,
|
||||
CreateWith::Slice(&data),
|
||||
array_buffer.handle_mut()
|
||||
)
|
||||
.is_ok()
|
||||
)
|
||||
};
|
||||
|
||||
(*array_buffer).safe_to_jsval(cx, message.handle_mut());
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
|
||||
MessageEvent::dispatch_jsval(
|
||||
self.upcast(),
|
||||
&global,
|
||||
message.handle(),
|
||||
Some(&global.origin().immutable().ascii_serialization()),
|
||||
None,
|
||||
vec![],
|
||||
can_gc,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn on_state_change(&self, state: DataChannelState, can_gc: CanGc) {
|
||||
if let DataChannelState::Closing = state {
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("closing"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
};
|
||||
self.ready_state.set(state.convert());
|
||||
}
|
||||
|
||||
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.get_servo_media_id(), message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum SendSource<'a, 'b> {
|
||||
String(&'a USVString),
|
||||
Blob(&'a Blob),
|
||||
ArrayBuffer(CustomAutoRooterGuard<'b, ArrayBuffer>),
|
||||
ArrayBufferView(CustomAutoRooterGuard<'b, ArrayBufferView>),
|
||||
}
|
||||
|
||||
impl RTCDataChannelMethods<crate::DomTypeHolder> 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.get_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 Convert<DataChannelInit> for &RTCDataChannelInit {
|
||||
fn convert(self) -> DataChannelInit {
|
||||
DataChannelInit {
|
||||
label: String::new(),
|
||||
id: self.id,
|
||||
max_packet_life_time: self.maxPacketLifeTime,
|
||||
max_retransmits: self.maxRetransmits,
|
||||
negotiated: self.negotiated,
|
||||
ordered: self.ordered,
|
||||
protocol: self.protocol.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCDataChannelState> for DataChannelState {
|
||||
fn convert(self) -> RTCDataChannelState {
|
||||
match self {
|
||||
DataChannelState::Connecting | DataChannelState::__Unknown(_) => {
|
||||
RTCDataChannelState::Connecting
|
||||
},
|
||||
DataChannelState::Open => RTCDataChannelState::Open,
|
||||
DataChannelState::Closing => RTCDataChannelState::Closing,
|
||||
DataChannelState::Closed => RTCDataChannelState::Closed,
|
||||
}
|
||||
}
|
||||
}
|
99
components/script/dom/webrtc/rtcdatachannelevent.rs
Normal file
99
components/script/dom/webrtc/rtcdatachannelevent.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCDataChannelEventBinding::{
|
||||
RTCDataChannelEventInit, RTCDataChannelEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::rtcdatachannel::RTCDataChannel;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) 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(crate) fn new(
|
||||
window: &Window,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
channel: &RTCDataChannel,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCDataChannelEvent> {
|
||||
Self::new_with_proto(window, None, type_, bubbles, cancelable, channel, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
channel: &RTCDataChannel,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCDataChannelEvent> {
|
||||
let event = reflect_dom_object_with_proto(
|
||||
Box::new(RTCDataChannelEvent::new_inherited(channel)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
{
|
||||
let event = event.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
event
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCDataChannelEventMethods<crate::DomTypeHolder> for RTCDataChannelEvent {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcdatachannelevent-constructor
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
type_: DOMString,
|
||||
init: &RTCDataChannelEventInit,
|
||||
) -> DomRoot<RTCDataChannelEvent> {
|
||||
RTCDataChannelEvent::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.channel,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
108
components/script/dom/webrtc/rtcerror.rs
Normal file
108
components/script/dom/webrtc/rtcerror.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{
|
||||
RTCErrorDetailType, RTCErrorInit, RTCErrorMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::domexception::DOMException;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCError {
|
||||
exception: 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(init: &RTCErrorInit, message: DOMString) -> RTCError {
|
||||
RTCError {
|
||||
exception: DOMException::new_inherited(message, "OperationError".into()),
|
||||
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(crate) fn new(
|
||||
window: &Window,
|
||||
init: &RTCErrorInit,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCError> {
|
||||
Self::new_with_proto(window, None, init, message, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
init: &RTCErrorInit,
|
||||
message: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCError> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(RTCError::new_inherited(init, message)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCErrorMethods<crate::DomTypeHolder> for RTCError {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerror-constructor
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
init: &RTCErrorInit,
|
||||
message: DOMString,
|
||||
) -> DomRoot<RTCError> {
|
||||
RTCError::new_with_proto(window, proto, init, message, can_gc)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
99
components/script/dom/webrtc/rtcerrorevent.rs
Normal file
99
components/script/dom/webrtc/rtcerrorevent.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCErrorEventBinding::{
|
||||
RTCErrorEventInit, RTCErrorEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::rtcerror::RTCError;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) 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(crate) fn new(
|
||||
window: &Window,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
error: &RTCError,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCErrorEvent> {
|
||||
Self::new_with_proto(window, None, type_, bubbles, cancelable, error, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
error: &RTCError,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCErrorEvent> {
|
||||
let event = reflect_dom_object_with_proto(
|
||||
Box::new(RTCErrorEvent::new_inherited(error)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
{
|
||||
let event = event.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
event
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCErrorEventMethods<crate::DomTypeHolder> for RTCErrorEvent {
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcerrorevent-constructor
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
type_: DOMString,
|
||||
init: &RTCErrorEventInit,
|
||||
) -> DomRoot<RTCErrorEvent> {
|
||||
RTCErrorEvent::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.error,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
138
components/script/dom/webrtc/rtcicecandidate.rs
Normal file
138
components/script/dom/webrtc/rtcicecandidate.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::RTCIceCandidateBinding::{
|
||||
RTCIceCandidateInit, RTCIceCandidateMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCIceCandidate {
|
||||
reflector: Reflector,
|
||||
candidate: DOMString,
|
||||
sdp_m_id: Option<DOMString>,
|
||||
sdp_m_line_index: Option<u16>,
|
||||
username_fragment: Option<DOMString>,
|
||||
}
|
||||
|
||||
impl RTCIceCandidate {
|
||||
pub(crate) fn new_inherited(
|
||||
candidate: DOMString,
|
||||
sdp_m_id: Option<DOMString>,
|
||||
sdp_m_line_index: Option<u16>,
|
||||
username_fragment: Option<DOMString>,
|
||||
) -> RTCIceCandidate {
|
||||
RTCIceCandidate {
|
||||
reflector: Reflector::new(),
|
||||
candidate,
|
||||
sdp_m_id,
|
||||
sdp_m_line_index,
|
||||
username_fragment,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
candidate: DOMString,
|
||||
sdp_m_id: Option<DOMString>,
|
||||
sdp_m_line_index: Option<u16>,
|
||||
username_fragment: Option<DOMString>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCIceCandidate> {
|
||||
Self::new_with_proto(
|
||||
window,
|
||||
None,
|
||||
candidate,
|
||||
sdp_m_id,
|
||||
sdp_m_line_index,
|
||||
username_fragment,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
candidate: DOMString,
|
||||
sdp_m_id: Option<DOMString>,
|
||||
sdp_m_line_index: Option<u16>,
|
||||
username_fragment: Option<DOMString>,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCIceCandidate> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(RTCIceCandidate::new_inherited(
|
||||
candidate,
|
||||
sdp_m_id,
|
||||
sdp_m_line_index,
|
||||
username_fragment,
|
||||
)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCIceCandidateMethods<crate::DomTypeHolder> for RTCIceCandidate {
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-constructor>
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
config: &RTCIceCandidateInit,
|
||||
) -> Fallible<DomRoot<RTCIceCandidate>> {
|
||||
if config.sdpMid.is_none() && config.sdpMLineIndex.is_none() {
|
||||
return Err(Error::Type(
|
||||
"one of sdpMid and sdpMLineIndex must be set".to_string(),
|
||||
));
|
||||
}
|
||||
Ok(RTCIceCandidate::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
config.candidate.clone(),
|
||||
config.sdpMid.clone(),
|
||||
config.sdpMLineIndex,
|
||||
config.usernameFragment.clone(),
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-candidate>
|
||||
fn Candidate(&self) -> DOMString {
|
||||
self.candidate.clone()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-sdpmid>
|
||||
fn GetSdpMid(&self) -> Option<DOMString> {
|
||||
self.sdp_m_id.clone()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-sdpmlineindex>
|
||||
fn GetSdpMLineIndex(&self) -> Option<u16> {
|
||||
self.sdp_m_line_index
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-usernamefragment>
|
||||
fn GetUsernameFragment(&self) -> Option<DOMString> {
|
||||
self.username_fragment.clone()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-tojson>
|
||||
fn ToJSON(&self) -> RTCIceCandidateInit {
|
||||
RTCIceCandidateInit {
|
||||
candidate: self.candidate.clone(),
|
||||
sdpMid: self.sdp_m_id.clone(),
|
||||
sdpMLineIndex: self.sdp_m_line_index,
|
||||
usernameFragment: self.username_fragment.clone(),
|
||||
}
|
||||
}
|
||||
}
|
858
components/script/dom/webrtc/rtcpeerconnection.rs
Normal file
858
components/script/dom/webrtc/rtcpeerconnection.rs
Normal file
|
@ -0,0 +1,858 @@
|
|||
/* 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 std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use servo_media::ServoMedia;
|
||||
use servo_media::streams::MediaStreamType;
|
||||
use servo_media::streams::registry::MediaStreamId;
|
||||
use servo_media::webrtc::{
|
||||
BundlePolicy, DataChannelEvent, DataChannelId, DataChannelState, GatheringState, IceCandidate,
|
||||
IceConnectionState, SdpType, SessionDescription, SignalingState, WebRtcController,
|
||||
WebRtcSignaller,
|
||||
};
|
||||
|
||||
use crate::conversions::Convert;
|
||||
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::{
|
||||
RTCAnswerOptions, RTCBundlePolicy, RTCConfiguration, RTCIceConnectionState,
|
||||
RTCIceGatheringState, RTCOfferOptions, RTCPeerConnectionMethods, RTCRtpTransceiverInit,
|
||||
RTCSignalingState,
|
||||
};
|
||||
use crate::dom::bindings::codegen::Bindings::RTCSessionDescriptionBinding::{
|
||||
RTCSdpType, RTCSessionDescriptionInit, RTCSessionDescriptionMethods,
|
||||
};
|
||||
use crate::dom::bindings::codegen::UnionTypes::{MediaStreamTrackOrString, StringOrStringSequence};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object_with_proto};
|
||||
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::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::rtcrtptransceiver::RTCRtpTransceiver;
|
||||
use crate::dom::rtcsessiondescription::RTCSessionDescription;
|
||||
use crate::dom::rtctrackevent::RTCTrackEvent;
|
||||
use crate::dom::window::Window;
|
||||
use crate::realms::{InRealm, enter_realm};
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::task_source::SendableTaskSource;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCPeerConnection {
|
||||
eventtarget: EventTarget,
|
||||
#[ignore_malloc_size_of = "defined in servo-media"]
|
||||
#[no_trace]
|
||||
controller: DomRefCell<Option<WebRtcController>>,
|
||||
closed: Cell<bool>,
|
||||
// Helps track state changes between the time createOffer/createAnswer
|
||||
// is called and resolved
|
||||
offer_answer_generation: Cell<u32>,
|
||||
#[ignore_malloc_size_of = "promises are hard"]
|
||||
offer_promises: DomRefCell<Vec<Rc<Promise>>>,
|
||||
#[ignore_malloc_size_of = "promises are hard"]
|
||||
answer_promises: DomRefCell<Vec<Rc<Promise>>>,
|
||||
local_description: MutNullableDom<RTCSessionDescription>,
|
||||
remote_description: MutNullableDom<RTCSessionDescription>,
|
||||
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 {
|
||||
trusted: Trusted<RTCPeerConnection>,
|
||||
task_source: SendableTaskSource,
|
||||
}
|
||||
|
||||
impl WebRtcSignaller for RTCSignaller {
|
||||
fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) {
|
||||
let this = self.trusted.clone();
|
||||
self.task_source.queue(task!(on_ice_candidate: move || {
|
||||
let this = this.root();
|
||||
this.on_ice_candidate(candidate, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn on_negotiation_needed(&self, _: &WebRtcController) {
|
||||
let this = self.trusted.clone();
|
||||
self.task_source
|
||||
.queue(task!(on_negotiation_needed: move || {
|
||||
let this = this.root();
|
||||
this.on_negotiation_needed(CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn update_gathering_state(&self, state: GatheringState) {
|
||||
let this = self.trusted.clone();
|
||||
self.task_source
|
||||
.queue(task!(update_gathering_state: move || {
|
||||
let this = this.root();
|
||||
this.update_gathering_state(state, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn update_ice_connection_state(&self, state: IceConnectionState) {
|
||||
let this = self.trusted.clone();
|
||||
self.task_source
|
||||
.queue(task!(update_ice_connection_state: move || {
|
||||
let this = this.root();
|
||||
this.update_ice_connection_state(state, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn update_signaling_state(&self, state: SignalingState) {
|
||||
let this = self.trusted.clone();
|
||||
self.task_source
|
||||
.queue(task!(update_signaling_state: move || {
|
||||
let this = this.root();
|
||||
this.update_signaling_state(state, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) {
|
||||
let this = self.trusted.clone();
|
||||
let id = *id;
|
||||
self.task_source.queue(task!(on_add_stream: move || {
|
||||
let this = this.root();
|
||||
this.on_add_stream(id, ty, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
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();
|
||||
self.task_source
|
||||
.queue(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, CanGc::note());
|
||||
}));
|
||||
}
|
||||
|
||||
fn close(&self) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCPeerConnection {
|
||||
pub(crate) fn new_inherited() -> RTCPeerConnection {
|
||||
RTCPeerConnection {
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
controller: DomRefCell::new(None),
|
||||
closed: Cell::new(false),
|
||||
offer_answer_generation: Cell::new(0),
|
||||
offer_promises: DomRefCell::new(vec![]),
|
||||
answer_promises: DomRefCell::new(vec![]),
|
||||
local_description: Default::default(),
|
||||
remote_description: Default::default(),
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
||||
fn new(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
config: &RTCConfiguration,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCPeerConnection> {
|
||||
let this = reflect_dom_object_with_proto(
|
||||
Box::new(RTCPeerConnection::new_inherited()),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
let signaller = this.make_signaller();
|
||||
*this.controller.borrow_mut() = Some(ServoMedia::get().create_webrtc(signaller));
|
||||
if let Some(ref servers) = config.iceServers {
|
||||
if let Some(server) = servers.first() {
|
||||
let server = match server.urls {
|
||||
StringOrStringSequence::String(ref s) => Some(s.clone()),
|
||||
StringOrStringSequence::StringSequence(ref s) => s.first().cloned(),
|
||||
};
|
||||
if let Some(server) = server {
|
||||
let policy = match config.bundlePolicy {
|
||||
RTCBundlePolicy::Balanced => BundlePolicy::Balanced,
|
||||
RTCBundlePolicy::Max_compat => BundlePolicy::MaxCompat,
|
||||
RTCBundlePolicy::Max_bundle => BundlePolicy::MaxBundle,
|
||||
};
|
||||
this.controller
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.configure(server.to_string(), policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
pub(crate) fn get_webrtc_controller(&self) -> &DomRefCell<Option<WebRtcController>> {
|
||||
&self.controller
|
||||
}
|
||||
|
||||
fn make_signaller(&self) -> Box<dyn WebRtcSignaller> {
|
||||
let trusted = Trusted::new(self);
|
||||
Box::new(RTCSignaller {
|
||||
trusted,
|
||||
task_source: self.global().task_manager().networking_task_source().into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn on_ice_candidate(&self, candidate: IceCandidate, can_gc: CanGc) {
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
let candidate = RTCIceCandidate::new(
|
||||
self.global().as_window(),
|
||||
candidate.candidate.into(),
|
||||
None,
|
||||
Some(candidate.sdp_mline_index as u16),
|
||||
None,
|
||||
can_gc,
|
||||
);
|
||||
let event = RTCPeerConnectionIceEvent::new(
|
||||
self.global().as_window(),
|
||||
atom!("icecandidate"),
|
||||
Some(&candidate),
|
||||
None,
|
||||
true,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
fn on_negotiation_needed(&self, can_gc: CanGc) {
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("negotiationneeded"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
fn on_add_stream(&self, id: MediaStreamId, ty: MediaStreamType, can_gc: CanGc) {
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
let track = MediaStreamTrack::new(&self.global(), id, ty, can_gc);
|
||||
let event = RTCTrackEvent::new(
|
||||
self.global().as_window(),
|
||||
atom!("track"),
|
||||
false,
|
||||
false,
|
||||
&track,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
fn on_data_channel_event(
|
||||
&self,
|
||||
channel_id: DataChannelId,
|
||||
event: DataChannelEvent,
|
||||
can_gc: CanGc,
|
||||
) {
|
||||
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),
|
||||
can_gc,
|
||||
);
|
||||
|
||||
let event = RTCDataChannelEvent::new(
|
||||
self.global().as_window(),
|
||||
atom!("datachannel"),
|
||||
false,
|
||||
false,
|
||||
&channel,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
},
|
||||
_ => {
|
||||
let channel: DomRoot<RTCDataChannel> =
|
||||
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(can_gc),
|
||||
DataChannelEvent::Close => channel.on_close(can_gc),
|
||||
DataChannelEvent::Error(error) => channel.on_error(error, can_gc),
|
||||
DataChannelEvent::OnMessage(message) => channel.on_message(message, can_gc),
|
||||
DataChannelEvent::StateChange(state) => channel.on_state_change(state, can_gc),
|
||||
DataChannelEvent::NewChannel => unreachable!(),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) 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(crate) 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, can_gc: CanGc) {
|
||||
// step 1
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
// step 2 (state derivation already done by gstreamer)
|
||||
let state: RTCIceGatheringState = state.convert();
|
||||
|
||||
// step 3
|
||||
if state == self.gathering_state.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
// step 4
|
||||
self.gathering_state.set(state);
|
||||
|
||||
// step 5
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("icegatheringstatechange"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
|
||||
// step 6
|
||||
if state == RTCIceGatheringState::Complete {
|
||||
let event = RTCPeerConnectionIceEvent::new(
|
||||
self.global().as_window(),
|
||||
atom!("icecandidate"),
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/webrtc/#update-ice-connection-state>
|
||||
fn update_ice_connection_state(&self, state: IceConnectionState, can_gc: CanGc) {
|
||||
// step 1
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
// step 2 (state derivation already done by gstreamer)
|
||||
let state: RTCIceConnectionState = state.convert();
|
||||
|
||||
// step 3
|
||||
if state == self.ice_connection_state.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
// step 4
|
||||
self.ice_connection_state.set(state);
|
||||
|
||||
// step 5
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("iceconnectionstatechange"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
fn update_signaling_state(&self, state: SignalingState, can_gc: CanGc) {
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
let state: RTCSignalingState = state.convert();
|
||||
|
||||
if state == self.signaling_state.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.signaling_state.set(state);
|
||||
|
||||
let event = Event::new(
|
||||
&self.global(),
|
||||
atom!("signalingstatechange"),
|
||||
EventBubbles::DoesNotBubble,
|
||||
EventCancelable::NotCancelable,
|
||||
can_gc,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast(), can_gc);
|
||||
}
|
||||
|
||||
fn create_offer(&self) {
|
||||
let generation = self.offer_answer_generation.get();
|
||||
let task_source = self
|
||||
.global()
|
||||
.task_manager()
|
||||
.networking_task_source()
|
||||
.to_sendable();
|
||||
let this = Trusted::new(self);
|
||||
self.controller
|
||||
.borrow_mut()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.create_offer(Box::new(move |desc: SessionDescription| {
|
||||
task_source.queue(task!(offer_created: move || {
|
||||
let this = this.root();
|
||||
if this.offer_answer_generation.get() != generation {
|
||||
// the state has changed since we last created the offer,
|
||||
// create a fresh one
|
||||
this.create_offer();
|
||||
} else {
|
||||
let init: RTCSessionDescriptionInit = desc.convert();
|
||||
for promise in this.offer_promises.borrow_mut().drain(..) {
|
||||
promise.resolve_native(&init, CanGc::note());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
fn create_answer(&self) {
|
||||
let generation = self.offer_answer_generation.get();
|
||||
let task_source = self
|
||||
.global()
|
||||
.task_manager()
|
||||
.networking_task_source()
|
||||
.to_sendable();
|
||||
let this = Trusted::new(self);
|
||||
self.controller
|
||||
.borrow_mut()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.create_answer(Box::new(move |desc: SessionDescription| {
|
||||
task_source.queue(task!(answer_created: move || {
|
||||
let this = this.root();
|
||||
if this.offer_answer_generation.get() != generation {
|
||||
// the state has changed since we last created the offer,
|
||||
// create a fresh one
|
||||
this.create_answer();
|
||||
} else {
|
||||
let init: RTCSessionDescriptionInit = desc.convert();
|
||||
for promise in this.answer_promises.borrow_mut().drain(..) {
|
||||
promise.resolve_native(&init, CanGc::note());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCPeerConnectionMethods<crate::DomTypeHolder> for RTCPeerConnection {
|
||||
// https://w3c.github.io/webrtc-pc/#dom-peerconnection
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
config: &RTCConfiguration,
|
||||
) -> Fallible<DomRoot<RTCPeerConnection>> {
|
||||
Ok(RTCPeerConnection::new(window, proto, config, can_gc))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icecandidate
|
||||
event_handler!(icecandidate, GetOnicecandidate, SetOnicecandidate);
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ontrack
|
||||
event_handler!(track, GetOntrack, SetOntrack);
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-iceconnectionstatechange
|
||||
event_handler!(
|
||||
iceconnectionstatechange,
|
||||
GetOniceconnectionstatechange,
|
||||
SetOniceconnectionstatechange
|
||||
);
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icegatheringstatechange
|
||||
event_handler!(
|
||||
icegatheringstatechange,
|
||||
GetOnicegatheringstatechange,
|
||||
SetOnicegatheringstatechange
|
||||
);
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-onnegotiationneeded
|
||||
event_handler!(
|
||||
negotiationneeded,
|
||||
GetOnnegotiationneeded,
|
||||
SetOnnegotiationneeded
|
||||
);
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-signalingstatechange
|
||||
event_handler!(
|
||||
signalingstatechange,
|
||||
GetOnsignalingstatechange,
|
||||
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,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let p = Promise::new_in_current_realm(comp, can_gc);
|
||||
if candidate.sdpMid.is_none() && candidate.sdpMLineIndex.is_none() {
|
||||
p.reject_error(
|
||||
Error::Type("one of sdpMid and sdpMLineIndex must be set".to_string()),
|
||||
can_gc,
|
||||
);
|
||||
return p;
|
||||
}
|
||||
|
||||
// XXXManishearth add support for sdpMid
|
||||
if candidate.sdpMLineIndex.is_none() {
|
||||
p.reject_error(
|
||||
Error::Type("servo only supports sdpMLineIndex right now".to_string()),
|
||||
can_gc,
|
||||
);
|
||||
return p;
|
||||
}
|
||||
|
||||
// XXXManishearth this should be enqueued
|
||||
// https://w3c.github.io/webrtc-pc/#enqueue-an-operation
|
||||
|
||||
self.controller
|
||||
.borrow_mut()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.add_ice_candidate(IceCandidate {
|
||||
sdp_mline_index: candidate.sdpMLineIndex.unwrap() as u32,
|
||||
candidate: candidate.candidate.to_string(),
|
||||
});
|
||||
|
||||
// XXXManishearth add_ice_candidate should have a callback
|
||||
p.resolve_native(&(), can_gc);
|
||||
p
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer>
|
||||
fn CreateOffer(&self, _options: &RTCOfferOptions, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
|
||||
let p = Promise::new_in_current_realm(comp, can_gc);
|
||||
if self.closed.get() {
|
||||
p.reject_error(Error::InvalidState, can_gc);
|
||||
return p;
|
||||
}
|
||||
self.offer_promises.borrow_mut().push(p.clone());
|
||||
self.create_offer();
|
||||
p
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer>
|
||||
fn CreateAnswer(
|
||||
&self,
|
||||
_options: &RTCAnswerOptions,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
let p = Promise::new_in_current_realm(comp, can_gc);
|
||||
if self.closed.get() {
|
||||
p.reject_error(Error::InvalidState, can_gc);
|
||||
return p;
|
||||
}
|
||||
self.answer_promises.borrow_mut().push(p.clone());
|
||||
self.create_answer();
|
||||
p
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-localdescription>
|
||||
fn GetLocalDescription(&self) -> Option<DomRoot<RTCSessionDescription>> {
|
||||
self.local_description.get()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-remotedescription>
|
||||
fn GetRemoteDescription(&self) -> Option<DomRoot<RTCSessionDescription>> {
|
||||
self.remote_description.get()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-setlocaldescription>
|
||||
fn SetLocalDescription(
|
||||
&self,
|
||||
desc: &RTCSessionDescriptionInit,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
// XXXManishearth validate the current state
|
||||
let p = Promise::new_in_current_realm(comp, can_gc);
|
||||
let this = Trusted::new(self);
|
||||
let desc: SessionDescription = desc.convert();
|
||||
let trusted_promise = TrustedPromise::new(p.clone());
|
||||
let task_source = self
|
||||
.global()
|
||||
.task_manager()
|
||||
.networking_task_source()
|
||||
.to_sendable();
|
||||
self.controller
|
||||
.borrow_mut()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set_local_description(
|
||||
desc.clone(),
|
||||
Box::new(move || {
|
||||
task_source.queue(task!(local_description_set: move || {
|
||||
// XXXManishearth spec actually asks for an intricate
|
||||
// dance between pending/current local/remote descriptions
|
||||
let this = this.root();
|
||||
let desc = desc.convert();
|
||||
let desc = RTCSessionDescription::Constructor(
|
||||
this.global().as_window(),
|
||||
None,
|
||||
CanGc::note(),
|
||||
&desc,
|
||||
).unwrap();
|
||||
this.local_description.set(Some(&desc));
|
||||
trusted_promise.root().resolve_native(&(), CanGc::note())
|
||||
}));
|
||||
}),
|
||||
);
|
||||
p
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-setremotedescription>
|
||||
fn SetRemoteDescription(
|
||||
&self,
|
||||
desc: &RTCSessionDescriptionInit,
|
||||
comp: InRealm,
|
||||
can_gc: CanGc,
|
||||
) -> Rc<Promise> {
|
||||
// XXXManishearth validate the current state
|
||||
let p = Promise::new_in_current_realm(comp, can_gc);
|
||||
let this = Trusted::new(self);
|
||||
let desc: SessionDescription = desc.convert();
|
||||
let trusted_promise = TrustedPromise::new(p.clone());
|
||||
let task_source = self
|
||||
.global()
|
||||
.task_manager()
|
||||
.networking_task_source()
|
||||
.to_sendable();
|
||||
self.controller
|
||||
.borrow_mut()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set_remote_description(
|
||||
desc.clone(),
|
||||
Box::new(move || {
|
||||
task_source.queue(task!(remote_description_set: move || {
|
||||
// XXXManishearth spec actually asks for an intricate
|
||||
// dance between pending/current local/remote descriptions
|
||||
let this = this.root();
|
||||
let desc = desc.convert();
|
||||
let desc = RTCSessionDescription::Constructor(
|
||||
this.global().as_window(),
|
||||
None,
|
||||
CanGc::note(),
|
||||
&desc,
|
||||
).unwrap();
|
||||
this.remote_description.set(Some(&desc));
|
||||
trusted_promise.root().resolve_native(&(), CanGc::note())
|
||||
}));
|
||||
}),
|
||||
);
|
||||
p
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
|
||||
fn AddStream(&self, stream: &MediaStream) {
|
||||
for track in &*stream.get_tracks() {
|
||||
self.controller
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.add_stream(&track.id());
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-icegatheringstate>
|
||||
fn IceGatheringState(&self) -> RTCIceGatheringState {
|
||||
self.gathering_state.get()
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-iceconnectionstate>
|
||||
fn IceConnectionState(&self) -> RTCIceConnectionState {
|
||||
self.ice_connection_state.get()
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-signalingstate>
|
||||
fn SignalingState(&self) -> RTCSignalingState {
|
||||
self.signaling_state.get()
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close>
|
||||
fn Close(&self, can_gc: CanGc) {
|
||||
// Step 1
|
||||
if self.closed.get() {
|
||||
return;
|
||||
}
|
||||
// Step 2
|
||||
self.closed.set(true);
|
||||
|
||||
// Step 4
|
||||
self.signaling_state.set(RTCSignalingState::Closed);
|
||||
|
||||
// Step 5 handled by backend
|
||||
self.controller.borrow_mut().as_ref().unwrap().quit();
|
||||
|
||||
// Step 6
|
||||
for (_, val) in self.data_channels.borrow().iter() {
|
||||
val.on_state_change(DataChannelState::Closed, can_gc);
|
||||
}
|
||||
|
||||
// Step 7-10
|
||||
// (no current support for transports, etc)
|
||||
|
||||
// Step 11
|
||||
self.ice_connection_state.set(RTCIceConnectionState::Closed);
|
||||
|
||||
// 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, CanGc::note())
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver>
|
||||
fn AddTransceiver(
|
||||
&self,
|
||||
_track_or_kind: MediaStreamTrackOrString,
|
||||
init: &RTCRtpTransceiverInit,
|
||||
) -> DomRoot<RTCRtpTransceiver> {
|
||||
RTCRtpTransceiver::new(&self.global(), init.direction, CanGc::note())
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCSessionDescriptionInit> for SessionDescription {
|
||||
fn convert(self) -> RTCSessionDescriptionInit {
|
||||
let type_ = match self.type_ {
|
||||
SdpType::Answer => RTCSdpType::Answer,
|
||||
SdpType::Offer => RTCSdpType::Offer,
|
||||
SdpType::Pranswer => RTCSdpType::Pranswer,
|
||||
SdpType::Rollback => RTCSdpType::Rollback,
|
||||
};
|
||||
RTCSessionDescriptionInit {
|
||||
type_,
|
||||
sdp: self.sdp.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<SessionDescription> for &RTCSessionDescriptionInit {
|
||||
fn convert(self) -> SessionDescription {
|
||||
let type_ = match self.type_ {
|
||||
RTCSdpType::Answer => SdpType::Answer,
|
||||
RTCSdpType::Offer => SdpType::Offer,
|
||||
RTCSdpType::Pranswer => SdpType::Pranswer,
|
||||
RTCSdpType::Rollback => SdpType::Rollback,
|
||||
};
|
||||
SessionDescription {
|
||||
type_,
|
||||
sdp: self.sdp.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCIceGatheringState> for GatheringState {
|
||||
fn convert(self) -> RTCIceGatheringState {
|
||||
match self {
|
||||
GatheringState::New => RTCIceGatheringState::New,
|
||||
GatheringState::Gathering => RTCIceGatheringState::Gathering,
|
||||
GatheringState::Complete => RTCIceGatheringState::Complete,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCIceConnectionState> for IceConnectionState {
|
||||
fn convert(self) -> RTCIceConnectionState {
|
||||
match self {
|
||||
IceConnectionState::New => RTCIceConnectionState::New,
|
||||
IceConnectionState::Checking => RTCIceConnectionState::Checking,
|
||||
IceConnectionState::Connected => RTCIceConnectionState::Connected,
|
||||
IceConnectionState::Completed => RTCIceConnectionState::Completed,
|
||||
IceConnectionState::Disconnected => RTCIceConnectionState::Disconnected,
|
||||
IceConnectionState::Failed => RTCIceConnectionState::Failed,
|
||||
IceConnectionState::Closed => RTCIceConnectionState::Closed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<RTCSignalingState> for SignalingState {
|
||||
fn convert(self) -> RTCSignalingState {
|
||||
match self {
|
||||
SignalingState::Stable => RTCSignalingState::Stable,
|
||||
SignalingState::HaveLocalOffer => RTCSignalingState::Have_local_offer,
|
||||
SignalingState::HaveRemoteOffer => RTCSignalingState::Have_remote_offer,
|
||||
SignalingState::HaveLocalPranswer => RTCSignalingState::Have_local_pranswer,
|
||||
SignalingState::HaveRemotePranswer => RTCSignalingState::Have_remote_pranswer,
|
||||
SignalingState::Closed => RTCSignalingState::Closed,
|
||||
}
|
||||
}
|
||||
}
|
112
components/script/dom/webrtc/rtcpeerconnectioniceevent.rs
Normal file
112
components/script/dom/webrtc/rtcpeerconnectioniceevent.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCPeerConnectionIceEventBinding::{
|
||||
RTCPeerConnectionIceEventInit, RTCPeerConnectionIceEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::rtcicecandidate::RTCIceCandidate;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCPeerConnectionIceEvent {
|
||||
event: Event,
|
||||
candidate: Option<Dom<RTCIceCandidate>>,
|
||||
url: Option<DOMString>,
|
||||
}
|
||||
|
||||
impl RTCPeerConnectionIceEvent {
|
||||
pub(crate) fn new_inherited(
|
||||
candidate: Option<&RTCIceCandidate>,
|
||||
url: Option<DOMString>,
|
||||
) -> RTCPeerConnectionIceEvent {
|
||||
RTCPeerConnectionIceEvent {
|
||||
event: Event::new_inherited(),
|
||||
candidate: candidate.map(Dom::from_ref),
|
||||
url,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
ty: Atom,
|
||||
candidate: Option<&RTCIceCandidate>,
|
||||
url: Option<DOMString>,
|
||||
trusted: bool,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCPeerConnectionIceEvent> {
|
||||
Self::new_with_proto(window, None, ty, candidate, url, trusted, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
ty: Atom,
|
||||
candidate: Option<&RTCIceCandidate>,
|
||||
url: Option<DOMString>,
|
||||
trusted: bool,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCPeerConnectionIceEvent> {
|
||||
let e = reflect_dom_object_with_proto(
|
||||
Box::new(RTCPeerConnectionIceEvent::new_inherited(candidate, url)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
let evt = e.upcast::<Event>();
|
||||
evt.init_event(ty, false, false); // XXXManishearth bubbles/cancelable?
|
||||
evt.set_trusted(trusted);
|
||||
e
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCPeerConnectionIceEventMethods<crate::DomTypeHolder> for RTCPeerConnectionIceEvent {
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectioniceevent-constructor>
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
ty: DOMString,
|
||||
init: &RTCPeerConnectionIceEventInit,
|
||||
) -> Fallible<DomRoot<RTCPeerConnectionIceEvent>> {
|
||||
Ok(RTCPeerConnectionIceEvent::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
ty.into(),
|
||||
init.candidate
|
||||
.as_ref()
|
||||
.and_then(|x| x.as_ref())
|
||||
.map(|x| &**x),
|
||||
init.url.as_ref().and_then(|x| x.clone()),
|
||||
false,
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectioniceevent-candidate>
|
||||
fn GetCandidate(&self) -> Option<DomRoot<RTCIceCandidate>> {
|
||||
self.candidate.as_ref().map(|x| DomRoot::from_ref(&**x))
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectioniceevent-url>
|
||||
fn GetUrl(&self) -> Option<DOMString> {
|
||||
self.url.clone()
|
||||
}
|
||||
|
||||
/// <https://dom.spec.whatwg.org/#dom-event-istrusted>
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
59
components/script/dom/webrtc/rtcrtpsender.rs
Normal file
59
components/script/dom/webrtc/rtcrtpsender.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* 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 std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::RTCRtpSenderBinding::{
|
||||
RTCRtcpParameters, RTCRtpParameters, RTCRtpSendParameters, RTCRtpSenderMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCRtpSender {
|
||||
reflector_: Reflector,
|
||||
}
|
||||
|
||||
impl RTCRtpSender {
|
||||
fn new_inherited() -> Self {
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Self> {
|
||||
reflect_dom_object(Box::new(Self::new_inherited()), global, can_gc)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCRtpSenderMethods<crate::DomTypeHolder> for RTCRtpSender {
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-getparameters
|
||||
fn GetParameters(&self) -> RTCRtpSendParameters {
|
||||
RTCRtpSendParameters {
|
||||
parent: RTCRtpParameters {
|
||||
headerExtensions: vec![],
|
||||
rtcp: RTCRtcpParameters {
|
||||
cname: None,
|
||||
reducedSize: None,
|
||||
},
|
||||
codecs: vec![],
|
||||
},
|
||||
transactionId: DOMString::new(),
|
||||
encodings: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-setparameters
|
||||
fn SetParameters(&self, _parameters: &RTCRtpSendParameters, can_gc: CanGc) -> Rc<Promise> {
|
||||
let promise = Promise::new(&self.global(), can_gc);
|
||||
promise.resolve_native(&(), can_gc);
|
||||
promise
|
||||
}
|
||||
}
|
67
components/script/dom/webrtc/rtcrtptransceiver.rs
Normal file
67
components/script/dom/webrtc/rtcrtptransceiver.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* 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 std::cell::Cell;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::RTCRtpTransceiverBinding::{
|
||||
RTCRtpTransceiverDirection, RTCRtpTransceiverMethods,
|
||||
};
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::rtcrtpsender::RTCRtpSender;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCRtpTransceiver {
|
||||
reflector_: Reflector,
|
||||
sender: Dom<RTCRtpSender>,
|
||||
direction: Cell<RTCRtpTransceiverDirection>,
|
||||
}
|
||||
|
||||
impl RTCRtpTransceiver {
|
||||
fn new_inherited(
|
||||
global: &GlobalScope,
|
||||
direction: RTCRtpTransceiverDirection,
|
||||
can_gc: CanGc,
|
||||
) -> Self {
|
||||
let sender = RTCRtpSender::new(global, can_gc);
|
||||
Self {
|
||||
reflector_: Reflector::new(),
|
||||
direction: Cell::new(direction),
|
||||
sender: Dom::from_ref(&*sender),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
global: &GlobalScope,
|
||||
direction: RTCRtpTransceiverDirection,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<Self> {
|
||||
reflect_dom_object(
|
||||
Box::new(Self::new_inherited(global, direction, can_gc)),
|
||||
global,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCRtpTransceiverMethods<crate::DomTypeHolder> for RTCRtpTransceiver {
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction>
|
||||
fn Direction(&self) -> RTCRtpTransceiverDirection {
|
||||
self.direction.get()
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction>
|
||||
fn SetDirection(&self, direction: RTCRtpTransceiverDirection) {
|
||||
self.direction.set(direction);
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender>
|
||||
fn Sender(&self) -> DomRoot<RTCRtpSender> {
|
||||
DomRoot::from_ref(&*self.sender)
|
||||
}
|
||||
}
|
76
components/script/dom/webrtc/rtcsessiondescription.rs
Normal file
76
components/script/dom/webrtc/rtcsessiondescription.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::RTCSessionDescriptionBinding::{
|
||||
RTCSdpType, RTCSessionDescriptionInit, RTCSessionDescriptionMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCSessionDescription {
|
||||
reflector: Reflector,
|
||||
ty: RTCSdpType,
|
||||
sdp: DOMString,
|
||||
}
|
||||
|
||||
impl RTCSessionDescription {
|
||||
pub(crate) fn new_inherited(ty: RTCSdpType, sdp: DOMString) -> RTCSessionDescription {
|
||||
RTCSessionDescription {
|
||||
reflector: Reflector::new(),
|
||||
ty,
|
||||
sdp,
|
||||
}
|
||||
}
|
||||
|
||||
fn new(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
ty: RTCSdpType,
|
||||
sdp: DOMString,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCSessionDescription> {
|
||||
reflect_dom_object_with_proto(
|
||||
Box::new(RTCSessionDescription::new_inherited(ty, sdp)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCSessionDescriptionMethods<crate::DomTypeHolder> for RTCSessionDescription {
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-sessiondescription>
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
config: &RTCSessionDescriptionInit,
|
||||
) -> Fallible<DomRoot<RTCSessionDescription>> {
|
||||
Ok(RTCSessionDescription::new(
|
||||
window,
|
||||
proto,
|
||||
config.type_,
|
||||
config.sdp.clone(),
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcsessiondescription-type>
|
||||
fn Type(&self) -> RTCSdpType {
|
||||
self.ty
|
||||
}
|
||||
|
||||
/// <https://w3c.github.io/webrtc-pc/#dom-rtcsessiondescription-sdp>
|
||||
fn Sdp(&self) -> DOMString {
|
||||
self.sdp.clone()
|
||||
}
|
||||
}
|
99
components/script/dom/webrtc/rtctrackevent.rs
Normal file
99
components/script/dom/webrtc/rtctrackevent.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
/* 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 dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use stylo_atoms::Atom;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::RTCTrackEventBinding::{self, RTCTrackEventMethods};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::mediastreamtrack::MediaStreamTrack;
|
||||
use crate::dom::window::Window;
|
||||
use crate::script_runtime::CanGc;
|
||||
|
||||
#[dom_struct]
|
||||
pub(crate) struct RTCTrackEvent {
|
||||
event: Event,
|
||||
track: Dom<MediaStreamTrack>,
|
||||
}
|
||||
|
||||
impl RTCTrackEvent {
|
||||
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
|
||||
fn new_inherited(track: &MediaStreamTrack) -> RTCTrackEvent {
|
||||
RTCTrackEvent {
|
||||
event: Event::new_inherited(),
|
||||
track: Dom::from_ref(track),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
window: &Window,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
track: &MediaStreamTrack,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCTrackEvent> {
|
||||
Self::new_with_proto(window, None, type_, bubbles, cancelable, track, can_gc)
|
||||
}
|
||||
|
||||
fn new_with_proto(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
track: &MediaStreamTrack,
|
||||
can_gc: CanGc,
|
||||
) -> DomRoot<RTCTrackEvent> {
|
||||
let trackevent = reflect_dom_object_with_proto(
|
||||
Box::new(RTCTrackEvent::new_inherited(track)),
|
||||
window,
|
||||
proto,
|
||||
can_gc,
|
||||
);
|
||||
{
|
||||
let event = trackevent.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
trackevent
|
||||
}
|
||||
}
|
||||
|
||||
impl RTCTrackEventMethods<crate::DomTypeHolder> for RTCTrackEvent {
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtctrackevent-constructor
|
||||
fn Constructor(
|
||||
window: &Window,
|
||||
proto: Option<HandleObject>,
|
||||
can_gc: CanGc,
|
||||
type_: DOMString,
|
||||
init: &RTCTrackEventBinding::RTCTrackEventInit,
|
||||
) -> Fallible<DomRoot<RTCTrackEvent>> {
|
||||
Ok(RTCTrackEvent::new_with_proto(
|
||||
window,
|
||||
proto,
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.track,
|
||||
can_gc,
|
||||
))
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webrtc-pc/#dom-rtctrackevent-track
|
||||
fn Track(&self) -> DomRoot<MediaStreamTrack> {
|
||||
DomRoot::from_ref(&*self.track)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue