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/usb_midi_descriptor_parser.h" | 5 #include "media/midi/usb_midi_descriptor_parser.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 SUBTYPE_MIDI_OUT_JACK = 3, | 38 SUBTYPE_MIDI_OUT_JACK = 3, |
39 SUBTYPE_ELEMENT = 4, | 39 SUBTYPE_ELEMENT = 4, |
40 }; | 40 }; |
41 | 41 |
42 enum JackType { | 42 enum JackType { |
43 JACK_TYPE_UNDEFINED = 0, | 43 JACK_TYPE_UNDEFINED = 0, |
44 JACK_TYPE_EMBEDDED = 1, | 44 JACK_TYPE_EMBEDDED = 1, |
45 JACK_TYPE_EXTERNAL = 2, | 45 JACK_TYPE_EXTERNAL = 2, |
46 }; | 46 }; |
47 | 47 |
48 const uint8 kAudioInterfaceClass = 1; | 48 const uint8_t kAudioInterfaceClass = 1; |
49 const uint8 kAudioMidiInterfaceSubclass = 3; | 49 const uint8_t kAudioMidiInterfaceSubclass = 3; |
50 | 50 |
51 class JackMatcher { | 51 class JackMatcher { |
52 public: | 52 public: |
53 explicit JackMatcher(uint8 id) : id_(id) {} | 53 explicit JackMatcher(uint8_t id) : id_(id) {} |
54 | 54 |
55 bool operator() (const UsbMidiJack& jack) const { | 55 bool operator() (const UsbMidiJack& jack) const { |
56 return jack.jack_id == id_; | 56 return jack.jack_id == id_; |
57 } | 57 } |
58 | 58 |
59 private: | 59 private: |
60 uint8 id_; | 60 uint8_t id_; |
61 }; | 61 }; |
62 | 62 |
63 int DecodeBcd(uint8 byte) { | 63 int DecodeBcd(uint8_t byte) { |
64 DCHECK_LT((byte & 0xf0) >> 4, 0xa); | 64 DCHECK_LT((byte & 0xf0) >> 4, 0xa); |
65 DCHECK_LT(byte & 0x0f, 0xa); | 65 DCHECK_LT(byte & 0x0f, 0xa); |
66 return ((byte & 0xf0) >> 4) * 10 + (byte & 0x0f); | 66 return ((byte & 0xf0) >> 4) * 10 + (byte & 0x0f); |
67 } | 67 } |
68 | 68 |
69 } // namespace | 69 } // namespace |
70 | 70 |
71 std::string UsbMidiDescriptorParser::DeviceInfo::BcdVersionToString( | 71 std::string UsbMidiDescriptorParser::DeviceInfo::BcdVersionToString( |
72 uint16 version) { | 72 uint16_t version) { |
73 return base::StringPrintf("%d.%02d", DecodeBcd(version >> 8), | 73 return base::StringPrintf("%d.%02d", DecodeBcd(version >> 8), |
74 DecodeBcd(version & 0xff)); | 74 DecodeBcd(version & 0xff)); |
75 } | 75 } |
76 | 76 |
77 UsbMidiDescriptorParser::UsbMidiDescriptorParser() | 77 UsbMidiDescriptorParser::UsbMidiDescriptorParser() |
78 : is_parsing_usb_midi_interface_(false), | 78 : is_parsing_usb_midi_interface_(false), |
79 current_endpoint_address_(0), | 79 current_endpoint_address_(0), |
80 current_cable_number_(0) {} | 80 current_cable_number_(0) {} |
81 | 81 |
82 UsbMidiDescriptorParser::~UsbMidiDescriptorParser() {} | 82 UsbMidiDescriptorParser::~UsbMidiDescriptorParser() {} |
83 | 83 |
84 bool UsbMidiDescriptorParser::Parse(UsbMidiDevice* device, | 84 bool UsbMidiDescriptorParser::Parse(UsbMidiDevice* device, |
85 const uint8* data, | 85 const uint8_t* data, |
86 size_t size, | 86 size_t size, |
87 std::vector<UsbMidiJack>* jacks) { | 87 std::vector<UsbMidiJack>* jacks) { |
88 jacks->clear(); | 88 jacks->clear(); |
89 bool result = ParseInternal(device, data, size, jacks); | 89 bool result = ParseInternal(device, data, size, jacks); |
90 if (!result) | 90 if (!result) |
91 jacks->clear(); | 91 jacks->clear(); |
92 Clear(); | 92 Clear(); |
93 return result; | 93 return result; |
94 } | 94 } |
95 | 95 |
96 bool UsbMidiDescriptorParser::ParseDeviceInfo( | 96 bool UsbMidiDescriptorParser::ParseDeviceInfo(const uint8_t* data, |
97 const uint8* data, size_t size, DeviceInfo* info) { | 97 size_t size, |
| 98 DeviceInfo* info) { |
98 *info = DeviceInfo(); | 99 *info = DeviceInfo(); |
99 for (const uint8* current = data; | 100 for (const uint8_t* current = data; current < data + size; |
100 current < data + size; | |
101 current += current[0]) { | 101 current += current[0]) { |
102 uint8 length = current[0]; | 102 uint8_t length = current[0]; |
103 if (length < 2) { | 103 if (length < 2) { |
104 DVLOG(1) << "Descriptor Type is not accessible."; | 104 DVLOG(1) << "Descriptor Type is not accessible."; |
105 return false; | 105 return false; |
106 } | 106 } |
107 if (current + length > data + size) { | 107 if (current + length > data + size) { |
108 DVLOG(1) << "The header size is incorrect."; | 108 DVLOG(1) << "The header size is incorrect."; |
109 return false; | 109 return false; |
110 } | 110 } |
111 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]); | 111 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]); |
112 if (descriptor_type != TYPE_DEVICE) | 112 if (descriptor_type != TYPE_DEVICE) |
113 continue; | 113 continue; |
114 // We assume that ParseDevice doesn't modify |*info| if it returns false. | 114 // We assume that ParseDevice doesn't modify |*info| if it returns false. |
115 return ParseDevice(current, length, info); | 115 return ParseDevice(current, length, info); |
116 } | 116 } |
117 // No DEVICE descriptor is found. | 117 // No DEVICE descriptor is found. |
118 return false; | 118 return false; |
119 } | 119 } |
120 | 120 |
121 bool UsbMidiDescriptorParser::ParseInternal(UsbMidiDevice* device, | 121 bool UsbMidiDescriptorParser::ParseInternal(UsbMidiDevice* device, |
122 const uint8* data, | 122 const uint8_t* data, |
123 size_t size, | 123 size_t size, |
124 std::vector<UsbMidiJack>* jacks) { | 124 std::vector<UsbMidiJack>* jacks) { |
125 for (const uint8* current = data; | 125 for (const uint8_t* current = data; current < data + size; |
126 current < data + size; | |
127 current += current[0]) { | 126 current += current[0]) { |
128 uint8 length = current[0]; | 127 uint8_t length = current[0]; |
129 if (length < 2) { | 128 if (length < 2) { |
130 DVLOG(1) << "Descriptor Type is not accessible."; | 129 DVLOG(1) << "Descriptor Type is not accessible."; |
131 return false; | 130 return false; |
132 } | 131 } |
133 if (current + length > data + size) { | 132 if (current + length > data + size) { |
134 DVLOG(1) << "The header size is incorrect."; | 133 DVLOG(1) << "The header size is incorrect."; |
135 return false; | 134 return false; |
136 } | 135 } |
137 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]); | 136 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]); |
138 if (descriptor_type != TYPE_INTERFACE && !is_parsing_usb_midi_interface_) | 137 if (descriptor_type != TYPE_INTERFACE && !is_parsing_usb_midi_interface_) |
(...skipping 22 matching lines...) Expand all Loading... |
161 return false; | 160 return false; |
162 break; | 161 break; |
163 default: | 162 default: |
164 // Ignore uninteresting types. | 163 // Ignore uninteresting types. |
165 break; | 164 break; |
166 } | 165 } |
167 } | 166 } |
168 return true; | 167 return true; |
169 } | 168 } |
170 | 169 |
171 bool UsbMidiDescriptorParser::ParseDevice( | 170 bool UsbMidiDescriptorParser::ParseDevice(const uint8_t* data, |
172 const uint8* data, size_t size, DeviceInfo* info) { | 171 size_t size, |
| 172 DeviceInfo* info) { |
173 if (size < 0x12) { | 173 if (size < 0x12) { |
174 DVLOG(1) << "DEVICE header size is incorrect."; | 174 DVLOG(1) << "DEVICE header size is incorrect."; |
175 return false; | 175 return false; |
176 } | 176 } |
177 | 177 |
178 info->vendor_id = data[8] | (data[9] << 8); | 178 info->vendor_id = data[8] | (data[9] << 8); |
179 info->product_id = data[0xa] | (data[0xb] << 8); | 179 info->product_id = data[0xa] | (data[0xb] << 8); |
180 info->bcd_device_version = data[0xc] | (data[0xd] << 8); | 180 info->bcd_device_version = data[0xc] | (data[0xd] << 8); |
181 info->manufacturer_index = data[0xe]; | 181 info->manufacturer_index = data[0xe]; |
182 info->product_index = data[0xf]; | 182 info->product_index = data[0xf]; |
183 return true; | 183 return true; |
184 } | 184 } |
185 | 185 |
186 bool UsbMidiDescriptorParser::ParseInterface(const uint8* data, size_t size) { | 186 bool UsbMidiDescriptorParser::ParseInterface(const uint8_t* data, size_t size) { |
187 if (size != 9) { | 187 if (size != 9) { |
188 DVLOG(1) << "INTERFACE header size is incorrect."; | 188 DVLOG(1) << "INTERFACE header size is incorrect."; |
189 return false; | 189 return false; |
190 } | 190 } |
191 incomplete_jacks_.clear(); | 191 incomplete_jacks_.clear(); |
192 | 192 |
193 uint8 interface_class = data[5]; | 193 uint8_t interface_class = data[5]; |
194 uint8 interface_subclass = data[6]; | 194 uint8_t interface_subclass = data[6]; |
195 | 195 |
196 // All descriptors of endpoints contained in this interface | 196 // All descriptors of endpoints contained in this interface |
197 // precede the next INTERFACE descriptor. | 197 // precede the next INTERFACE descriptor. |
198 is_parsing_usb_midi_interface_ = | 198 is_parsing_usb_midi_interface_ = |
199 interface_class == kAudioInterfaceClass && | 199 interface_class == kAudioInterfaceClass && |
200 interface_subclass == kAudioMidiInterfaceSubclass; | 200 interface_subclass == kAudioMidiInterfaceSubclass; |
201 return true; | 201 return true; |
202 } | 202 } |
203 | 203 |
204 bool UsbMidiDescriptorParser::ParseCSInterface(UsbMidiDevice* device, | 204 bool UsbMidiDescriptorParser::ParseCSInterface(UsbMidiDevice* device, |
205 const uint8* data, | 205 const uint8_t* data, |
206 size_t size) { | 206 size_t size) { |
207 // Descriptor Type and Descriptor Subtype should be accessible. | 207 // Descriptor Type and Descriptor Subtype should be accessible. |
208 if (size < 3) { | 208 if (size < 3) { |
209 DVLOG(1) << "CS_INTERFACE header size is incorrect."; | 209 DVLOG(1) << "CS_INTERFACE header size is incorrect."; |
210 return false; | 210 return false; |
211 } | 211 } |
212 | 212 |
213 DescriptorSubType subtype = static_cast<DescriptorSubType>(data[2]); | 213 DescriptorSubType subtype = static_cast<DescriptorSubType>(data[2]); |
214 | 214 |
215 if (subtype != SUBTYPE_MIDI_OUT_JACK && | 215 if (subtype != SUBTYPE_MIDI_OUT_JACK && |
216 subtype != SUBTYPE_MIDI_IN_JACK) | 216 subtype != SUBTYPE_MIDI_IN_JACK) |
217 return true; | 217 return true; |
218 | 218 |
219 if (size < 6) { | 219 if (size < 6) { |
220 DVLOG(1) << "CS_INTERFACE (MIDI JACK) header size is incorrect."; | 220 DVLOG(1) << "CS_INTERFACE (MIDI JACK) header size is incorrect."; |
221 return false; | 221 return false; |
222 } | 222 } |
223 uint8 jack_type = data[3]; | 223 uint8_t jack_type = data[3]; |
224 uint8 id = data[4]; | 224 uint8_t id = data[4]; |
225 if (jack_type == JACK_TYPE_EMBEDDED) { | 225 if (jack_type == JACK_TYPE_EMBEDDED) { |
226 // We can't determine the associated endpoint now. | 226 // We can't determine the associated endpoint now. |
227 incomplete_jacks_.push_back(UsbMidiJack(device, id, 0, 0)); | 227 incomplete_jacks_.push_back(UsbMidiJack(device, id, 0, 0)); |
228 } | 228 } |
229 return true; | 229 return true; |
230 } | 230 } |
231 | 231 |
232 bool UsbMidiDescriptorParser::ParseEndpoint(const uint8* data, size_t size) { | 232 bool UsbMidiDescriptorParser::ParseEndpoint(const uint8_t* data, size_t size) { |
233 if (size < 4) { | 233 if (size < 4) { |
234 DVLOG(1) << "ENDPOINT header size is incorrect."; | 234 DVLOG(1) << "ENDPOINT header size is incorrect."; |
235 return false; | 235 return false; |
236 } | 236 } |
237 current_endpoint_address_ = data[2]; | 237 current_endpoint_address_ = data[2]; |
238 current_cable_number_ = 0; | 238 current_cable_number_ = 0; |
239 return true; | 239 return true; |
240 } | 240 } |
241 | 241 |
242 bool UsbMidiDescriptorParser::ParseCSEndpoint(const uint8* data, | 242 bool UsbMidiDescriptorParser::ParseCSEndpoint(const uint8_t* data, |
243 size_t size, | 243 size_t size, |
244 std::vector<UsbMidiJack>* jacks) { | 244 std::vector<UsbMidiJack>* jacks) { |
245 const size_t kSizeForEmptyJacks = 4; | 245 const size_t kSizeForEmptyJacks = 4; |
246 // CS_ENDPOINT must be of size 4 + n where n is the number of associated | 246 // CS_ENDPOINT must be of size 4 + n where n is the number of associated |
247 // jacks. | 247 // jacks. |
248 if (size < kSizeForEmptyJacks) { | 248 if (size < kSizeForEmptyJacks) { |
249 DVLOG(1) << "CS_ENDPOINT header size is incorrect."; | 249 DVLOG(1) << "CS_ENDPOINT header size is incorrect."; |
250 return false; | 250 return false; |
251 } | 251 } |
252 uint8 num_jacks = data[3]; | 252 uint8_t num_jacks = data[3]; |
253 if (size != kSizeForEmptyJacks + num_jacks) { | 253 if (size != kSizeForEmptyJacks + num_jacks) { |
254 DVLOG(1) << "CS_ENDPOINT header size is incorrect."; | 254 DVLOG(1) << "CS_ENDPOINT header size is incorrect."; |
255 return false; | 255 return false; |
256 } | 256 } |
257 | 257 |
258 for (size_t i = 0; i < num_jacks; ++i) { | 258 for (size_t i = 0; i < num_jacks; ++i) { |
259 uint8 jack = data[kSizeForEmptyJacks + i]; | 259 uint8_t jack = data[kSizeForEmptyJacks + i]; |
260 std::vector<UsbMidiJack>::iterator it = | 260 std::vector<UsbMidiJack>::iterator it = |
261 std::find_if(incomplete_jacks_.begin(), | 261 std::find_if(incomplete_jacks_.begin(), |
262 incomplete_jacks_.end(), | 262 incomplete_jacks_.end(), |
263 JackMatcher(jack)); | 263 JackMatcher(jack)); |
264 if (it == incomplete_jacks_.end()) { | 264 if (it == incomplete_jacks_.end()) { |
265 DVLOG(1) << "A non-existing MIDI jack is associated."; | 265 DVLOG(1) << "A non-existing MIDI jack is associated."; |
266 return false; | 266 return false; |
267 } | 267 } |
268 if (current_cable_number_ > 0xf) { | 268 if (current_cable_number_ > 0xf) { |
269 DVLOG(1) << "Cable number should range from 0x0 to 0xf."; | 269 DVLOG(1) << "Cable number should range from 0x0 to 0xf."; |
(...skipping 11 matching lines...) Expand all Loading... |
281 | 281 |
282 void UsbMidiDescriptorParser::Clear() { | 282 void UsbMidiDescriptorParser::Clear() { |
283 is_parsing_usb_midi_interface_ = false; | 283 is_parsing_usb_midi_interface_ = false; |
284 current_endpoint_address_ = 0; | 284 current_endpoint_address_ = 0; |
285 current_cable_number_ = 0; | 285 current_cable_number_ = 0; |
286 incomplete_jacks_.clear(); | 286 incomplete_jacks_.clear(); |
287 } | 287 } |
288 | 288 |
289 } // namespace midi | 289 } // namespace midi |
290 } // namespace media | 290 } // namespace media |
OLD | NEW |