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 |
722 void AbstractAudioContext::handlePreRenderTasks() | 734 void AbstractAudioContext::handlePreRenderTasks() |
723 { | 735 { |
724 ASSERT(isAudioThread()); | 736 ASSERT(isAudioThread()); |
725 | 737 |
| 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 |
726 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 754 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
727 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 755 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
728 if (tryLock()) { | 756 if (tryLock()) { |
729 deferredTaskHandler().handleDeferredTasks(); | 757 deferredTaskHandler().handleDeferredTasks(); |
730 | 758 |
731 resolvePromisesForResume(); | 759 resolvePromisesForResume(); |
732 | 760 |
733 // Check to see if source nodes can be stopped because the end time has
passed. | 761 // Check to see if source nodes can be stopped because the end time has
passed. |
734 handleStoppableSourceNodes(); | 762 handleStoppableSourceNodes(); |
735 | 763 |
736 unlock(); | 764 unlock(); |
737 } | 765 } |
738 } | 766 } |
739 | 767 |
740 void AbstractAudioContext::handlePostRenderTasks() | 768 void AbstractAudioContext::handlePostRenderTasks() |
741 { | 769 { |
742 ASSERT(isAudioThread()); | 770 ASSERT(isAudioThread()); |
743 | 771 |
| 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 |
744 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 781 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
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 | 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 |
746 // from the render graph (in which case they'll render silence). | 783 // from the render graph (in which case they'll render silence). |
747 if (tryLock()) { | 784 if (tryLock()) { |
748 // Take care of AudioNode tasks where the tryLock() failed previously. | 785 performPostRenderTasks(); |
749 deferredTaskHandler().breakConnections(); | |
750 | |
751 // Dynamically clean up nodes which are no longer needed. | |
752 releaseFinishedSourceNodes(); | |
753 | |
754 deferredTaskHandler().handleDeferredTasks(); | |
755 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | |
756 | |
757 unlock(); | 786 unlock(); |
758 } | 787 } |
759 } | 788 } |
760 | 789 |
761 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() | 790 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() |
762 { | 791 { |
763 ASSERT(isMainThread()); | 792 ASSERT(isMainThread()); |
764 AutoLocker locker(this); | 793 AutoLocker locker(this); |
765 | 794 |
766 for (auto& resolver : m_resumeResolvers) { | 795 for (auto& resolver : m_resumeResolvers) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 // This is called for both online and offline contexts. | 848 // This is called for both online and offline contexts. |
820 ASSERT(isMainThread()); | 849 ASSERT(isMainThread()); |
821 ASSERT(m_destinationNode); | 850 ASSERT(m_destinationNode); |
822 | 851 |
823 if (m_contextState == Suspended) { | 852 if (m_contextState == Suspended) { |
824 destination()->audioDestinationHandler().startRendering(); | 853 destination()->audioDestinationHandler().startRendering(); |
825 setContextState(Running); | 854 setContextState(Running); |
826 } | 855 } |
827 } | 856 } |
828 | 857 |
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 | |
853 DEFINE_TRACE(AbstractAudioContext) | 858 DEFINE_TRACE(AbstractAudioContext) |
854 { | 859 { |
855 visitor->trace(m_offlineResolver); | |
856 visitor->trace(m_renderTarget); | 860 visitor->trace(m_renderTarget); |
857 visitor->trace(m_destinationNode); | 861 visitor->trace(m_destinationNode); |
858 visitor->trace(m_listener); | 862 visitor->trace(m_listener); |
859 // trace() can be called in AbstractAudioContext constructor, and | 863 // trace() can be called in AbstractAudioContext constructor, and |
860 // m_contextGraphMutex might be unavailable. | 864 // m_contextGraphMutex might be unavailable. |
861 if (m_didInitializeContextGraphMutex) { | 865 if (m_didInitializeContextGraphMutex) { |
862 AutoLocker lock(this); | 866 AutoLocker lock(this); |
863 visitor->trace(m_activeSourceNodes); | 867 visitor->trace(m_activeSourceNodes); |
864 } else { | 868 } else { |
865 visitor->trace(m_activeSourceNodes); | 869 visitor->trace(m_activeSourceNodes); |
866 } | 870 } |
867 visitor->trace(m_resumeResolvers); | 871 visitor->trace(m_resumeResolvers); |
868 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); | 872 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); |
869 ActiveDOMObject::trace(visitor); | 873 ActiveDOMObject::trace(visitor); |
870 } | 874 } |
871 | 875 |
872 SecurityOrigin* AbstractAudioContext::securityOrigin() const | 876 SecurityOrigin* AbstractAudioContext::securityOrigin() const |
873 { | 877 { |
874 if (executionContext()) | 878 if (executionContext()) |
875 return executionContext()->securityOrigin(); | 879 return executionContext()->securityOrigin(); |
876 | 880 |
877 return nullptr; | 881 return nullptr; |
878 } | 882 } |
879 | 883 |
880 } // namespace blink | 884 } // namespace blink |
881 | 885 |
882 #endif // ENABLE(WEB_AUDIO) | 886 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |