| 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 701 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 | 712 |
| 713 // Find AudioBufferSourceNodes to see if we can stop playing them. | 713 // Find AudioBufferSourceNodes to see if we can stop playing them. |
| 714 for (AudioNode* node : m_activeSourceNodes) { | 714 for (AudioNode* node : m_activeSourceNodes) { |
| 715 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { | 715 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { |
| 716 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); | 716 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); |
| 717 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); | 717 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); |
| 718 } | 718 } |
| 719 } | 719 } |
| 720 } | 720 } |
| 721 | 721 |
| 722 void AbstractAudioContext::performPostRenderTasks() | |
| 723 { | |
| 724 // Take care of AudioNode tasks where the tryLock() failed previously. | |
| 725 deferredTaskHandler().breakConnections(); | |
| 726 | |
| 727 // Dynamically clean up nodes which are no longer needed. | |
| 728 releaseFinishedSourceNodes(); | |
| 729 | |
| 730 deferredTaskHandler().handleDeferredTasks(); | |
| 731 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | |
| 732 } | |
| 733 | |
| 734 void AbstractAudioContext::handlePreRenderTasks() | 722 void AbstractAudioContext::handlePreRenderTasks() |
| 735 { | 723 { |
| 736 ASSERT(isAudioThread()); | 724 ASSERT(isAudioThread()); |
| 737 | 725 |
| 738 // For the precise offline audio rendering, we need these tasks to be | |
| 739 // performed every render quantum. Thus, we wait for the graph lock (rather | |
| 740 // than tryLock()) so we can run the pre-render tasks without deferring | |
| 741 // them. | |
| 742 // | |
| 743 // Also note that we do not need to run resolvePromiseForResume() here | |
| 744 // because the offline audio context keeps its own suspend/resume promise | |
| 745 // resolvers separately. | |
| 746 if (!hasRealtimeConstraint()) { | |
| 747 deferredTaskHandler().offlineContextLock(); | |
| 748 deferredTaskHandler().handleDeferredTasks(); | |
| 749 handleStoppableSourceNodes(); | |
| 750 unlock(); | |
| 751 return; | |
| 752 } | |
| 753 | |
| 754 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 726 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
| 755 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 727 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
| 756 if (tryLock()) { | 728 if (tryLock()) { |
| 757 deferredTaskHandler().handleDeferredTasks(); | 729 deferredTaskHandler().handleDeferredTasks(); |
| 758 | 730 |
| 759 resolvePromisesForResume(); | 731 resolvePromisesForResume(); |
| 760 | 732 |
| 761 // Check to see if source nodes can be stopped because the end time has
passed. | 733 // Check to see if source nodes can be stopped because the end time has
passed. |
| 762 handleStoppableSourceNodes(); | 734 handleStoppableSourceNodes(); |
| 763 | 735 |
| 764 unlock(); | 736 unlock(); |
| 765 } | 737 } |
| 766 } | 738 } |
| 767 | 739 |
| 768 void AbstractAudioContext::handlePostRenderTasks() | 740 void AbstractAudioContext::handlePostRenderTasks() |
| 769 { | 741 { |
| 770 ASSERT(isAudioThread()); | 742 ASSERT(isAudioThread()); |
| 771 | 743 |
| 772 // Same as |handlePreRenderTasks()|. We force to perform the post-render | |
| 773 // tasks for the offline rendering. | |
| 774 if (!hasRealtimeConstraint()) { | |
| 775 deferredTaskHandler().offlineContextLock(); | |
| 776 performPostRenderTasks(); | |
| 777 unlock(); | |
| 778 return; | |
| 779 } | |
| 780 | |
| 781 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 744 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
| 782 // 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 | 745 // 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 |
| 783 // from the render graph (in which case they'll render silence). | 746 // from the render graph (in which case they'll render silence). |
| 784 if (tryLock()) { | 747 if (tryLock()) { |
| 785 performPostRenderTasks(); | 748 // Take care of AudioNode tasks where the tryLock() failed previously. |
| 749 deferredTaskHandler().breakConnections(); |
| 750 |
| 751 // Dynamically clean up nodes which are no longer needed. |
| 752 releaseFinishedSourceNodes(); |
| 753 |
| 754 deferredTaskHandler().handleDeferredTasks(); |
| 755 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); |
| 756 |
| 786 unlock(); | 757 unlock(); |
| 787 } | 758 } |
| 788 } | 759 } |
| 789 | 760 |
| 790 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() | 761 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() |
| 791 { | 762 { |
| 792 ASSERT(isMainThread()); | 763 ASSERT(isMainThread()); |
| 793 AutoLocker locker(this); | 764 AutoLocker locker(this); |
| 794 | 765 |
| 795 for (auto& resolver : m_resumeResolvers) { | 766 for (auto& resolver : m_resumeResolvers) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 // This is called for both online and offline contexts. | 819 // This is called for both online and offline contexts. |
| 849 ASSERT(isMainThread()); | 820 ASSERT(isMainThread()); |
| 850 ASSERT(m_destinationNode); | 821 ASSERT(m_destinationNode); |
| 851 | 822 |
| 852 if (m_contextState == Suspended) { | 823 if (m_contextState == Suspended) { |
| 853 destination()->audioDestinationHandler().startRendering(); | 824 destination()->audioDestinationHandler().startRendering(); |
| 854 setContextState(Running); | 825 setContextState(Running); |
| 855 } | 826 } |
| 856 } | 827 } |
| 857 | 828 |
| 829 void AbstractAudioContext::fireCompletionEvent() |
| 830 { |
| 831 ASSERT(isMainThread()); |
| 832 if (!isMainThread()) |
| 833 return; |
| 834 |
| 835 AudioBuffer* renderedBuffer = m_renderTarget.get(); |
| 836 |
| 837 // For an offline context, we set the state to closed here so that the oncom
plete handler sees |
| 838 // that the context has been closed. |
| 839 setContextState(Closed); |
| 840 |
| 841 ASSERT(renderedBuffer); |
| 842 if (!renderedBuffer) |
| 843 return; |
| 844 |
| 845 // Avoid firing the event if the document has already gone away. |
| 846 if (executionContext()) { |
| 847 // Call the offline rendering completion event listener and resolve the
promise too. |
| 848 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); |
| 849 m_offlineResolver->resolve(renderedBuffer); |
| 850 } |
| 851 } |
| 852 |
| 858 DEFINE_TRACE(AbstractAudioContext) | 853 DEFINE_TRACE(AbstractAudioContext) |
| 859 { | 854 { |
| 855 visitor->trace(m_offlineResolver); |
| 860 visitor->trace(m_renderTarget); | 856 visitor->trace(m_renderTarget); |
| 861 visitor->trace(m_destinationNode); | 857 visitor->trace(m_destinationNode); |
| 862 visitor->trace(m_listener); | 858 visitor->trace(m_listener); |
| 863 // trace() can be called in AbstractAudioContext constructor, and | 859 // trace() can be called in AbstractAudioContext constructor, and |
| 864 // m_contextGraphMutex might be unavailable. | 860 // m_contextGraphMutex might be unavailable. |
| 865 if (m_didInitializeContextGraphMutex) { | 861 if (m_didInitializeContextGraphMutex) { |
| 866 AutoLocker lock(this); | 862 AutoLocker lock(this); |
| 867 visitor->trace(m_activeSourceNodes); | 863 visitor->trace(m_activeSourceNodes); |
| 868 } else { | 864 } else { |
| 869 visitor->trace(m_activeSourceNodes); | 865 visitor->trace(m_activeSourceNodes); |
| 870 } | 866 } |
| 871 visitor->trace(m_resumeResolvers); | 867 visitor->trace(m_resumeResolvers); |
| 872 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); | 868 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); |
| 873 ActiveDOMObject::trace(visitor); | 869 ActiveDOMObject::trace(visitor); |
| 874 } | 870 } |
| 875 | 871 |
| 876 SecurityOrigin* AbstractAudioContext::securityOrigin() const | 872 SecurityOrigin* AbstractAudioContext::securityOrigin() const |
| 877 { | 873 { |
| 878 if (executionContext()) | 874 if (executionContext()) |
| 879 return executionContext()->securityOrigin(); | 875 return executionContext()->securityOrigin(); |
| 880 | 876 |
| 881 return nullptr; | 877 return nullptr; |
| 882 } | 878 } |
| 883 | 879 |
| 884 } // namespace blink | 880 } // namespace blink |
| 885 | 881 |
| 886 #endif // ENABLE(WEB_AUDIO) | 882 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |