Chromium Code Reviews| 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 |