| 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 |