Closed Bug 1829054 Opened 2 years ago Closed 1 year ago

Resume decoded audio when device is replugged after setSinkId()

Categories

(Core :: Audio/Video: Playback, enhancement, P1)

enhancement

Tracking

()

RESOLVED FIXED
116 Branch
Tracking Status
firefox114 --- wontfix
firefox115 --- wontfix
firefox116 --- fixed

People

(Reporter: karlt, Assigned: karlt)

References

(Depends on 1 open bug)

Details

Attachments

(15 files)

1.14 KB, text/html
Details
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
Attached file testcase

+++ This bug was initially created as a clone of Bug #1801190 +++

https://w3c.github.io/mediacapture-output/#algorithms-new-sink-available

New audio devices may become available to the user agent, or an audio device (identified by a media element's sinkId attribute) that had previously become unavailable may become available again, for example, if it is unplugged and later plugged back in.

In this scenario, the user agent must run the following steps:

  1. Let sinkId be the identifier for the newly available device.
  2. For each media element whose sinkId attribute is equal to sinkId:
  3. If the media element's paused attribute is false, start rendering this object's audio out of the device represented by the sinkId attribute.

STR:

  1. Set pref media.setsinkid.enabled true (unnecessary on Nightly, as this is the default).
  2. Load testcase.
  3. Play video.
  4. Click "Default system output..."
  5. Select a removable speaker device.
  6. Click "Allow".
  7. Remove and re-plug removable speaker device.

Expect: audio in speaker selected in 5.
Actual: no audio.

Summary: Resume audio when device is replugged after setSinkId() → Resume decoded audio when device is replugged after setSinkId()

to remove risk of leak.

Depends on D180651

Move Ensure() to Start() to clarify that muting and SetPlaying() should not
create a different promise for clients to watch.

Move ResolveIfExists() from Shutdown() to Stop() to make the behavior when
muted consistent with behavior when unmuted and with DecodedStream and
VideoSink.

Shutdown() asserts that Stop() has been called.

Depends on D180652

This naming uses "position" instead of "duration" to clarify that this does
not include remaining playback duration.

mPlayStartTime was reset on playback rate changes and muting changes, so was
not necessarily the start of playback.

Depends on D180653

for consistency with state before start and to simplify IsPlaying().

Depends on D180654

SetPlaying() and asynchronous sink creation no longer starts an AudioSink if
audio has ended.

The ended test with OnMuted() is now effective even when audio ended while
using system time for the clock, when mAudioEnded does not get set.

Depends on D180655

Tracking of the AudioSink's promise is now only performed if the AudioSink
successfully starts.

The existing mEndedPromiseHolder.RejectIfExists() does not behave as expected
because the AudioStream::Start() steals the promise even if it fails. This
will be addressed in the next patch to use separate ended promises for
AudioSink and AudioSinkWrapper.

Depends on D180656

In a future patch this will allow the AudioSinkWrapper to remain unended when
the AudioSink ends due to the device becoming unavailable, and to reopen
another AudioSink when the device becomes available again.

Re-enqueuing unplayed audio even when not required is favored over
the complexity of an otherwise unnecessary parameter.

Depends on D180657

This helps clarify the difference between mEndedPromiseHolder managed by
AudioSinkWrapper and mAudioSinkEndedRequest watching a promise managed by the
AudioSink/AudioStream.

Depends on D180658

This clarifies that the aStartTime parameter is not used in the async method.

Depends on D180659

This will simplify keeping track of a previous AudioSink's end time when
switching between clocks. OnAudioEnded() will also use this helper in a
future patch.

Depends on D180660

This last packet time is similar to the upper limit used with the return value
from AudioSink::GetEndTime(). It also now correctly returns zero, even when
muted (tested in test_background_video_resume_after_end_show_last_frame.html),
if there is no audio track, as documented in MediaSink.h.

Returning an advancing time was leading to incorrect durations when muted, as
now tested in test_seek_duration.html. MediaSink::GetEndTime() also needs to
cap the system clock so MDSM will not advance playback position beyond the end
of media. https://bugzilla.mozilla.org/show_bug.cgi?id=1386478#c6

Zero is no longer returned when the AudioSink callbacks have not yet started,
which would have the effect of briefly not advancing the current playback
position of a playing audio element when unmuting.

Depends on D180661

to keep current playback position progressing and to resume audio output on
replugging a removed device.

Depends on D180662

Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/1638fd63ec28 remove declaration of non-existent AudioStream::Reset r=kinetik https://hg.mozilla.org/integration/autoland/rev/1cce87bd67c5 use std::function to reduce templating and indirection of AudioSink creation r=padenot https://hg.mozilla.org/integration/autoland/rev/b7125a21f04f store new AudioSink in a UniquePtr immediately r=padenot https://hg.mozilla.org/integration/autoland/rev/2fbfefb8c6cf clarify the Start() to Stop() lifetime of AudioSinkWrapper::mEndedPromise r=padenot

Thank you for flagging me.

Depends on: 1825456
Flags: needinfo?(karlt)
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/bd4296891041 remove declaration of non-existent AudioStream::Reset r=kinetik https://hg.mozilla.org/integration/autoland/rev/2cee8a5d0209 use std::function to reduce templating and indirection of AudioSink creation r=padenot https://hg.mozilla.org/integration/autoland/rev/3661d47fd7f7 store new AudioSink in a UniquePtr immediately r=padenot
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/9fd95d83faf1 document and rename some AudioSinkWrapper state variables r=padenot https://hg.mozilla.org/integration/autoland/rev/69915e513481 reset mClockStartTime and mPositionAtClockStart on Stop() r=padenot

https://phabricator.services.mozilla.com/D180653 needs to land with https://phabricator.services.mozilla.com/D180656 to avoid failures in dom/media/mediasource/test/test_BufferingWait.html, dom/media/test/test_background_video_ended_event.html, and dom/media/test/test_reset_src.html as reported in comment 17 and now documented in the commit message.

Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/5ef69e37cbf5 clarify the Start() to Stop() lifetime of AudioSinkWrapper::mEndedPromise r=padenot https://hg.mozilla.org/integration/autoland/rev/d27814dbcf7f decide whether an AudioSink should be used in a single method r=padenot
Attachment #9338594 - Attachment description: Bug 1829054 split StartAudioSink into sink and async methods r?padenot → Bug 1829054 split StartAudioSink into sync and async methods r?padenot
See Also: → 1838141
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/81468f8b39fd use a shared helper method to start and listen to AudioSink r=padenot https://hg.mozilla.org/integration/autoland/rev/203bf275e99e use a separate promise to track AudioSink and AudioSinkWrapper ended r=padenot
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/039e59ad276e rename mAudioSinkEndedPromise to mAudioSinkEndedRequest r=padenot https://hg.mozilla.org/integration/autoland/rev/449ecd31e049 split StartAudioSink into sync and async methods r=padenot
Keywords: leave-open
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/2b9574ef0cc1 share a helper method to shut down the AudioSink r=padenot
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/ecdb4d9d26dc use last queued packet end time when no AudioSink is in use r=padenot
Regressions: 1838233
Keywords: leave-open
Blocks: 1780150
No longer regressions: 1838233
Pushed by ktomlinson@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/4ca8d0459e42 re-try explicit audio device periodically after stream failure r=padenot
Status: NEW → RESOLVED
Closed: 1 year ago
Resolution: --- → FIXED
Target Milestone: --- → 116 Branch

Since nightly and release are affected, beta will likely be affected too.
For more information, please visit BugBot documentation.

:Karlt is this something you would like to nominate for 116 release notes?

Flags: needinfo?(karlt)

The key change here will come into effect on release only when bug 1498512 is fixed, so that's the one to watch for release notes, thank you.

Flags: needinfo?(karlt)
Regressions: 1845811
Regressions: 1846854
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: