Skip to content

Commit 7fe1384

Browse files
Property "muted" for <audio> and <video> (#4690)
* Audio two-way `muted` bind property Loosely based on fend25@a37ee81?w=1 * Documentation * fix test * dont bother coercing muted, it happens automatically Co-authored-by: Richard Harris <richard.a.harris@gmail.com>
1 parent c19542b commit 7fe1384

File tree

8 files changed

+57
-36
lines changed

8 files changed

+57
-36
lines changed

site/content/docs/02-template-syntax.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,13 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — six
603603
* `seeking` (readonly) — boolean
604604
* `ended` (readonly) — boolean
605605

606-
...and four *two-way* bindings:
606+
...and five *two-way* bindings:
607607

608608
* `currentTime` — the current point in the video, in seconds
609609
* `playbackRate` — how fast to play the video, where 1 is 'normal'
610610
* `paused` — this one should be self-explanatory
611611
* `volume` — a value between 0 and 1
612+
* `muted` — a boolean value where true is muted
612613

613614
Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
614615

@@ -624,6 +625,7 @@ Videos additionally have readonly `videoWidth` and `videoHeight` bindings.
624625
bind:currentTime
625626
bind:paused
626627
bind:volume
628+
bind:muted
627629
bind:videoWidth
628630
bind:videoHeight
629631
></video>

site/content/tutorial/06-bindings/10-media-elements/text.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ The complete set of bindings for `<audio>` and `<video>` is as follows — six *
3333
* `seeking` (readonly) — boolean
3434
* `ended` (readonly) — boolean
3535

36-
...and four *two-way* bindings:
36+
...and five *two-way* bindings:
3737

3838
* `currentTime` — the current point in the video, in seconds
3939
* `playbackRate` — how fast to play the video, where `1` is 'normal'
4040
* `paused` — this one should be self-explanatory
4141
* `volume` — a value between 0 and 1
42+
* `muted` — a boolean value where true is muted
4243

4344
Videos additionally have readonly `videoWidth` and `videoHeight` bindings.

src/compiler/compile/nodes/Element.ts

+1
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ export default class Element extends Node {
638638
name === 'seekable' ||
639639
name === 'played' ||
640640
name === 'volume' ||
641+
name === 'muted' ||
641642
name === 'playbackRate' ||
642643
name === 'seeking' ||
643644
name === 'ended'

src/compiler/compile/render_dom/wrappers/Element/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ const events = [
9393
event_names: ['volumechange'],
9494
filter: (node: Element, name: string) =>
9595
node.is_media_node() &&
96-
name === 'volume'
96+
(name === 'volume' || name === 'muted')
9797
},
9898
{
9999
event_names: ['ratechange'],

test/js/samples/media-bindings/expected.js

+43-31
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,18 @@ function create_fragment(ctx) {
2929
audio_updating = true;
3030
}
3131

32-
/*audio_timeupdate_handler*/ ctx[12].call(audio);
32+
/*audio_timeupdate_handler*/ ctx[13].call(audio);
3333
}
3434

3535
return {
3636
c() {
3737
audio = element("audio");
38-
if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[10].call(audio));
39-
if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[11].call(audio));
40-
if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[9] === void 0) add_render_callback(audio_timeupdate_handler);
41-
if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[13].call(audio));
42-
if (/*seeking*/ ctx[8] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[17].call(audio));
43-
if (/*ended*/ ctx[9] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[18].call(audio));
38+
if (/*buffered*/ ctx[0] === void 0) add_render_callback(() => /*audio_progress_handler*/ ctx[11].call(audio));
39+
if (/*buffered*/ ctx[0] === void 0 || /*seekable*/ ctx[1] === void 0) add_render_callback(() => /*audio_loadedmetadata_handler*/ ctx[12].call(audio));
40+
if (/*played*/ ctx[2] === void 0 || /*currentTime*/ ctx[3] === void 0 || /*ended*/ ctx[10] === void 0) add_render_callback(audio_timeupdate_handler);
41+
if (/*duration*/ ctx[4] === void 0) add_render_callback(() => /*audio_durationchange_handler*/ ctx[14].call(audio));
42+
if (/*seeking*/ ctx[9] === void 0) add_render_callback(() => /*audio_seeking_seeked_handler*/ ctx[18].call(audio));
43+
if (/*ended*/ ctx[10] === void 0) add_render_callback(() => /*audio_ended_handler*/ ctx[19].call(audio));
4444
},
4545
m(target, anchor, remount) {
4646
insert(target, audio, anchor);
@@ -49,24 +49,26 @@ function create_fragment(ctx) {
4949
audio.volume = /*volume*/ ctx[6];
5050
}
5151

52-
if (!isNaN(/*playbackRate*/ ctx[7])) {
53-
audio.playbackRate = /*playbackRate*/ ctx[7];
52+
audio.muted = /*muted*/ ctx[7];
53+
54+
if (!isNaN(/*playbackRate*/ ctx[8])) {
55+
audio.playbackRate = /*playbackRate*/ ctx[8];
5456
}
5557

5658
if (remount) run_all(dispose);
5759

5860
dispose = [
59-
listen(audio, "progress", /*audio_progress_handler*/ ctx[10]),
60-
listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[11]),
61+
listen(audio, "progress", /*audio_progress_handler*/ ctx[11]),
62+
listen(audio, "loadedmetadata", /*audio_loadedmetadata_handler*/ ctx[12]),
6163
listen(audio, "timeupdate", audio_timeupdate_handler),
62-
listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[13]),
63-
listen(audio, "play", /*audio_play_pause_handler*/ ctx[14]),
64-
listen(audio, "pause", /*audio_play_pause_handler*/ ctx[14]),
65-
listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[15]),
66-
listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[16]),
67-
listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[17]),
68-
listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[17]),
69-
listen(audio, "ended", /*audio_ended_handler*/ ctx[18])
64+
listen(audio, "durationchange", /*audio_durationchange_handler*/ ctx[14]),
65+
listen(audio, "play", /*audio_play_pause_handler*/ ctx[15]),
66+
listen(audio, "pause", /*audio_play_pause_handler*/ ctx[15]),
67+
listen(audio, "volumechange", /*audio_volumechange_handler*/ ctx[16]),
68+
listen(audio, "ratechange", /*audio_ratechange_handler*/ ctx[17]),
69+
listen(audio, "seeking", /*audio_seeking_seeked_handler*/ ctx[18]),
70+
listen(audio, "seeked", /*audio_seeking_seeked_handler*/ ctx[18]),
71+
listen(audio, "ended", /*audio_ended_handler*/ ctx[19])
7072
];
7173
},
7274
p(ctx, [dirty]) {
@@ -84,8 +86,12 @@ function create_fragment(ctx) {
8486
audio.volume = /*volume*/ ctx[6];
8587
}
8688

87-
if (dirty & /*playbackRate*/ 128 && !isNaN(/*playbackRate*/ ctx[7])) {
88-
audio.playbackRate = /*playbackRate*/ ctx[7];
89+
if (dirty & /*muted*/ 128) {
90+
audio.muted = /*muted*/ ctx[7];
91+
}
92+
93+
if (dirty & /*playbackRate*/ 256 && !isNaN(/*playbackRate*/ ctx[8])) {
94+
audio.playbackRate = /*playbackRate*/ ctx[8];
8995
}
9096
},
9197
i: noop,
@@ -105,6 +111,7 @@ function instance($$self, $$props, $$invalidate) {
105111
let { duration } = $$props;
106112
let { paused } = $$props;
107113
let { volume } = $$props;
114+
let { muted } = $$props;
108115
let { playbackRate } = $$props;
109116
let { seeking } = $$props;
110117
let { ended } = $$props;
@@ -127,7 +134,7 @@ function instance($$self, $$props, $$invalidate) {
127134
ended = this.ended;
128135
$$invalidate(2, played);
129136
$$invalidate(3, currentTime);
130-
$$invalidate(9, ended);
137+
$$invalidate(10, ended);
131138
}
132139

133140
function audio_durationchange_handler() {
@@ -142,22 +149,24 @@ function instance($$self, $$props, $$invalidate) {
142149

143150
function audio_volumechange_handler() {
144151
volume = this.volume;
152+
muted = this.muted;
145153
$$invalidate(6, volume);
154+
$$invalidate(7, muted);
146155
}
147156

148157
function audio_ratechange_handler() {
149158
playbackRate = this.playbackRate;
150-
$$invalidate(7, playbackRate);
159+
$$invalidate(8, playbackRate);
151160
}
152161

153162
function audio_seeking_seeked_handler() {
154163
seeking = this.seeking;
155-
$$invalidate(8, seeking);
164+
$$invalidate(9, seeking);
156165
}
157166

158167
function audio_ended_handler() {
159168
ended = this.ended;
160-
$$invalidate(9, ended);
169+
$$invalidate(10, ended);
161170
}
162171

163172
$$self.$set = $$props => {
@@ -168,9 +177,10 @@ function instance($$self, $$props, $$invalidate) {
168177
if ("duration" in $$props) $$invalidate(4, duration = $$props.duration);
169178
if ("paused" in $$props) $$invalidate(5, paused = $$props.paused);
170179
if ("volume" in $$props) $$invalidate(6, volume = $$props.volume);
171-
if ("playbackRate" in $$props) $$invalidate(7, playbackRate = $$props.playbackRate);
172-
if ("seeking" in $$props) $$invalidate(8, seeking = $$props.seeking);
173-
if ("ended" in $$props) $$invalidate(9, ended = $$props.ended);
180+
if ("muted" in $$props) $$invalidate(7, muted = $$props.muted);
181+
if ("playbackRate" in $$props) $$invalidate(8, playbackRate = $$props.playbackRate);
182+
if ("seeking" in $$props) $$invalidate(9, seeking = $$props.seeking);
183+
if ("ended" in $$props) $$invalidate(10, ended = $$props.ended);
174184
};
175185

176186
return [
@@ -181,6 +191,7 @@ function instance($$self, $$props, $$invalidate) {
181191
duration,
182192
paused,
183193
volume,
194+
muted,
184195
playbackRate,
185196
seeking,
186197
ended,
@@ -208,9 +219,10 @@ class Component extends SvelteComponent {
208219
duration: 4,
209220
paused: 5,
210221
volume: 6,
211-
playbackRate: 7,
212-
seeking: 8,
213-
ended: 9
222+
muted: 7,
223+
playbackRate: 8,
224+
seeking: 9,
225+
ended: 10
214226
});
215227
}
216228
}

test/js/samples/media-bindings/input.svelte

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
export let duration;
77
export let paused;
88
export let volume;
9+
export let muted;
910
export let playbackRate;
1011
export let seeking;
1112
export let ended;
1213
</script>
1314

14-
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:playbackRate bind:seeking bind:ended/>
15+
<audio bind:buffered bind:seekable bind:played bind:currentTime bind:duration bind:paused bind:volume bind:muted bind:playbackRate bind:seeking bind:ended/>

test/runtime/samples/binding-audio-currenttime-duration-volume/_config.js

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export default {
88
assert.equal(component.t, 0);
99
assert.equal(component.d, 0);
1010
assert.equal(component.v, 0.5);
11+
assert.equal(component.m, true);
1112
assert.equal(component.r, 1);
1213
assert.equal(component.paused, true);
1314

@@ -20,6 +21,7 @@ export default {
2021
audio.currentTime = 10;
2122
audio.duration = 20;
2223
audio.volume = 0.75;
24+
audio.muted = false;
2325
audio.playbackRate = 2;
2426
audio.dispatchEvent(timeupdate);
2527
audio.dispatchEvent(durationchange);
@@ -30,6 +32,7 @@ export default {
3032
assert.equal(component.t, 10);
3133
assert.equal(component.d, 0); // not 20, because read-only. Not sure how to test this!
3234
assert.equal(component.v, 0.75);
35+
assert.equal(component.m, false);
3336
assert.equal(component.r, 2);
3437
assert.equal(component.paused, true); // ditto...
3538
}

test/runtime/samples/binding-audio-currenttime-duration-volume/main.svelte

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
export let paused;
55
export let v;
66
export let r;
7+
export let m;
78
</script>
89

9-
<audio bind:currentTime={t} bind:duration={d} bind:paused bind:volume={v} bind:playbackRate={r}
10+
<audio bind:currentTime={t} bind:duration={d} bind:paused bind:volume={v} bind:muted={m} bind:playbackRate={r}
1011
src='music.mp3'></audio>

0 commit comments

Comments
 (0)