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 |