OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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_output_stream.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "media/midi/usb_midi_device.h" | |
9 | |
10 namespace media { | |
11 | |
12 namespace { | |
13 | |
14 const uint8 kSysExByte = 0xf0; | |
15 const uint8 kSysExEndByte = 0xf7; | |
16 const uint8 kSystemMessagePattern = 0xf0; | |
Takashi Toyoshima
2013/12/24 07:39:41
We already have similar definitions at content/bro
yhirano
2014/01/14 10:52:49
Done.
| |
17 | |
18 } // namespace | |
19 | |
20 void UsbMidiOutputStream::Send(const std::vector<uint8>& data) { | |
21 // To prevent link errors caused by DCHECK_*. | |
Takashi Toyoshima
2013/12/24 07:39:41
It seems to be a check between a constant value an
yhirano
2014/01/14 10:52:49
The DCHECK_LE on l59 can't be replaced, so I would
| |
22 const size_t kPacketContentSize = UsbMidiOutputStream::kPacketContentSize; | |
23 DCHECK_LT(jack_.cable_number, 16u); | |
24 DCHECK_EQ(3u, kPacketContentSize); | |
25 | |
26 std::vector<uint8> data_to_send; | |
27 size_t current = 0; | |
28 size_t size = GetSize(data); | |
29 while (current < size) { | |
30 uint8 first_byte = Get(data, current); | |
31 if (first_byte == kSysExByte || is_sending_sysex_) { | |
32 // System Exclusive messages | |
33 if (!PushSysExMessage(data, ¤t, &data_to_send)) | |
34 break; | |
35 } else if ((first_byte & 0xf0) == kSystemMessagePattern) { | |
36 if (first_byte & 0x08) { | |
37 // System Real-Time messages | |
38 if (!PushSysRTMessage(data, ¤t, &data_to_send)) | |
39 break; | |
40 } else { | |
41 // System Common messages | |
42 if (!PushSysCommonMessage(data, ¤t, &data_to_send)) | |
43 break; | |
44 } | |
45 } else if (first_byte & 0x80) { | |
46 if (!PushChannelMessage(data, ¤t, &data_to_send)) | |
47 break; | |
48 } else { | |
49 // Unknown messages | |
50 DVLOG(1) << "Unknown byte: " << static_cast<unsigned int>(first_byte); | |
51 ++current; | |
52 } | |
53 } | |
54 | |
55 if (data_to_send.size() > 0) | |
56 jack_.device->Send(jack_.GetEndpointNumber(), data_to_send); | |
57 | |
58 DCHECK_LE(current, size); | |
59 DCHECK_LE(size - current, kPacketContentSize); | |
60 // Note that this can be a self-copying and the iteration order is important. | |
61 for (size_t i = current; i < size; ++i) | |
62 pending_data_[i - current] = Get(data, i); | |
63 pending_size_ = size - current; | |
64 } | |
65 | |
66 size_t UsbMidiOutputStream::GetSize(const std::vector<uint8>& data) const { | |
67 return data.size() + pending_size_; | |
68 } | |
69 | |
70 uint8_t UsbMidiOutputStream::Get(const std::vector<uint8>& data, | |
71 size_t index) const { | |
72 DCHECK_LT(index, GetSize(data)); | |
73 if (index < pending_size_) | |
74 return pending_data_[index]; | |
75 return data[index - pending_size_]; | |
76 } | |
77 | |
78 bool UsbMidiOutputStream::PushSysExMessage(const std::vector<uint8>& data, | |
79 size_t* current, | |
80 std::vector<uint8>* data_to_send) { | |
81 size_t index = *current; | |
82 for (size_t j = index; j < GetSize(data); ++j) { | |
83 if (j == index + 3) { | |
84 // We can't find the end-of-message mark in the three bytes. | |
85 *current = j; | |
86 data_to_send->push_back((jack_.cable_number << 4) | 0x4); | |
87 data_to_send->push_back(Get(data, index)); | |
88 data_to_send->push_back(Get(data, index + 1)); | |
89 data_to_send->push_back(Get(data, index + 2)); | |
90 is_sending_sysex_ = true; | |
91 return true; | |
92 } | |
93 if (Get(data, j) == kSysExEndByte) { | |
94 uint8 cin = (j - index) + 0x5; | |
95 DCHECK(cin == 0x5 || cin == 0x6 || cin == 0x7); | |
96 data_to_send->push_back((jack_.cable_number << 4) | cin); | |
97 for (size_t k = index; k < index + 3; ++k) | |
98 data_to_send->push_back(k <= j ? Get(data, k) : 0); | |
99 *current = j + 1; | |
100 is_sending_sysex_ = false; | |
101 return true; | |
102 } | |
103 } | |
104 return false; | |
105 } | |
106 | |
107 bool UsbMidiOutputStream::PushSysCommonMessage(const std::vector<uint8>& data, | |
108 size_t* current, | |
109 std::vector<uint8>* data_to_send) { | |
110 size_t index = *current; | |
111 uint8 first_byte = Get(data, index); | |
112 DCHECK_LE(0xf1, first_byte); | |
113 DCHECK_LE(first_byte, 0xf7); | |
114 const size_t message_size_table[8] = { | |
115 0, 2, 3, 2, 1, 1, 1, 0, | |
116 }; | |
117 size_t message_size = message_size_table[first_byte & 0x0f]; | |
118 DCHECK_NE(0u, message_size); | |
119 DCHECK_LE(message_size, 3u); | |
120 | |
121 if (GetSize(data) < index + message_size) { | |
122 // The message is incomplete. | |
123 return false; | |
124 } | |
125 | |
126 uint8 cin = message_size == 1 ? 0x5 : static_cast<uint8>(message_size); | |
127 data_to_send->push_back((jack_.cable_number << 4) | cin); | |
128 for (size_t i = index; i < index + 3; ++i) | |
129 data_to_send->push_back(i < index + message_size ? Get(data, i) : 0); | |
130 *current += message_size; | |
131 return true; | |
132 } | |
133 | |
134 bool UsbMidiOutputStream::PushSysRTMessage(const std::vector<uint8>& data, | |
135 size_t* current, | |
136 std::vector<uint8>* data_to_send) { | |
137 size_t index = *current; | |
138 uint8 first_byte = Get(data, index); | |
139 DCHECK_LE(0xf8, first_byte); | |
140 DCHECK_LE(first_byte, 0xff); | |
141 | |
142 data_to_send->push_back((jack_.cable_number << 4) | 0x5); | |
143 data_to_send->push_back(first_byte); | |
144 data_to_send->push_back(0); | |
145 data_to_send->push_back(0); | |
146 *current += 1; | |
147 return true; | |
148 } | |
149 | |
150 bool UsbMidiOutputStream::PushChannelMessage(const std::vector<uint8>& data, | |
151 size_t* current, | |
152 std::vector<uint8>* data_to_send) { | |
153 size_t index = *current; | |
154 uint8 first_byte = Get(data, index); | |
155 DCHECK_LE(0x80, (first_byte & 0xf0)); | |
156 DCHECK_LE((first_byte & 0xf0), 0xe0); | |
157 | |
158 const size_t message_size_table[8] = { | |
159 3, 3, 3, 3, 2, 3, 3, 0, | |
160 }; | |
161 uint8 cin = first_byte >> 4; | |
162 size_t message_size = message_size_table[cin & 0x7]; | |
163 DCHECK_NE(0u, message_size); | |
164 DCHECK_LE(message_size, 3u); | |
165 | |
166 if (GetSize(data) < index + message_size) { | |
167 // The message is incomplete. | |
168 return false; | |
169 } | |
170 | |
171 data_to_send->push_back((jack_.cable_number << 4) | cin); | |
172 for (size_t i = index; i < index + 3; ++i) | |
173 data_to_send->push_back(i < index + message_size ? Get(data, i) : 0); | |
174 *current += message_size; | |
175 return true; | |
176 } | |
177 | |
178 } // namespace media | |
OLD | NEW |