-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Examples] Add WebRTC DataChannel example (#2131)
* Add WebRTC DataChannel example * Add guide * Fix format * Use webpack to build example
- Loading branch information
Yuji Sugiura
authored
May 12, 2020
1 parent
6b5f734
commit f94e377
Showing
9 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
[package] | ||
name = "webrtc_datachannel" | ||
version = "0.1.0" | ||
authors = ["The wasm-bindgen Developers"] | ||
edition = "2018" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
wasm-bindgen = "0.2.62" | ||
js-sys = "0.3" | ||
wasm-bindgen-futures = "0.4.12" | ||
|
||
[dependencies.web-sys] | ||
version = "0.3.22" | ||
features = [ | ||
"MessageEvent", | ||
"RtcPeerConnection", | ||
"RtcSignalingState", | ||
"RtcSdpType", | ||
"RtcSessionDescriptionInit", | ||
"RtcPeerConnectionIceEvent", | ||
"RtcIceCandidate", | ||
"RtcDataChannel", | ||
"RtcDataChannelEvent", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# WebRTC DataChannel Example | ||
|
||
[View documentation for this example online][dox] or [View compiled example | ||
online][compiled] | ||
|
||
[compiled]: https://rustwasm.github.io/wasm-bindgen/exbuild/webrtc_datachannel/ | ||
[dox]: https://rustwasm.github.io/wasm-bindgen/examples/webrtc_datachannel.html | ||
|
||
You can build the example locally with: | ||
|
||
``` | ||
$ npm run serve | ||
``` | ||
|
||
and then visiting http://localhost:8080 in a browser should run the example! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>WebRTC DataChannel example</title> | ||
</head> | ||
<body> | ||
<p>Open DevTools and check the Console.</p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
window.addEventListener('load', async () => { | ||
await import('./pkg'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"scripts": { | ||
"build": "webpack", | ||
"serve": "webpack-dev-server" | ||
}, | ||
"devDependencies": { | ||
"@wasm-tool/wasm-pack-plugin": "1.0.1", | ||
"text-encoding": "^0.7.0", | ||
"html-webpack-plugin": "^3.2.0", | ||
"webpack": "^4.29.4", | ||
"webpack-cli": "^3.1.1", | ||
"webpack-dev-server": "^3.1.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
use js_sys::Reflect; | ||
use wasm_bindgen::prelude::*; | ||
use wasm_bindgen::JsCast; | ||
use wasm_bindgen_futures::JsFuture; | ||
use web_sys::{ | ||
MessageEvent, RtcDataChannelEvent, RtcPeerConnection, RtcPeerConnectionIceEvent, RtcSdpType, | ||
RtcSessionDescriptionInit, | ||
}; | ||
|
||
macro_rules! console_log { | ||
($($t:tt)*) => (log(&format_args!($($t)*).to_string())) | ||
} | ||
macro_rules! console_warn { | ||
($($t:tt)*) => (warn(&format_args!($($t)*).to_string())) | ||
} | ||
|
||
#[wasm_bindgen] | ||
extern "C" { | ||
#[wasm_bindgen(js_namespace = console)] | ||
fn log(s: &str); | ||
#[wasm_bindgen(js_namespace = console)] | ||
fn warn(s: &str); | ||
} | ||
|
||
#[wasm_bindgen(start)] | ||
pub async fn start() -> Result<(), JsValue> { | ||
/* | ||
* Set up PeerConnections | ||
* pc1 <=> pc2 | ||
* | ||
*/ | ||
let pc1 = RtcPeerConnection::new()?; | ||
console_log!("pc1 created: state {:?}", pc1.signaling_state()); | ||
let pc2 = RtcPeerConnection::new()?; | ||
console_log!("pc2 created: state {:?}", pc2.signaling_state()); | ||
|
||
/* | ||
* Create DataChannel on pc1 to negotiate | ||
* Message will be shonw here after connection established | ||
* | ||
*/ | ||
let dc1 = pc1.create_data_channel("my-data-channel"); | ||
console_log!("dc1 created: label {:?}", dc1.label()); | ||
|
||
let dc1_clone = dc1.clone(); | ||
let onmessage_callback = | ||
Closure::wrap( | ||
Box::new(move |ev: MessageEvent| match ev.data().as_string() { | ||
Some(message) => { | ||
console_warn!("{:?}", message); | ||
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap(); | ||
} | ||
None => {} | ||
}) as Box<dyn FnMut(MessageEvent)>, | ||
); | ||
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); | ||
onmessage_callback.forget(); | ||
|
||
/* | ||
* If negotiaion has done, this closure will be called | ||
* | ||
*/ | ||
let ondatachannel_callback = Closure::wrap(Box::new(move |ev: RtcDataChannelEvent| { | ||
let dc2 = ev.channel(); | ||
console_log!("pc2.ondatachannel!: {:?}", dc2.label()); | ||
|
||
let onmessage_callback = | ||
Closure::wrap( | ||
Box::new(move |ev: MessageEvent| match ev.data().as_string() { | ||
Some(message) => console_warn!("{:?}", message), | ||
None => {} | ||
}) as Box<dyn FnMut(MessageEvent)>, | ||
); | ||
dc2.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref())); | ||
onmessage_callback.forget(); | ||
|
||
dc2.send_with_str("Ping from pc2.dc!").unwrap(); | ||
}) as Box<dyn FnMut(RtcDataChannelEvent)>); | ||
pc2.set_ondatachannel(Some(ondatachannel_callback.as_ref().unchecked_ref())); | ||
ondatachannel_callback.forget(); | ||
|
||
/* | ||
* Handle ICE candidate each other | ||
* | ||
*/ | ||
let pc2_clone = pc2.clone(); | ||
let onicecandidate_callback1 = | ||
Closure::wrap( | ||
Box::new(move |ev: RtcPeerConnectionIceEvent| match ev.candidate() { | ||
Some(candidate) => { | ||
console_log!("pc1.onicecandidate: {:#?}", candidate.candidate()); | ||
let _ = | ||
pc2_clone.add_ice_candidate_with_opt_rtc_ice_candidate(Some(&candidate)); | ||
} | ||
None => {} | ||
}) as Box<dyn FnMut(RtcPeerConnectionIceEvent)>, | ||
); | ||
pc1.set_onicecandidate(Some(onicecandidate_callback1.as_ref().unchecked_ref())); | ||
onicecandidate_callback1.forget(); | ||
|
||
let pc1_clone = pc1.clone(); | ||
let onicecandidate_callback2 = | ||
Closure::wrap( | ||
Box::new(move |ev: RtcPeerConnectionIceEvent| match ev.candidate() { | ||
Some(candidate) => { | ||
console_log!("pc2.onicecandidate: {:#?}", candidate.candidate()); | ||
let _ = | ||
pc1_clone.add_ice_candidate_with_opt_rtc_ice_candidate(Some(&candidate)); | ||
} | ||
None => {} | ||
}) as Box<dyn FnMut(RtcPeerConnectionIceEvent)>, | ||
); | ||
pc2.set_onicecandidate(Some(onicecandidate_callback2.as_ref().unchecked_ref())); | ||
onicecandidate_callback2.forget(); | ||
|
||
/* | ||
* Send OFFER from pc1 to pc2 | ||
* | ||
*/ | ||
let offer = JsFuture::from(pc1.create_offer()).await?; | ||
let offer_sdp = Reflect::get(&offer, &JsValue::from_str("sdp"))? | ||
.as_string() | ||
.unwrap(); | ||
console_log!("pc1: offer {:?}", offer_sdp); | ||
|
||
let mut offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); | ||
offer_obj.sdp(&offer_sdp); | ||
let sld_promise = pc1.set_local_description(&offer_obj); | ||
JsFuture::from(sld_promise).await?; | ||
console_log!("pc1: state {:?}", pc1.signaling_state()); | ||
|
||
/* | ||
* Receive OFFER from pc1 | ||
* Create and send ANSWER from pc2 to pc1 | ||
* | ||
*/ | ||
let mut offer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Offer); | ||
offer_obj.sdp(&offer_sdp); | ||
let srd_promise = pc2.set_remote_description(&offer_obj); | ||
JsFuture::from(srd_promise).await?; | ||
console_log!("pc2: state {:?}", pc2.signaling_state()); | ||
|
||
let answer = JsFuture::from(pc2.create_answer()).await?; | ||
let answer_sdp = Reflect::get(&answer, &JsValue::from_str("sdp"))? | ||
.as_string() | ||
.unwrap(); | ||
console_log!("pc2: answer {:?}", answer_sdp); | ||
|
||
let mut answer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Answer); | ||
answer_obj.sdp(&answer_sdp); | ||
let sld_promise = pc2.set_local_description(&answer_obj); | ||
JsFuture::from(sld_promise).await?; | ||
console_log!("pc2: state {:?}", pc2.signaling_state()); | ||
|
||
/* | ||
* Receive ANSWER from pc2 | ||
* | ||
*/ | ||
let mut answer_obj = RtcSessionDescriptionInit::new(RtcSdpType::Answer); | ||
answer_obj.sdp(&answer_sdp); | ||
let srd_promise = pc1.set_remote_description(&answer_obj); | ||
JsFuture::from(srd_promise).await?; | ||
console_log!("pc1: state {:?}", pc1.signaling_state()); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
const path = require('path'); | ||
const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
const webpack = require('webpack'); | ||
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); | ||
|
||
module.exports = { | ||
entry: './index.js', | ||
output: { | ||
path: path.resolve(__dirname, 'dist'), | ||
filename: 'index.js', | ||
}, | ||
plugins: [ | ||
new HtmlWebpackPlugin({ | ||
template: 'index.html' | ||
}), | ||
new WasmPackPlugin({ | ||
crateDirectory: path.resolve(__dirname, ".") | ||
}), | ||
// Have this example work in Edge which doesn't ship `TextEncoder` or | ||
// `TextDecoder` at this time. | ||
new webpack.ProvidePlugin({ | ||
TextDecoder: ['text-encoding', 'TextDecoder'], | ||
TextEncoder: ['text-encoding', 'TextEncoder'] | ||
}) | ||
], | ||
mode: 'development' | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# WebRTC DataChannel Example | ||
|
||
[View full source code][code] or [view the compiled example online][online] | ||
|
||
[online]: https://rustwasm.github.io/wasm-bindgen/exbuild/webrtc_datachannel/ | ||
[code]: https://github.com/rustwasm/wasm-bindgen/tree/master/examples/webrtc_datachannel/ | ||
|
||
This example creates 2 peer connections and 2 data channels in single browser tab. | ||
Send ping/pong between `peer1.dc` and `peer2.dc`. | ||
|
||
## `Cargo.toml` | ||
|
||
The `Cargo.toml` enables features necessary to use WebRTC DataChannel and its negotiation. | ||
|
||
```toml | ||
{{#include ../../../examples/webrtc_datachannel/Cargo.toml}} | ||
``` | ||
|
||
## `src/lib.rs` | ||
|
||
The Rust code connects WebRTC data channel. | ||
|
||
```rust | ||
{{#include ../../../examples/webrtc_datachannel/src/lib.rs}} | ||
``` |