[iOS] When Web Audio is interrupted by a phone call, it cannot be restarted.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 30 Mar 2015 16:15:00 +0000 (16:15 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 30 Mar 2015 16:15:00 +0000 (16:15 +0000)
commite749ad740c905ae885f8fd3ea1cc4d930252266e
tree4fc063ac9e96db2bd89b81454f1e4a69771b7a9b
parentd4013a7622780d7562e02befc035a5950a92a696
[iOS] When Web Audio is interrupted by a phone call, it cannot be restarted.
https://bugs.webkit.org/show_bug.cgi?id=143190

Reviewed by Darin Adler.

Source/WebCore:

Tests: webaudio/audiocontext-state-interrupted.html
       webaudio/audiocontext-state.html

Implement the following methods and properties from the Web Audio spec:
close(), suspend(), resume(), onstatechange.

AudioContext will take more responsibility for tracking state and interruptions (and
AudioDestination will give up that responsibility). This means AudioContext must be a
MediaSessionClient, and own its own MediaSession. In return, AudioDestinationIOS and
AudioDestinationMac relinquish both.

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::AudioContext): Set default values in header.
(WebCore::AudioContext::uninitialize): Call setState() instead of setting m_state.
(WebCore::AudioContext::addReaction): Added. Append the callback to the appropriate vector for the state.
(WebCore::AudioContext::setState): Added. Fire events and resolve the appropriate reaction callbacks for the new state.
(WebCore::AudioContext::state): Return a string representing the context's state.
(WebCore::AudioContext::stop): Close the event queue.
(WebCore::AudioContext::startRendering): Call setState().
(WebCore::AudioContext::fireCompletionEvent): Call setState().
(WebCore::AudioContext::suspendContext): Added. Add reaction callback and call suspend() on the destination node.
(WebCore::AudioContext::resumeContext): Added. Add reaction callback and call resume() on the destination node.
(WebCore::AudioContext::closeContext): Added. Add reaction callback and call close() on the destination node.
(WebCore::AudioContext::suspendPlayback): Added. Suspend playback and set state to interrupted.
(WebCore::AudioContext::mayResumePlayback): Added. Conditionally resume playback.
* bindings/js/JSAudioContextCustom.cpp:
(WebCore::JSAudioContext::suspend): Added. Create and return a new Promise object.
(WebCore::JSAudioContext::resume): Ditto.
(WebCore::JSAudioContext::close): Ditto.
* Modules/webaudio/AudioContext.idl: Add new methods and properties.

Extensive organizational changes were made to AudioContext.h to group instance
variables together and add C++11 initializers in their declarations:

* Modules/webaudio/AudioContext.h:
(WebCore::AudioContext::mediaType): Moved from AudioDestinationNode.
(WebCore::AudioContext::presentationType): Ditto.
(WebCore::AudioContext::canReceiveRemoteControlCommands): Ditto.
(WebCore::AudioContext::didReceiveRemoteControlCommand): Ditto.
(WebCore::AudioContext::overrideBackgroundPlaybackRestriction): Ditto.

Other changes to support the new AudioContext methods:

* Modules/webaudio/AudioDestinationNode.h:
(WebCore::AudioDestinationNode::resume): Add empty default virtual method.
(WebCore::AudioDestinationNode::suspend): Ditto.
(WebCore::AudioDestinationNode::close): Ditto.
* Modules/webaudio/DefaultAudioDestinationNode.cpp:
(WebCore::DefaultAudioDestinationNode::resume): Added. Pass to AudioDestination.
(WebCore::DefaultAudioDestinationNode::suspend): Ditto.
(WebCore::DefaultAudioDestinationNode::close): Ditto.
* Modules/webaudio/DefaultAudioDestinationNode.h:
* bindings/js/JSDOMPromise.h:
(WebCore::DeferredWrapper::resolve): Add an overload for a nullptr resolve value.
* dom/EventNames.h: Added 'statechange'.
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::Task::Task): Add a constructor which takes a void() callback.

Modify MediaSession, AudioSession, and MediaSessionManager to support the new
interruption behavior.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::suspendPlayback): Renamed from pausePlayback().
(WebCore::HTMLMediaElement::mayResumePlayback): Renamed from resumePlayback().
* html/HTMLMediaElement.h:
* platform/audio/AudioSession.cpp:
(WebCore::AudioSession::tryToSetActive): Renamed from setActive. Return true by default.
(WebCore::AudioSession::setActive): Deleted.
* platform/audio/AudioSession.h:
* platform/audio/MediaSession.cpp:
(WebCore::MediaSession::beginInterruption): pausePlayback() was renamed to suspendPlayback().
(WebCore::MediaSession::endInterruption): Always notify the client, telling it whether to resume.
(WebCore::MediaSession::clientWillBeginPlayback): Bail early if reentrant.  Check the (new)
    return value of sessionWillBeginPlayback() and remember to resume once the interruption ends.
(WebCore::MediaSession::clientWillPausePlayback): Bail early if reentrant.
(WebCore::MediaSession::pauseSession): pausePlayback() was renamed to suspendPlayback().
* platform/audio/MediaSession.h:
* platform/audio/MediaSessionManager.cpp:
(WebCore::MediaSessionManager::sessionWillBeginPlayback): Return false if not allowed to break interruption or
    if activating the audio session failed. Otherwise, end the interruption.
* platform/audio/MediaSessionManager.h:
* platform/audio/ios/AudioDestinationIOS.cpp:
(WebCore::AudioDestinationIOS::AudioDestinationIOS): m_mediaSession was removed.
(WebCore::AudioDestinationIOS::start): Ditto.
* platform/audio/ios/AudioDestinationIOS.h:
* platform/audio/ios/AudioSessionIOS.mm:
(WebCore::AudioSession::tryToSetActive): Renamed from setActive. Return false if the AVAudioSession could not be activated.
(WebCore::AudioSession::setActive): Deleted.
* platform/audio/ios/MediaSessionManagerIOS.h:
* platform/audio/ios/MediaSessionManagerIOS.mm:
(WebCore::MediaSessionManageriOS::sessionWillBeginPlayback): Do not update the now playing info if session playback was blocked.
* platform/audio/mac/AudioDestinationMac.cpp:
(WebCore::AudioDestinationMac::AudioDestinationMac): m_mediaSession was removed.
* platform/audio/mac/AudioDestinationMac.h:
* platform/audio/mac/AudioSessionMac.cpp:
(WebCore::AudioSession::tryToSetActive): Renamed from setActive(). Return true by default.
(WebCore::AudioSession::setActive): Deleted.
* platform/audio/mac/MediaSessionManagerMac.cpp:
(MediaSessionManager::updateSessionState): No longer attempt to activate the session, as this is done
    MediaSessionManager::sessionWillBeginPlayback().
* testing/Internals.cpp:
(WebCore::Internals::setMediaSessionRestrictions): Add "InterruptedPlaybackNotPermitted".

LayoutTests:

* webaudio/audiocontext-state-expected.txt: Added.
* webaudio/audiocontext-state-interrupted-expected.txt: Added.
* webaudio/audiocontext-state-interrupted.html: Added.
* webaudio/audiocontext-state.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182141 268f45cc-cd09-0410-ab3c-d52691b4dbfc
35 files changed:
LayoutTests/ChangeLog
LayoutTests/webaudio/audiocontext-state-expected.txt [new file with mode: 0644]
LayoutTests/webaudio/audiocontext-state-interrupted-expected.txt [new file with mode: 0644]
LayoutTests/webaudio/audiocontext-state-interrupted.html [new file with mode: 0644]
LayoutTests/webaudio/audiocontext-state.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/Modules/webaudio/AudioContext.cpp
Source/WebCore/Modules/webaudio/AudioContext.h
Source/WebCore/Modules/webaudio/AudioContext.idl
Source/WebCore/Modules/webaudio/AudioDestinationNode.h
Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.cpp
Source/WebCore/Modules/webaudio/DefaultAudioDestinationNode.h
Source/WebCore/bindings/js/JSAudioContextCustom.cpp
Source/WebCore/bindings/js/JSCallbackData.h
Source/WebCore/bindings/js/JSDOMPromise.h
Source/WebCore/dom/EventNames.h
Source/WebCore/dom/ScriptExecutionContext.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/platform/audio/AudioSession.cpp
Source/WebCore/platform/audio/AudioSession.h
Source/WebCore/platform/audio/MediaSession.cpp
Source/WebCore/platform/audio/MediaSession.h
Source/WebCore/platform/audio/MediaSessionManager.cpp
Source/WebCore/platform/audio/MediaSessionManager.h
Source/WebCore/platform/audio/ios/AudioDestinationIOS.cpp
Source/WebCore/platform/audio/ios/AudioDestinationIOS.h
Source/WebCore/platform/audio/ios/AudioSessionIOS.mm
Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.h
Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm
Source/WebCore/platform/audio/mac/AudioDestinationMac.cpp
Source/WebCore/platform/audio/mac/AudioDestinationMac.h
Source/WebCore/platform/audio/mac/AudioSessionMac.cpp
Source/WebCore/platform/audio/mac/MediaSessionManagerMac.cpp
Source/WebCore/testing/Internals.cpp