OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_alsa.h" | 5 #include "media/midi/midi_manager_alsa.h" |
6 | 6 |
7 #include <alsa/asoundlib.h> | 7 #include <alsa/asoundlib.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "base/threading/thread.h" | 15 #include "base/threading/thread.h" |
16 #include "media/midi/midi_port_info.h" | 16 #include "media/midi/midi_port_info.h" |
17 | 17 |
18 namespace media { | 18 namespace media { |
19 | 19 |
20 class MIDIManagerAlsa::MIDIDeviceInfo | 20 class MidiManagerAlsa::MidiDeviceInfo |
21 : public base::RefCounted<MIDIDeviceInfo> { | 21 : public base::RefCounted<MidiDeviceInfo> { |
22 public: | 22 public: |
23 MIDIDeviceInfo(MIDIManagerAlsa* manager, | 23 MidiDeviceInfo(MidiManagerAlsa* manager, |
24 const std::string& bus_id, | 24 const std::string& bus_id, |
25 snd_ctl_card_info_t* card, | 25 snd_ctl_card_info_t* card, |
26 const snd_rawmidi_info_t* midi, | 26 const snd_rawmidi_info_t* midi, |
27 int device) { | 27 int device) { |
28 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, bus_id.c_str(), 0); | 28 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, bus_id.c_str(), 0); |
29 if (!opened_) | 29 if (!opened_) |
30 return; | 30 return; |
31 | 31 |
32 const std::string id = base::StringPrintf("%s:%d", bus_id.c_str(), device); | 32 const std::string id = base::StringPrintf("%s:%d", bus_id.c_str(), device); |
33 const std::string name = snd_rawmidi_info_get_name(midi); | 33 const std::string name = snd_rawmidi_info_get_name(midi); |
34 // We assume that card longname is in the format of | 34 // We assume that card longname is in the format of |
35 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect | 35 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
36 // a manufacturer name here. | 36 // a manufacturer name here. |
37 std::string manufacturer; | 37 std::string manufacturer; |
38 const std::string card_name = snd_ctl_card_info_get_longname(card); | 38 const std::string card_name = snd_ctl_card_info_get_longname(card); |
39 size_t name_index = card_name.find(name); | 39 size_t name_index = card_name.find(name); |
40 if (std::string::npos != name_index) | 40 if (std::string::npos != name_index) |
41 manufacturer = card_name.substr(0, name_index - 1); | 41 manufacturer = card_name.substr(0, name_index - 1); |
42 const std::string version = | 42 const std::string version = |
43 base::StringPrintf("%s / ALSA library version %d.%d.%d", | 43 base::StringPrintf("%s / ALSA library version %d.%d.%d", |
44 snd_ctl_card_info_get_driver(card), | 44 snd_ctl_card_info_get_driver(card), |
45 SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR); | 45 SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR); |
46 port_info_ = MIDIPortInfo(id, manufacturer, name, version); | 46 port_info_ = MidiPortInfo(id, manufacturer, name, version); |
47 } | 47 } |
48 | 48 |
49 void Send(MIDIManagerClient* client, const std::vector<uint8>& data) { | 49 void Send(MidiManagerClient* client, const std::vector<uint8>& data) { |
50 ssize_t result = snd_rawmidi_write( | 50 ssize_t result = snd_rawmidi_write( |
51 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); | 51 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); |
52 if (static_cast<size_t>(result) != data.size()) { | 52 if (static_cast<size_t>(result) != data.size()) { |
53 // TODO(toyoshim): Disconnect and reopen the device. | 53 // TODO(toyoshim): Disconnect and reopen the device. |
54 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); | 54 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); |
55 } | 55 } |
56 base::MessageLoop::current()->PostTask( | 56 base::MessageLoop::current()->PostTask( |
57 FROM_HERE, | 57 FROM_HERE, |
58 base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, | 58 base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
59 base::Unretained(client), data.size())); | 59 base::Unretained(client), data.size())); |
60 } | 60 } |
61 | 61 |
62 const MIDIPortInfo& GetMIDIPortInfo() const { return port_info_; } | 62 const MidiPortInfo& GetMidiPortInfo() const { return port_info_; } |
63 bool IsOpened() const { return opened_; } | 63 bool IsOpened() const { return opened_; } |
64 | 64 |
65 private: | 65 private: |
66 friend class base::RefCounted<MIDIDeviceInfo>; | 66 friend class base::RefCounted<MidiDeviceInfo>; |
67 virtual ~MIDIDeviceInfo() { | 67 virtual ~MidiDeviceInfo() { |
68 if (opened_) { | 68 if (opened_) { |
69 snd_rawmidi_close(midi_in_); | 69 snd_rawmidi_close(midi_in_); |
70 snd_rawmidi_close(midi_out_); | 70 snd_rawmidi_close(midi_out_); |
71 } | 71 } |
72 } | 72 } |
73 | 73 |
74 bool opened_; | 74 bool opened_; |
75 MIDIPortInfo port_info_; | 75 MidiPortInfo port_info_; |
76 snd_rawmidi_t* midi_in_; | 76 snd_rawmidi_t* midi_in_; |
77 snd_rawmidi_t* midi_out_; | 77 snd_rawmidi_t* midi_out_; |
78 | 78 |
79 DISALLOW_COPY_AND_ASSIGN(MIDIDeviceInfo); | 79 DISALLOW_COPY_AND_ASSIGN(MidiDeviceInfo); |
80 }; | 80 }; |
81 | 81 |
82 MIDIManagerAlsa::MIDIManagerAlsa() | 82 MidiManagerAlsa::MidiManagerAlsa() |
83 : send_thread_("MIDISendThread") { | 83 : send_thread_("MidiSendThread") { |
84 } | 84 } |
85 | 85 |
86 bool MIDIManagerAlsa::Initialize() { | 86 bool MidiManagerAlsa::Initialize() { |
87 // TODO(toyoshim): Make Initialize() asynchronous. | 87 // TODO(toyoshim): Make Initialize() asynchronous. |
88 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); | 88 // See http://crbug.com/339746. |
| 89 TRACE_EVENT0("midi", "MidiManagerMac::Initialize"); |
89 | 90 |
90 // Enumerate only hardware MIDI devices because software MIDIs running in | 91 // Enumerate only hardware MIDI devices because software MIDIs running in |
91 // the browser process is not secure. | 92 // the browser process is not secure. |
92 snd_ctl_card_info_t* card; | 93 snd_ctl_card_info_t* card; |
93 snd_rawmidi_info_t* midi_out; | 94 snd_rawmidi_info_t* midi_out; |
94 snd_rawmidi_info_t* midi_in; | 95 snd_rawmidi_info_t* midi_in; |
95 snd_ctl_card_info_alloca(&card); | 96 snd_ctl_card_info_alloca(&card); |
96 snd_rawmidi_info_alloca(&midi_out); | 97 snd_rawmidi_info_alloca(&midi_out); |
97 snd_rawmidi_info_alloca(&midi_in); | 98 snd_rawmidi_info_alloca(&midi_in); |
98 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { | 99 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { |
(...skipping 17 matching lines...) Expand all Loading... |
116 snd_rawmidi_info_set_device(midi_out, device); | 117 snd_rawmidi_info_set_device(midi_out, device); |
117 snd_rawmidi_info_set_subdevice(midi_out, 0); | 118 snd_rawmidi_info_set_subdevice(midi_out, 0); |
118 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | 119 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); |
119 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | 120 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; |
120 snd_rawmidi_info_set_device(midi_in, device); | 121 snd_rawmidi_info_set_device(midi_in, device); |
121 snd_rawmidi_info_set_subdevice(midi_in, 0); | 122 snd_rawmidi_info_set_subdevice(midi_in, 0); |
122 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | 123 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); |
123 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | 124 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; |
124 if (!output && !input) | 125 if (!output && !input) |
125 continue; | 126 continue; |
126 scoped_refptr<MIDIDeviceInfo> port = new MIDIDeviceInfo( | 127 scoped_refptr<MidiDeviceInfo> port = new MidiDeviceInfo( |
127 this, id, card, output ? midi_out : midi_in, device); | 128 this, id, card, output ? midi_out : midi_in, device); |
128 if (!port->IsOpened()) { | 129 if (!port->IsOpened()) { |
129 DLOG(ERROR) << "MIDIDeviceInfo open fails"; | 130 DLOG(ERROR) << "MidiDeviceInfo open fails"; |
130 continue; | 131 continue; |
131 } | 132 } |
132 if (input) { | 133 if (input) { |
133 in_devices_.push_back(port); | 134 in_devices_.push_back(port); |
134 AddInputPort(port->GetMIDIPortInfo()); | 135 AddInputPort(port->GetMidiPortInfo()); |
135 } | 136 } |
136 if (output) { | 137 if (output) { |
137 out_devices_.push_back(port); | 138 out_devices_.push_back(port); |
138 AddOutputPort(port->GetMIDIPortInfo()); | 139 AddOutputPort(port->GetMidiPortInfo()); |
139 } | 140 } |
140 } | 141 } |
141 snd_ctl_close(handle); | 142 snd_ctl_close(handle); |
142 } | 143 } |
143 return true; | 144 return true; |
144 } | 145 } |
145 | 146 |
146 MIDIManagerAlsa::~MIDIManagerAlsa() { | 147 MidiManagerAlsa::~MidiManagerAlsa() { |
147 send_thread_.Stop(); | 148 send_thread_.Stop(); |
148 } | 149 } |
149 | 150 |
150 void MIDIManagerAlsa::DispatchSendMIDIData(MIDIManagerClient* client, | 151 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
151 uint32 port_index, | 152 uint32 port_index, |
152 const std::vector<uint8>& data, | 153 const std::vector<uint8>& data, |
153 double timestamp) { | 154 double timestamp) { |
154 if (out_devices_.size() <= port_index) | 155 if (out_devices_.size() <= port_index) |
155 return; | 156 return; |
156 | 157 |
157 base::TimeDelta delay; | 158 base::TimeDelta delay; |
158 if (timestamp != 0.0) { | 159 if (timestamp != 0.0) { |
159 base::TimeTicks time_to_send = | 160 base::TimeTicks time_to_send = |
160 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 161 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
161 timestamp * base::Time::kMicrosecondsPerSecond); | 162 timestamp * base::Time::kMicrosecondsPerSecond); |
162 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 163 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
163 } | 164 } |
164 | 165 |
165 if (!send_thread_.IsRunning()) | 166 if (!send_thread_.IsRunning()) |
166 send_thread_.Start(); | 167 send_thread_.Start(); |
167 | 168 |
168 scoped_refptr<MIDIDeviceInfo> device = out_devices_[port_index]; | 169 scoped_refptr<MidiDeviceInfo> device = out_devices_[port_index]; |
169 send_thread_.message_loop()->PostDelayedTask( | 170 send_thread_.message_loop()->PostDelayedTask( |
170 FROM_HERE, | 171 FROM_HERE, |
171 base::Bind(&MIDIDeviceInfo::Send, device, client, data), | 172 base::Bind(&MidiDeviceInfo::Send, device, client, data), |
172 delay); | 173 delay); |
173 } | 174 } |
174 | 175 |
175 MIDIManager* MIDIManager::Create() { | 176 MidiManager* MidiManager::Create() { |
176 return new MIDIManagerAlsa(); | 177 return new MidiManagerAlsa(); |
177 } | 178 } |
178 | 179 |
179 } // namespace media | 180 } // namespace media |
OLD | NEW |