Changeset 271401 in webkit
- Timestamp:
- Jan 12, 2021, 6:34:28 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 12 edited
-
LayoutTests/fast/mediastream/media-stream-track-interrupted.html (modified) (3 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp (modified) (3 diffs)
-
Source/WebCore/Modules/mediastream/MediaStreamTrack.h (modified) (2 diffs)
-
Source/WebCore/dom/Document.cpp (modified) (2 diffs)
-
Source/WebCore/page/Page.cpp (modified) (2 diffs)
-
Source/WebCore/page/Page.h (modified) (1 diff)
-
Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp (modified) (2 diffs)
-
Source/WebCore/testing/Internals.cpp (modified) (1 diff)
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/WebProcess/WebProcess.cpp (modified) (1 diff)
-
Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/fast/mediastream/media-stream-track-interrupted.html
r268400 r271401 51 51 function testTrack(track, title) 52 52 { 53 promise_test((test) => { 54 return new Promise((resolve, reject) => { 53 promise_test(async (test) => { 54 if (track.muted) 55 await new Promise(resolve => track.onunmute = resolve); 56 57 await new Promise((resolve, reject) => { 55 58 let isVideo = track.kind == "video"; 56 59 if (window.internals) { … … 68 71 waitForPageStateChange(10, pageState, resolve, reject) 69 72 } 70 71 73 if (window.internals) { 72 assert_true(pageMediaState.includes(isVideo ? 'HasMutedVideoCaptureDevice' : 'HasMutedAudioCaptureDevice')); 73 assert_false(pageMediaState.includes(isVideo ? 'HasMutedAudioCaptureDevice' : 'HasMutedVideoCaptureDevice')); 74 assert_true(pageMediaState.includes(isVideo ? 'HasActiveAudioCaptureDevice' : 'HasActiveVideoCaptureDevice')); 75 assert_false(pageMediaState.includes(isVideo ? 'HasActiveVideoCaptureDevice' : 'HasActiveAudioCaptureDevice')); 74 assert_true(pageMediaState.includes('HasMutedAudioCaptureDevice'), 'audio muted'); 75 assert_true(pageMediaState.includes('HasMutedVideoCaptureDevice'), 'video muted'); 76 76 pageState = internals.pageMediaState(); 77 77 internals.setMediaStreamSourceInterrupted(track, false) … … 86 86 setTimeout(() => reject("Muted state did not change in 1 second"), 1000); 87 87 }); 88 track.onmute = () => { }; 89 track.onunmute = () => { }; 88 90 }, title); 89 91 } -
trunk/Source/WebCore/ChangeLog
r271399 r271401 1 2021-01-12 Youenn Fablet <youenn@apple.com> 2 3 Unmuting a track in case of end of interruption by another web process tab is not working well with capture muting icons 4 https://bugs.webkit.org/show_bug.cgi?id=220058 5 6 Reviewed by Eric Carlson. 7 8 Before the patch, we were muting all tracks in case of Audio Session interruption. 9 This works well in case another application triggers the interruption. 10 11 In case the interruption is done by another tab, this does not work well for two reasons: 12 - The UIProcess is doing the work of muting the tracks when another tab is starting to capture 13 - Unmuting in case of interruption might unmute several tabs if they are in the same process 14 As an example, if a tab is capturing, and another tab starts to capture, going back to first tab will automatically 15 restart the audio capture as the Audio Session will end its interruption. But it will not mute the camera track. 16 17 To fix that, the Audio Shared Unit is no longer directly muting or unmuting the audio tracks. 18 Instead, each page is notified of start/end of AudioSession interruption. 19 When an interruption starts, all capture tracks are muted. 20 When an interruption ends, all capture tracks are updated according the page muted state, which is controlled by UIProcess. 21 This also covers the case of several tabs capturing in the same process, since only one tab will not be set as muted by UIProcess. 22 23 In case of several capture MediaStreamTrack in the same document and they are not the active source, we pick the first one as there is 24 no way to know which one was the last unmuted one. 25 We should probably add some support to always remember the last living track of a tab in iOS. 26 27 Manually tested. 28 29 * Modules/mediastream/MediaStreamTrack.cpp: 30 (WebCore::MediaStreamTrack::create): 31 (WebCore::MediaStreamTrack::updateCaptureAccordingToMutedState): 32 (WebCore::MediaStreamTrack::updateToPageMutedState): 33 * Modules/mediastream/MediaStreamTrack.h: 34 * dom/Document.cpp: 35 (WebCore::Document::visibilityStateChanged): 36 (WebCore::Document::pageMutedStateDidChange): 37 * page/Page.cpp: 38 (WebCore::Page::beginAudioCaptureInterruption): 39 (WebCore::Page::endAudioCaptureInterruption): 40 * page/Page.h: 41 * platform/mediastream/mac/BaseAudioSharedUnit.cpp: 42 (WebCore::BaseAudioSharedUnit::resume): 43 (WebCore::BaseAudioSharedUnit::suspend): 44 1 45 2021-01-12 Philippe Normand <pnormand@igalia.com> 2 46 -
trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
r271060 r271401 72 72 track->suspendIfNeeded(); 73 73 74 if (track->isCaptureTrack()) 75 track->updateToPageMutedState(); 74 if (track->isCaptureTrack()) { 75 if (auto* page = track->document()->page()) 76 track->updateToPageMutedState(page->mutedState()); 77 } 76 78 77 79 return track; … … 470 472 #endif 471 473 472 void MediaStreamTrack::updateCaptureAccordingToMutedState(Document& document )474 void MediaStreamTrack::updateCaptureAccordingToMutedState(Document& document, MediaProducer::MutedStateFlags mutedState) 473 475 { 474 476 #if PLATFORM(IOS_FAMILY) … … 477 479 return; 478 480 481 bool pageMuted = mutedState & MediaProducer::AudioAndVideoCaptureIsMuted; 482 483 auto updateTracksAccordingPageMutedState = [](const Document& document, CaptureDevice::DeviceType deviceType, bool pageMuted) { 484 // We can only have one source at a time: we can mute all tracks but unmute only one of them. 485 for (auto* captureTrack : allCaptureTracks()) { 486 if (captureTrack->document() != &document || captureTrack->ended() || captureTrack->source().deviceType() != deviceType) 487 continue; 488 captureTrack->m_private->setMuted(pageMuted); 489 // If unmuting, unmute the first source of the document we know. 490 if (!pageMuted) 491 break; 492 } 493 }; 479 494 auto* activeAudioSource = RealtimeMediaSourceCenter::singleton().audioCaptureFactory().activeSource(); 480 if (activeAudioSource && isSourceCapturingForTrackInDocument(*activeAudioSource, document)) { 481 bool pageMuted = page->mutedState() & MediaProducer::AudioAndVideoCaptureIsMuted; 495 if (activeAudioSource && isSourceCapturingForTrackInDocument(*activeAudioSource, document)) 482 496 activeAudioSource->setMuted(pageMuted || (document.hidden() && document.settings().interruptAudioOnPageVisibilityChangeEnabled())); 483 } 497 else 498 updateTracksAccordingPageMutedState(document, CaptureDevice::DeviceType::Microphone, pageMuted); 484 499 485 500 auto* activeVideoSource = RealtimeMediaSourceCenter::singleton().videoCaptureFactory().activeSource(); 486 if (activeVideoSource && isSourceCapturingForTrackInDocument(*activeVideoSource, document)) { 487 bool pageMuted = page->mutedState() & MediaProducer::AudioAndVideoCaptureIsMuted; 501 if (activeVideoSource && isSourceCapturingForTrackInDocument(*activeVideoSource, document)) 488 502 activeVideoSource->setMuted(pageMuted || document.hidden()); 489 } 503 else 504 updateTracksAccordingPageMutedState(document, CaptureDevice::DeviceType::Camera, pageMuted); 490 505 #else 491 506 for (auto* captureTrack : allCaptureTracks()) { 492 507 if (captureTrack->document() == &document && !captureTrack->ended()) 493 captureTrack->updateToPageMutedState( );508 captureTrack->updateToPageMutedState(mutedState); 494 509 } 495 510 #endif 496 511 } 497 512 498 void MediaStreamTrack::updateToPageMutedState( )513 void MediaStreamTrack::updateToPageMutedState(MediaProducer::MutedStateFlags mutedState) 499 514 { 500 515 ASSERT(isCaptureTrack()); 501 auto* page = document()->page();502 if (!page)503 return;504 516 505 517 switch (source().deviceType()) { 506 518 case CaptureDevice::DeviceType::Microphone: 507 519 case CaptureDevice::DeviceType::Camera: 508 m_private->setMuted( page->mutedState()& MediaProducer::AudioAndVideoCaptureIsMuted);520 m_private->setMuted(mutedState & MediaProducer::AudioAndVideoCaptureIsMuted); 509 521 break; 510 522 case CaptureDevice::DeviceType::Screen: 511 523 case CaptureDevice::DeviceType::Window: 512 m_private->setMuted( page->mutedState()& MediaProducer::ScreenCaptureIsMuted);524 m_private->setMuted(mutedState & MediaProducer::ScreenCaptureIsMuted); 513 525 break; 514 526 case CaptureDevice::DeviceType::Speaker: -
trunk/Source/WebCore/Modules/mediastream/MediaStreamTrack.h
r271060 r271401 73 73 74 74 static MediaProducer::MediaStateFlags captureState(Document&); 75 static void updateCaptureAccordingToMutedState(Document& );75 static void updateCaptureAccordingToMutedState(Document&, MediaProducer::MutedStateFlags); 76 76 77 77 virtual bool isCanvas() const { return false; } … … 170 170 171 171 void configureTrackRendering(); 172 void updateToPageMutedState( );172 void updateToPageMutedState(MediaProducer::MutedStateFlags); 173 173 174 174 // ActiveDOMObject API. -
trunk/Source/WebCore/dom/Document.cpp
r271270 r271401 1811 1811 1812 1812 #if ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY) 1813 auto* page = this->page(); 1814 if (!page) 1815 return; 1816 1813 1817 if (auto mediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists()) { 1814 1818 if (!mediaSessionManager->isInterrupted()) 1815 MediaStreamTrack::updateCaptureAccordingToMutedState(*this );1819 MediaStreamTrack::updateCaptureAccordingToMutedState(*this, page->mutedState()); 1816 1820 } 1817 1821 #endif … … 4299 4303 4300 4304 #if ENABLE(MEDIA_STREAM) 4301 MediaStreamTrack::updateCaptureAccordingToMutedState(*this );4305 MediaStreamTrack::updateCaptureAccordingToMutedState(*this, page()->mutedState()); 4302 4306 #endif 4303 4307 } -
trunk/Source/WebCore/page/Page.cpp
r270480 r271401 80 80 #include "MediaCanStartListener.h" 81 81 #include "MediaRecorderProvider.h" 82 #include "MediaStreamTrack.h" 82 83 #include "Navigator.h" 83 84 #include "PageConfiguration.h" … … 2075 2076 } 2076 2077 2078 void Page::beginAudioCaptureInterruption() 2079 { 2080 #if ENABLE(MEDIA_STREAM) 2081 forEachDocument([mutedState = mutedState()](auto& document) { 2082 MediaStreamTrack::updateCaptureAccordingToMutedState(document, mutedState | MediaProducer::AudioAndVideoCaptureIsMuted); 2083 }); 2084 #endif 2085 } 2086 2087 void Page::endAudioCaptureInterruption() 2088 { 2089 #if ENABLE(MEDIA_STREAM) 2090 forEachDocument([mutedState = mutedState()](auto& document) { 2091 MediaStreamTrack::updateCaptureAccordingToMutedState(document, mutedState); 2092 }); 2093 #endif 2094 } 2095 2077 2096 bool Page::mediaPlaybackExists() 2078 2097 { -
trunk/Source/WebCore/page/Page.h
r270480 r271401 832 832 void setTextInteractionEnabled(bool value) { m_textInteractionEnabled = value; } 833 833 834 WEBCORE_EXPORT void beginAudioCaptureInterruption(); 835 WEBCORE_EXPORT void endAudioCaptureInterruption(); 836 834 837 private: 835 838 struct Navigation { -
trunk/Source/WebCore/platform/mediastream/mac/BaseAudioSharedUnit.cpp
r267838 r271401 184 184 reconfigure(); 185 185 } 186 187 ASSERT(!m_producingCount);188 189 forEachClient([](auto& client) {190 client.setMuted(false);191 });192 193 186 return 0; 194 187 } … … 202 195 m_suspended = true; 203 196 stopInternal(); 204 205 forEachClient([](auto& client) {206 client.setMuted(true);207 });208 209 ASSERT(!m_producingCount);210 211 197 return 0; 212 198 } -
trunk/Source/WebCore/testing/Internals.cpp
r270919 r271401 5274 5274 void Internals::setMediaStreamSourceInterrupted(MediaStreamTrack& track, bool interrupted) 5275 5275 { 5276 auto* document = contextDocument(); 5277 auto* page = document ? document->page() : nullptr; 5278 if (!page) 5279 return; 5280 5276 5281 track.source().setInterruptedForTesting(interrupted); 5282 if (interrupted) 5283 page->beginAudioCaptureInterruption(); 5284 else 5285 page->endAudioCaptureInterruption(); 5277 5286 } 5278 5287 -
trunk/Source/WebKit/ChangeLog
r271396 r271401 1 2021-01-12 Youenn Fablet <youenn@apple.com> 2 3 Unmuting a track in case of end of interruption by another web process tab is not working well with capture muting icons 4 https://bugs.webkit.org/show_bug.cgi?id=220058 5 6 Reviewed by Eric Carlson. 7 8 Add an observer of AudioSession interruptions that forwards the signal to all tabs of the process. 9 10 * WebProcess/cocoa/WebProcessCocoa.mm: 11 (WebKit::WebProcess::platformInitializeWebProcess): 12 (WebKit::PageAudioSessionInterruptionObserver::PageAudioSessionInterruptionObserver): 13 (WebKit::PageAudioSessionInterruptionObserver::~PageAudioSessionInterruptionObserver): 14 (WebKit::PageAudioSessionInterruptionObserver::beginAudioSessionInterruption): 15 (WebKit::PageAudioSessionInterruptionObserver::endAudioSessionInterruption): 16 (WebKit::listenToAudioSessionInterruption): 17 1 18 2021-01-12 Philippe Normand <pnormand@igalia.com> 2 19 -
trunk/Source/WebKit/WebProcess/WebProcess.cpp
r270932 r271401 1815 1815 void WebProcess::revokeUserMediaDeviceSandboxExtensions(const Vector<String>& extensionIDs) 1816 1816 { 1817 checkDocumentsCaptureStateConsistency(extensionIDs); 1817 if (!MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled()) 1818 checkDocumentsCaptureStateConsistency(extensionIDs); 1818 1819 1819 1820 for (const auto& extensionID : extensionIDs) { -
trunk/Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm
r271294 r271401 55 55 #import <WebCore/AVAssetMIMETypeCache.h> 56 56 #import <WebCore/AXObjectCache.h> 57 #import <WebCore/AudioSession.h> 57 58 #import <WebCore/CPUMonitor.h> 58 59 #import <WebCore/DisplayRefreshMonitorManager.h> … … 171 172 #endif 172 173 174 #if PLATFORM(IOS) 175 static void listenToAudioSessionInterruption(); 176 #endif 177 173 178 void WebProcess::platformSetCacheModel(CacheModel) 174 179 { … … 407 412 408 413 WebCore::IOSurface::setMaximumSize(parameters.maximumIOSurfaceSize); 414 415 #if PLATFORM(IOS) 416 listenToAudioSessionInterruption(); 417 #endif 409 418 } 410 419 … … 1178 1187 } 1179 1188 1189 #if PLATFORM(IOS) 1190 class PageAudioSessionInterruptionObserver : public AudioSession::InterruptionObserver { 1191 public: 1192 PageAudioSessionInterruptionObserver(); 1193 ~PageAudioSessionInterruptionObserver(); 1194 1195 private: 1196 void beginAudioSessionInterruption() final; 1197 void endAudioSessionInterruption(WebCore::AudioSession::MayResume) final; 1198 }; 1199 1200 PageAudioSessionInterruptionObserver::PageAudioSessionInterruptionObserver() 1201 { 1202 AudioSession::sharedSession().addInterruptionObserver(*this); 1203 } 1204 1205 PageAudioSessionInterruptionObserver::~PageAudioSessionInterruptionObserver() 1206 { 1207 AudioSession::sharedSession().removeInterruptionObserver(*this); 1208 } 1209 1210 void PageAudioSessionInterruptionObserver::beginAudioSessionInterruption() 1211 { 1212 Page::forEachPage([](auto& page) { 1213 page.beginAudioCaptureInterruption(); 1214 }); 1215 } 1216 1217 void PageAudioSessionInterruptionObserver::endAudioSessionInterruption(AudioSession::MayResume mayResume) 1218 { 1219 if (mayResume == AudioSession::MayResume::No) 1220 return; 1221 Page::forEachPage([](auto& page) { 1222 page.endAudioCaptureInterruption(); 1223 }); 1224 } 1225 1226 void listenToAudioSessionInterruption() 1227 { 1228 static NeverDestroyed<PageAudioSessionInterruptionObserver> observer; 1229 } 1230 #endif 1231 1180 1232 } // namespace WebKit 1181 1233
Note:
See TracChangeset
for help on using the changeset viewer.