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_mac.h" | 5 #include "media/midi/midi_manager_mac.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
13 | 13 |
14 #include <CoreAudio/HostTime.h> | 14 #include <CoreAudio/HostTime.h> |
15 | 15 |
16 using base::IntToString; | 16 using base::IntToString; |
17 using base::SysCFStringRefToUTF8; | 17 using base::SysCFStringRefToUTF8; |
18 using std::string; | 18 using std::string; |
19 | 19 |
20 // NB: System MIDI types are pointer types in 32-bit and integer types in | 20 // NB: System MIDI types are pointer types in 32-bit and integer types in |
21 // 64-bit. Therefore, the initialization is the simplest one that satisfies both | 21 // 64-bit. Therefore, the initialization is the simplest one that satisfies both |
22 // (if possible). | 22 // (if possible). |
23 | 23 |
24 namespace media { | 24 namespace media { |
25 | 25 |
26 MIDIManager* MIDIManager::Create() { | 26 MidiManager* MidiManager::Create() { |
27 return new MIDIManagerMac(); | 27 return new MidiManagerMac(); |
28 } | 28 } |
29 | 29 |
30 MIDIManagerMac::MIDIManagerMac() | 30 MidiManagerMac::MidiManagerMac() |
31 : midi_client_(0), | 31 : midi_client_(0), |
32 coremidi_input_(0), | 32 coremidi_input_(0), |
33 coremidi_output_(0), | 33 coremidi_output_(0), |
34 packet_list_(NULL), | 34 packet_list_(NULL), |
35 midi_packet_(NULL), | 35 midi_packet_(NULL), |
36 send_thread_("MIDISendThread") { | 36 send_thread_("MidiSendThread") { |
37 } | 37 } |
38 | 38 |
39 bool MIDIManagerMac::Initialize() { | 39 bool MidiManagerMac::Initialize() { |
40 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); | 40 TRACE_EVENT0("midi", "MidiManagerMac::Initialize"); |
41 | 41 |
42 // CoreMIDI registration. | 42 // CoreMIDI registration. |
43 midi_client_ = 0; | 43 midi_client_ = 0; |
44 OSStatus result = MIDIClientCreate( | 44 OSStatus result = MIDIClientCreate( |
45 CFSTR("Google Chrome"), | 45 CFSTR("Google Chrome"), |
46 NULL, | 46 NULL, |
47 NULL, | 47 NULL, |
48 &midi_client_); | 48 &midi_client_); |
49 | 49 |
50 if (result != noErr) | 50 if (result != noErr) |
51 return false; | 51 return false; |
52 | 52 |
53 coremidi_input_ = 0; | 53 coremidi_input_ = 0; |
54 | 54 |
55 // Create input and output port. | 55 // Create input and output port. |
56 result = MIDIInputPortCreate( | 56 result = MIDIInputPortCreate( |
57 midi_client_, | 57 midi_client_, |
58 CFSTR("MIDI Input"), | 58 CFSTR("MIDI Input"), |
59 ReadMIDIDispatch, | 59 ReadMidiDispatch, |
60 this, | 60 this, |
61 &coremidi_input_); | 61 &coremidi_input_); |
62 if (result != noErr) | 62 if (result != noErr) |
63 return false; | 63 return false; |
64 | 64 |
65 result = MIDIOutputPortCreate( | 65 result = MIDIOutputPortCreate( |
66 midi_client_, | 66 midi_client_, |
67 CFSTR("MIDI Output"), | 67 CFSTR("MIDI Output"), |
68 &coremidi_output_); | 68 &coremidi_output_); |
69 if (result != noErr) | 69 if (result != noErr) |
70 return false; | 70 return false; |
71 | 71 |
72 uint32 destination_count = MIDIGetNumberOfDestinations(); | 72 uint32 destination_count = MIDIGetNumberOfDestinations(); |
73 destinations_.resize(destination_count); | 73 destinations_.resize(destination_count); |
74 | 74 |
75 for (uint32 i = 0; i < destination_count ; i++) { | 75 for (uint32 i = 0; i < destination_count ; i++) { |
76 MIDIEndpointRef destination = MIDIGetDestination(i); | 76 MIDIEndpointRef destination = MIDIGetDestination(i); |
77 | 77 |
78 // Keep track of all destinations (known as outputs by the Web MIDI API). | 78 // Keep track of all destinations (known as outputs by the Web MIDI API). |
79 // Cache to avoid any possible overhead in calling MIDIGetDestination(). | 79 // Cache to avoid any possible overhead in calling MIDIGetDestination(). |
80 destinations_[i] = destination; | 80 destinations_[i] = destination; |
81 | 81 |
82 MIDIPortInfo info = GetPortInfoFromEndpoint(destination); | 82 MidiPortInfo info = GetPortInfoFromEndpoint(destination); |
83 AddOutputPort(info); | 83 AddOutputPort(info); |
84 } | 84 } |
85 | 85 |
86 // Open connections from all sources. | 86 // Open connections from all sources. |
87 uint32 source_count = MIDIGetNumberOfSources(); | 87 uint32 source_count = MIDIGetNumberOfSources(); |
88 | 88 |
89 for (uint32 i = 0; i < source_count; ++i) { | 89 for (uint32 i = 0; i < source_count; ++i) { |
90 // Receive from all sources. | 90 // Receive from all sources. |
91 MIDIEndpointRef src = MIDIGetSource(i); | 91 MIDIEndpointRef src = MIDIGetSource(i); |
92 MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src)); | 92 MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src)); |
93 | 93 |
94 // Keep track of all sources (known as inputs in Web MIDI API terminology). | 94 // Keep track of all sources (known as inputs in Web MIDI API terminology). |
95 source_map_[src] = i; | 95 source_map_[src] = i; |
96 | 96 |
97 MIDIPortInfo info = GetPortInfoFromEndpoint(src); | 97 MidiPortInfo info = GetPortInfoFromEndpoint(src); |
98 AddInputPort(info); | 98 AddInputPort(info); |
99 } | 99 } |
100 | 100 |
101 // TODO(crogers): Fix the memory management here! | 101 // TODO(toyoshim): Fix the memory management here! |
palmer
2014/01/31 19:40:01
Should I be concerned? :)
Takashi Toyoshima
2014/02/03 04:24:53
Actually, I already fixed some memory problems rel
| |
102 packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_); | 102 packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_); |
103 midi_packet_ = MIDIPacketListInit(packet_list_); | 103 midi_packet_ = MIDIPacketListInit(packet_list_); |
104 | 104 |
105 return true; | 105 return true; |
106 } | 106 } |
107 | 107 |
108 void MIDIManagerMac::DispatchSendMIDIData(MIDIManagerClient* client, | 108 void MidiManagerMac::DispatchSendMidiData(MidiManagerClient* client, |
109 uint32 port_index, | 109 uint32 port_index, |
110 const std::vector<uint8>& data, | 110 const std::vector<uint8>& data, |
111 double timestamp) { | 111 double timestamp) { |
112 if (!send_thread_.IsRunning()) | 112 if (!send_thread_.IsRunning()) |
113 send_thread_.Start(); | 113 send_thread_.Start(); |
114 | 114 |
115 // OK to use base::Unretained(this) since we join to thread in dtor(). | 115 // OK to use base::Unretained(this) since we join to thread in dtor(). |
116 send_thread_.message_loop()->PostTask( | 116 send_thread_.message_loop()->PostTask( |
117 FROM_HERE, | 117 FROM_HERE, |
118 base::Bind(&MIDIManagerMac::SendMIDIData, base::Unretained(this), | 118 base::Bind(&MidiManagerMac::SendMidiData, base::Unretained(this), |
119 client, port_index, data, timestamp)); | 119 client, port_index, data, timestamp)); |
120 } | 120 } |
121 | 121 |
122 MIDIManagerMac::~MIDIManagerMac() { | 122 MidiManagerMac::~MidiManagerMac() { |
123 // Wait for the termination of |send_thread_| before disposing MIDI ports. | 123 // Wait for the termination of |send_thread_| before disposing MIDI ports. |
124 send_thread_.Stop(); | 124 send_thread_.Stop(); |
125 | 125 |
126 if (coremidi_input_) | 126 if (coremidi_input_) |
127 MIDIPortDispose(coremidi_input_); | 127 MIDIPortDispose(coremidi_input_); |
128 if (coremidi_output_) | 128 if (coremidi_output_) |
129 MIDIPortDispose(coremidi_output_); | 129 MIDIPortDispose(coremidi_output_); |
130 } | 130 } |
131 | 131 |
132 // static | 132 // static |
133 void MIDIManagerMac::ReadMIDIDispatch(const MIDIPacketList* packet_list, | 133 void MidiManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list, |
134 void* read_proc_refcon, | 134 void* read_proc_refcon, |
135 void* src_conn_refcon) { | 135 void* src_conn_refcon) { |
136 MIDIManagerMac* manager = static_cast<MIDIManagerMac*>(read_proc_refcon); | 136 MidiManagerMac* manager = static_cast<MidiManagerMac*>(read_proc_refcon); |
137 #if __LP64__ | 137 #if __LP64__ |
138 MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon); | 138 MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon); |
139 #else | 139 #else |
140 MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon); | 140 MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon); |
141 #endif | 141 #endif |
142 | 142 |
143 // Dispatch to class method. | 143 // Dispatch to class method. |
144 manager->ReadMIDI(source, packet_list); | 144 manager->ReadMidi(source, packet_list); |
145 } | 145 } |
146 | 146 |
147 void MIDIManagerMac::ReadMIDI(MIDIEndpointRef source, | 147 void MidiManagerMac::ReadMidi(MIDIEndpointRef source, |
148 const MIDIPacketList* packet_list) { | 148 const MIDIPacketList* packet_list) { |
149 // Lookup the port index based on the source. | 149 // Lookup the port index based on the source. |
150 SourceMap::iterator j = source_map_.find(source); | 150 SourceMap::iterator j = source_map_.find(source); |
151 if (j == source_map_.end()) | 151 if (j == source_map_.end()) |
152 return; | 152 return; |
153 uint32 port_index = source_map_[source]; | 153 uint32 port_index = source_map_[source]; |
154 | 154 |
155 // Go through each packet and process separately. | 155 // Go through each packet and process separately. |
156 for (size_t i = 0; i < packet_list->numPackets; i++) { | 156 for (size_t i = 0; i < packet_list->numPackets; i++) { |
157 // Each packet contains MIDI data for one or more messages (like note-on). | 157 // Each packet contains MIDI data for one or more messages (like note-on). |
158 const MIDIPacket &packet = packet_list->packet[i]; | 158 const MIDIPacket &packet = packet_list->packet[i]; |
159 double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp); | 159 double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp); |
160 | 160 |
161 ReceiveMIDIData( | 161 ReceiveMidiData( |
162 port_index, | 162 port_index, |
163 packet.data, | 163 packet.data, |
164 packet.length, | 164 packet.length, |
165 timestamp_seconds); | 165 timestamp_seconds); |
166 } | 166 } |
167 } | 167 } |
168 | 168 |
169 void MIDIManagerMac::SendMIDIData(MIDIManagerClient* client, | 169 void MidiManagerMac::SendMidiData(MidiManagerClient* client, |
170 uint32 port_index, | 170 uint32 port_index, |
171 const std::vector<uint8>& data, | 171 const std::vector<uint8>& data, |
172 double timestamp) { | 172 double timestamp) { |
173 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 173 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
174 | 174 |
175 // System Exclusive has already been filtered. | 175 // System Exclusive has already been filtered. |
176 MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp); | 176 MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp); |
177 | 177 |
178 midi_packet_ = MIDIPacketListAdd( | 178 midi_packet_ = MIDIPacketListAdd( |
179 packet_list_, | 179 packet_list_, |
180 kMaxPacketListSize, | 180 kMaxPacketListSize, |
181 midi_packet_, | 181 midi_packet_, |
182 coremidi_timestamp, | 182 coremidi_timestamp, |
183 data.size(), | 183 data.size(), |
184 &data[0]); | 184 &data[0]); |
185 | 185 |
186 // Lookup the destination based on the port index. | 186 // Lookup the destination based on the port index. |
187 if (static_cast<size_t>(port_index) >= destinations_.size()) | 187 if (static_cast<size_t>(port_index) >= destinations_.size()) |
188 return; | 188 return; |
189 | 189 |
190 MIDIEndpointRef destination = destinations_[port_index]; | 190 MIDIEndpointRef destination = destinations_[port_index]; |
191 | 191 |
192 MIDISend(coremidi_output_, destination, packet_list_); | 192 MIDISend(coremidi_output_, destination, packet_list_); |
193 | 193 |
194 // Re-initialize for next time. | 194 // Re-initialize for next time. |
195 midi_packet_ = MIDIPacketListInit(packet_list_); | 195 midi_packet_ = MIDIPacketListInit(packet_list_); |
196 | 196 |
197 client->AccumulateMIDIBytesSent(data.size()); | 197 client->AccumulateMidiBytesSent(data.size()); |
198 } | 198 } |
199 | 199 |
200 // static | 200 // static |
201 MIDIPortInfo MIDIManagerMac::GetPortInfoFromEndpoint( | 201 MidiPortInfo MidiManagerMac::GetPortInfoFromEndpoint( |
202 MIDIEndpointRef endpoint) { | 202 MIDIEndpointRef endpoint) { |
203 SInt32 id_number = 0; | 203 SInt32 id_number = 0; |
204 MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number); | 204 MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number); |
205 string id = IntToString(id_number); | 205 string id = IntToString(id_number); |
206 | 206 |
207 string manufacturer; | 207 string manufacturer; |
208 CFStringRef manufacturer_ref = NULL; | 208 CFStringRef manufacturer_ref = NULL; |
209 OSStatus result = MIDIObjectGetStringProperty( | 209 OSStatus result = MIDIObjectGetStringProperty( |
210 endpoint, kMIDIPropertyManufacturer, &manufacturer_ref); | 210 endpoint, kMIDIPropertyManufacturer, &manufacturer_ref); |
211 if (result == noErr) { | 211 if (result == noErr) { |
(...skipping 19 matching lines...) Expand all Loading... | |
231 endpoint, kMIDIPropertyDriverVersion, &version_number); | 231 endpoint, kMIDIPropertyDriverVersion, &version_number); |
232 if (result == noErr) { | 232 if (result == noErr) { |
233 version = IntToString(version_number); | 233 version = IntToString(version_number); |
234 } else { | 234 } else { |
235 // kMIDIPropertyDriverVersion is not supported in IAC driver providing | 235 // kMIDIPropertyDriverVersion is not supported in IAC driver providing |
236 // endpoints, and the result will be kMIDIUnknownProperty (-10835). | 236 // endpoints, and the result will be kMIDIUnknownProperty (-10835). |
237 DLOG(WARNING) << "Failed to get kMIDIPropertyDriverVersion with status " | 237 DLOG(WARNING) << "Failed to get kMIDIPropertyDriverVersion with status " |
238 << result; | 238 << result; |
239 } | 239 } |
240 | 240 |
241 return MIDIPortInfo(id, manufacturer, name, version); | 241 return MidiPortInfo(id, manufacturer, name, version); |
242 } | 242 } |
243 | 243 |
244 // static | 244 // static |
245 double MIDIManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) { | 245 double MidiManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) { |
246 UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp); | 246 UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp); |
247 return static_cast<double>(nanoseconds) / 1.0e9; | 247 return static_cast<double>(nanoseconds) / 1.0e9; |
248 } | 248 } |
249 | 249 |
250 // static | 250 // static |
251 MIDITimeStamp MIDIManagerMac::SecondsToMIDITimeStamp(double seconds) { | 251 MIDITimeStamp MidiManagerMac::SecondsToMIDITimeStamp(double seconds) { |
252 UInt64 nanos = UInt64(seconds * 1.0e9); | 252 UInt64 nanos = UInt64(seconds * 1.0e9); |
253 return AudioConvertNanosToHostTime(nanos); | 253 return AudioConvertNanosToHostTime(nanos); |
254 } | 254 } |
255 | 255 |
256 } // namespace media | 256 } // namespace media |
OLD | NEW |