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 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 | 686 |
687 // Find AudioBufferSourceNodes to see if we can stop playing them. | 687 // Find AudioBufferSourceNodes to see if we can stop playing them. |
688 for (AudioNode* node : m_activeSourceNodes) { | 688 for (AudioNode* node : m_activeSourceNodes) { |
689 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { | 689 if (node->handler().nodeType() == AudioHandler::NodeTypeAudioBufferSourc
e) { |
690 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); | 690 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod
e*>(node); |
691 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); | 691 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); |
692 } | 692 } |
693 } | 693 } |
694 } | 694 } |
695 | 695 |
| 696 void AbstractAudioContext::performPostRenderTasks() |
| 697 { |
| 698 // Take care of AudioNode tasks where the tryLock() failed previously. |
| 699 deferredTaskHandler().breakConnections(); |
| 700 |
| 701 // Dynamically clean up nodes which are no longer needed. |
| 702 releaseFinishedSourceNodes(); |
| 703 |
| 704 deferredTaskHandler().handleDeferredTasks(); |
| 705 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); |
| 706 } |
| 707 |
696 void AbstractAudioContext::handlePreRenderTasks() | 708 void AbstractAudioContext::handlePreRenderTasks() |
697 { | 709 { |
698 ASSERT(isAudioThread()); | 710 ASSERT(isAudioThread()); |
699 | 711 |
| 712 // For the precise offline audio rendering, we need these tasks to be |
| 713 // performed every render quantum. Thus, we wait for the graph lock (rather |
| 714 // than tryLock()) so we can run the pre-render tasks without deferring |
| 715 // them. |
| 716 // |
| 717 // Also note that we do not need to run resolvePromiseForResume() here |
| 718 // because the offline audio context keeps its own suspend/resume promise |
| 719 // resolvers separately. |
| 720 if (!hasRealtimeConstraint()) { |
| 721 deferredTaskHandler().offlineContextLock(); |
| 722 deferredTaskHandler().handleDeferredTasks(); |
| 723 handleStoppableSourceNodes(); |
| 724 unlock(); |
| 725 return; |
| 726 } |
| 727 |
700 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). | 728 // At the beginning of every render quantum, try to update the internal rend
ering graph state (from main thread changes). |
701 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. | 729 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u
p the changes. |
702 if (tryLock()) { | 730 if (tryLock()) { |
703 deferredTaskHandler().handleDeferredTasks(); | 731 deferredTaskHandler().handleDeferredTasks(); |
704 | 732 |
705 resolvePromisesForResume(); | 733 resolvePromisesForResume(); |
706 | 734 |
707 // Check to see if source nodes can be stopped because the end time has
passed. | 735 // Check to see if source nodes can be stopped because the end time has
passed. |
708 handleStoppableSourceNodes(); | 736 handleStoppableSourceNodes(); |
709 | 737 |
710 unlock(); | 738 unlock(); |
711 } | 739 } |
712 } | 740 } |
713 | 741 |
714 void AbstractAudioContext::handlePostRenderTasks() | 742 void AbstractAudioContext::handlePostRenderTasks() |
715 { | 743 { |
716 ASSERT(isAudioThread()); | 744 ASSERT(isAudioThread()); |
717 | 745 |
| 746 // Same as |handlePreRenderTasks()|. We force to perform the post-render |
| 747 // tasks for the offline rendering. |
| 748 if (!hasRealtimeConstraint()) { |
| 749 deferredTaskHandler().offlineContextLock(); |
| 750 performPostRenderTasks(); |
| 751 unlock(); |
| 752 return; |
| 753 } |
| 754 |
718 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. | 755 // Must use a tryLock() here too. Don't worry, the lock will very rarely be
contended and this method is called frequently. |
719 // 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 | 756 // 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 |
720 // from the render graph (in which case they'll render silence). | 757 // from the render graph (in which case they'll render silence). |
721 if (tryLock()) { | 758 if (tryLock()) { |
722 // Take care of AudioNode tasks where the tryLock() failed previously. | 759 performPostRenderTasks(); |
723 deferredTaskHandler().breakConnections(); | |
724 | |
725 // Dynamically clean up nodes which are no longer needed. | |
726 releaseFinishedSourceNodes(); | |
727 | |
728 deferredTaskHandler().handleDeferredTasks(); | |
729 deferredTaskHandler().requestToDeleteHandlersOnMainThread(); | |
730 | |
731 unlock(); | 760 unlock(); |
732 } | 761 } |
733 } | 762 } |
734 | 763 |
735 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() | 764 void AbstractAudioContext::resolvePromisesForResumeOnMainThread() |
736 { | 765 { |
737 ASSERT(isMainThread()); | 766 ASSERT(isMainThread()); |
738 AutoLocker locker(this); | 767 AutoLocker locker(this); |
739 | 768 |
740 for (auto& resolver : m_resumeResolvers) { | 769 for (auto& resolver : m_resumeResolvers) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 // This is called for both online and offline contexts. | 822 // This is called for both online and offline contexts. |
794 ASSERT(isMainThread()); | 823 ASSERT(isMainThread()); |
795 ASSERT(m_destinationNode); | 824 ASSERT(m_destinationNode); |
796 | 825 |
797 if (m_contextState == Suspended) { | 826 if (m_contextState == Suspended) { |
798 destination()->audioDestinationHandler().startRendering(); | 827 destination()->audioDestinationHandler().startRendering(); |
799 setContextState(Running); | 828 setContextState(Running); |
800 } | 829 } |
801 } | 830 } |
802 | 831 |
803 void AbstractAudioContext::fireCompletionEvent() | |
804 { | |
805 ASSERT(isMainThread()); | |
806 if (!isMainThread()) | |
807 return; | |
808 | |
809 AudioBuffer* renderedBuffer = m_renderTarget.get(); | |
810 | |
811 // For an offline context, we set the state to closed here so that the oncom
plete handler sees | |
812 // that the context has been closed. | |
813 setContextState(Closed); | |
814 | |
815 ASSERT(renderedBuffer); | |
816 if (!renderedBuffer) | |
817 return; | |
818 | |
819 // Avoid firing the event if the document has already gone away. | |
820 if (executionContext()) { | |
821 // Call the offline rendering completion event listener and resolve the
promise too. | |
822 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer)); | |
823 m_offlineResolver->resolve(renderedBuffer); | |
824 } | |
825 } | |
826 | |
827 DEFINE_TRACE(AbstractAudioContext) | 832 DEFINE_TRACE(AbstractAudioContext) |
828 { | 833 { |
829 visitor->trace(m_offlineResolver); | |
830 visitor->trace(m_renderTarget); | 834 visitor->trace(m_renderTarget); |
831 visitor->trace(m_destinationNode); | 835 visitor->trace(m_destinationNode); |
832 visitor->trace(m_listener); | 836 visitor->trace(m_listener); |
833 // trace() can be called in AbstractAudioContext constructor, and | 837 // trace() can be called in AbstractAudioContext constructor, and |
834 // m_contextGraphMutex might be unavailable. | 838 // m_contextGraphMutex might be unavailable. |
835 if (m_didInitializeContextGraphMutex) { | 839 if (m_didInitializeContextGraphMutex) { |
836 AutoLocker lock(this); | 840 AutoLocker lock(this); |
837 visitor->trace(m_activeSourceNodes); | 841 visitor->trace(m_activeSourceNodes); |
838 } else { | 842 } else { |
839 visitor->trace(m_activeSourceNodes); | 843 visitor->trace(m_activeSourceNodes); |
840 } | 844 } |
841 visitor->trace(m_resumeResolvers); | 845 visitor->trace(m_resumeResolvers); |
842 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); | 846 RefCountedGarbageCollectedEventTargetWithInlineData<AbstractAudioContext>::t
race(visitor); |
843 ActiveDOMObject::trace(visitor); | 847 ActiveDOMObject::trace(visitor); |
844 } | 848 } |
845 | 849 |
846 SecurityOrigin* AbstractAudioContext::securityOrigin() const | 850 SecurityOrigin* AbstractAudioContext::securityOrigin() const |
847 { | 851 { |
848 if (executionContext()) | 852 if (executionContext()) |
849 return executionContext()->securityOrigin(); | 853 return executionContext()->securityOrigin(); |
850 | 854 |
851 return nullptr; | 855 return nullptr; |
852 } | 856 } |
853 | 857 |
854 } // namespace blink | 858 } // namespace blink |
855 | 859 |
856 #endif // ENABLE(WEB_AUDIO) | 860 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |