Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: Source/modules/webaudio/AudioContext.cpp

Issue 1140723003: Implement suspend() and resume() for OfflineAudioContext (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Ready for Review (2) Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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();
haraken 2015/06/30 07:41:50 Don't we need to call resolvePromisesForResume()?
hongchan 2015/06/30 18:52:10 No. resolvePromisesForResume() here is for promise
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698