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 #ifndef MEDIA_MIDI_MIDI_MANAGER_H_ 6 #define MEDIA_MIDI_MIDI_MANAGER_H_ 7 8 #include <map> 9 #include <set> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/synchronization/lock.h" 15 #include "base/time/time.h" 16 #include "media/base/media_export.h" 17 #include "media/midi/midi_port_info.h" 18 #include "media/midi/midi_result.h" 19 20 namespace base { 21 class SingleThreadTaskRunner; 22 } // namespace base 23 24 namespace media { 25 26 // A MidiManagerClient registers with the MidiManager to receive MIDI data. 27 // See MidiManager::RequestAccess() and MidiManager::ReleaseAccess() 28 // for details. 29 class MEDIA_EXPORT MidiManagerClient { 30 public: ~MidiManagerClient()31 virtual ~MidiManagerClient() {} 32 33 // CompleteStartSession() is called when platform dependent preparation is 34 // finished. 35 virtual void CompleteStartSession(int client_id, MidiResult result) = 0; 36 37 // ReceiveMidiData() is called when MIDI data has been received from the 38 // MIDI system. 39 // |port_index| represents the specific input port from input_ports(). 40 // |data| represents a series of bytes encoding one or more MIDI messages. 41 // |length| is the number of bytes in |data|. 42 // |timestamp| is the time the data was received, in seconds. 43 virtual void ReceiveMidiData(uint32 port_index, 44 const uint8* data, 45 size_t length, 46 double timestamp) = 0; 47 48 // AccumulateMidiBytesSent() is called to acknowledge when bytes have 49 // successfully been sent to the hardware. 50 // This happens as a result of the client having previously called 51 // MidiManager::DispatchSendMidiData(). 52 virtual void AccumulateMidiBytesSent(size_t n) = 0; 53 }; 54 55 // Manages access to all MIDI hardware. 56 class MEDIA_EXPORT MidiManager { 57 public: 58 static const size_t kMaxPendingClientCount = 128; 59 60 MidiManager(); 61 virtual ~MidiManager(); 62 63 // The constructor and the destructor will be called on the CrBrowserMain 64 // thread. 65 static MidiManager* Create(); 66 67 // A client calls StartSession() to receive and send MIDI data. 68 // If the session is ready to start, the MIDI system is lazily initialized 69 // and the client is registered to receive MIDI data. 70 // CompleteStartSession() is called with MIDI_OK if the session is started. 71 // Otherwise CompleteStartSession() is called with proper MidiResult code. 72 // StartSession() and EndSession() can be called on the Chrome_IOThread. 73 // CompleteStartSession() will be invoked on the same Chrome_IOThread. 74 void StartSession(MidiManagerClient* client, int client_id); 75 76 // A client calls EndSession() to stop receiving MIDI data. 77 void EndSession(MidiManagerClient* client); 78 79 // DispatchSendMidiData() is called when MIDI data should be sent to the MIDI 80 // system. 81 // This method is supposed to return immediately and should not block. 82 // |port_index| represents the specific output port from output_ports(). 83 // |data| represents a series of bytes encoding one or more MIDI messages. 84 // |length| is the number of bytes in |data|. 85 // |timestamp| is the time to send the data, in seconds. A value of 0 86 // means send "now" or as soon as possible. 87 // The default implementation is for unsupported platforms. 88 virtual void DispatchSendMidiData(MidiManagerClient* client, 89 uint32 port_index, 90 const std::vector<uint8>& data, 91 double timestamp); 92 93 // input_ports() is a list of MIDI ports for receiving MIDI data. 94 // Each individual port in this list can be identified by its 95 // integer index into this list. input_ports()96 const MidiPortInfoList& input_ports() const { return input_ports_; } 97 98 // output_ports() is a list of MIDI ports for sending MIDI data. 99 // Each individual port in this list can be identified by its 100 // integer index into this list. output_ports()101 const MidiPortInfoList& output_ports() const { return output_ports_; } 102 103 protected: 104 friend class MidiManagerUsb; 105 106 // Initializes the platform dependent MIDI system. MidiManager class has a 107 // default implementation that synchronously calls CompleteInitialization() 108 // with MIDI_NOT_SUPPORTED on the caller thread. A derived class for a 109 // specific platform should override this method correctly. 110 // This method is called on Chrome_IOThread thread inside StartSession(). 111 // Platform dependent initialization can be processed synchronously or 112 // asynchronously. When the initialization is completed, 113 // CompleteInitialization() should be called with |result|. 114 // |result| should be MIDI_OK on success, otherwise a proper MidiResult. 115 virtual void StartInitialization(); 116 117 // Called from a platform dependent implementation of StartInitialization(). 118 // It invokes CompleteInitializationInternal() on the thread that calls 119 // StartSession() and distributes |result| to MIDIManagerClient objects in 120 // |pending_clients_|. 121 void CompleteInitialization(MidiResult result); 122 123 void AddInputPort(const MidiPortInfo& info); 124 void AddOutputPort(const MidiPortInfo& info); 125 126 // Dispatches to all clients. 127 // TODO(toyoshim): Fix the mac implementation to use 128 // |ReceiveMidiData(..., base::TimeTicks)|. 129 void ReceiveMidiData(uint32 port_index, 130 const uint8* data, 131 size_t length, 132 double timestamp); 133 ReceiveMidiData(uint32 port_index,const uint8 * data,size_t length,base::TimeTicks time)134 void ReceiveMidiData(uint32 port_index, 135 const uint8* data, 136 size_t length, 137 base::TimeTicks time) { 138 ReceiveMidiData(port_index, data, length, 139 (time - base::TimeTicks()).InSecondsF()); 140 } 141 clients_size_for_testing()142 size_t clients_size_for_testing() const { return clients_.size(); } pending_clients_size_for_testing()143 size_t pending_clients_size_for_testing() const { 144 return pending_clients_.size(); 145 } 146 147 private: 148 void CompleteInitializationInternal(MidiResult result); 149 150 // Keeps track of all clients who wish to receive MIDI data. 151 typedef std::set<MidiManagerClient*> ClientList; 152 ClientList clients_; 153 154 // Keeps track of all clients who are waiting for CompleteStartSession(). 155 typedef std::multimap<MidiManagerClient*, int> PendingClientMap; 156 PendingClientMap pending_clients_; 157 158 // Keeps a SingleThreadTaskRunner of the thread that calls StartSession in 159 // order to invoke CompleteStartSession() on the thread. 160 scoped_refptr<base::SingleThreadTaskRunner> session_thread_runner_; 161 162 // Keeps true if platform dependent initialization is already completed. 163 bool initialized_; 164 165 // Keeps the platform dependent initialization result if initialization is 166 // completed. Otherwise keeps MIDI_NOT_SUPPORTED. 167 MidiResult result_; 168 169 // Protects access to |clients_|, |pending_clients_|, |initialized_|, and 170 // |result_|. 171 base::Lock lock_; 172 173 MidiPortInfoList input_ports_; 174 MidiPortInfoList output_ports_; 175 176 DISALLOW_COPY_AND_ASSIGN(MidiManager); 177 }; 178 179 } // namespace media 180 181 #endif // MEDIA_MIDI_MIDI_MANAGER_H_ 182