Changeset 184204 in webkit
- Timestamp:
- May 12, 2015, 9:41:48 AM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/Source/WebCore/ChangeLog ¶
r184199 r184204 1 2015-05-12 Eric Carlson <eric.carlson@apple.com> 2 3 [Mac] Refine media playback target client configuration 4 https://bugs.webkit.org/show_bug.cgi?id=144892 5 6 Reviewed by Brent Fulgham. 7 8 Client and target picker state changes fequently happen several times in quick succession, so 9 don't react to immediately so we can batch callbacks to the web process. 10 * Modules/mediasession/WebMediaSessionManager.cpp: 11 (WebCore::ClientState::ClientState): Store the client as a reference rather than a pointer 12 because it can never be NULL. 13 (WebCore::ClientState::operator == ): New. 14 (WebCore::WebMediaSessionManager::addPlaybackTargetPickerClient): Schedule the initial client 15 configuration and a target configuration check. 16 (WebCore::WebMediaSessionManager::removePlaybackTargetPickerClient): Schedule a target monitoring 17 update, and a target configuration check. 18 (WebCore::WebMediaSessionManager::removeAllPlaybackTargetPickerClients): Ditto. 19 (WebCore::WebMediaSessionManager::showPlaybackTargetPicker): Schedule a target monitoring update. 20 (WebCore::WebMediaSessionManager::clientStateDidChange): If the client whose state has changed 21 can play to a target, tell it to start using the target even if it isn't playing as long as 22 no other client is actively using a target. 23 (WebCore::WebMediaSessionManager::setPlaybackTarget): Configure clients after a pause. 24 (WebCore::WebMediaSessionManager::configureNewClients): New, do new client configuration. 25 (WebCore::WebMediaSessionManager::configurePlaybackTargetClients): New, configure target clients. 26 (WebCore::WebMediaSessionManager::scheduleDelayedTask): Schedule the timer. 27 (WebCore::WebMediaSessionManager::taskTimerFired): Execute delayed tasks. 28 (WebCore::WebMediaSessionManager::find): 29 * Modules/mediasession/WebMediaSessionManager.h: 30 31 * html/HTMLMediaElement.cpp: 32 (WebCore::HTMLMediaElement::setMuted): Call updateMediaState. 33 (WebCore::HTMLMediaElement::setPlaying): Ditto. 34 (WebCore::HTMLMediaElement::mediaPlayerCurrentPlaybackTargetIsWirelessChanged): Ditto. 35 (WebCore::HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent): Expand logging. 36 (WebCore::HTMLMediaElement::updateMediaState): New, don't broadcast a media state change 37 unless something actually changed. 38 * html/HTMLMediaElement.h: 39 40 * html/HTMLMediaSession.cpp: 41 (WebCore::HTMLMediaSession::externalOutputDeviceAvailableDidChange): Update logging. 42 (WebCore::HTMLMediaSession::setShouldPlayToPlaybackTarget): Ditto. 43 (WebCore::HTMLMediaSession::mediaEngineUpdated): Cleanup. 44 45 * platform/graphics/avfoundation/objc/MediaPlaybackTargetPickerMac.mm: 46 (WebCore::MediaPlaybackTargetPickerMac::showPlaybackTargetPicker): Remove the call to 47 deprecated API and the "-Wdeprecated-declarations". 48 1 49 2015-05-12 Joanmarie Diggs <jdiggs@igalia.com> 2 50 -
TabularUnified trunk/Source/WebCore/Modules/mediasession/WebMediaSessionManager.cpp ¶
r183613 r184204 35 35 namespace WebCore { 36 36 37 static double taskDelayInterval = 1.0 / 10.0; 38 37 39 struct ClientState { 38 40 explicit ClientState(WebMediaSessionManagerClient& client, uint64_t contextId) 39 : client( &client)41 : client(client) 40 42 , contextId(contextId) 41 43 { 42 44 } 43 45 44 WebMediaSessionManagerClient* client { nullptr }; 46 bool operator == (ClientState const& other) const 47 { 48 return contextId == other.contextId && &client == &other.client; 49 } 50 51 WebMediaSessionManagerClient& client; 45 52 uint64_t contextId { 0 }; 46 53 WebCore::MediaProducer::MediaStateFlags flags { WebCore::MediaProducer::IsNotPlaying }; 47 54 bool requestedPicker { false }; 55 bool configurationRequired { true }; 48 56 }; 49 57 … … 71 79 m_clientState.append(std::make_unique<ClientState>(client, contextId)); 72 80 73 if (m_externalOutputDeviceAvailable || m_playbackTarget) { 74 75 TaskCallback callback = std::make_tuple(&client, contextId, [this](ClientState& state) { 76 77 if (m_externalOutputDeviceAvailable) 78 state.client->externalOutputDeviceAvailableDidChange(state.contextId, true); 79 80 if (m_playbackTarget) { 81 state.client->setPlaybackTarget(state.contextId, *m_playbackTarget.copyRef()); 82 83 if (m_clientState.size() == 1 && m_playbackTarget->hasActiveRoute()) 84 state.client->setShouldPlayToPlaybackTarget(state.contextId, true); 85 } 86 }); 87 88 m_taskQueue.append(callback); 89 m_taskTimer.startOneShot(0); 90 } 81 if (m_externalOutputDeviceAvailable || m_playbackTarget) 82 scheduleDelayedTask(InitialConfigurationTask | TargetClientsConfigurationTask); 91 83 92 84 return contextId; … … 101 93 102 94 m_clientState.remove(index); 103 configurePlaybackTargetMonitoring(); 104 105 if (m_playbackTarget && m_clientState.size() == 1 && m_playbackTarget->hasActiveRoute()) 106 m_clientState[0]->client->setShouldPlayToPlaybackTarget(m_clientState[0]->contextId, true); 95 scheduleDelayedTask(TargetMonitoringConfigurationTask | TargetClientsConfigurationTask); 107 96 } 108 97 … … 110 99 { 111 100 for (size_t i = m_clientState.size(); i > 0; --i) { 112 if ( m_clientState[i - 1]->client == &client)101 if (&m_clientState[i - 1]->client == &client) 113 102 m_clientState.remove(i - 1); 114 103 } 104 scheduleDelayedTask(TargetMonitoringConfigurationTask | TargetClientsConfigurationTask); 115 105 } 116 106 … … 122 112 return; 123 113 114 auto& clientRequestingPicker = m_clientState[index]; 124 115 for (auto& state : m_clientState) 125 state->requestedPicker = (state->contextId == contextId && state->client == &client);116 state->requestedPicker = state == clientRequestingPicker; 126 117 127 118 bool hasActiveRoute = flagsAreSet(m_clientState[index]->flags, MediaProducer::IsPlayingToExternalDevice); … … 143 134 changedClientState->flags = newFlags; 144 135 if (!flagsAreSet(oldFlags, MediaProducer::RequiresPlaybackTargetMonitoring) && flagsAreSet(newFlags, MediaProducer::RequiresPlaybackTargetMonitoring)) 145 configurePlaybackTargetMonitoring();146 147 if (!flagsAreSet(newFlags, MediaProducer:: IsPlayingVideo) || !flagsAreSet(newFlags, MediaProducer::ExternalDeviceAutoPlayCandidate))136 scheduleDelayedTask(TargetMonitoringConfigurationTask); 137 138 if (!flagsAreSet(newFlags, MediaProducer::ExternalDeviceAutoPlayCandidate)) 148 139 return; 149 140 … … 152 143 153 144 // Do not interrupt another element already playing to a device. 154 for (auto& state : m_clientState) { 155 if (state->contextId == contextId && state->client == &client) 145 bool anotherClientHasActiveTarget = false; 146 for (auto& state : m_clientState) { 147 if (flagsAreSet(state->flags, MediaProducer::IsPlayingToExternalDevice)) { 148 if (flagsAreSet(state->flags, MediaProducer::IsPlayingVideo)) 149 return; 150 anotherClientHasActiveTarget = true; 151 } 152 } 153 154 // Do not take the target if another client has it and the client reporting a state change is not playing. 155 if (anotherClientHasActiveTarget && !flagsAreSet(newFlags, MediaProducer::IsPlayingVideo)) 156 return; 157 158 for (auto& state : m_clientState) { 159 if (state == changedClientState) 156 160 continue; 157 158 if (flagsAreSet(state->flags, MediaProducer::IsPlayingVideo) && flagsAreSet(state->flags, MediaProducer::IsPlayingToExternalDevice)) 159 return; 160 } 161 162 for (auto& state : m_clientState) { 163 if (state->contextId == contextId && state->client == &client) 164 continue; 165 state->client->setShouldPlayToPlaybackTarget(state->contextId, false); 166 } 167 168 changedClientState->client->setShouldPlayToPlaybackTarget(changedClientState->contextId, true); 161 state->client.setShouldPlayToPlaybackTarget(state->contextId, false); 162 } 163 164 changedClientState->client.setShouldPlayToPlaybackTarget(changedClientState->contextId, true); 169 165 170 166 if (index && m_clientState.size() > 1) … … 175 171 { 176 172 m_playbackTarget = WTF::move(target); 177 178 size_t indexThatRequestedPicker = notFound; 173 scheduleDelayedTask(TargetClientsConfigurationTask); 174 } 175 176 void WebMediaSessionManager::externalOutputDeviceAvailableDidChange(bool available) 177 { 178 m_externalOutputDeviceAvailable = available; 179 for (auto& state : m_clientState) 180 state->client.externalOutputDeviceAvailableDidChange(state->contextId, available); 181 } 182 183 void WebMediaSessionManager::configureNewClients() 184 { 185 for (auto& state : m_clientState) { 186 if (!state->configurationRequired) 187 continue; 188 189 state->configurationRequired = false; 190 if (m_externalOutputDeviceAvailable) 191 state->client.externalOutputDeviceAvailableDidChange(state->contextId, true); 192 193 if (m_playbackTarget) 194 state->client.setPlaybackTarget(state->contextId, *m_playbackTarget.copyRef()); 195 } 196 } 197 198 void WebMediaSessionManager::configurePlaybackTargetClients() 199 { 200 size_t indexOfClientThatRequestedPicker = notFound; 201 size_t indexOfAutoPlayCandidate = notFound; 202 size_t indexOfClientWillPlayToTarget = notFound; 203 bool haveActiveRoute = m_playbackTarget && m_playbackTarget->hasActiveRoute(); 204 179 205 for (size_t i = 0; i < m_clientState.size(); ++i) { 180 206 auto& state = m_clientState[i]; 181 state->client->setPlaybackTarget(state->contextId, *m_playbackTarget.copyRef()); 182 if (state->requestedPicker) { 183 indexThatRequestedPicker = i; 184 continue; 185 } 186 state->client->setShouldPlayToPlaybackTarget(state->contextId, false); 207 208 if (indexOfClientThatRequestedPicker == notFound && state->requestedPicker) 209 indexOfClientThatRequestedPicker = i; 210 211 if (indexOfClientWillPlayToTarget == notFound && flagsAreSet(state->flags, MediaProducer::IsPlayingToExternalDevice)) 212 indexOfClientWillPlayToTarget = i; 213 214 if (indexOfAutoPlayCandidate == notFound && flagsAreSet(state->flags, MediaProducer::ExternalDeviceAutoPlayCandidate) && !flagsAreSet(state->flags, MediaProducer::IsPlayingVideo)) 215 indexOfAutoPlayCandidate = i; 216 } 217 218 if (indexOfClientThatRequestedPicker != notFound) 219 indexOfClientWillPlayToTarget = indexOfClientThatRequestedPicker; 220 if (indexOfClientWillPlayToTarget == notFound && haveActiveRoute && indexOfAutoPlayCandidate != notFound) 221 indexOfClientWillPlayToTarget = indexOfAutoPlayCandidate; 222 223 for (size_t i = 0; i < m_clientState.size(); ++i) { 224 auto& state = m_clientState[i]; 225 226 if (m_playbackTarget) 227 state->client.setPlaybackTarget(state->contextId, *m_playbackTarget.copyRef()); 228 229 if (i != indexOfClientWillPlayToTarget) 230 state->client.setShouldPlayToPlaybackTarget(state->contextId, false); 231 else if (!flagsAreSet(state->flags, MediaProducer::IsPlayingToExternalDevice)) 232 state->client.setShouldPlayToPlaybackTarget(state->contextId, haveActiveRoute); 233 234 state->configurationRequired = false; 187 235 state->requestedPicker = false; 188 236 } 189 190 if (indexThatRequestedPicker == notFound)191 return;192 193 auto& state = m_clientState[indexThatRequestedPicker];194 state->client->setShouldPlayToPlaybackTarget(state->contextId, m_playbackTarget && m_playbackTarget->hasActiveRoute());195 state->requestedPicker = false;196 }197 198 void WebMediaSessionManager::externalOutputDeviceAvailableDidChange(bool available)199 {200 m_externalOutputDeviceAvailable = available;201 for (auto& state : m_clientState)202 state->client->externalOutputDeviceAvailableDidChange(state->contextId, available);203 237 } 204 238 … … 219 253 } 220 254 255 void WebMediaSessionManager::scheduleDelayedTask(ConfigurationTasks tasks) 256 { 257 m_taskFlags |= tasks; 258 m_taskTimer.startOneShot(taskDelayInterval); 259 } 260 221 261 void WebMediaSessionManager::taskTimerFired() 222 262 { 223 auto taskQueue = WTF::move(m_taskQueue); 224 if (taskQueue.isEmpty()) 225 return; 226 227 for (auto& task : taskQueue) { 228 size_t index = find(std::get<0>(task), std::get<1>(task)); 229 230 if (index == notFound) 231 continue; 232 233 std::get<2>(task)(*m_clientState[index]); 234 } 263 if (m_taskFlags & InitialConfigurationTask) 264 configureNewClients(); 265 if (m_taskFlags & TargetClientsConfigurationTask) 266 configurePlaybackTargetClients(); 267 if (m_taskFlags & TargetMonitoringConfigurationTask) 268 configurePlaybackTargetMonitoring(); 269 270 m_taskFlags = NoTask; 235 271 } 236 272 … … 238 274 { 239 275 for (size_t i = 0; i < m_clientState.size(); ++i) { 240 if (m_clientState[i]->contextId == contextId && m_clientState[i]->client == client)276 if (m_clientState[i]->contextId == contextId && &m_clientState[i]->client == client) 241 277 return i; 242 278 } -
TabularUnified trunk/Source/WebCore/Modules/mediasession/WebMediaSessionManager.h ¶
r183096 r184204 65 65 66 66 size_t find(WebMediaSessionManagerClient*, uint64_t); 67 void configurePlaybackTargetClients(); 68 void configureNewClients(); 67 69 void configurePlaybackTargetMonitoring(); 70 71 enum ConfigurationTaskFlags { 72 NoTask = 0, 73 InitialConfigurationTask = 1 << 0, 74 TargetClientsConfigurationTask = 1 << 1, 75 TargetMonitoringConfigurationTask = 1 << 2, 76 }; 77 typedef unsigned ConfigurationTasks; 78 79 void scheduleDelayedTask(ConfigurationTasks); 68 80 void taskTimerFired(); 69 70 typedef std::tuple<WebMediaSessionManagerClient*, uint64_t, std::function<void(ClientState&)>> TaskCallback;71 Vector<TaskCallback> m_taskQueue;72 81 RunLoop::Timer<WebMediaSessionManager> m_taskTimer; 73 82 74 83 Vector<std::unique_ptr<ClientState>> m_clientState; 75 84 RefPtr<MediaPlaybackTarget> m_playbackTarget; 85 ConfigurationTasks m_taskFlags { NoTask }; 76 86 bool m_externalOutputDeviceAvailable { false }; 77 87 }; -
TabularUnified trunk/Source/WebCore/html/HTMLMediaElement.cpp ¶
r184001 r184204 3035 3035 3036 3036 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 3037 m_mediaSession->mediaStateDidChange(*this, mediaState());3037 updateMediaState(); 3038 3038 #endif 3039 3039 } … … 4633 4633 4634 4634 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 4635 m_mediaSession->mediaStateDidChange(*this, mediaState());4635 updateMediaState(); 4636 4636 #endif 4637 4637 } … … 4896 4896 configureMediaControls(); 4897 4897 scheduleEvent(eventNames().webkitcurrentplaybacktargetiswirelesschangedEvent); 4898 m_mediaSession->mediaStateDidChange(*this, mediaState());4898 updateMediaState(); 4899 4899 } 4900 4900 … … 4947 4947 void HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent() 4948 4948 { 4949 LOG(Media, "HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent(%p)", this); 4950 RefPtr<Event> event = WebKitPlaybackTargetAvailabilityEvent::create(eventNames().webkitplaybacktargetavailabilitychangedEvent, m_mediaSession->hasWirelessPlaybackTargets(*this)); 4949 bool hasTargets = m_mediaSession->hasWirelessPlaybackTargets(*this); 4950 LOG(Media, "HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent(%p) - hasTargets = %s", this, boolString(hasTargets)); 4951 RefPtr<Event> event = WebKitPlaybackTargetAvailabilityEvent::create(eventNames().webkitplaybacktargetavailabilitychangedEvent, hasTargets); 4951 4952 event->setTarget(this); 4952 4953 m_asyncEventQueue.enqueueEvent(event.release()); … … 6219 6220 } 6220 6221 6222 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 6223 void HTMLMediaElement::updateMediaState() 6224 { 6225 MediaProducer::MediaStateFlags state = mediaState(); 6226 if (m_mediaState == state) 6227 return; 6228 6229 m_mediaState = state; 6230 m_mediaSession->mediaStateDidChange(*this, m_mediaState); 6231 } 6232 #endif 6233 6221 6234 MediaProducer::MediaStateFlags HTMLMediaElement::mediaState() const 6222 6235 { -
TabularUnified trunk/Source/WebCore/html/HTMLMediaElement.h ¶
r184001 r184204 741 741 virtual void documentWillSuspendForPageCache() override final; 742 742 virtual void documentDidResumeFromPageCache() override final; 743 void updateMediaState(); 743 744 #endif 744 745 … … 932 933 933 934 #if ENABLE(WIRELESS_PLAYBACK_TARGET) 935 MediaProducer::MediaStateFlags m_mediaState { MediaProducer::IsNotPlaying }; 934 936 bool m_hasPlaybackTargetAvailabilityListeners { false }; 935 937 #endif -
TabularUnified trunk/Source/WebCore/html/HTMLMediaSession.cpp ¶
r183509 r184204 306 306 return; 307 307 308 LOG(Media, "HTMLMediaSession::externalOutputDeviceAvailableDidChange - hasTargets %s", hasTargets ? "TRUE" : "FALSE");308 LOG(Media, "HTMLMediaSession::externalOutputDeviceAvailableDidChange(%p) - hasTargets %s", this, hasTargets ? "TRUE" : "FALSE"); 309 309 310 310 m_hasPlaybackTargets = hasTargets; 311 if (!m_targetAvailabilityChangedTimer.isActive()) 312 m_targetAvailabilityChangedTimer.startOneShot(0); 311 m_targetAvailabilityChangedTimer.startOneShot(0); 313 312 } 314 313 … … 331 330 void HTMLMediaSession::setShouldPlayToPlaybackTarget(bool shouldPlay) 332 331 { 332 LOG(Media, "HTMLMediaSession::setShouldPlayToPlaybackTarget - shouldPlay %s", shouldPlay ? "TRUE" : "FALSE"); 333 333 m_shouldPlayToPlaybackTarget = shouldPlay; 334 334 client().setShouldPlayToPlaybackTarget(shouldPlay); … … 387 387 client().setWirelessPlaybackTarget(*m_playbackTarget.copyRef()); 388 388 if (m_shouldPlayToPlaybackTarget) 389 client().setShouldPlayToPlaybackTarget( m_shouldPlayToPlaybackTarget);389 client().setShouldPlayToPlaybackTarget(true); 390 390 #else 391 391 UNUSED_PARAM(element); -
TabularUnified trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlaybackTargetPickerMac.mm ¶
r183831 r184204 131 131 } 132 132 133 #pragma clang diagnostic push134 #pragma clang diagnostic ignored "-Wdeprecated-declarations"135 133 void MediaPlaybackTargetPickerMac::showPlaybackTargetPicker(const FloatRect& location, bool checkActiveRoute) 136 134 { … … 138 136 return; 139 137 138 AVOutputDeviceMenuControllerType *picker = devicePicker(); 139 if (![picker respondsToSelector:@selector(showMenuForRect:appearanceName:allowReselectionOfSelectedOutputDevice:)]) 140 return; 141 140 142 m_showingMenu = true; 141 AVOutputDeviceMenuControllerType *picker = devicePicker(); 142 if ([picker respondsToSelector:@selector(showMenuForRect:appearanceName:allowReselectionOfSelectedOutputDevice:)]) { 143 if ([picker showMenuForRect:location appearanceName:NSAppearanceNameVibrantLight allowReselectionOfSelectedOutputDevice:!checkActiveRoute]) 143 if ([picker showMenuForRect:location appearanceName:NSAppearanceNameVibrantLight allowReselectionOfSelectedOutputDevice:!checkActiveRoute]) { 144 if (!checkActiveRoute) 144 145 currentDeviceDidChange(); 145 } else 146 [picker showMenuForRect:location appearanceName:NSAppearanceNameVibrantLight]; 146 } 147 147 m_showingMenu = false; 148 148 } 149 #pragma clang diagnostic pop150 149 151 150 void MediaPlaybackTargetPickerMac::addPendingAction(PendingActionFlags action)
Note:
See TracChangeset
for help on using the changeset viewer.