Chromium Code Reviews| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 | 88 |
| 89 // FIXME(dominicc): Devolve these constructors to AudioContext | 89 // FIXME(dominicc): Devolve these constructors to AudioContext |
| 90 // and OfflineAudioContext respectively. | 90 // and OfflineAudioContext respectively. |
| 91 | 91 |
| 92 // Constructor for rendering to the audio hardware. | 92 // Constructor for rendering to the audio hardware. |
| 93 BaseAudioContext::BaseAudioContext(Document* document) | 93 BaseAudioContext::BaseAudioContext(Document* document) |
| 94 : SuspendableObject(document), | 94 : SuspendableObject(document), |
| 95 destination_node_(nullptr), | 95 destination_node_(nullptr), |
| 96 is_cleared_(false), | 96 is_cleared_(false), |
| 97 is_resolving_resume_promises_(false), | 97 is_resolving_resume_promises_(false), |
| 98 has_posted_cleanup_task_(false), | |
| 98 user_gesture_required_(false), | 99 user_gesture_required_(false), |
| 99 connection_count_(0), | 100 connection_count_(0), |
| 100 deferred_task_handler_(DeferredTaskHandler::Create()), | 101 deferred_task_handler_(DeferredTaskHandler::Create()), |
| 101 context_state_(kSuspended), | 102 context_state_(kSuspended), |
| 102 closed_context_sample_rate_(-1), | 103 closed_context_sample_rate_(-1), |
| 103 periodic_wave_sine_(nullptr), | 104 periodic_wave_sine_(nullptr), |
| 104 periodic_wave_square_(nullptr), | 105 periodic_wave_square_(nullptr), |
| 105 periodic_wave_sawtooth_(nullptr), | 106 periodic_wave_sawtooth_(nullptr), |
| 106 periodic_wave_triangle_(nullptr), | 107 periodic_wave_triangle_(nullptr), |
| 107 output_position_() { | 108 output_position_() { |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 752 | 753 |
| 753 NOTREACHED(); | 754 NOTREACHED(); |
| 754 return false; | 755 return false; |
| 755 } | 756 } |
| 756 | 757 |
| 757 bool BaseAudioContext::ReleaseFinishedSourceNodes() { | 758 bool BaseAudioContext::ReleaseFinishedSourceNodes() { |
| 758 DCHECK(IsGraphOwner()); | 759 DCHECK(IsGraphOwner()); |
| 759 DCHECK(IsAudioThread()); | 760 DCHECK(IsAudioThread()); |
| 760 bool did_remove = false; | 761 bool did_remove = false; |
| 761 for (AudioHandler* handler : finished_source_handlers_) { | 762 for (AudioHandler* handler : finished_source_handlers_) { |
| 763 // A main thread GC must not be running while the audio | |
| 764 // thread iterates over the |active_source_nodes_| heap object. | |
| 765 ThreadState::GCLockScope gc_lock(ThreadState::MainThreadState()); | |
|
haraken
2017/06/08 01:07:55
Add a TODO to remove this somehow. We should refac
| |
| 766 | |
| 762 for (AudioNode* node : active_source_nodes_) { | 767 for (AudioNode* node : active_source_nodes_) { |
| 763 if (finished_source_nodes_.Contains(node)) | 768 if (finished_source_nodes_.Contains(node)) |
| 764 continue; | 769 continue; |
| 765 if (handler == &node->Handler()) { | 770 if (handler == &node->Handler()) { |
| 766 handler->BreakConnection(); | 771 handler->BreakConnection(); |
| 767 finished_source_nodes_.insert(node); | 772 finished_source_nodes_.insert(node); |
| 768 did_remove = true; | 773 did_remove = true; |
| 769 break; | 774 break; |
| 770 } | 775 } |
| 771 } | 776 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 784 | 789 |
| 785 void BaseAudioContext::ReleaseActiveSourceNodes() { | 790 void BaseAudioContext::ReleaseActiveSourceNodes() { |
| 786 DCHECK(IsMainThread()); | 791 DCHECK(IsMainThread()); |
| 787 for (auto& source_node : active_source_nodes_) | 792 for (auto& source_node : active_source_nodes_) |
| 788 source_node->Handler().BreakConnection(); | 793 source_node->Handler().BreakConnection(); |
| 789 | 794 |
| 790 active_source_nodes_.clear(); | 795 active_source_nodes_.clear(); |
| 791 } | 796 } |
| 792 | 797 |
| 793 void BaseAudioContext::HandleStoppableSourceNodes() { | 798 void BaseAudioContext::HandleStoppableSourceNodes() { |
| 799 DCHECK(IsAudioThread()); | |
| 794 DCHECK(IsGraphOwner()); | 800 DCHECK(IsGraphOwner()); |
| 795 | 801 |
| 796 // Find AudioBufferSourceNodes to see if we can stop playing them. | 802 ScheduleMainThreadCleanup(); |
| 797 for (AudioNode* node : active_source_nodes_) { | |
| 798 // If the AudioNode has been marked as finished and released by | |
| 799 // the audio thread, but not yet removed by the main thread | |
| 800 // (see releaseActiveSourceNodes() above), |node| must not be | |
| 801 // touched as its handler may have been released already. | |
| 802 if (finished_source_nodes_.Contains(node)) | |
| 803 continue; | |
| 804 if (node->Handler().GetNodeType() == | |
| 805 AudioHandler::kNodeTypeAudioBufferSource) { | |
| 806 AudioBufferSourceNode* source_node = | |
| 807 static_cast<AudioBufferSourceNode*>(node); | |
| 808 source_node->GetAudioBufferSourceHandler().HandleStoppableSourceNode(); | |
| 809 } | |
| 810 } | |
| 811 } | 803 } |
| 812 | 804 |
| 813 void BaseAudioContext::HandlePreRenderTasks( | 805 void BaseAudioContext::HandlePreRenderTasks( |
| 814 const AudioIOPosition& output_position) { | 806 const AudioIOPosition& output_position) { |
| 815 DCHECK(IsAudioThread()); | 807 DCHECK(IsAudioThread()); |
| 816 | 808 |
| 817 // At the beginning of every render quantum, try to update the internal | 809 // At the beginning of every render quantum, try to update the internal |
| 818 // rendering graph state (from main thread changes). It's OK if the tryLock() | 810 // rendering graph state (from main thread changes). It's OK if the tryLock() |
| 819 // fails, we'll just take slightly longer to pick up the changes. | 811 // fails, we'll just take slightly longer to pick up the changes. |
| 820 if (TryLock()) { | 812 if (TryLock()) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 | 846 |
| 855 GetDeferredTaskHandler().HandleDeferredTasks(); | 847 GetDeferredTaskHandler().HandleDeferredTasks(); |
| 856 GetDeferredTaskHandler().RequestToDeleteHandlersOnMainThread(); | 848 GetDeferredTaskHandler().RequestToDeleteHandlersOnMainThread(); |
| 857 | 849 |
| 858 unlock(); | 850 unlock(); |
| 859 } | 851 } |
| 860 | 852 |
| 861 RemoveFinishedSourceNodes(did_remove); | 853 RemoveFinishedSourceNodes(did_remove); |
| 862 } | 854 } |
| 863 | 855 |
| 864 void BaseAudioContext::ResolvePromisesForResumeOnMainThread() { | 856 void BaseAudioContext::PerformCleanupOnMainThread() { |
| 865 DCHECK(IsMainThread()); | 857 DCHECK(IsMainThread()); |
| 866 AutoLocker locker(this); | 858 AutoLocker locker(this); |
| 867 | 859 |
| 868 for (auto& resolver : resume_resolvers_) { | 860 if (is_resolving_resume_promises_) { |
| 869 if (context_state_ == kClosed) { | 861 for (auto& resolver : resume_resolvers_) { |
| 870 resolver->Reject(DOMException::Create( | 862 if (context_state_ == kClosed) { |
| 871 kInvalidStateError, "Cannot resume a context that has been closed")); | 863 resolver->Reject(DOMException::Create( |
| 872 } else { | 864 kInvalidStateError, |
| 873 SetContextState(kRunning); | 865 "Cannot resume a context that has been closed")); |
| 874 resolver->Resolve(); | 866 } else { |
| 867 SetContextState(kRunning); | |
| 868 resolver->Resolve(); | |
| 869 } | |
| 870 } | |
| 871 resume_resolvers_.clear(); | |
| 872 is_resolving_resume_promises_ = false; | |
| 873 } | |
| 874 | |
| 875 // Find AudioBufferSourceNodes to see if we can stop playing them. | |
| 876 for (AudioNode* node : active_source_nodes_) { | |
| 877 // If the AudioNode has been marked as finished and released by | |
| 878 // the audio thread, but not yet removed by the main thread | |
| 879 // (see releaseActiveSourceNodes() above), |node| must not be | |
| 880 // touched as its handler may have been released already. | |
| 881 if (finished_source_nodes_.Contains(node)) | |
| 882 continue; | |
| 883 if (node->Handler().GetNodeType() == | |
| 884 AudioHandler::kNodeTypeAudioBufferSource) { | |
| 885 AudioBufferSourceNode* source_node = | |
| 886 static_cast<AudioBufferSourceNode*>(node); | |
| 887 source_node->GetAudioBufferSourceHandler().HandleStoppableSourceNode(); | |
| 875 } | 888 } |
| 876 } | 889 } |
| 890 has_posted_cleanup_task_ = false; | |
| 891 } | |
| 877 | 892 |
| 878 resume_resolvers_.clear(); | 893 void BaseAudioContext::ScheduleMainThreadCleanup() { |
| 879 is_resolving_resume_promises_ = false; | 894 if (has_posted_cleanup_task_) |
| 895 return; | |
| 896 Platform::Current()->MainThread()->GetWebTaskRunner()->PostTask( | |
| 897 BLINK_FROM_HERE, | |
| 898 CrossThreadBind(&BaseAudioContext::PerformCleanupOnMainThread, | |
| 899 WrapCrossThreadPersistent(this))); | |
| 900 has_posted_cleanup_task_ = true; | |
| 880 } | 901 } |
| 881 | 902 |
| 882 void BaseAudioContext::ResolvePromisesForResume() { | 903 void BaseAudioContext::ResolvePromisesForResume() { |
| 883 // This runs inside the BaseAudioContext's lock when handling pre-render | 904 // This runs inside the BaseAudioContext's lock when handling pre-render |
| 884 // tasks. | 905 // tasks. |
| 885 DCHECK(IsAudioThread()); | 906 DCHECK(IsAudioThread()); |
| 886 DCHECK(IsGraphOwner()); | 907 DCHECK(IsGraphOwner()); |
| 887 | 908 |
| 888 // Resolve any pending promises created by resume(). Only do this if we | 909 // Resolve any pending promises created by resume(). Only do this if we |
| 889 // haven't already started resolving these promises. This gets called very | 910 // haven't already started resolving these promises. This gets called very |
| 890 // often and it takes some time to resolve the promises in the main thread. | 911 // often and it takes some time to resolve the promises in the main thread. |
| 891 if (!is_resolving_resume_promises_ && resume_resolvers_.size() > 0) { | 912 if (!is_resolving_resume_promises_ && resume_resolvers_.size() > 0) { |
| 892 is_resolving_resume_promises_ = true; | 913 is_resolving_resume_promises_ = true; |
| 893 Platform::Current()->MainThread()->GetWebTaskRunner()->PostTask( | 914 ScheduleMainThreadCleanup(); |
| 894 BLINK_FROM_HERE, | |
| 895 CrossThreadBind(&BaseAudioContext::ResolvePromisesForResumeOnMainThread, | |
| 896 WrapCrossThreadPersistent(this))); | |
| 897 } | 915 } |
| 898 } | 916 } |
| 899 | 917 |
| 900 void BaseAudioContext::RejectPendingDecodeAudioDataResolvers() { | 918 void BaseAudioContext::RejectPendingDecodeAudioDataResolvers() { |
| 901 // Now reject any pending decodeAudioData resolvers | 919 // Now reject any pending decodeAudioData resolvers |
| 902 for (auto& resolver : decode_audio_resolvers_) | 920 for (auto& resolver : decode_audio_resolvers_) |
| 903 resolver->Reject(DOMException::Create(kInvalidStateError, | 921 resolver->Reject(DOMException::Create(kInvalidStateError, |
| 904 "Audio context is going away")); | 922 "Audio context is going away")); |
| 905 decode_audio_resolvers_.clear(); | 923 decode_audio_resolvers_.clear(); |
| 906 } | 924 } |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1022 } | 1040 } |
| 1023 | 1041 |
| 1024 SecurityOrigin* BaseAudioContext::GetSecurityOrigin() const { | 1042 SecurityOrigin* BaseAudioContext::GetSecurityOrigin() const { |
| 1025 if (GetExecutionContext()) | 1043 if (GetExecutionContext()) |
| 1026 return GetExecutionContext()->GetSecurityOrigin(); | 1044 return GetExecutionContext()->GetSecurityOrigin(); |
| 1027 | 1045 |
| 1028 return nullptr; | 1046 return nullptr; |
| 1029 } | 1047 } |
| 1030 | 1048 |
| 1031 } // namespace blink | 1049 } // namespace blink |
| OLD | NEW |