| 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 |