Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: media/midi/usb_midi_descriptor_parser.cc

Issue 105043008: Introduce USB MIDI descriptor parser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 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.
4
5 #include "media/midi/usb_midi_descriptor_parser.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10
11 namespace media {
12
13 namespace {
14
15 // The constants below are specified in USB spec, USB audio spec
16 // and USB midi spec.
17
18 enum DescriptorType {
19 TYPE_DEVICE = 1,
20 TYPE_CONFIGURATION = 2,
21 TYPE_STRING = 3,
22 TYPE_INTERFACE = 4,
23 TYPE_ENDPOINT = 5,
24 TYPE_DEVICE_QUALIFIER = 6,
25 TYPE_OTHER_SPEED_CONFIGURATION = 7,
26 TYPE_INTERFACE_POWER = 8,
27
28 TYPE_CS_INTERFACE = 36,
29 TYPE_CS_ENDPOINT = 37,
30 };
31
32 enum DescriptorSubType {
33 SUBTYPE_MS_DESCRIPTOR_UNDEFINED = 0,
34 SUBTYPE_MS_HEADER = 1,
35 SUBTYPE_MIDI_IN_JACK = 2,
36 SUBTYPE_MIDI_OUT_JACK = 3,
37 SUBTYPE_ELEMENT = 4,
38 };
39
40 enum JackType {
41 JACK_TYPE_UNDEFINED = 0,
42 JACK_TYPE_EMBEDDED = 1,
43 JACK_TYPE_EXTERNAL = 2,
44 };
45
46 const uint8 kAudioInterfaceClass = 1;
47 const uint8 kAudioMidiInterfaceSubclass = 3;
48
49 class JackMatcher {
50 public:
51 explicit JackMatcher(uint8 id) : id_(id) {}
52
53 bool operator() (const UsbMidiJack& jack) const {
54 return jack.jack_id == id_;
55 }
56
57 private:
58 uint8 id_;
59 };
60
61 } // namespace
62
63 UsbMidiDescriptorParser::UsbMidiDescriptorParser()
64 : is_parsing_usb_midi_interface_(false),
65 current_endpoint_address_(0),
66 current_cable_number_(0) {}
67
68 UsbMidiDescriptorParser::~UsbMidiDescriptorParser() {}
69
70 bool UsbMidiDescriptorParser::Parse(UsbMidiDevice* device,
71 const uint8* data,
72 size_t size,
73 std::vector<UsbMidiJack>* jacks) {
74 jacks->clear();
75 bool result = ParseInternal(device, data, size, jacks);
76 if (!result)
77 jacks->clear();
78 Clear();
79 return result;
80 }
81
82 bool UsbMidiDescriptorParser::ParseInternal(UsbMidiDevice* device,
83 const uint8* data,
84 size_t size,
85 std::vector<UsbMidiJack>* jacks) {
86 for (const uint8* current = data;
87 current < data + size;
88 current += current[0]) {
89 uint8 length = current[0];
90 if (length < 2) {
91 DVLOG(1) << "Descriptor Type is not accessible.";
92 return false;
93 }
94 if (current + length > data + size) {
95 DVLOG(1) << "The header size is incorrect.";
96 return false;
97 }
98 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]);
99 const bool is_interface = descriptor_type == TYPE_INTERFACE;
DaleCurtis 2014/01/10 02:40:14 Unnecessary to extract as const if you're only usi
yhirano 2014/01/10 03:14:36 Done.
100 if (!is_interface && !is_parsing_usb_midi_interface_)
101 continue;
102
103 switch (descriptor_type) {
104 case TYPE_INTERFACE:
105 if (!ParseInterface(current, length))
106 return false;
107 break;
108 case TYPE_CS_INTERFACE:
109 // We are assuming that the corresponding INTERFACE precedes
110 // the CS_INTERFACE descriptor, as specified.
111 if (!ParseCSInterface(device, current, length))
112 return false;
113 break;
114 case TYPE_ENDPOINT:
115 // We are assuming that endpoints are contained in an interface.
116 if (!ParseEndpoint(current, length))
117 return false;
118 break;
119 case TYPE_CS_ENDPOINT:
120 // We are assuming that the corresponding ENDPOINT precedes
121 // the CS_ENDPOINT descriptor, as specified.
122 if (!ParseCSEndpoint(current, length, jacks))
123 return false;
124 break;
125 default:
126 // Ignore uninteresting types.
127 break;
128 }
129 }
130 return true;
131 }
132
133 bool UsbMidiDescriptorParser::ParseInterface(const uint8* data, size_t size) {
134 if (size != 9) {
135 DVLOG(1) << "INTERFACE header size is incorrect.";
136 return false;
137 }
138 incomplete_jacks_.clear();
139
140 uint8 interface_class = data[5];
141 uint8 interface_subclass = data[6];
142
143 // All descriptors of endpoints contained in this interface
144 // precede the next INTERFACE descriptor.
145 is_parsing_usb_midi_interface_ =
146 interface_class == kAudioInterfaceClass &&
147 interface_subclass == kAudioMidiInterfaceSubclass;
148 return true;
149 }
150
151 bool UsbMidiDescriptorParser::ParseCSInterface(UsbMidiDevice* device,
152 const uint8* data,
153 size_t size) {
154 // Descriptor Type and Descriptor Subtype should be accessible.
155 if (size < 3) {
156 DVLOG(1) << "CS_INTERFACE header size is incorrect.";
157 return false;
158 }
159
160 DescriptorSubType subtype = static_cast<DescriptorSubType>(data[2]);
161
162 if (subtype != SUBTYPE_MIDI_OUT_JACK &&
163 subtype != SUBTYPE_MIDI_IN_JACK)
164 return true;
165
166 if (size < 6) {
167 DVLOG(1) << "CS_INTERFACE (MIDI JACK) header size is incorrect.";
168 return false;
169 }
170 uint8 jack_type = data[3];
171 uint8 id = data[4];
172 if (jack_type == JACK_TYPE_EMBEDDED) {
173 // We can't determine the associated endpoint now.
174 incomplete_jacks_.push_back(UsbMidiJack(device, id, 0, 0));
175 }
176 return true;
177 }
178
179 bool UsbMidiDescriptorParser::ParseEndpoint(const uint8* data, size_t size) {
180 if (size < 4) {
181 DVLOG(1) << "ENDPOINT header size is incorrect.";
182 return false;
183 }
184 current_endpoint_address_ = data[2];
185 current_cable_number_ = 0;
186 return true;
187 }
188
189 bool UsbMidiDescriptorParser::ParseCSEndpoint(const uint8* data,
190 size_t size,
191 std::vector<UsbMidiJack>* jacks) {
192 const size_t kSizeForEmptyJacks = 4;
193 // CS_ENDPOINT must be of size 4 + n where n is the number of associated
194 // jacks.
195 if (size < kSizeForEmptyJacks) {
196 DVLOG(1) << "CS_ENDPOINT header size is incorrect.";
197 return false;
198 }
199 uint8 num_jacks = data[3];
200 if (size != kSizeForEmptyJacks + num_jacks) {
201 DVLOG(1) << "CS_ENDPOINT header size is incorrect.";
202 return false;
203 }
204
205 for (size_t i = 0; i < num_jacks; ++i) {
206 uint8 jack = data[kSizeForEmptyJacks + i];
207 std::vector<UsbMidiJack>::iterator it =
208 std::find_if(incomplete_jacks_.begin(),
209 incomplete_jacks_.end(),
210 JackMatcher(jack));
211 if (it == incomplete_jacks_.end()) {
212 DVLOG(1) << "A non-existing MIDI jack is associated.";
213 return false;
214 }
215 if (current_cable_number_ > 0xf) {
216 DVLOG(1) << "Cable number should range from 0x0 to 0xf.";
217 return false;
218 }
219 // CS_ENDPOINT follows ENDPOINT and hence we can use the following
220 // member variables.
221 it->cable_number = current_cable_number_++;
222 it->endpoint_address = current_endpoint_address_;
223 jacks->push_back(*it);
224 incomplete_jacks_.erase(it);
225 }
226 return true;
227 }
228
229 void UsbMidiDescriptorParser::Clear() {
230 is_parsing_usb_midi_interface_ = false;
231 current_endpoint_address_ = 0;
232 current_cable_number_ = 0;
233 incomplete_jacks_.clear();
234 }
235
236 } // namespace media
OLDNEW
« no previous file with comments | « media/midi/usb_midi_descriptor_parser.h ('k') | media/midi/usb_midi_descriptor_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698