Skip to content

Commit f07754c

Browse files
authored
fix: check muted property for mute getter (#69)
* fix: check muted property for mute getter * fix: update mute event conditions * test: update unit tests --------- Co-authored-by: Bryce Tham <[email protected]>
1 parent 7737912 commit f07754c

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

src/media/local-stream.spec.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { WebrtcCoreError } from '../errors';
22
import { createMockedStream } from '../util/test-utils';
33
import { LocalStream, LocalStreamEventNames, TrackEffect } from './local-stream';
4+
import { StreamEventNames } from './stream';
45

56
/**
67
* A dummy LocalStream implementation so we can instantiate it for testing.
@@ -10,20 +11,58 @@ class TestLocalStream extends LocalStream {}
1011
describe('LocalStream', () => {
1112
const mockStream = createMockedStream();
1213
let localStream: LocalStream;
14+
1315
beforeEach(() => {
1416
localStream = new TestLocalStream(mockStream);
1517
});
1618

1719
describe('setMuted', () => {
18-
it('should change the input track state based on being muted & unmuted', () => {
19-
expect.assertions(2);
20+
let emitSpy: jest.SpyInstance;
21+
22+
beforeEach(() => {
23+
localStream = new TestLocalStream(mockStream);
24+
emitSpy = jest.spyOn(localStream[StreamEventNames.MuteStateChange], 'emit');
25+
});
26+
27+
it('should change the input track enabled state and fire an event', () => {
28+
expect.assertions(6);
29+
2030
// Simulate the default state of the track's enabled state.
2131
mockStream.getTracks()[0].enabled = true;
2232

2333
localStream.setMuted(true);
2434
expect(mockStream.getTracks()[0].enabled).toBe(false);
35+
expect(emitSpy).toHaveBeenCalledTimes(1);
36+
expect(emitSpy).toHaveBeenLastCalledWith(true);
37+
2538
localStream.setMuted(false);
2639
expect(mockStream.getTracks()[0].enabled).toBe(true);
40+
expect(emitSpy).toHaveBeenCalledTimes(2);
41+
expect(emitSpy).toHaveBeenLastCalledWith(false);
42+
});
43+
44+
it('should not fire an event if the same mute state is set twice', () => {
45+
expect.assertions(1);
46+
47+
// Simulate the default state of the track's enabled state.
48+
mockStream.getTracks()[0].enabled = true;
49+
50+
localStream.setMuted(false);
51+
expect(emitSpy).toHaveBeenCalledTimes(0);
52+
});
53+
54+
it('should not fire an event if the track has been muted by the browser', () => {
55+
expect.assertions(2);
56+
57+
// Simulate the default state of the track's enabled state.
58+
mockStream.getTracks()[0].enabled = true;
59+
60+
// Simulate the track being muted by the browser.
61+
Object.defineProperty(mockStream.getTracks()[0], 'muted', { value: true });
62+
63+
localStream.setMuted(true);
64+
expect(mockStream.getTracks()[0].enabled).toBe(false);
65+
expect(emitSpy).toHaveBeenCalledTimes(0);
2766
});
2867
});
2968

src/media/local-stream.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,32 @@ abstract class _LocalStream extends Stream {
5757
return this.inputStream.getTracks()[0];
5858
}
5959

60+
/**
61+
* @inheritdoc
62+
*/
63+
protected handleTrackMuted() {
64+
if (this.inputTrack.enabled) {
65+
super.handleTrackMuted();
66+
}
67+
}
68+
69+
/**
70+
* @inheritdoc
71+
*/
72+
protected handleTrackUnmuted() {
73+
if (this.inputTrack.enabled) {
74+
super.handleTrackUnmuted();
75+
}
76+
}
77+
6078
/**
6179
* @inheritdoc
6280
*/
6381
get muted(): boolean {
64-
return !this.inputTrack.enabled;
82+
// Calls to `setMuted` will only affect the "enabled" state, but there are specific cases in
83+
// which the browser may mute the track, which will affect the "muted" state but not the
84+
// "enabled" state, e.g. minimizing a shared window or unplugging a shared screen.
85+
return !this.inputTrack.enabled || this.inputTrack.muted;
6586
}
6687

6788
/**
@@ -73,7 +94,9 @@ abstract class _LocalStream extends Stream {
7394
if (this.inputTrack.enabled === isMuted) {
7495
this.inputTrack.enabled = !isMuted;
7596
// setting `enabled` will not automatically emit MuteStateChange, so we emit it here
76-
this[StreamEventNames.MuteStateChange].emit(isMuted);
97+
if (!this.inputTrack.muted) {
98+
this[StreamEventNames.MuteStateChange].emit(isMuted);
99+
}
77100
}
78101
}
79102

src/media/stream.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ abstract class _Stream {
3939
/**
4040
* Handler which is called when a track's mute event fires.
4141
*/
42-
private handleTrackMuted() {
42+
protected handleTrackMuted() {
4343
this[StreamEventNames.MuteStateChange].emit(true);
4444
}
4545

4646
/**
4747
* Handler which is called when a track's unmute event fires.
4848
*/
49-
private handleTrackUnmuted() {
49+
protected handleTrackUnmuted() {
5050
this[StreamEventNames.MuteStateChange].emit(false);
5151
}
5252

0 commit comments

Comments
 (0)