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 3 // found in the LICENSE file. 4 5 #include "media/midi/midi_manager.h" 6 7 #include "base/bind.h" 8 #include "base/debug/trace_event.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 12 namespace media { 13 14 MidiManager::MidiManager() 15 : initialized_(false), 16 result_(MIDI_NOT_SUPPORTED) { 17 } 18 19 MidiManager::~MidiManager() { 20 } 21 22 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(USE_ALSA) && \ 23 !defined(OS_ANDROID) && !defined(OS_CHROMEOS) 24 MidiManager* MidiManager::Create() { 25 return new MidiManager; 26 } 27 #endif 28 29 void MidiManager::StartSession(MidiManagerClient* client, int client_id) { 30 bool session_is_ready; 31 bool session_needs_initialization = false; 32 bool too_many_pending_clients_exist = false; 33 34 { 35 base::AutoLock auto_lock(lock_); 36 session_is_ready = initialized_; 37 if (!session_is_ready) { 38 // Do not accept a new request if the pending client list contains too 39 // many clients. 40 too_many_pending_clients_exist = 41 pending_clients_.size() >= kMaxPendingClientCount; 42 43 if (!too_many_pending_clients_exist) { 44 // Call StartInitialization() only for the first request. 45 session_needs_initialization = pending_clients_.empty(); 46 pending_clients_.insert(std::make_pair(client, client_id)); 47 } 48 } 49 } 50 51 // Lazily initialize the MIDI back-end. 52 if (!session_is_ready) { 53 if (session_needs_initialization) { 54 TRACE_EVENT0("midi", "MidiManager::StartInitialization"); 55 session_thread_runner_ = 56 base::MessageLoop::current()->message_loop_proxy(); 57 StartInitialization(); 58 } 59 if (too_many_pending_clients_exist) { 60 // Return an error immediately if there are too many requests. 61 client->CompleteStartSession(client_id, MIDI_INITIALIZATION_ERROR); 62 return; 63 } 64 // CompleteInitialization() will be called asynchronously when platform 65 // dependent initialization is finished. 66 return; 67 } 68 69 // Platform dependent initialization was already finished for previously 70 // initialized clients. 71 MidiResult result; 72 { 73 base::AutoLock auto_lock(lock_); 74 if (result_ == MIDI_OK) 75 clients_.insert(client); 76 result = result_; 77 } 78 client->CompleteStartSession(client_id, result); 79 } 80 81 void MidiManager::EndSession(MidiManagerClient* client) { 82 base::AutoLock auto_lock(lock_); 83 clients_.erase(client); 84 pending_clients_.erase(client); 85 } 86 87 void MidiManager::DispatchSendMidiData(MidiManagerClient* client, 88 uint32 port_index, 89 const std::vector<uint8>& data, 90 double timestamp) { 91 NOTREACHED(); 92 } 93 94 void MidiManager::StartInitialization() { 95 CompleteInitialization(MIDI_NOT_SUPPORTED); 96 } 97 98 void MidiManager::CompleteInitialization(MidiResult result) { 99 DCHECK(session_thread_runner_.get()); 100 // It is safe to post a task to the IO thread from here because the IO thread 101 // should have stopped if the MidiManager is going to be destructed. 102 session_thread_runner_->PostTask( 103 FROM_HERE, 104 base::Bind(&MidiManager::CompleteInitializationInternal, 105 base::Unretained(this), 106 result)); 107 } 108 109 void MidiManager::AddInputPort(const MidiPortInfo& info) { 110 input_ports_.push_back(info); 111 } 112 113 void MidiManager::AddOutputPort(const MidiPortInfo& info) { 114 output_ports_.push_back(info); 115 } 116 117 void MidiManager::ReceiveMidiData( 118 uint32 port_index, 119 const uint8* data, 120 size_t length, 121 double timestamp) { 122 base::AutoLock auto_lock(lock_); 123 124 for (ClientList::iterator i = clients_.begin(); i != clients_.end(); ++i) 125 (*i)->ReceiveMidiData(port_index, data, length, timestamp); 126 } 127 128 void MidiManager::CompleteInitializationInternal(MidiResult result) { 129 TRACE_EVENT0("midi", "MidiManager::CompleteInitialization"); 130 131 base::AutoLock auto_lock(lock_); 132 DCHECK(clients_.empty()); 133 DCHECK(!initialized_); 134 initialized_ = true; 135 result_ = result; 136 137 for (PendingClientMap::iterator it = pending_clients_.begin(); 138 it != pending_clients_.end(); 139 ++it) { 140 if (result_ == MIDI_OK) 141 clients_.insert(it->first); 142 it->first->CompleteStartSession(it->second, result_); 143 } 144 pending_clients_.clear(); 145 } 146 147 } // namespace media 148