OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 } | 723 } |
724 | 724 |
725 void AudioContext::notifyStateChange() | 725 void AudioContext::notifyStateChange() |
726 { | 726 { |
727 dispatchEvent(Event::create(EventTypeNames::statechange)); | 727 dispatchEvent(Event::create(EventTypeNames::statechange)); |
728 } | 728 } |
729 | 729 |
730 ScriptPromise AudioContext::suspendContext(ScriptState* scriptState) | 730 ScriptPromise AudioContext::suspendContext(ScriptState* scriptState) |
731 { | 731 { |
732 ASSERT(isMainThread()); | 732 ASSERT(isMainThread()); |
| 733 ASSERT(!isOfflineContext()); |
| 734 |
733 AutoLocker locker(this); | 735 AutoLocker locker(this); |
734 | 736 |
735 if (isOfflineContext()) { | |
736 return ScriptPromise::rejectWithDOMException( | |
737 scriptState, | |
738 DOMException::create( | |
739 InvalidAccessError, | |
740 "cannot suspend an OfflineAudioContext")); | |
741 } | |
742 | |
743 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); | 737 RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::
create(scriptState); |
744 ScriptPromise promise = resolver->promise(); | 738 ScriptPromise promise = resolver->promise(); |
745 | 739 |
746 if (m_contextState == Closed) { | 740 if (m_contextState == Closed) { |
747 resolver->reject( | 741 resolver->reject( |
748 DOMException::create(InvalidStateError, "Cannot suspend a context th
at has been closed")); | 742 DOMException::create(InvalidStateError, "Cannot suspend a context th
at has been closed")); |
749 } else { | 743 } else { |
750 // Stop rendering now. | 744 // Stop rendering now. |
751 if (m_destinationNode) | 745 if (m_destinationNode) |
752 stopRendering(); | 746 stopRendering(); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 | 835 |
842 // Find AudioBufferSourceNodes to see if we can stop playing them. | 836 // Find AudioBufferSourceNodes to see if we can stop playing them. |
843 for (AudioNode* node : m_activeSourceNodes) { | 837 for (AudioNode* node : m_activeSourceNodes) { |
844 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { | 838 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { |
845 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); | 839 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); |
846 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); | 840 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); |
847 } | 841 } |
848 } | 842 } |
849 } | 843 } |
850 | 844 |
| 845 void AudioContext::performPostRenderTasks() |
| 846 { |
| 847 // Take care of AudioNode tasks where the tryLock() failed previously. |
| 848 deferredTaskHandler().breakConnections(); |
| 849 |
| 850 // Dynamically clean up nodes which are no longer needed. |
| 851 releaseFinishedSourceNodes(); |
| 852 |
| 853 deferredTaskHandler().handleDeferredTasks(); |
| 854 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); |
| 855 } |
| 856 |
851 void AudioContext::handlePreRenderTasks() | 857 void AudioContext::handlePreRenderTasks() |
852 { | 858 { |
853 ASSERT(isAudioThread()); | 859 ASSERT(isAudioThread()); |
854 | 860 |
| 861 // For the precise offline audio rendering, we need these tasks to be |
| 862 // performed every render quantum. Thus, we wait for the graph lock (rather |
| 863 // than tryLock()) so we can run the pre-render tasks without deferring |
| 864 // them. |
| 865 if (isOfflineContext()) { |
| 866 deferredTaskHandler().forceLock(); |
| 867 deferredTaskHandler().handleDeferredTasks(); |
| 868 handleStoppableSourceNodes(); |
| 869 unlock(); |
| 870 return; |
| 871 } |
| 872 |
855 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 873 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
856 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 874 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
857 if (tryLock()) { | 875 if (tryLock()) { |
858 deferredTaskHandler().handleDeferredTasks(); | 876 deferredTaskHandler().handleDeferredTasks(); |
859 | 877 |
860 resolvePromisesForResume(); | 878 resolvePromisesForResume(); |
861 | 879 |
862 // Check to see if source nodes can be stopped because the end time has
passed. | 880 // Check to see if source nodes can be stopped because the end time has
passed. |
863 handleStoppableSourceNodes(); | 881 handleStoppableSourceNodes(); |
864 | 882 |
865 unlock(); | 883 unlock(); |
866 } | 884 } |
867 } | 885 } |
868 | 886 |
869 void AudioContext::handlePostRenderTasks() | 887 void AudioContext::handlePostRenderTasks() |
870 { | 888 { |
871 ASSERT(isAudioThread()); | 889 ASSERT(isAudioThread()); |
872 | 890 |
| 891 // Same as |handlePreRenderTasks()|. We force to perform the post-render |
| 892 // tasks for the offline rendering. |
| 893 if (isOfflineContext()) { |
| 894 deferredTaskHandler().forceLock(); |
| 895 performPostRenderTasks(); |
| 896 unlock(); |
| 897 return; |
| 898 } |
| 899 |
873 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 900 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
874 // The worst that can happen is that there will be some nodes which will tak
e slightly longer than usual to be deleted or removed | 901 // The worst that can happen is that there will be some nodes which will tak
e slightly longer than usual to be deleted or removed |
875 // from the render graph (in which case they'll render silence). | 902 // from the render graph (in which case they'll render silence). |
876 if (tryLock()) { | 903 if (tryLock()) { |
877 // Take care of AudioNode tasks where the tryLock() failed previously. | 904 performPostRenderTasks(); |
878 deferredTaskHandler().breakConnections(); | |
879 | |
880 // Dynamically clean up nodes which are no longer needed. | |
881 releaseFinishedSourceNodes(); | |
882 | |
883 deferredTaskHandler().handleDeferredTasks(); | |
884 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | |
885 | |
886 unlock(); | 905 unlock(); |
887 } | 906 } |
888 } | 907 } |
889 | 908 |
890 void AudioContext::resolvePromisesForResumeOnMainThread() | 909 void AudioContext::resolvePromisesForResumeOnMainThread() |
891 { | 910 { |
892 ASSERT(isMainThread()); | 911 ASSERT(isMainThread()); |
893 AutoLocker locker(this); | 912 AutoLocker locker(this); |
894 | 913 |
895 for (auto& resolver : m_resumeResolvers) { | 914 for (auto& resolver : m_resumeResolvers) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 return EventTargetNames::AudioContext; | 957 return EventTargetNames::AudioContext; |
939 } | 958 } |
940 | 959 |
941 ExecutionContext* AudioContext::executionContext() const | 960 ExecutionContext* AudioContext::executionContext() const |
942 { | 961 { |
943 return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext(); | 962 return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext(); |
944 } | 963 } |
945 | 964 |
946 void AudioContext::startRendering() | 965 void AudioContext::startRendering() |
947 { | 966 { |
948 // This is called for both online and offline contexts. | 967 // This is only for the real-time context. |
949 ASSERT(isMainThread()); | 968 ASSERT(isMainThread()); |
950 ASSERT(m_destinationNode); | 969 ASSERT(m_destinationNode); |
| 970 ASSERT(!isOfflineContext()); |
951 | 971 |
952 if (m_contextState == Suspended) { | 972 if (m_contextState == Suspended) { |
953 destination()->audioDestinationHandler().startRendering(); | 973 destination()->audioDestinationHandler().startRendering(); |
954 setContextState(Running); | 974 setContextState(Running); |
955 } | 975 } |
956 } | 976 } |
957 | 977 |
958 void AudioContext::stopRendering() | 978 void AudioContext::stopRendering() |
959 { | 979 { |
960 ASSERT(isMainThread()); | 980 ASSERT(isMainThread()); |
961 ASSERT(m_destinationNode); | 981 ASSERT(m_destinationNode); |
962 ASSERT(!isOfflineContext()); | 982 ASSERT(!isOfflineContext()); |
963 | 983 |
964 if (m_contextState == Running) { | 984 if (m_contextState == Running) { |
965 destination()->audioDestinationHandler().stopRendering(); | 985 destination()->audioDestinationHandler().stopRendering(); |
966 setContextState(Suspended); | 986 setContextState(Suspended); |
967 deferredTaskHandler().clearHandlersToBeDeleted(); | 987 deferredTaskHandler().clearHandlersToBeDeleted(); |
968 } | 988 } |
969 } | 989 } |
970 | 990 |
971 void AudioContext::fireCompletionEvent() | 991 void AudioContext::fireCompletionEvent() |
972 { | 992 { |
973 ASSERT(isMainThread()); | 993 ASSERT_WITH_MESSAGE(1, "fireCompletionEvent() only valid for offline audio c
ontext"); |
974 if (!isMainThread()) | 994 } |
975 return; | |
976 | 995 |
977 AudioBuffer* renderedBuffer = m_renderTarget.get(); | 996 bool AudioContext::shouldSuspendNow() |
| 997 { |
| 998 ASSERT_WITH_MESSAGE(1, "shouldSuspendNow() only valid for offline audio cont
ext"); |
| 999 return false; |
| 1000 } |
978 | 1001 |
979 // For an offline context, we set the state to closed here so that the oncom
plete handler sees | 1002 void AudioContext::resolvePendingSuspendPromises() |
980 // that the context has been closed. | 1003 { |
981 setContextState(Closed); | 1004 ASSERT_WITH_MESSAGE(1, "clearResolvedSuspend() only valid for offline audio
context"); |
982 | |
983 ASSERT(renderedBuffer); | |
984 if (!renderedBuffer) | |
985 return; | |
986 | |
987 // Avoid firing the event if the document has already gone away. | |
988 if (executionContext()) { | |
989 // Call the offline rendering completion event listener and resolve the
promise too. | |
990 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); | |
991 m_offlineResolver->resolve(renderedBuffer); | |
992 } | |
993 } | 1005 } |
994 | 1006 |
995 DEFINE_TRACE(AudioContext) | 1007 DEFINE_TRACE(AudioContext) |
996 { | 1008 { |
997 visitor->trace(m_closeResolver); | 1009 visitor->trace(m_closeResolver); |
998 visitor->trace(m_offlineResolver); | |
999 visitor->trace(m_renderTarget); | 1010 visitor->trace(m_renderTarget); |
1000 visitor->trace(m_destinationNode); | 1011 visitor->trace(m_destinationNode); |
1001 visitor->trace(m_listener); | 1012 visitor->trace(m_listener); |
1002 // trace() can be called in AudioContext constructor, and | 1013 // trace() can be called in AudioContext constructor, and |
1003 // m_contextGraphMutex might be unavailable. | 1014 // m_contextGraphMutex might be unavailable. |
1004 if (m_didInitializeContextGraphMutex) { | 1015 if (m_didInitializeContextGraphMutex) { |
1005 AutoLocker lock(this); | 1016 AutoLocker lock(this); |
1006 visitor->trace(m_activeSourceNodes); | 1017 visitor->trace(m_activeSourceNodes); |
1007 } else { | 1018 } else { |
1008 visitor->trace(m_activeSourceNodes); | 1019 visitor->trace(m_activeSourceNodes); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1045 // the destination node can GCed if JS has no references. stop() will also r
esolve the Promise | 1056 // the destination node can GCed if JS has no references. stop() will also r
esolve the Promise |
1046 // created here. | 1057 // created here. |
1047 stop(); | 1058 stop(); |
1048 | 1059 |
1049 return promise; | 1060 return promise; |
1050 } | 1061 } |
1051 | 1062 |
1052 } // namespace blink | 1063 } // namespace blink |
1053 | 1064 |
1054 #endif // ENABLE(WEB_AUDIO) | 1065 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |