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 12 matching lines...) Expand all Loading... |
23 */ | 23 */ |
24 | 24 |
25 #include "config.h" | 25 #include "config.h" |
26 | 26 |
27 #if ENABLE(WEB_AUDIO) | 27 #if ENABLE(WEB_AUDIO) |
28 | 28 |
29 #include "modules/webaudio/AudioContext.h" | 29 #include "modules/webaudio/AudioContext.h" |
30 | 30 |
31 #include "bindings/core/v8/ExceptionMessages.h" | 31 #include "bindings/core/v8/ExceptionMessages.h" |
32 #include "bindings/core/v8/ExceptionState.h" | 32 #include "bindings/core/v8/ExceptionState.h" |
| 33 #include "bindings/core/v8/ScriptState.h" |
| 34 #include "core/dom/DOMException.h" |
33 #include "core/dom/Document.h" | 35 #include "core/dom/Document.h" |
34 #include "core/dom/ExceptionCode.h" | 36 #include "core/dom/ExceptionCode.h" |
35 #include "core/html/HTMLMediaElement.h" | 37 #include "core/html/HTMLMediaElement.h" |
36 #include "core/inspector/ScriptCallStack.h" | 38 #include "core/inspector/ScriptCallStack.h" |
37 #include "modules/mediastream/MediaStream.h" | 39 #include "modules/mediastream/MediaStream.h" |
38 #include "modules/webaudio/AnalyserNode.h" | 40 #include "modules/webaudio/AnalyserNode.h" |
39 #include "modules/webaudio/AudioBuffer.h" | 41 #include "modules/webaudio/AudioBuffer.h" |
40 #include "modules/webaudio/AudioBufferCallback.h" | 42 #include "modules/webaudio/AudioBufferCallback.h" |
41 #include "modules/webaudio/AudioBufferSourceNode.h" | 43 #include "modules/webaudio/AudioBufferSourceNode.h" |
42 #include "modules/webaudio/AudioListener.h" | 44 #include "modules/webaudio/AudioListener.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 return audioContext; | 94 return audioContext; |
93 } | 95 } |
94 | 96 |
95 // Constructor for rendering to the audio hardware. | 97 // Constructor for rendering to the audio hardware. |
96 AudioContext::AudioContext(Document* document) | 98 AudioContext::AudioContext(Document* document) |
97 : ActiveDOMObject(document) | 99 : ActiveDOMObject(document) |
98 , m_isStopScheduled(false) | 100 , m_isStopScheduled(false) |
99 , m_isCleared(false) | 101 , m_isCleared(false) |
100 , m_isInitialized(false) | 102 , m_isInitialized(false) |
101 , m_destinationNode(nullptr) | 103 , m_destinationNode(nullptr) |
| 104 , m_isResolvingResumePromises(false) |
102 , m_automaticPullNodesNeedUpdating(false) | 105 , m_automaticPullNodesNeedUpdating(false) |
103 , m_connectionCount(0) | 106 , m_connectionCount(0) |
104 , m_audioThread(0) | 107 , m_audioThread(0) |
105 , m_isOfflineContext(false) | 108 , m_isOfflineContext(false) |
| 109 , m_contextState(Suspended) |
106 { | 110 { |
107 m_destinationNode = DefaultAudioDestinationNode::create(this); | 111 m_destinationNode = DefaultAudioDestinationNode::create(this); |
108 | 112 |
109 initialize(); | 113 initialize(); |
110 #if DEBUG_AUDIONODE_REFERENCES | 114 #if DEBUG_AUDIONODE_REFERENCES |
111 fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext
::s_hardwareContextCount); | 115 fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext
::s_hardwareContextCount); |
112 #endif | 116 #endif |
113 } | 117 } |
114 | 118 |
115 // Constructor for offline (non-realtime) rendering. | 119 // Constructor for offline (non-realtime) rendering. |
116 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t
numberOfFrames, float sampleRate) | 120 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t
numberOfFrames, float sampleRate) |
117 : ActiveDOMObject(document) | 121 : ActiveDOMObject(document) |
118 , m_isStopScheduled(false) | 122 , m_isStopScheduled(false) |
119 , m_isCleared(false) | 123 , m_isCleared(false) |
120 , m_isInitialized(false) | 124 , m_isInitialized(false) |
121 , m_destinationNode(nullptr) | 125 , m_destinationNode(nullptr) |
| 126 , m_isResolvingResumePromises(false) |
122 , m_automaticPullNodesNeedUpdating(false) | 127 , m_automaticPullNodesNeedUpdating(false) |
123 , m_connectionCount(0) | 128 , m_connectionCount(0) |
124 , m_audioThread(0) | 129 , m_audioThread(0) |
125 , m_isOfflineContext(true) | 130 , m_isOfflineContext(true) |
| 131 , m_contextState(Suspended) |
126 { | 132 { |
127 // Create a new destination for offline rendering. | 133 // Create a new destination for offline rendering. |
128 m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampl
eRate); | 134 m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampl
eRate); |
129 if (m_renderTarget.get()) | 135 if (m_renderTarget.get()) |
130 m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTa
rget.get()); | 136 m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTa
rget.get()); |
131 | 137 |
132 initialize(); | 138 initialize(); |
133 } | 139 } |
134 | 140 |
135 AudioContext::~AudioContext() | 141 AudioContext::~AudioContext() |
136 { | 142 { |
137 #if DEBUG_AUDIONODE_REFERENCES | 143 #if DEBUG_AUDIONODE_REFERENCES |
138 fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this); | 144 fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this); |
139 #endif | 145 #endif |
140 // AudioNodes keep a reference to their context, so there should be no way t
o be in the destructor if there are still AudioNodes around. | 146 // AudioNodes keep a reference to their context, so there should be no way t
o be in the destructor if there are still AudioNodes around. |
141 ASSERT(!m_isInitialized); | 147 ASSERT(!m_isInitialized); |
142 ASSERT(!m_referencedNodes.size()); | 148 ASSERT(!m_referencedNodes.size()); |
143 ASSERT(!m_finishedNodes.size()); | 149 ASSERT(!m_finishedNodes.size()); |
144 ASSERT(!m_automaticPullNodes.size()); | 150 ASSERT(!m_automaticPullNodes.size()); |
145 if (m_automaticPullNodesNeedUpdating) | 151 if (m_automaticPullNodesNeedUpdating) |
146 m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size()); | 152 m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size()); |
147 ASSERT(!m_renderingAutomaticPullNodes.size()); | 153 ASSERT(!m_renderingAutomaticPullNodes.size()); |
| 154 ASSERT(!m_resumePromises.size()); |
148 } | 155 } |
149 | 156 |
150 void AudioContext::initialize() | 157 void AudioContext::initialize() |
151 { | 158 { |
152 if (isInitialized()) | 159 if (isInitialized()) |
153 return; | 160 return; |
154 | 161 |
155 FFTFrame::initialize(); | 162 FFTFrame::initialize(); |
156 m_listener = AudioListener::create(); | 163 m_listener = AudioListener::create(); |
157 | 164 |
158 if (m_destinationNode.get()) { | 165 if (m_destinationNode.get()) { |
159 m_destinationNode->initialize(); | 166 m_destinationNode->initialize(); |
160 | 167 |
161 if (!isOfflineContext()) { | 168 if (!isOfflineContext()) { |
162 // This starts the audio thread. The destination node's provideInput
() method will now be called repeatedly to render audio. | 169 // This starts the audio thread. The destination node's provideInput
() method will now be called repeatedly to render audio. |
163 // Each time provideInput() is called, a portion of the audio stream
is rendered. Let's call this time period a "render quantum". | 170 // Each time provideInput() is called, a portion of the audio stream
is rendered. Let's call this time period a "render quantum". |
164 // NOTE: for now default AudioContext does not need an explicit star
tRendering() call from JavaScript. | 171 // NOTE: for now default AudioContext does not need an explicit star
tRendering() call from JavaScript. |
165 // We may want to consider requiring it for symmetry with OfflineAud
ioContext. | 172 // We may want to consider requiring it for symmetry with OfflineAud
ioContext. |
166 m_destinationNode->startRendering(); | 173 startRendering(); |
167 ++s_hardwareContextCount; | 174 ++s_hardwareContextCount; |
168 } | 175 } |
169 | 176 |
170 m_isInitialized = true; | 177 m_isInitialized = true; |
171 } | 178 } |
172 } | 179 } |
173 | 180 |
174 void AudioContext::clear() | 181 void AudioContext::clear() |
175 { | 182 { |
176 // We need to run disposers before destructing m_contextGraphMutex. | 183 // We need to run disposers before destructing m_contextGraphMutex. |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 exceptionState.throwDOMException( | 529 exceptionState.throwDOMException( |
523 IndexSizeError, | 530 IndexSizeError, |
524 "length of imaginary array (" + String::number(imag->length()) | 531 "length of imaginary array (" + String::number(imag->length()) |
525 + ") exceeds allowed maximum of 4096"); | 532 + ") exceeds allowed maximum of 4096"); |
526 return 0; | 533 return 0; |
527 } | 534 } |
528 | 535 |
529 return PeriodicWave::create(sampleRate(), real->view(), imag->view()); | 536 return PeriodicWave::create(sampleRate(), real->view(), imag->view()); |
530 } | 537 } |
531 | 538 |
| 539 String AudioContext::state() const |
| 540 { |
| 541 // These strings had better match the strings for AudioContextState in Audio
Context.idl. |
| 542 switch (m_contextState) { |
| 543 case Suspended: |
| 544 return "suspended"; |
| 545 case Running: |
| 546 return "running"; |
| 547 case Closed: |
| 548 return "closed"; |
| 549 } |
| 550 ASSERT_NOT_REACHED(); |
| 551 return ""; |
| 552 } |
| 553 |
| 554 void AudioContext::setContextState(AudioContextState newState) |
| 555 { |
| 556 // Validate the transitions |
| 557 switch (newState) { |
| 558 case Suspended: |
| 559 ASSERT(m_contextState == Running); |
| 560 break; |
| 561 case Running: |
| 562 ASSERT(m_contextState == Suspended); |
| 563 break; |
| 564 case Closed: |
| 565 ASSERT(m_contextState != Closed); |
| 566 break; |
| 567 } |
| 568 |
| 569 m_contextState = newState; |
| 570 } |
| 571 |
| 572 ScriptPromise AudioContext::suspendContext(ScriptState* scriptState) |
| 573 { |
| 574 ASSERT(isMainThread()); |
| 575 AutoLocker locker(this); |
| 576 |
| 577 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip
tState); |
| 578 |
| 579 ScriptPromise promise = resolver->promise(); |
| 580 |
| 581 if (isOfflineContext()) { |
| 582 resolver->reject( |
| 583 DOMException::create( |
| 584 InvalidStateError, |
| 585 "cannot suspend an OfflineAudioContext")); |
| 586 } else { |
| 587 // Save the promise which will get resolved at the end of the rendering
quantum. |
| 588 m_suspendPromises.append(resolver); |
| 589 } |
| 590 |
| 591 return promise; |
| 592 } |
| 593 |
| 594 ScriptPromise AudioContext::resumeContext(ScriptState* scriptState) |
| 595 { |
| 596 ASSERT(isMainThread()); |
| 597 AutoLocker locker(this); |
| 598 |
| 599 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip
tState); |
| 600 |
| 601 ScriptPromise promise = resolver->promise(); |
| 602 |
| 603 if (isOfflineContext()) { |
| 604 resolver->reject( |
| 605 DOMException::create( |
| 606 InvalidStateError, |
| 607 "cannot resume an OfflineAudioContext")); |
| 608 } else { |
| 609 // Restart the destination node to pull on the audio graph. |
| 610 if (m_destinationNode) |
| 611 startRendering(); |
| 612 |
| 613 // Save the promise which will get resolved when the destination node st
arts pulling on the |
| 614 // graph again. |
| 615 m_resumePromises.append(resolver); |
| 616 } |
| 617 |
| 618 return promise; |
| 619 } |
| 620 |
532 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node) | 621 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node) |
533 { | 622 { |
534 ASSERT(isAudioThread()); | 623 ASSERT(isAudioThread()); |
535 m_finishedNodes.append(node); | 624 m_finishedNodes.append(node); |
536 } | 625 } |
537 | 626 |
538 void AudioContext::derefFinishedSourceNodes() | 627 void AudioContext::derefFinishedSourceNodes() |
539 { | 628 { |
540 ASSERT(isGraphOwner()); | 629 ASSERT(isGraphOwner()); |
541 ASSERT(isAudioThread()); | 630 ASSERT(isAudioThread()); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 717 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
629 if (tryLock()) { | 718 if (tryLock()) { |
630 // Update the channel count mode. | 719 // Update the channel count mode. |
631 updateChangedChannelCountMode(); | 720 updateChangedChannelCountMode(); |
632 | 721 |
633 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu
ts. | 722 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu
ts. |
634 handleDirtyAudioSummingJunctions(); | 723 handleDirtyAudioSummingJunctions(); |
635 handleDirtyAudioNodeOutputs(); | 724 handleDirtyAudioNodeOutputs(); |
636 | 725 |
637 updateAutomaticPullNodes(); | 726 updateAutomaticPullNodes(); |
| 727 resolvePromisesForResume(); |
| 728 |
638 unlock(); | 729 unlock(); |
639 } | 730 } |
640 } | 731 } |
641 | 732 |
642 void AudioContext::handlePostRenderTasks() | 733 void AudioContext::handlePostRenderTasks() |
643 { | 734 { |
644 ASSERT(isAudioThread()); | 735 ASSERT(isAudioThread()); |
645 | 736 |
646 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 737 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
647 // 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 | 738 // 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 |
648 // from the render graph (in which case they'll render silence). | 739 // from the render graph (in which case they'll render silence). |
649 if (tryLock()) { | 740 if (tryLock()) { |
650 // Update the channel count mode. | 741 // Update the channel count mode. |
651 updateChangedChannelCountMode(); | 742 updateChangedChannelCountMode(); |
652 | 743 |
653 // Take care of AudioNode tasks where the tryLock() failed previously. | 744 // Take care of AudioNode tasks where the tryLock() failed previously. |
654 handleDeferredAudioNodeTasks(); | 745 handleDeferredAudioNodeTasks(); |
655 | 746 |
656 // Dynamically clean up nodes which are no longer needed. | 747 // Dynamically clean up nodes which are no longer needed. |
657 derefFinishedSourceNodes(); | 748 derefFinishedSourceNodes(); |
658 | 749 |
659 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu
ts. | 750 // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutpu
ts. |
660 handleDirtyAudioSummingJunctions(); | 751 handleDirtyAudioSummingJunctions(); |
661 handleDirtyAudioNodeOutputs(); | 752 handleDirtyAudioNodeOutputs(); |
662 | 753 |
663 updateAutomaticPullNodes(); | 754 updateAutomaticPullNodes(); |
| 755 resolvePromisesForSuspend(); |
| 756 |
664 unlock(); | 757 unlock(); |
665 } | 758 } |
666 } | 759 } |
667 | 760 |
668 void AudioContext::handleDeferredAudioNodeTasks() | 761 void AudioContext::handleDeferredAudioNodeTasks() |
669 { | 762 { |
670 ASSERT(isAudioThread() && isGraphOwner()); | 763 ASSERT(isAudioThread() && isGraphOwner()); |
671 | 764 |
672 for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i) | 765 for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i) |
673 m_deferredBreakConnectionList[i]->breakConnectionWithLock(); | 766 m_deferredBreakConnectionList[i]->breakConnectionWithLock(); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 } | 886 } |
794 | 887 |
795 void AudioContext::processAutomaticPullNodes(size_t framesToProcess) | 888 void AudioContext::processAutomaticPullNodes(size_t framesToProcess) |
796 { | 889 { |
797 ASSERT(isAudioThread()); | 890 ASSERT(isAudioThread()); |
798 | 891 |
799 for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i) | 892 for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i) |
800 m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess); | 893 m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess); |
801 } | 894 } |
802 | 895 |
| 896 void AudioContext::resolvePromisesForResumeOnMainThread() |
| 897 { |
| 898 ASSERT(isMainThread()); |
| 899 AutoLocker locker(this); |
| 900 |
| 901 for (unsigned k = 0; k < m_resumePromises.size(); ++k) { |
| 902 if (m_contextState == Closed) { |
| 903 m_resumePromises[k]->reject( |
| 904 DOMException::create(InvalidStateError, "Cannot resume a context
that has been released")); |
| 905 } else { |
| 906 m_resumePromises[k]->resolve(); |
| 907 } |
| 908 } |
| 909 |
| 910 m_resumePromises.clear(); |
| 911 m_isResolvingResumePromises = false; |
| 912 } |
| 913 |
| 914 void AudioContext::resolvePromisesForResume() |
| 915 { |
| 916 // This runs inside the AudioContext's lock when handling pre-render tasks. |
| 917 ASSERT(isAudioThread()); |
| 918 ASSERT(isGraphOwner()); |
| 919 |
| 920 // Resolve any pending promises created by resume(). Only do this we if have
n't already started |
| 921 // resolving these promises. This gets called very often and it takes some t
ime to resolve the |
| 922 // promises in the main thread. |
| 923 if (!m_isResolvingResumePromises && m_resumePromises.size() > 0) { |
| 924 m_isResolvingResumePromises = true; |
| 925 callOnMainThread(bind(&AudioContext::resolvePromisesForResumeOnMainThrea
d, this)); |
| 926 } |
| 927 } |
| 928 |
| 929 void AudioContext::resolvePromisesForSuspendOnMainThread() |
| 930 { |
| 931 ASSERT(isMainThread()); |
| 932 AutoLocker locker(this); |
| 933 |
| 934 // We can stop rendering now. |
| 935 if (m_destinationNode) |
| 936 stopRendering(); |
| 937 |
| 938 for (unsigned k = 0; k < m_suspendPromises.size(); ++k) { |
| 939 if (m_contextState == Closed) { |
| 940 m_suspendPromises[k]->reject( |
| 941 DOMException::create(InvalidStateError, "Cannot suspend a contex
t that has been released")); |
| 942 } else { |
| 943 m_suspendPromises[k]->resolve(); |
| 944 } |
| 945 } |
| 946 |
| 947 m_suspendPromises.clear(); |
| 948 } |
| 949 |
| 950 void AudioContext::resolvePromisesForSuspend() |
| 951 { |
| 952 // This runs inside the AudioContext's lock when handling pre-render tasks. |
| 953 ASSERT(isAudioThread()); |
| 954 ASSERT(isGraphOwner()); |
| 955 |
| 956 // Resolve any pending promises created by suspend() |
| 957 if (m_suspendPromises.size() > 0) |
| 958 callOnMainThread(bind(&AudioContext::resolvePromisesForSuspendOnMainThre
ad, this)); |
| 959 |
| 960 } |
| 961 |
803 const AtomicString& AudioContext::interfaceName() const | 962 const AtomicString& AudioContext::interfaceName() const |
804 { | 963 { |
805 return EventTargetNames::AudioContext; | 964 return EventTargetNames::AudioContext; |
806 } | 965 } |
807 | 966 |
808 ExecutionContext* AudioContext::executionContext() const | 967 ExecutionContext* AudioContext::executionContext() const |
809 { | 968 { |
810 return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext(); | 969 return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext(); |
811 } | 970 } |
812 | 971 |
813 void AudioContext::startRendering() | 972 void AudioContext::startRendering() |
814 { | 973 { |
815 destination()->startRendering(); | 974 // This is called for both online and offline contexts. |
| 975 ASSERT(isMainThread()); |
| 976 ASSERT(m_destinationNode); |
| 977 |
| 978 if (m_contextState == Suspended) { |
| 979 destination()->startRendering(); |
| 980 setContextState(Running); |
| 981 } |
| 982 } |
| 983 |
| 984 void AudioContext::stopRendering() |
| 985 { |
| 986 ASSERT(isMainThread()); |
| 987 ASSERT(m_destinationNode); |
| 988 ASSERT(!isOfflineContext()); |
| 989 |
| 990 if (m_contextState == Running) { |
| 991 destination()->stopRendering(); |
| 992 setContextState(Suspended); |
| 993 } |
816 } | 994 } |
817 | 995 |
818 void AudioContext::fireCompletionEvent() | 996 void AudioContext::fireCompletionEvent() |
819 { | 997 { |
820 ASSERT(isMainThread()); | 998 ASSERT(isMainThread()); |
821 if (!isMainThread()) | 999 if (!isMainThread()) |
822 return; | 1000 return; |
823 | 1001 |
824 AudioBuffer* renderedBuffer = m_renderTarget.get(); | 1002 AudioBuffer* renderedBuffer = m_renderTarget.get(); |
825 | 1003 |
| 1004 setContextState(Closed); |
| 1005 |
826 ASSERT(renderedBuffer); | 1006 ASSERT(renderedBuffer); |
827 if (!renderedBuffer) | 1007 if (!renderedBuffer) |
828 return; | 1008 return; |
829 | 1009 |
830 // Avoid firing the event if the document has already gone away. | 1010 // Avoid firing the event if the document has already gone away. |
831 if (executionContext()) { | 1011 if (executionContext()) { |
832 // Call the offline rendering completion event listener. | 1012 // Call the offline rendering completion event listener. |
833 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); | 1013 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); |
834 } | 1014 } |
835 } | 1015 } |
(...skipping 29 matching lines...) Expand all Loading... |
865 | 1045 |
866 for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k
!= m_deferredCountModeChange.end(); ++k) | 1046 for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k
!= m_deferredCountModeChange.end(); ++k) |
867 (*k)->updateChannelCountMode(); | 1047 (*k)->updateChannelCountMode(); |
868 | 1048 |
869 m_deferredCountModeChange.clear(); | 1049 m_deferredCountModeChange.clear(); |
870 } | 1050 } |
871 | 1051 |
872 } // namespace blink | 1052 } // namespace blink |
873 | 1053 |
874 #endif // ENABLE(WEB_AUDIO) | 1054 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |