Fix some potential after free errors on TestCompletionCallback
[chromium-blink-merge.git] / media / midi / midi_manager_mac.cc
blobfa4b3fd7e12bc5a99dff35e231aa4b6526df0a5f
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.
5 #include "media/midi/midi_manager_mac.h"
7 #include <iostream>
8 #include <string>
10 #include "base/debug/trace_event.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include <CoreAudio/HostTime.h>
15 using base::IntToString;
16 using base::SysCFStringRefToUTF8;
17 using std::string;
19 // NB: System MIDI types are pointer types in 32-bit and integer types in
20 // 64-bit. Therefore, the initialization is the simplest one that satisfies both
21 // (if possible).
23 namespace media {
25 MIDIManager* MIDIManager::Create() {
26 return new MIDIManagerMac();
29 MIDIManagerMac::MIDIManagerMac()
30 : midi_client_(0),
31 coremidi_input_(0),
32 coremidi_output_(0),
33 packet_list_(NULL),
34 midi_packet_(NULL) {
37 bool MIDIManagerMac::Initialize() {
38 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize");
40 // CoreMIDI registration.
41 midi_client_ = 0;
42 OSStatus result = MIDIClientCreate(
43 CFSTR("Google Chrome"),
44 NULL,
45 NULL,
46 &midi_client_);
48 if (result != noErr)
49 return false;
51 coremidi_input_ = 0;
53 // Create input and output port.
54 result = MIDIInputPortCreate(
55 midi_client_,
56 CFSTR("MIDI Input"),
57 ReadMidiDispatch,
58 this,
59 &coremidi_input_);
60 if (result != noErr)
61 return false;
63 result = MIDIOutputPortCreate(
64 midi_client_,
65 CFSTR("MIDI Output"),
66 &coremidi_output_);
67 if (result != noErr)
68 return false;
70 int destination_count = MIDIGetNumberOfDestinations();
71 destinations_.reserve(destination_count);
73 for (int i = 0; i < destination_count ; i++) {
74 MIDIEndpointRef destination = MIDIGetDestination(i);
76 // Keep track of all destinations (known as outputs by the Web MIDI API).
77 // Cache to avoid any possible overhead in calling MIDIGetDestination().
78 destinations_[i] = destination;
80 MIDIPortInfo info = GetPortInfoFromEndpoint(destination);
81 AddOutputPort(info);
84 // Open connections from all sources.
85 int source_count = MIDIGetNumberOfSources();
87 for (int i = 0; i < source_count; ++i) {
88 // Receive from all sources.
89 MIDIEndpointRef src = MIDIGetSource(i);
90 MIDIPortConnectSource(coremidi_input_, src, reinterpret_cast<void*>(src));
92 // Keep track of all sources (known as inputs in Web MIDI API terminology).
93 source_map_[src] = i;
95 MIDIPortInfo info = GetPortInfoFromEndpoint(src);
96 AddInputPort(info);
99 // TODO(crogers): Fix the memory management here!
100 packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_);
101 midi_packet_ = MIDIPacketListInit(packet_list_);
103 return true;
106 MIDIManagerMac::~MIDIManagerMac() {
107 if (coremidi_input_)
108 MIDIPortDispose(coremidi_input_);
109 if (coremidi_output_)
110 MIDIPortDispose(coremidi_output_);
113 void MIDIManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list,
114 void* read_proc_refcon,
115 void* src_conn_refcon) {
116 MIDIManagerMac* manager = static_cast<MIDIManagerMac*>(read_proc_refcon);
117 #if __LP64__
118 MIDIEndpointRef source = reinterpret_cast<uintptr_t>(src_conn_refcon);
119 #else
120 MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon);
121 #endif
123 // Dispatch to class method.
124 manager->ReadMidi(source, packet_list);
127 void MIDIManagerMac::ReadMidi(MIDIEndpointRef source,
128 const MIDIPacketList* packet_list) {
129 // Lookup the port index based on the source.
130 SourceMap::iterator j = source_map_.find(source);
131 if (j == source_map_.end())
132 return;
133 int port_index = source_map_[source];
135 // Go through each packet and process separately.
136 for(size_t i = 0; i < packet_list->numPackets; i++) {
137 // Each packet contains MIDI data for one or more messages (like note-on).
138 const MIDIPacket &packet = packet_list->packet[i];
139 double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp);
141 ReceiveMIDIData(
142 port_index,
143 packet.data,
144 packet.length,
145 timestamp_seconds);
149 void MIDIManagerMac::SendMIDIData(int port_index,
150 const uint8* data,
151 size_t length,
152 double timestamp) {
153 // TODO(crogers): Filter out sysex.
155 MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp);
157 midi_packet_ = MIDIPacketListAdd(
158 packet_list_,
159 kMaxPacketListSize,
160 midi_packet_,
161 coremidi_timestamp,
162 length,
163 data);
165 // Lookup the destination based on the port index.
166 // TODO(crogers): re-factor |port_index| to use unsigned
167 // to avoid the need for this check.
168 if (port_index < 0 ||
169 static_cast<size_t>(port_index) >= destinations_.size())
170 return;
172 MIDIEndpointRef destination = destinations_[port_index];
174 MIDISend(coremidi_output_, destination, packet_list_);
176 // Re-initialize for next time.
177 midi_packet_ = MIDIPacketListInit(packet_list_);
180 MIDIPortInfo MIDIManagerMac::GetPortInfoFromEndpoint(
181 MIDIEndpointRef endpoint) {
182 SInt32 id_number = 0;
183 MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number);
184 string id = IntToString(id_number);
186 CFStringRef manufacturer_ref = NULL;
187 MIDIObjectGetStringProperty(
188 endpoint, kMIDIPropertyManufacturer, &manufacturer_ref);
189 string manufacturer = SysCFStringRefToUTF8(manufacturer_ref);
191 CFStringRef name_ref = NULL;
192 MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref);
193 string name = SysCFStringRefToUTF8(name_ref);
195 SInt32 version_number = 0;
196 MIDIObjectGetIntegerProperty(
197 endpoint, kMIDIPropertyDriverVersion, &version_number);
198 string version = IntToString(version_number);
200 return MIDIPortInfo(id, manufacturer, name, version);
203 double MIDIManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) {
204 UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp);
205 return static_cast<double>(nanoseconds) / 1.0e9;
208 MIDITimeStamp MIDIManagerMac::SecondsToMIDITimeStamp(double seconds) {
209 UInt64 nanos = UInt64(seconds * 1.0e9);
210 return AudioConvertNanosToHostTime(nanos);
213 } // namespace media