OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/midi/midi_manager.h" | 5 #include "media/midi/midi_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 SESSION_STARTED, | 31 SESSION_STARTED, |
32 SESSION_ENDED, | 32 SESSION_ENDED, |
33 INITIALIZED, | 33 INITIALIZED, |
34 INPUT_PORT_ADDED, | 34 INPUT_PORT_ADDED, |
35 OUTPUT_PORT_ADDED, | 35 OUTPUT_PORT_ADDED, |
36 | 36 |
37 // New items should be inserted here, and |MAX| should point the last item. | 37 // New items should be inserted here, and |MAX| should point the last item. |
38 MAX = INITIALIZED, | 38 MAX = INITIALIZED, |
39 }; | 39 }; |
40 | 40 |
41 // Used in StartSession. | |
42 enum class Completion { | |
43 COMPLETE_SYNCHRONOUSLY, | |
44 INVOKE_INITIALIZATION, | |
45 COMPLETE_ASYNCHRONOUSLY, | |
46 }; | |
47 | |
48 void ReportUsage(Usage usage) { | 41 void ReportUsage(Usage usage) { |
49 UMA_HISTOGRAM_ENUMERATION("Media.Midi.Usage", | 42 UMA_HISTOGRAM_ENUMERATION("Media.Midi.Usage", |
50 static_cast<Sample>(usage), | 43 static_cast<Sample>(usage), |
51 static_cast<Sample>(Usage::MAX) + 1); | 44 static_cast<Sample>(Usage::MAX) + 1); |
52 } | 45 } |
53 | 46 |
54 } // namespace | 47 } // namespace |
55 | 48 |
56 MidiManager::MidiManager() | 49 MidiManager::MidiManager() |
57 : initialized_(false), finalized_(false), result_(Result::NOT_INITIALIZED) { | 50 : initialization_state_(InitializationState::NOT_STARTED), |
51 finalized_(false), | |
52 result_(Result::NOT_INITIALIZED) { | |
58 ReportUsage(Usage::CREATED); | 53 ReportUsage(Usage::CREATED); |
59 } | 54 } |
60 | 55 |
61 MidiManager::~MidiManager() { | 56 MidiManager::~MidiManager() { |
62 // Make sure that Finalize() is called to clean up resources allocated on | 57 // Make sure that Finalize() is called to clean up resources allocated on |
63 // the Chrome_IOThread. | 58 // the Chrome_IOThread. |
64 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
65 CHECK(finalized_); | 60 CHECK(finalized_); |
66 } | 61 } |
67 | 62 |
(...skipping 16 matching lines...) Expand all Loading... | |
84 base::Unretained(this))); | 79 base::Unretained(this))); |
85 session_thread_runner_ = nullptr; | 80 session_thread_runner_ = nullptr; |
86 } else { | 81 } else { |
87 finalized_ = true; | 82 finalized_ = true; |
88 } | 83 } |
89 } | 84 } |
90 | 85 |
91 void MidiManager::StartSession(MidiManagerClient* client) { | 86 void MidiManager::StartSession(MidiManagerClient* client) { |
92 ReportUsage(Usage::SESSION_STARTED); | 87 ReportUsage(Usage::SESSION_STARTED); |
93 | 88 |
94 Completion completion = Completion::COMPLETE_SYNCHRONOUSLY; | 89 bool needs_initialization = false; |
95 Result result = Result::NOT_INITIALIZED; | |
96 | 90 |
97 { | 91 { |
98 base::AutoLock auto_lock(lock_); | 92 base::AutoLock auto_lock(lock_); |
99 if (clients_.find(client) != clients_.end() || | 93 if (clients_.find(client) != clients_.end() || |
100 pending_clients_.find(client) != pending_clients_.end()) { | 94 pending_clients_.find(client) != pending_clients_.end()) { |
101 // Should not happen. But just in case the renderer is compromised. | 95 // Should not happen. But just in case the renderer is compromised. |
102 NOTREACHED(); | 96 NOTREACHED(); |
103 return; | 97 return; |
104 } | 98 } |
105 | 99 |
106 if (initialized_) { | 100 // Do not accept a new request if Shutdown() was already called. |
Shao-Chuan Lee
2016/10/24 08:54:34
I guess this check should be moved in front of the
Takashi Toyoshima
2016/10/24 10:07:29
Thanks, this looks a nice improvement!
| |
101 if (finalized_) { | |
102 client->CompleteStartSession(Result::INITIALIZATION_ERROR); | |
103 return; | |
104 } | |
105 | |
106 if (initialization_state_ == InitializationState::COMPLETED) { | |
107 // Platform dependent initialization was already finished for previously | 107 // Platform dependent initialization was already finished for previously |
108 // initialized clients. | 108 // initialized clients. |
109 if (result_ == Result::OK) { | 109 if (result_ == Result::OK) { |
110 AddInitialPorts(client); | 110 AddInitialPorts(client); |
111 clients_.insert(client); | 111 clients_.insert(client); |
112 } | 112 } |
113 // Complete synchronously with |result_|; | 113 // Complete synchronously with |result_|; |
114 result = result_; | 114 client->CompleteStartSession(result_); |
115 } else { | 115 return; |
116 bool too_many_pending_clients_exist = | |
117 pending_clients_.size() >= kMaxPendingClientCount; | |
118 // Do not accept a new request if the pending client list contains too | |
119 // many clients, or Shutdown() was already called. | |
120 if (too_many_pending_clients_exist || finalized_) { | |
121 result = Result::INITIALIZATION_ERROR; | |
122 } else { | |
123 // Call StartInitialization() only for the first request. | |
124 if (pending_clients_.empty()) { | |
125 completion = Completion::INVOKE_INITIALIZATION; | |
126 session_thread_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
127 } else { | |
128 completion = Completion::COMPLETE_ASYNCHRONOUSLY; | |
129 } | |
130 pending_clients_.insert(client); | |
131 } | |
132 } | 116 } |
133 | 117 |
134 if (completion == Completion::COMPLETE_SYNCHRONOUSLY) { | 118 // Do not accept a new request if the pending client list contains too |
135 client->CompleteStartSession(result); | 119 // many clients. |
120 if (pending_clients_.size() >= kMaxPendingClientCount) { | |
121 client->CompleteStartSession(Result::INITIALIZATION_ERROR); | |
136 return; | 122 return; |
137 } | 123 } |
124 | |
125 if (initialization_state_ == InitializationState::NOT_STARTED) { | |
126 // Set fields protected by |lock_| here and call StartInitialization() | |
127 // later. | |
128 needs_initialization = true; | |
129 session_thread_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
130 initialization_state_ = InitializationState::STARTED; | |
131 } | |
132 | |
133 pending_clients_.insert(client); | |
138 } | 134 } |
139 | 135 |
140 if (completion == Completion::INVOKE_INITIALIZATION) { | 136 if (needs_initialization) { |
141 // Lazily initialize the MIDI back-end. | 137 // Lazily initialize the MIDI back-end. |
142 TRACE_EVENT0("midi", "MidiManager::StartInitialization"); | 138 TRACE_EVENT0("midi", "MidiManager::StartInitialization"); |
143 // CompleteInitialization() will be called asynchronously when platform | 139 // CompleteInitialization() will be called asynchronously when platform |
144 // dependent initialization is finished. | 140 // dependent initialization is finished. |
145 StartInitialization(); | 141 StartInitialization(); |
146 } | 142 } |
147 } | 143 } |
148 | 144 |
149 void MidiManager::EndSession(MidiManagerClient* client) { | 145 void MidiManager::EndSession(MidiManagerClient* client) { |
150 ReportUsage(Usage::SESSION_ENDED); | 146 ReportUsage(Usage::SESSION_ENDED); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
234 ReportUsage(Usage::INITIALIZED); | 230 ReportUsage(Usage::INITIALIZED); |
235 UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts", | 231 UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts", |
236 static_cast<Sample>(input_ports_.size()), | 232 static_cast<Sample>(input_ports_.size()), |
237 kMaxUmaDevices + 1); | 233 kMaxUmaDevices + 1); |
238 UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts", | 234 UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts", |
239 static_cast<Sample>(output_ports_.size()), | 235 static_cast<Sample>(output_ports_.size()), |
240 kMaxUmaDevices + 1); | 236 kMaxUmaDevices + 1); |
241 | 237 |
242 base::AutoLock auto_lock(lock_); | 238 base::AutoLock auto_lock(lock_); |
243 DCHECK(clients_.empty()); | 239 DCHECK(clients_.empty()); |
244 DCHECK(!initialized_); | 240 DCHECK_EQ(initialization_state_, InitializationState::STARTED); |
245 initialized_ = true; | 241 initialization_state_ = InitializationState::COMPLETED; |
246 result_ = result; | 242 result_ = result; |
247 | 243 |
248 for (auto* client : pending_clients_) { | 244 for (auto* client : pending_clients_) { |
249 if (result_ == Result::OK) { | 245 if (result_ == Result::OK) { |
250 AddInitialPorts(client); | 246 AddInitialPorts(client); |
251 clients_.insert(client); | 247 clients_.insert(client); |
252 } | 248 } |
253 client->CompleteStartSession(result_); | 249 client->CompleteStartSession(result_); |
254 } | 250 } |
255 pending_clients_.clear(); | 251 pending_clients_.clear(); |
(...skipping 12 matching lines...) Expand all Loading... | |
268 Finalize(); | 264 Finalize(); |
269 base::AutoLock auto_lock(lock_); | 265 base::AutoLock auto_lock(lock_); |
270 finalized_ = true; | 266 finalized_ = true; |
271 | 267 |
272 // Detach all clients so that they do not call MidiManager methods any more. | 268 // Detach all clients so that they do not call MidiManager methods any more. |
273 for (auto* client : clients_) | 269 for (auto* client : clients_) |
274 client->Detach(); | 270 client->Detach(); |
275 } | 271 } |
276 | 272 |
277 } // namespace midi | 273 } // namespace midi |
OLD | NEW |