@@ -43,15 +43,20 @@ export default function Tile(props) {
4343 const audioEl = useRef ( null ) ;
4444
4545 const videoTrack = useMemo ( ( ) => {
46- return props . videoTrackState && props . videoTrackState . state === 'playable'
47- ? props . videoTrackState . track
48- : null ;
46+ // For video let's use the `track` field, which is only present when video
47+ // is in the "playable" state.
48+ // (Using `persistentTrack` could result in a still frame being shown when
49+ // remote video is muted).
50+ return props . videoTrackState ?. track ;
4951 } , [ props . videoTrackState ] ) ;
5052
5153 const audioTrack = useMemo ( ( ) => {
52- return props . audioTrackState && props . audioTrackState . state === 'playable'
53- ? props . audioTrackState . track
54- : null ;
54+ // For audio let's use the `persistentTrack` field, which is present whether
55+ // or not audio is in the "playable" state.
56+ // (Using `track` would result in a bug where, if remote audio were unmuted
57+ // while this call was is in a Safari background tab, audio wouldn't resume
58+ // playing).
59+ return props . audioTrackState ?. persistentTrack ;
5560 } , [ props . audioTrackState ] ) ;
5661
5762 const videoUnavailableMessage = useMemo ( ( ) => {
@@ -67,15 +72,15 @@ export default function Tile(props) {
6772 */
6873 useEffect ( ( ) => {
6974 videoEl . current &&
70- ( videoEl . current . srcObject = new MediaStream ( [ videoTrack ] ) ) ;
75+ ( videoEl . current . srcObject = videoTrack && new MediaStream ( [ videoTrack ] ) ) ;
7176 } , [ videoTrack ] ) ;
7277
7378 /**
7479 * When audio track changes, update audio srcObject
7580 */
7681 useEffect ( ( ) => {
7782 audioEl . current &&
78- ( audioEl . current . srcObject = new MediaStream ( [ audioTrack ] ) ) ;
83+ ( audioEl . current . srcObject = audioTrack && new MediaStream ( [ audioTrack ] ) ) ;
7984 } , [ audioTrack ] ) ;
8085
8186 function getVideoComponent ( ) {
0 commit comments