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 namespace { | 19 namespace { |
20 const char kUnknown[] = "[unknown]"; | 20 const char kUnknown[] = "[unknown]"; |
21 } // namespace | 21 } // namespace |
22 | 22 |
23 class MIDIManagerAlsa::MIDIDeviceInfo | 23 class MidiManagerAlsa::MidiDeviceInfo |
24 : public base::RefCounted<MIDIDeviceInfo> { | 24 : public base::RefCounted<MidiDeviceInfo> { |
25 public: | 25 public: |
26 MIDIDeviceInfo(MIDIManagerAlsa* manager, | 26 MidiDeviceInfo(MidiManagerAlsa* manager, |
27 const std::string& card, | 27 const std::string& card, |
28 const snd_rawmidi_info_t* midi, | 28 const snd_rawmidi_info_t* midi, |
29 int device) { | 29 int device) { |
30 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, card.c_str(), 0); | 30 opened_ = !snd_rawmidi_open(&midi_in_, &midi_out_, card.c_str(), 0); |
31 if (!opened_) | 31 if (!opened_) |
32 return; | 32 return; |
33 | 33 |
34 const std::string name = snd_rawmidi_info_get_name(midi); | 34 const std::string name = snd_rawmidi_info_get_name(midi); |
35 const std::string id = base::StringPrintf("%s:%d", card.c_str(), device); | 35 const std::string id = base::StringPrintf("%s:%d", card.c_str(), device); |
36 port_info_ = MIDIPortInfo(id, kUnknown, name, kUnknown); | 36 port_info_ = MidiPortInfo(id, kUnknown, name, kUnknown); |
37 } | 37 } |
38 | 38 |
39 void Send(MIDIManagerClient* client, const std::vector<uint8>& data) { | 39 void Send(MidiManagerClient* client, const std::vector<uint8>& data) { |
40 ssize_t result = snd_rawmidi_write( | 40 ssize_t result = snd_rawmidi_write( |
41 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); | 41 midi_out_, reinterpret_cast<const void*>(&data[0]), data.size()); |
42 if (static_cast<size_t>(result) != data.size()) { | 42 if (static_cast<size_t>(result) != data.size()) { |
43 // TODO(toyoshim): Disconnect and reopen the device. | 43 // TODO(toyoshim): Disconnect and reopen the device. |
44 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); | 44 LOG(ERROR) << "snd_rawmidi_write fails: " << strerror(-result); |
45 } | 45 } |
46 base::MessageLoop::current()->PostTask( | 46 base::MessageLoop::current()->PostTask( |
47 FROM_HERE, | 47 FROM_HERE, |
48 base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, | 48 base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
49 base::Unretained(client), data.size())); | 49 base::Unretained(client), data.size())); |
50 } | 50 } |
51 | 51 |
52 const MIDIPortInfo& GetMIDIPortInfo() const { return port_info_; } | 52 const MidiPortInfo& GetMidiPortInfo() const { return port_info_; } |
53 bool IsOpened() const { return opened_; } | 53 bool IsOpened() const { return opened_; } |
54 | 54 |
55 private: | 55 private: |
56 friend class base::RefCounted<MIDIDeviceInfo>; | 56 friend class base::RefCounted<MidiDeviceInfo>; |
57 virtual ~MIDIDeviceInfo() { | 57 virtual ~MidiDeviceInfo() { |
58 if (opened_) { | 58 if (opened_) { |
59 snd_rawmidi_close(midi_in_); | 59 snd_rawmidi_close(midi_in_); |
60 snd_rawmidi_close(midi_out_); | 60 snd_rawmidi_close(midi_out_); |
61 } | 61 } |
62 } | 62 } |
63 | 63 |
64 bool opened_; | 64 bool opened_; |
65 MIDIPortInfo port_info_; | 65 MidiPortInfo port_info_; |
66 snd_rawmidi_t* midi_in_; | 66 snd_rawmidi_t* midi_in_; |
67 snd_rawmidi_t* midi_out_; | 67 snd_rawmidi_t* midi_out_; |
68 | 68 |
69 DISALLOW_COPY_AND_ASSIGN(MIDIDeviceInfo); | 69 DISALLOW_COPY_AND_ASSIGN(MidiDeviceInfo); |
70 }; | 70 }; |
71 | 71 |
72 MIDIManagerAlsa::MIDIManagerAlsa() | 72 MidiManagerAlsa::MidiManagerAlsa() |
73 : send_thread_("MIDISendThread") { | 73 : send_thread_("MidiSendThread") { |
74 } | 74 } |
75 | 75 |
76 bool MIDIManagerAlsa::Initialize() { | 76 bool MidiManagerAlsa::Initialize() { |
77 // TODO(toyoshim): Make Initialize() asynchronous. | 77 // TODO(crbug.com/339746): Make Initialize() asynchronous. |
78 TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); | 78 TRACE_EVENT0("midi", "MidiManagerMac::Initialize"); |
79 | 79 |
80 // Enumerate only hardware MIDI devices because software MIDIs running in | 80 // Enumerate only hardware MIDI devices because software MIDIs running in |
81 // the browser process is not secure. | 81 // the browser process is not secure. |
82 snd_ctl_card_info_t* card; | 82 snd_ctl_card_info_t* card; |
83 snd_rawmidi_info_t* midi_out; | 83 snd_rawmidi_info_t* midi_out; |
84 snd_rawmidi_info_t* midi_in; | 84 snd_rawmidi_info_t* midi_in; |
85 snd_ctl_card_info_alloca(&card); | 85 snd_ctl_card_info_alloca(&card); |
86 snd_rawmidi_info_alloca(&midi_out); | 86 snd_rawmidi_info_alloca(&midi_out); |
87 snd_rawmidi_info_alloca(&midi_in); | 87 snd_rawmidi_info_alloca(&midi_in); |
88 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { | 88 for (int index = -1; !snd_card_next(&index) && index >= 0; ) { |
(...skipping 17 matching lines...) Expand all Loading... |
106 snd_rawmidi_info_set_device(midi_out, device); | 106 snd_rawmidi_info_set_device(midi_out, device); |
107 snd_rawmidi_info_set_subdevice(midi_out, 0); | 107 snd_rawmidi_info_set_subdevice(midi_out, 0); |
108 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | 108 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); |
109 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | 109 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; |
110 snd_rawmidi_info_set_device(midi_in, device); | 110 snd_rawmidi_info_set_device(midi_in, device); |
111 snd_rawmidi_info_set_subdevice(midi_in, 0); | 111 snd_rawmidi_info_set_subdevice(midi_in, 0); |
112 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | 112 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); |
113 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | 113 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; |
114 if (!output && !input) | 114 if (!output && !input) |
115 continue; | 115 continue; |
116 scoped_refptr<MIDIDeviceInfo> port = | 116 scoped_refptr<MidiDeviceInfo> port = |
117 new MIDIDeviceInfo(this, id, output ? midi_out : midi_in, device); | 117 new MidiDeviceInfo(this, id, output ? midi_out : midi_in, device); |
118 if (!port->IsOpened()) { | 118 if (!port->IsOpened()) { |
119 DLOG(ERROR) << "MIDIDeviceInfo open fails"; | 119 DLOG(ERROR) << "MidiDeviceInfo open fails"; |
120 continue; | 120 continue; |
121 } | 121 } |
122 if (input) { | 122 if (input) { |
123 in_devices_.push_back(port); | 123 in_devices_.push_back(port); |
124 AddInputPort(port->GetMIDIPortInfo()); | 124 AddInputPort(port->GetMidiPortInfo()); |
125 } | 125 } |
126 if (output) { | 126 if (output) { |
127 out_devices_.push_back(port); | 127 out_devices_.push_back(port); |
128 AddOutputPort(port->GetMIDIPortInfo()); | 128 AddOutputPort(port->GetMidiPortInfo()); |
129 } | 129 } |
130 } | 130 } |
131 snd_ctl_close(handle); | 131 snd_ctl_close(handle); |
132 } | 132 } |
133 return true; | 133 return true; |
134 } | 134 } |
135 | 135 |
136 MIDIManagerAlsa::~MIDIManagerAlsa() { | 136 MidiManagerAlsa::~MidiManagerAlsa() { |
137 send_thread_.Stop(); | 137 send_thread_.Stop(); |
138 } | 138 } |
139 | 139 |
140 void MIDIManagerAlsa::DispatchSendMIDIData(MIDIManagerClient* client, | 140 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
141 uint32 port_index, | 141 uint32 port_index, |
142 const std::vector<uint8>& data, | 142 const std::vector<uint8>& data, |
143 double timestamp) { | 143 double timestamp) { |
144 if (out_devices_.size() <= port_index) | 144 if (out_devices_.size() <= port_index) |
145 return; | 145 return; |
146 | 146 |
147 base::TimeDelta delay; | 147 base::TimeDelta delay; |
148 if (timestamp != 0.0) { | 148 if (timestamp != 0.0) { |
149 base::TimeTicks time_to_send = | 149 base::TimeTicks time_to_send = |
150 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 150 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
151 timestamp * base::Time::kMicrosecondsPerSecond); | 151 timestamp * base::Time::kMicrosecondsPerSecond); |
152 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 152 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
153 } | 153 } |
154 | 154 |
155 if (!send_thread_.IsRunning()) | 155 if (!send_thread_.IsRunning()) |
156 send_thread_.Start(); | 156 send_thread_.Start(); |
157 | 157 |
158 scoped_refptr<MIDIDeviceInfo> device = out_devices_[port_index]; | 158 scoped_refptr<MidiDeviceInfo> device = out_devices_[port_index]; |
159 send_thread_.message_loop()->PostDelayedTask( | 159 send_thread_.message_loop()->PostDelayedTask( |
160 FROM_HERE, | 160 FROM_HERE, |
161 base::Bind(&MIDIDeviceInfo::Send, device, client, data), | 161 base::Bind(&MidiDeviceInfo::Send, device, client, data), |
162 delay); | 162 delay); |
163 } | 163 } |
164 | 164 |
165 MIDIManager* MIDIManager::Create() { | 165 MidiManager* MidiManager::Create() { |
166 return new MIDIManagerAlsa(); | 166 return new MidiManagerAlsa(); |
167 } | 167 } |
168 | 168 |
169 } // namespace media | 169 } // namespace media |
OLD | NEW |