Skip to content

Commit 2cee685

Browse files
MartinKavikDavid-OConnor
authored andcommittedOct 11, 2019
feat(examples): UserMedia example
1 parent 291c639 commit 2cee685

File tree

8 files changed

+181
-0
lines changed

8 files changed

+181
-0
lines changed
 

‎Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ members = [
104104
# "examples/server_interaction_detailed", # has own workspace
105105
"examples/todomvc",
106106
"examples/update_from_js",
107+
"examples/user_media",
107108
"examples/websocket",
108109
"examples/window_events",
109110
]

‎examples/user_media/Cargo.toml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "user_media"
3+
version = "0.1.0"
4+
authors = ["David O'Connor <david.alan.oconnor@gmail.com>"]
5+
edition = "2018"
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
seed = {path = "../../"}
12+
wasm-bindgen = "0.2.45"
13+
wasm-bindgen-futures = "0.3.22"
14+
futures = "^0.1.27"
15+
16+
[dependencies.web-sys]
17+
version = "0.3.27"
18+
features = [
19+
"MediaDevices",
20+
"MediaStreamConstraints",
21+
"Navigator",
22+
"MediaStream",
23+
"HtmlMediaElement",
24+
]

‎examples/user_media/Makefile.toml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extend = "../../Makefile.toml"
2+
3+
# ---- BUILD ----
4+
5+
[tasks.build]
6+
alias = "default_build"
7+
8+
[tasks.build_release]
9+
alias = "default_build_release"
10+
11+
# ---- START ----
12+
13+
[tasks.start]
14+
alias = "default_start"
15+
16+
[tasks.start_release]
17+
alias = "default_start_release"
18+
19+
# ---- LINT ----
20+
21+
[tasks.clippy]
22+
alias = "default_clippy"

‎examples/user_media/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## UserMedia example
2+
3+
How to show your webcam output in `video` element.
4+
5+
---
6+
7+
```bash
8+
cargo make start
9+
```
10+
11+
Open [127.0.0.1:8000](http://127.0.0.1:8000) in your browser.

‎examples/user_media/index.html

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1, shrink-to-fit=no"
8+
/>
9+
10+
<meta name="description" content="" />
11+
12+
<link rel="icon" type="image/png" href="/public/favicon.png" />
13+
14+
<!--<link rel="stylesheet" type="text/css" href="/style.css">-->
15+
16+
<title>UserMedia example</title>
17+
18+
<!-- Because of Edge, see https://github.com/samthor/fast-text-encoding -->
19+
<script type="text/javascript" src="/public/text-polyfill.min.js"></script>
20+
</head>
21+
<body>
22+
<section id="app"></section>
23+
<script type="module">
24+
// https://rustwasm.github.io/docs/wasm-bindgen/examples/without-a-bundler.html
25+
import init from '/pkg/package.js';
26+
init('/pkg/package_bg.wasm');
27+
</script>
28+
</body>
29+
</html>

‎examples/user_media/public/text-polyfill.min.js

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎examples/user_media/src/lib.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#[macro_use]
2+
extern crate seed;
3+
use futures::future;
4+
use futures::prelude::*;
5+
use seed::prelude::*;
6+
use seed::{document, window};
7+
use wasm_bindgen::JsCast;
8+
use wasm_bindgen_futures::JsFuture;
9+
use web_sys::{HtmlMediaElement, MediaStream, MediaStreamConstraints};
10+
11+
// Model
12+
13+
struct Model {}
14+
15+
// Init
16+
17+
fn init(_: Url, orders: &mut impl Orders<Msg>) -> Init<Model> {
18+
orders.perform_cmd(user_media());
19+
Init::new(Model {})
20+
}
21+
22+
fn user_media() -> impl Future<Item = Msg, Error = Msg> {
23+
future::ok::<(), ()>(()).then(|_| {
24+
let mut constraints = MediaStreamConstraints::new();
25+
constraints.video(&JsValue::from(true));
26+
27+
let media_stream_promise = window()
28+
.navigator()
29+
.media_devices()
30+
.unwrap()
31+
.get_user_media_with_constraints(&constraints)
32+
.unwrap();
33+
34+
JsFuture::from(media_stream_promise)
35+
.map(MediaStream::from)
36+
.then(|result| Ok(Msg::UserMedia(result)))
37+
})
38+
}
39+
40+
// Update
41+
42+
#[derive(Clone, Debug)]
43+
enum Msg {
44+
UserMedia(Result<MediaStream, JsValue>),
45+
}
46+
47+
fn update(msg: Msg, _: &mut Model, _: &mut impl Orders<Msg>) {
48+
match msg {
49+
Msg::UserMedia(Ok(media_stream)) => {
50+
let video_el = document()
51+
.query_selector("video")
52+
.unwrap()
53+
.unwrap()
54+
.dyn_into::<HtmlMediaElement>()
55+
.unwrap();
56+
57+
video_el.set_src_object(Some(&media_stream));
58+
}
59+
Msg::UserMedia(Err(error)) => {
60+
log!(error);
61+
}
62+
}
63+
}
64+
65+
// View
66+
67+
fn view(_: &Model) -> impl View<Msg> {
68+
video![attrs! {
69+
At::Width => 320,
70+
At::Height => 240,
71+
At::AutoPlay => AtValue::None,
72+
}]
73+
}
74+
75+
#[wasm_bindgen(start)]
76+
pub fn start() {
77+
seed::App::build(init, update, view).finish().run();
78+
}

0 commit comments

Comments
 (0)
Please sign in to comment.