Diff
Modified: trunk/LayoutTests/ChangeLog (267471 => 267472)
--- trunk/LayoutTests/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/LayoutTests/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,17 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ Skip new tests on WK1 since mediaDevices is not implemented in WK1.
+
+ * http/wpt/audio-output/setSinkId.https-expected.txt: Added.
+ * http/wpt/audio-output/setSinkId.https.html: Added.
+ * platform/mac-wk1/TestExpectations:
+ * platform/win/TestExpectations:
+
2020-09-23 Philippe Normand <[email protected]>
REGRESSION(r267383): fast/mediastream/getUserMedia-webaudio.html is failing
Added: trunk/LayoutTests/http/wpt/audio-output/setSinkId.https-expected.txt (0 => 267472)
--- trunk/LayoutTests/http/wpt/audio-output/setSinkId.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/wpt/audio-output/setSinkId.https-expected.txt 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,4 @@
+
+PASS setSinkId requires user gesture
+PASS setSinkId and sinkId
+
Added: trunk/LayoutTests/http/wpt/audio-output/setSinkId.https.html (0 => 267472)
--- trunk/LayoutTests/http/wpt/audio-output/setSinkId.https.html (rev 0)
+++ trunk/LayoutTests/http/wpt/audio-output/setSinkId.https.html 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,36 @@
+<!doctype html>
+<head>
+<title>Test setSinkId behavior </title>
+<link rel="author" title="Dominique Hazael-Massieux" href=""
+<link rel="help" href=""
+</head>
+<script src=""
+<script src=""
+<script>
+"use strict";
+
+const audio = new Audio();
+
+promise_test(t => {
+ if (!window.internals)
+ return;
+ internals.settings.setSpeakerSelectionRequiresUserGesture(true);
+ t.add_cleanup(() => { internals.settings.setSpeakerSelectionRequiresUserGesture(false); });
+
+ return promise_rejects_dom(t, "NotAllowedError", audio.setSinkId(""));
+}, "setSinkId requires user gesture");
+
+
+promise_test(async t => {
+ await navigator.mediaDevices.getUserMedia({ audio : true });
+ const list = await navigator.mediaDevices.enumerateDevices();
+ const outputDevicesList = list.filter(({kind}) => kind == "audiooutput");
+ assert_not_equals(outputDevicesList.length, 0, "media device list includes at least one audio output device");
+
+ let promise = audio.setSinkId(outputDevicesList[0].deviceId);
+
+ assert_equals(audio.sinkId, "");
+ await promise;
+ assert_equals(audio.sinkId, outputDevicesList[0].deviceId);
+}, "setSinkId and sinkId");
+</script>
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (267471 => 267472)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,19 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ * resources/import-expectations.json:
+ * web-platform-tests/audio-output/META.yml: Added.
+ * web-platform-tests/audio-output/idlharness.https.window-expected.txt: Added.
+ * web-platform-tests/audio-output/idlharness.https.window.html: Added.
+ * web-platform-tests/audio-output/idlharness.https.window.js: Added.
+ * web-platform-tests/audio-output/setSinkId.https-expected.txt: Added.
+ * web-platform-tests/audio-output/setSinkId.https.html: Added.
+ * web-platform-tests/audio-output/w3c-import.log: Added.
+
2020-09-22 Chris Dumez <[email protected]>
Slightly improve AudioBufferSourceNode resampling
Modified: trunk/LayoutTests/imported/w3c/resources/import-expectations.json (267471 => 267472)
--- trunk/LayoutTests/imported/w3c/resources/import-expectations.json 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/LayoutTests/imported/w3c/resources/import-expectations.json 2020-09-23 14:04:20 UTC (rev 267472)
@@ -49,7 +49,7 @@
"web-platform-tests/apng": "skip",
"web-platform-tests/app-uri": "skip",
"web-platform-tests/assumptions": "skip",
- "web-platform-tests/audio-output": "skip",
+ "web-platform-tests/audio-output": "import",
"web-platform-tests/auxclick": "skip",
"web-platform-tests/background-fetch": "import",
"web-platform-tests/battery-status": "skip",
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/META.yml (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/META.yml (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/META.yml 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,4 @@
+spec: https://w3c.github.io/mediacapture-output/
+suggested_reviewers:
+ - guidou
+ - jan-ivar
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window-expected.txt (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window-expected.txt 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,16 @@
+
+PASS idl_test setup
+PASS idl_test validation
+PASS Partial interface HTMLMediaElement: original interface defined
+PASS Partial interface HTMLMediaElement: member names are unique
+PASS HTMLElement includes GlobalEventHandlers: member names are unique
+PASS HTMLElement includes DocumentAndElementEventHandlers: member names are unique
+PASS HTMLElement includes ElementContentEditable: member names are unique
+PASS HTMLElement includes HTMLOrSVGElement: member names are unique
+PASS Element includes ParentNode: member names are unique
+PASS Element includes NonDocumentTypeChildNode: member names are unique
+PASS Element includes ChildNode: member names are unique
+PASS Element includes Slottable: member names are unique
+PASS HTMLMediaElement interface: attribute sinkId
+PASS HTMLMediaElement interface: operation setSinkId(DOMString)
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.html (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.html 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1 @@
+<!-- This file is required for WebKit test infrastructure to run the templated test -->
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.js (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.js 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,20 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// https://w3c.github.io/mediacapture-output/
+
+'use strict';
+
+idl_test(
+ ['audio-output'],
+ ['mediacapture-streams', 'html', 'dom'],
+ idl_array => {
+ self.audio = document.createElement('audio');
+ self.video = document.createElement('video');
+ idl_array.add_objects({
+ HTMLAudioElement: ['audio'],
+ HTMLVideoElement: ['video'],
+ MediaDevices: ['navigator.mediaDevices'],
+ });
+ }
+);
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https-expected.txt (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https-expected.txt 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,5 @@
+
+PASS setSinkId on default audio output should always work
+PASS setSinkId fails with NotFoundError on made up deviceid
+FAIL List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError assert_not_equals: media device list includes at least one audio output device got disallowed value 0
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https.html (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https.html 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,46 @@
+<!doctype html>
+<head>
+<title>Test setSinkId behavior </title>
+<link rel="author" title="Dominique Hazael-Massieux" href=""
+<link rel="help" href=""
+</head>
+<script src=""
+<script src=""
+<script>
+"use strict";
+
+const audio = new Audio();
+
+promise_test(t => audio.setSinkId(""), "setSinkId on default audio output should always work");
+
+promise_test(t => promise_rejects_dom(t, "NotFoundError", audio.setSinkId("nonexistent_device_id")),
+ "setSinkId fails with NotFoundError on made up deviceid");
+
+promise_test(async t => {
+ const list = await navigator.mediaDevices.enumerateDevices();
+ const outputDevicesList = list.filter(({kind}) => kind == "audiooutput");
+ assert_not_equals(outputDevicesList.length, 0,
+ "media device list includes at least one audio output device");
+
+ let acceptedDevices = 0;
+ for (const {deviceId} of outputDevicesList) {
+ const {deviceId} = outputDevicesList[0];
+ const p1 = audio.setSinkId(deviceId);
+ assert_equals(audio.sinkId, "", "before it resolves, setSinkId is unchanged");
+ try {
+ let r = await p1;
+ assert_equals(acceptedDevices, 0, "only the default sink device can be set");
+ acceptedDevices++;
+ assert_equals(r, undefined, "setSinkId resolves with undefined");
+ assert_equals(audio.sinkId, deviceId, "when it resolves, setSinkId updates sinkId to the requested deviceId");
+ r = await audio.setSinkId(deviceId);
+ assert_equals(r, undefined, "resetting sinkid on same current value should always work");
+ r = await audio.setSinkId("");
+ assert_equals(r, undefined, "resetting sinkid on default audio output should always work");
+ } catch (e) {
+ assert_equals(e.name, "NotAllowedError", "Non-default devices are failing with NotAllowed error");
+ }
+ }
+}, "List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError");
+
+</script>
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/w3c-import.log (0 => 267472)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/w3c-import.log (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/audio-output/w3c-import.log 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,20 @@
+The tests in this directory were imported from the W3C repository.
+Do NOT modify these tests directly in WebKit.
+Instead, create a pull request on the WPT github:
+ https://github.com/web-platform-tests/wpt
+
+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport
+
+Do NOT modify or remove this file.
+
+------------------------------------------------------------------------
+Properties requiring vendor prefixes:
+None
+Property values requiring vendor prefixes:
+None
+------------------------------------------------------------------------
+List of files:
+/LayoutTests/imported/w3c/web-platform-tests/audio-output/META.yml
+/LayoutTests/imported/w3c/web-platform-tests/audio-output/idlharness.https.window.js
+/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId-manual.https.html
+/LayoutTests/imported/w3c/web-platform-tests/audio-output/setSinkId.https.html
Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (267471 => 267472)
--- trunk/LayoutTests/platform/mac-wk1/TestExpectations 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations 2020-09-23 14:04:20 UTC (rev 267472)
@@ -65,6 +65,9 @@
http/tests/navigation/page-cache-getUserMedia-pending-promise.html [ Skip ]
http/tests/navigation/page-cache-mediastream.html [ Skip ]
+http/wpt/audio-output [ Skip ]
+imported/w3c/web-platform-tests/audio-output [ Skip ]
+
# Datalist is unsupported in WK1
accessibility/datalist.html [ WontFix ]
fast/forms/datalist [ WontFix ]
Modified: trunk/LayoutTests/platform/win/TestExpectations (267471 => 267472)
--- trunk/LayoutTests/platform/win/TestExpectations 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/LayoutTests/platform/win/TestExpectations 2020-09-23 14:04:20 UTC (rev 267472)
@@ -859,6 +859,9 @@
http/tests/media/media-stream [ Skip ]
http/tests/navigation/page-cache-getUserMedia-pending-promise.html [ Skip ]
+http/wpt/audio-output [ Skip ]
+imported/w3c/web-platform-tests/audio-output [ Skip ]
+
# needs enhanced eventSender.contextMenu() return value
#webkit.org/b/45021 media/context-menu-actions.html
Modified: trunk/Source/WTF/ChangeLog (267471 => 267472)
--- trunk/Source/WTF/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WTF/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,13 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ Add HAVE_AUDIO_OUTPUT_DEVICE_UNIQUE_ID.
+ * wtf/PlatformHave.h:
+
2020-09-21 Yusuke Suzuki <[email protected]>
[JSC] BigInt should work with Map / Set
Modified: trunk/Source/WTF/wtf/PlatformHave.h (267471 => 267472)
--- trunk/Source/WTF/wtf/PlatformHave.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WTF/wtf/PlatformHave.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -682,6 +682,10 @@
#define HAVE_NSTABLEVIEWSTYLE 1
#endif
+#if PLATFORM(MAC)
+#define HAVE_AUDIO_OUTPUT_DEVICE_UNIQUE_ID 1
+#endif
+
#if ((PLATFORM(IOS) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 140000) \
|| (PLATFORM(WATCHOS) && __WATCH_OS_VERSION_MIN_REQUIRED >= 70000) \
|| (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 140000)
Modified: trunk/Source/WebCore/CMakeLists.txt (267471 => 267472)
--- trunk/Source/WebCore/CMakeLists.txt 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/CMakeLists.txt 2020-09-23 14:04:20 UTC (rev 267472)
@@ -919,6 +919,7 @@
html/HTMLMapElement.idl
html/HTMLMarqueeElement.idl
html/HTMLMediaElement.idl
+ html/HTMLMediaElementAudioOutput.idl
html/HTMLMenuElement.idl
html/HTMLMenuItemElement.idl
html/HTMLMetaElement.idl
Modified: trunk/Source/WebCore/ChangeLog (267471 => 267472)
--- trunk/Source/WebCore/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,68 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ Implement setSinkId and sinkId as per https://w3c.github.io/mediacapture-output/#htmlmediaelement-extensions.
+ Introduce a setting to expose these methods and to enable/disable user gesture requirement.
+ Add interfaces to change device output for specific media players.
+ Add support for HLS, MSE and MediaStreamTrack renderers on MacOS.
+ In case of setting the empty string, the default output device is used
+
+ Tests: http/wpt/audio-output/setSinkId.https.html
+ imported/w3c/web-platform-tests/audio-output/idlharness.https.window.html
+ imported/w3c/web-platform-tests/audio-output/setSinkId.https.html
+
+ * CMakeLists.txt:
+ * DerivedSources.make:
+ * Modules/mediastream/MediaDevices.cpp:
+ (WebCore::MediaDevices::exposeDevices):
+ * Modules/mediastream/MediaDevices.h:
+ * WebCore.xcodeproj/project.pbxproj:
+ * html/HTMLMediaElement.cpp:
+ (WebCore::HTMLMediaElement::audioOutputDevice const):
+ (WebCore::HTMLMediaElement::setAudioOutputDevice):
+ (WebCore::HTMLMediaElement::audioOutputDeviceId const):
+ * html/HTMLMediaElement.h:
+ (WebCore::HTMLMediaElement::audioOutputHashedDeviceId const):
+ * html/HTMLMediaElementAudioOutput.idl: Added.
+ * page/Settings.yaml:
+ * platform/graphics/MediaPlayer.cpp:
+ (WebCore::MediaPlayer::audioOutputDeviceChanged):
+ * platform/graphics/MediaPlayer.h:
+ (WebCore::MediaPlayerClient::audioOutputDeviceId const):
+ (WebCore::MediaPlayerClient::audioOutputDeviceIdOverride const):
+ (WebCore::MediaPlayer::audioOutputDeviceId const):
+ (WebCore::MediaPlayer::audioOutputDeviceIdOverride const):
+ * platform/graphics/MediaPlayerPrivate.h:
+ (WebCore::MediaPlayerPrivateInterface::audioOutputDeviceChanged):
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::audioOutputDeviceChanged):
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::audioOutputDeviceChanged):
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::updateTracks):
+ (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::audioOutputDeviceChanged):
+ * platform/mediastream/AudioMediaStreamTrackRenderer.h:
+ (WebCore::AudioMediaStreamTrackRenderer::setAudioOutputDevice):
+ * platform/mediastream/AudioTrackPrivateMediaStream.cpp:
+ (WebCore::AudioTrackPrivateMediaStream::setAudioOutputDevice):
+ * platform/mediastream/AudioTrackPrivateMediaStream.h:
+ * platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp:
+ (WebCore::AudioMediaStreamTrackRendererCocoa::setAudioOutputDevice):
+ (WebCore::AudioMediaStreamTrackRendererCocoa::pushSamples):
+ * platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h:
+ * platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.cpp:
+ (WebCore::AudioMediaStreamTrackRendererUnit::setAudioOutputDevice):
+ (WebCore::AudioMediaStreamTrackRendererUnit::createAudioUnitIfNeeded):
+ * platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.h:
+
2020-09-23 Philippe Normand <[email protected]>
REGRESSION(r267383): fast/mediastream/getUserMedia-webaudio.html is failing
Modified: trunk/Source/WebCore/DerivedSources-input.xcfilelist (267471 => 267472)
--- trunk/Source/WebCore/DerivedSources-input.xcfilelist 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/DerivedSources-input.xcfilelist 2020-09-23 14:04:20 UTC (rev 267472)
@@ -843,6 +843,7 @@
$(PROJECT_DIR)/html/HTMLMapElement.idl
$(PROJECT_DIR)/html/HTMLMarqueeElement.idl
$(PROJECT_DIR)/html/HTMLMediaElement.idl
+$(PROJECT_DIR)/html/HTMLMediaElementAudioOutput.idl
$(PROJECT_DIR)/html/HTMLMenuElement.idl
$(PROJECT_DIR)/html/HTMLMenuItemElement.idl
$(PROJECT_DIR)/html/HTMLMetaElement.idl
Modified: trunk/Source/WebCore/DerivedSources-output.xcfilelist (267471 => 267472)
--- trunk/Source/WebCore/DerivedSources-output.xcfilelist 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/DerivedSources-output.xcfilelist 2020-09-23 14:04:20 UTC (rev 267472)
@@ -966,6 +966,8 @@
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElement+RemotePlayback.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElement.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElement.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElementAudioOutput.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElementAudioOutput.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElementMediaSession.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElementMediaSession.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSHTMLMediaElementRemotePlayback.cpp
Modified: trunk/Source/WebCore/DerivedSources.make (267471 => 267472)
--- trunk/Source/WebCore/DerivedSources.make 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/DerivedSources.make 2020-09-23 14:04:20 UTC (rev 267472)
@@ -864,6 +864,7 @@
$(WebCore)/html/HTMLMapElement.idl \
$(WebCore)/html/HTMLMarqueeElement.idl \
$(WebCore)/html/HTMLMediaElement.idl \
+ $(WebCore)/html/HTMLMediaElementAudioOutput.idl \
$(WebCore)/html/HTMLMenuElement.idl \
$(WebCore)/html/HTMLMenuItemElement.idl \
$(WebCore)/html/HTMLMetaElement.idl \
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp (267471 => 267472)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -202,6 +202,8 @@
bool canAccessMicrophone = checkMicrophoneAccess(document);
bool canAccessSpeaker = checkSpeakerAccess(document);
+ m_audioOutputDeviceIdToPersistentId.clear();
+
Vector<Ref<MediaDeviceInfo>> devices;
for (auto& newDevice : newDevices) {
if (!canAccessMicrophone && newDevice.type() == CaptureDevice::DeviceType::Microphone)
@@ -214,6 +216,9 @@
auto deviceId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(newDevice.persistentId(), deviceIDHashSalt);
auto groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(newDevice.groupId(), m_groupIdHashSalt);
+ if (newDevice.type() == CaptureDevice::DeviceType::Speaker)
+ m_audioOutputDeviceIdToPersistentId.add(deviceId, newDevice.persistentId());
+
devices.append(MediaDeviceInfo::create(newDevice.label(), WTFMove(deviceId), WTFMove(groupId), toMediaDeviceInfoKind(newDevice.type())));
}
promise.resolve(devices);
Modified: trunk/Source/WebCore/Modules/mediastream/MediaDevices.h (267471 => 267472)
--- trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/Modules/mediastream/MediaDevices.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -89,6 +89,8 @@
void enumerateDevices(EnumerateDevicesPromise&&);
MediaTrackSupportedConstraints getSupportedConstraints();
+ String deviceIdToPersistentId(const String& deviceId) const { return m_audioOutputDeviceIdToPersistentId.get(deviceId); }
+
using RefCounted<MediaDevices>::ref;
using RefCounted<MediaDevices>::deref;
@@ -130,6 +132,9 @@
OptionSet<GestureAllowedRequest> m_requestTypesForCurrentGesture;
WeakPtr<UserGestureToken> m_currentGestureToken;
+
+ HashMap<String, String> m_audioOutputDeviceIdToPersistentId;
+ String m_audioOutputDeviceId;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (267471 => 267472)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-09-23 14:04:20 UTC (rev 267472)
@@ -7696,6 +7696,7 @@
41D28D0C2139E01E00F4206F /* LibWebRTCStatsCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCStatsCollector.h; path = libwebrtc/LibWebRTCStatsCollector.h; sourceTree = "<group>"; };
41D41C652256859200697942 /* ServiceWorkerInternals.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ServiceWorkerInternals.mm; sourceTree = "<group>"; };
41D51BB21E4E2E8100131A5B /* LibWebRTCAudioFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LibWebRTCAudioFormat.h; path = libwebrtc/LibWebRTCAudioFormat.h; sourceTree = "<group>"; };
+ 41D6BD98251B3ADA0055A7B7 /* HTMLMediaElementAudioOutput.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLMediaElementAudioOutput.idl; sourceTree = "<group>"; };
41DE7C7A222DA13D00532B65 /* StorageQuotaManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageQuotaManager.cpp; sourceTree = "<group>"; };
41DE7C7B222DA13E00532B65 /* StorageQuotaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageQuotaManager.h; sourceTree = "<group>"; };
41DEFCB21E56C1B9000D9E5F /* JSDOMBindingInternals.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = JSDOMBindingInternals.js; sourceTree = "<group>"; };
@@ -22916,6 +22917,7 @@
E44613920CD6331000FADA75 /* HTMLMediaElement.cpp */,
E44613930CD6331000FADA75 /* HTMLMediaElement.h */,
E44613940CD6331000FADA75 /* HTMLMediaElement.idl */,
+ 41D6BD98251B3ADA0055A7B7 /* HTMLMediaElementAudioOutput.idl */,
CD5209E51B0BD9E10077184E /* HTMLMediaElementEnums.h */,
A8EA79EC0A1916DF00A8EF5F /* HTMLMenuElement.cpp */,
A8EA79E80A1916DF00A8EF5F /* HTMLMenuElement.h */,
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (267471 => 267472)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -71,6 +71,7 @@
#include "MIMETypeRegistry.h"
#include "MediaController.h"
#include "MediaControlsHost.h"
+#include "MediaDevices.h"
#include "MediaDocument.h"
#include "MediaError.h"
#include "MediaFragmentURIParser.h"
@@ -78,6 +79,7 @@
#include "MediaPlayer.h"
#include "MediaQueryEvaluator.h"
#include "MediaResourceLoader.h"
+#include "NavigatorMediaDevices.h"
#include "NetworkingContext.h"
#include "PODIntervalTree.h"
#include "Page.h"
@@ -2843,6 +2845,49 @@
seekWithTolerance(time, negativeTolerance, MediaTime::zeroTime(), true);
}
+#if ENABLE(MEDIA_STREAM)
+void HTMLMediaElement::setAudioOutputDevice(String&& deviceId, DOMPromiseDeferred<void>&& promise)
+{
+ auto* window = document().domWindow();
+ auto* mediaDevices = window ? NavigatorMediaDevices::mediaDevices(window->navigator()) : nullptr;
+ if (!mediaDevices) {
+ promise.reject(Exception { NotAllowedError });
+ return;
+ }
+
+ if (!document().processingUserGestureForMedia() && document().settings().speakerSelectionRequiresUserGesture()) {
+ promise.reject(Exception { NotAllowedError, "A user gesture is required"_s });
+ return;
+ }
+
+ if (deviceId.isEmpty())
+ deviceId = { };
+
+ if (deviceId == m_audioOutputHashedDeviceId) {
+ promise.resolve();
+ return;
+ }
+
+ String persistentId;
+ if (!deviceId.isNull()) {
+ persistentId = mediaDevices->deviceIdToPersistentId(deviceId);
+ if (persistentId.isNull()) {
+ promise.reject(Exception { NotFoundError });
+ return;
+ }
+ }
+
+ m_audioOutputPersistentDeviceId = WTFMove(persistentId);
+ if (m_player)
+ m_player->audioOutputDeviceChanged();
+
+ scriptExecutionContext()->eventLoop().queueTask(TaskSource::MediaElement, [this, protectedThis = makeRef(*this), deviceId = WTFMove(deviceId), promise = WTFMove(promise)]() mutable {
+ m_audioOutputHashedDeviceId = WTFMove(deviceId);
+ promise.resolve();
+ });
+}
+#endif
+
void HTMLMediaElement::seek(const MediaTime& time)
{
ALWAYS_LOG(LOGIDENTIFIER, time);
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (267471 => 267472)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -268,6 +268,11 @@
double minFastReverseRate() const;
double maxFastForwardRate() const;
+#if ENABLE(MEDIA_STREAM)
+ void setAudioOutputDevice(String&& deviceId, DOMPromiseDeferred<void>&&);
+ String audioOutputHashedDeviceId() const { return m_audioOutputHashedDeviceId; }
+#endif
+
using HTMLMediaElementEnums::BufferingPolicy;
void setBufferingPolicy(BufferingPolicy);
WEBCORE_EXPORT BufferingPolicy bufferingPolicy() const;
@@ -605,6 +610,9 @@
SecurityOriginData documentSecurityOrigin() const final;
+ String audioOutputDeviceId() const final { return m_audioOutputPersistentDeviceId; }
+ String audioOutputDeviceIdOverride() const final { return m_audioOutputPersistentDeviceId; }
+
bool mediaControlsDependOnPageScaleFactor() const { return m_mediaControlsDependOnPageScaleFactor; }
void setMediaControlsDependOnPageScaleFactor(bool);
void updateMediaControlsAfterPresentationModeChange();
@@ -1197,6 +1205,11 @@
bool m_isPlayingToWirelessTarget { false };
bool m_playingOnSecondScreen { false };
bool m_removedBehaviorRestrictionsAfterFirstUserGesture { false };
+
+ String m_audioOutputPersistentDeviceId;
+#if ENABLE(MEDIA_STREAM)
+ String m_audioOutputHashedDeviceId;
+#endif
};
String convertEnumerationToString(HTMLMediaElement::AutoplayEventPlaybackState);
Added: trunk/Source/WebCore/html/HTMLMediaElementAudioOutput.idl (0 => 267472)
--- trunk/Source/WebCore/html/HTMLMediaElementAudioOutput.idl (rev 0)
+++ trunk/Source/WebCore/html/HTMLMediaElementAudioOutput.idl 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+[
+ Conditional=VIDEO&MEDIA_STREAM,
+] partial interface HTMLMediaElement {
+ [EnabledBySetting=ExposeSpeakers&PerElementSpeakerSelection, ImplementedAs=audioOutputHashedDeviceId] readonly attribute DOMString sinkId;
+ [EnabledBySetting=ExposeSpeakers&PerElementSpeakerSelection, ImplementedAs=setAudioOutputDevice] Promise<undefined> setSinkId(DOMString deviceId);
+};
Copied: trunk/Source/WebCore/page/AudioOutputProvider.h (from rev 267471, trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h) (0 => 267472)
--- trunk/Source/WebCore/page/AudioOutputProvider.h (rev 0)
+++ trunk/Source/WebCore/page/AudioOutputProvider.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+class Page;
+
+class WEBCORE_EXPORT AudioOutputProvider {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ AudioOutputProvider() = default;
+ virtual ~AudioOutputProvider() = default;
+
+ virtual void defaultAudioOutputDeviceChanged(Page&);
+};
+
+inline void AudioOutputProvider::defaultAudioOutputDeviceChanged(Page&)
+{
+}
+
+}
Modified: trunk/Source/WebCore/page/Settings.yaml (267471 => 267472)
--- trunk/Source/WebCore/page/Settings.yaml 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/page/Settings.yaml 2020-09-23 14:04:20 UTC (rev 267472)
@@ -826,6 +826,12 @@
exposeSpeakersEnabled:
initial: false
+perElementSpeakerSelectionEnabled:
+ initial: false
+
+speakerSelectionRequiresUserGesture:
+ initial: true
+
mediaDeviceIdentifierStorageDirectory:
type: String
conditional: ENABLE(MEDIA_STREAM)
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1604,6 +1604,11 @@
m_private->setPreferredDynamicRangeMode(mode);
}
+void MediaPlayer::audioOutputDeviceChanged()
+{
+ m_private->audioOutputDeviceChanged();
+}
+
#if !RELEASE_LOG_DISABLED
const Logger& MediaPlayer::mediaPlayerLogger()
{
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -273,6 +273,9 @@
virtual SecurityOriginData documentSecurityOrigin() const { return { }; }
+ virtual String audioOutputDeviceId() const { return { }; }
+ virtual String audioOutputDeviceIdOverride() const { return { }; }
+
#if !RELEASE_LOG_DISABLED
virtual const void* mediaPlayerLogIdentifier() { return nullptr; }
virtual const Logger& mediaPlayerLogger() = 0;
@@ -631,6 +634,10 @@
DynamicRangeMode preferredDynamicRangeMode() const { return m_preferredDynamicRangeMode; }
void setPreferredDynamicRangeMode(DynamicRangeMode);
+ String audioOutputDeviceId() const;
+ String audioOutputDeviceIdOverride() const;
+ void audioOutputDeviceChanged();
+
private:
MediaPlayer(MediaPlayerClient&);
MediaPlayer(MediaPlayerClient&, MediaPlayerEnums::MediaEngineIdentifier);
@@ -705,6 +712,16 @@
};
+inline String MediaPlayer::audioOutputDeviceId() const
+{
+ return m_client ? m_client->audioOutputDeviceId() : String { };
+}
+
+inline String MediaPlayer::audioOutputDeviceIdOverride() const
+{
+ return m_client ? m_client->audioOutputDeviceIdOverride() : String { };
+}
+
} // namespace WebCore
#endif // ENABLE(VIDEO)
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -289,6 +289,8 @@
virtual bool shouldIgnoreIntrinsicSize() { return false; }
virtual void setPreferredDynamicRangeMode(DynamicRangeMode) { }
+
+ virtual void audioOutputDeviceChanged() { }
};
}
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -318,6 +318,7 @@
void setShouldObserveTimeControlStatus(bool);
void setPreferredDynamicRangeMode(DynamicRangeMode) final;
+ void audioOutputDeviceChanged() final;
RetainPtr<AVURLAsset> m_avAsset;
RetainPtr<AVPlayer> m_avPlayer;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2020-09-23 14:04:20 UTC (rev 267472)
@@ -953,6 +953,16 @@
if (m_avPlayerItem)
setAVPlayerItem(m_avPlayerItem.get());
+#if HAVE(AUDIO_OUTPUT_DEVICE_UNIQUE_ID)
+ auto audioOutputDeviceId = player()->audioOutputDeviceIdOverride();
+ if (!audioOutputDeviceId.isNull()) {
+ if (audioOutputDeviceId.isEmpty())
+ m_avPlayer.get().audioOutputDeviceUniqueID = nil;
+ else
+ m_avPlayer.get().audioOutputDeviceUniqueID = audioOutputDeviceId;
+ }
+#endif
+
setDelayCallbacks(false);
}
@@ -3293,6 +3303,19 @@
#endif
}
+void MediaPlayerPrivateAVFoundationObjC::audioOutputDeviceChanged()
+{
+#if HAVE(AUDIO_OUTPUT_DEVICE_UNIQUE_ID)
+ if (!m_avPlayer || !player())
+ return;
+ auto deviceId = player()->audioOutputDeviceId();
+ if (deviceId.isEmpty())
+ m_avPlayer.get().audioOutputDeviceUniqueID = nil;
+ else
+ m_avPlayer.get().audioOutputDeviceUniqueID = deviceId;
+#endif
+}
+
NSArray* assetMetadataKeyNames()
{
static NSArray* keys = [[NSArray alloc] initWithObjects:
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -254,6 +254,7 @@
#endif
bool performTaskAtMediaTime(Function<void()>&&, const MediaTime&) final;
+ void audioOutputDeviceChanged() final;
void ensureLayer();
void destroyLayer();
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1166,6 +1166,16 @@
[audioRenderer setVolume:m_player->volume()];
[audioRenderer setAudioTimePitchAlgorithm:(m_player->preservesPitch() ? AVAudioTimePitchAlgorithmSpectral : AVAudioTimePitchAlgorithmVarispeed)];
+#if HAVE(AUDIO_OUTPUT_DEVICE_UNIQUE_ID)
+ auto deviceId = m_player->audioOutputDeviceIdOverride();
+ if (!deviceId.isNull()) {
+ if (deviceId.isEmpty())
+ audioRenderer.audioOutputDeviceUniqueID = nil;
+ else
+ audioRenderer.audioOutputDeviceUniqueID = deviceId;
+ }
+#endif
+
@try {
[m_synchronizer addRenderer:audioRenderer];
} @catch(NSException *exception) {
@@ -1276,6 +1286,22 @@
return true;
}
+void MediaPlayerPrivateMediaSourceAVFObjC::audioOutputDeviceChanged()
+{
+#if HAVE(AUDIO_OUTPUT_DEVICE_UNIQUE_ID)
+ if (!m_player)
+ return;
+ auto deviceId = m_player->audioOutputDeviceId();
+ for (auto& key : m_sampleBufferAudioRendererMap.keys()) {
+ auto renderer = ((__bridge AVSampleBufferAudioRenderer *)key.get());
+ if (deviceId.isEmpty())
+ renderer.audioOutputDeviceUniqueID = nil;
+ else
+ renderer.audioOutputDeviceUniqueID = deviceId;
+ }
+#endif
+}
+
WTFLogChannel& MediaPlayerPrivateMediaSourceAVFObjC::logChannel() const
{
return LogMediaSource;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -159,6 +159,7 @@
bool ended() const override { return m_ended; }
void setBufferingPolicy(MediaPlayer::BufferingPolicy) override;
+ void audioOutputDeviceChanged() final;
MediaPlayer::ReadyState currentReadyState();
void updateReadyState();
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm (267471 => 267472)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm 2020-09-23 14:04:20 UTC (rev 267472)
@@ -867,7 +867,8 @@
{
MediaStreamTrackPrivateVector currentTracks = m_mediaStreamPrivate->tracks();
- auto setAudioTrackState = [this](AudioTrackPrivateMediaStream& track, int index, TrackState state)
+ auto deviceId = m_player->audioOutputDeviceIdOverride();
+ auto setAudioTrackState = [this, &deviceId](AudioTrackPrivateMediaStream& track, int index, TrackState state)
{
switch (state) {
case TrackState::Remove:
@@ -884,6 +885,9 @@
track.setVolume(m_volume);
track.setMuted(m_muted);
track.setEnabled(track.streamTrack().enabled() && !track.streamTrack().muted());
+ if (!deviceId.isNull())
+ track.setAudioOutputDevice(deviceId);
+
if (playing())
track.play();
break;
@@ -1017,6 +1021,15 @@
m_sampleBufferDisplayLayer->flushAndRemoveImage();
}
+void MediaPlayerPrivateMediaStreamAVFObjC::audioOutputDeviceChanged()
+{
+ if (!m_player)
+ return;
+ auto deviceId = m_player->audioOutputDeviceId();
+ for (auto& audioTrack : m_audioTrackMap.values())
+ audioTrack->setAudioOutputDevice(deviceId);
+}
+
void MediaPlayerPrivateMediaStreamAVFObjC::scheduleDeferredTask(Function<void ()>&& function)
{
ASSERT(function);
Modified: trunk/Source/WebCore/platform/mediastream/AudioMediaStreamTrackRenderer.h (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/AudioMediaStreamTrackRenderer.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/AudioMediaStreamTrackRenderer.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -53,6 +53,8 @@
virtual void setVolume(float);
float volume() const;
+ virtual void setAudioOutputDevice(const String&);
+
#if !RELEASE_LOG_DISABLED
void setLogger(const Logger&, const void*);
#endif
@@ -109,6 +111,10 @@
}
#endif
+inline void AudioMediaStreamTrackRenderer::setAudioOutputDevice(const String&)
+{
}
+}
+
#endif // ENABLE(MEDIA_STREAM)
Modified: trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -97,6 +97,11 @@
updateRenderer();
}
+void AudioTrackPrivateMediaStream::setAudioOutputDevice(const String& deviceId)
+{
+ m_renderer->setAudioOutputDevice(deviceId);
+}
+
float AudioTrackPrivateMediaStream::volume() const
{
return m_renderer->volume();
Modified: trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/AudioTrackPrivateMediaStream.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -47,6 +47,7 @@
~AudioTrackPrivateMediaStream();
void setTrackIndex(int index) { m_index = index; }
+ void setAudioOutputDevice(const String&);
MediaStreamTrackPrivate& streamTrack() { return m_streamTrack.get(); }
Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -67,11 +67,18 @@
m_dataSource->setVolume(volume);
}
+void AudioMediaStreamTrackRendererCocoa::setAudioOutputDevice(const String& deviceId)
+{
+ // FIXME: We should create a unit for ourselves here or use the default unit if deviceId is matching.
+ AudioMediaStreamTrackRendererUnit::singleton().setAudioOutputDevice(deviceId);
+ m_shouldReset = true;
+}
+
void AudioMediaStreamTrackRendererCocoa::pushSamples(const MediaTime& sampleTime, const PlatformAudioData& audioData, const AudioStreamDescription& description, size_t sampleCount)
{
ASSERT(!isMainThread());
ASSERT(description.platformDescription().type == PlatformDescription::CAAudioStreamBasicType);
- if (!m_dataSource || !m_dataSource->inputDescription() || *m_dataSource->inputDescription() != description) {
+ if (!m_dataSource || m_shouldReset || !m_dataSource->inputDescription() || *m_dataSource->inputDescription() != description) {
auto dataSource = AudioSampleDataSource::create(description.sampleRate() * 2, *this);
if (dataSource->setInputFormat(toCAAudioStreamDescription(description))) {
@@ -95,6 +102,7 @@
AudioMediaStreamTrackRendererUnit::singleton().addSource(WTFMove(newSource));
});
m_dataSource = WTFMove(dataSource);
+ m_shouldReset = false;
}
m_dataSource->pushSamples(sampleTime, audioData, sampleCount);
Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererCocoa.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -53,9 +53,11 @@
void stop() final;
void clear() final;
void setVolume(float) final;
+ void setAudioOutputDevice(const String&) final;
std::unique_ptr<CAAudioStreamDescription> m_outputDescription;
RefPtr<AudioSampleDataSource> m_dataSource;
+ bool m_shouldReset { false };
};
}
Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.cpp (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -36,6 +36,11 @@
#include <pal/spi/cocoa/AudioToolboxSPI.h>
#include <wtf/Lock.h>
+#if PLATFORM(COCOA)
+#include "CoreAudioCaptureDevice.h"
+#include "CoreAudioCaptureDeviceManager.h"
+#endif
+
#include <pal/cf/CoreMediaSoftLink.h>
namespace WebCore {
@@ -51,6 +56,33 @@
stop();
}
+void AudioMediaStreamTrackRendererUnit::setAudioOutputDevice(const String& deviceID)
+{
+#if PLATFORM(MAC)
+ auto device = CoreAudioCaptureDeviceManager::singleton().coreAudioDeviceWithUID(deviceID);
+
+ if (!device && !deviceID.isEmpty()) {
+ RELEASE_LOG(WebRTC, "AudioMediaStreamTrackRendererUnit::setAudioOutputDeviceId - did not find device");
+ return;
+ }
+
+ auto audioUnitDeviceID = device ? device->deviceID() : 0;
+ if (m_deviceID == audioUnitDeviceID)
+ return;
+
+ bool shouldRestart = m_isStarted;
+ if (m_isStarted)
+ stop();
+
+ m_deviceID = audioUnitDeviceID;
+
+ if (shouldRestart)
+ start();
+#else
+ UNUSED_PARAM(deviceID);
+#endif
+}
+
void AudioMediaStreamTrackRendererUnit::addSource(Ref<AudioSampleDataSource>&& source)
{
RELEASE_LOG(WebRTC, "AudioMediaStreamTrackRendererUnit::addSource");
@@ -161,6 +193,16 @@
}
#endif
+#if PLATFORM(MAC)
+ if (m_deviceID) {
+ error = AudioUnitSetProperty(remoteIOUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &m_deviceID, sizeof(m_deviceID));
+ if (error) {
+ RELEASE_LOG_ERROR(WebRTC, "AudioMediaStreamTrackRendererUnit::createAudioUnit unable to set unit device ID %d, error %d (%.4s)", (int)m_deviceID, (int)error, (char*)&error);
+ return;
+ }
+ }
+#endif
+
AURenderCallbackStruct callback = { inputProc, nullptr };
error = AudioUnitSetProperty(remoteIOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
if (error) {
Modified: trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.h (267471 => 267472)
--- trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.h 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebCore/platform/mediastream/mac/AudioMediaStreamTrackRendererUnit.h 2020-09-23 14:04:20 UTC (rev 267472)
@@ -51,6 +51,8 @@
void start();
void stop();
+ void setAudioOutputDevice(const String&);
+
void addSource(Ref<AudioSampleDataSource>&&);
void removeSource(AudioSampleDataSource&);
@@ -68,6 +70,9 @@
bool m_shouldUpdateRenderSources { false };
Lock m_sourcesLock;
bool m_isStarted { false };
+#if PLATFORM(MAC)
+ uint32_t m_deviceID { 0 };
+#endif
};
}
Modified: trunk/Source/WebKit/ChangeLog (267471 => 267472)
--- trunk/Source/WebKit/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebKit/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,16 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ Add internal flag to enable/disable user gesture requirement for setting audio output device,
+ and for per media element setting of audio output device.
+
+ * Shared/WebPreferencesExperimental.yaml:
+ * Shared/WebPreferencesInternals.yaml:
+
2020-09-22 Wenson Hsieh <[email protected]>
[GPU Process] fast/canvas/canvas-blend-image.html and fast/canvas/canvas-blend-solid.html fail on macOS
Modified: trunk/Source/WebKit/Shared/WebPreferencesExperimental.yaml (267471 => 267472)
--- trunk/Source/WebKit/Shared/WebPreferencesExperimental.yaml 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebKit/Shared/WebPreferencesExperimental.yaml 2020-09-23 14:04:20 UTC (rev 267472)
@@ -144,8 +144,15 @@
defaultValue: false
humanReadableName: "Allow speaker device selection"
humanReadableDescription: "Allow speaker device selection"
- condition: ENABLE(WEB_RTC)
+ condition: ENABLE(MEDIA_STREAM)
+PerElementSpeakerSelectionEnabled:
+ type: bool
+ defaultValue: false
+ humanReadableName: "Allow per media element speaker device selection"
+ humanReadableDescription: "Allow per media element speaker device selection"
+ condition: ENABLE(MEDIA_STREAM)
+
VP9DecoderEnabled:
type: bool
defaultValue: defaultVP9DecoderEnabled()
Modified: trunk/Source/WebKit/Shared/WebPreferencesInternal.yaml (267471 => 267472)
--- trunk/Source/WebKit/Shared/WebPreferencesInternal.yaml 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Source/WebKit/Shared/WebPreferencesInternal.yaml 2020-09-23 14:04:20 UTC (rev 267472)
@@ -72,6 +72,13 @@
webcoreBinding: RuntimeEnabledFeatures
condition: ENABLE(WEB_RTC)
+SpeakerSelectionRequiresUserGesture:
+ type: bool
+ defaultValue: true
+ humanReadableName: "Require a user gesture for speaker selection"
+ humanReadableDescription: "Require a user gesture for speaker selection"
+ condition: ENABLE(MEDIA_STREAM)
+
FrameFlatteningEnabled:
type: bool
defaultValue: DEFAULT_FRAME_FLATTENING
Modified: trunk/Tools/ChangeLog (267471 => 267472)
--- trunk/Tools/ChangeLog 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Tools/ChangeLog 2020-09-23 14:04:20 UTC (rev 267472)
@@ -1,3 +1,13 @@
+2020-09-23 Youenn Fablet <[email protected]>
+
+ Add support for HTMLMediaElement.setSinkId
+ https://bugs.webkit.org/show_bug.cgi?id=216696
+
+ Reviewed by Eric Carlson.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetPreferencesToConsistentValues):
+
2020-09-22 Keith Rollin <[email protected]>
Unify debug and release target aliases
Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (267471 => 267472)
--- trunk/Tools/WebKitTestRunner/TestController.cpp 2020-09-23 13:36:28 UTC (rev 267471)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp 2020-09-23 14:04:20 UTC (rev 267472)
@@ -992,6 +992,7 @@
WKPreferencesSetMediaPlaybackRequiresUserGesture(preferences, false);
WKPreferencesSetVideoPlaybackRequiresUserGesture(preferences, false);
WKPreferencesSetAudioPlaybackRequiresUserGesture(preferences, false);
+ WKPreferencesSetInternalDebugFeatureForKey(preferences, false, WKStringCreateWithUTF8CString("SpeakerSelectionRequiresUserGesture"));
WKPreferencesSetShouldUseServiceWorkerShortTimeout(preferences, options.contextOptions.useServiceWorkerShortTimeout);