| 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 <errno.h> | 7 #include <errno.h> |
| 8 #include <poll.h> | 8 #include <poll.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 // Close the out client. This will trigger the event thread to stop, | 271 // Close the out client. This will trigger the event thread to stop, |
| 272 // because of SND_SEQ_EVENT_CLIENT_EXIT. | 272 // because of SND_SEQ_EVENT_CLIENT_EXIT. |
| 273 if (out_client_.get()) | 273 if (out_client_.get()) |
| 274 snd_seq_close(out_client_.release()); | 274 snd_seq_close(out_client_.release()); |
| 275 | 275 |
| 276 // Wait for the event thread to stop. | 276 // Wait for the event thread to stop. |
| 277 event_thread_.Stop(); | 277 event_thread_.Stop(); |
| 278 } | 278 } |
| 279 | 279 |
| 280 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, | 280 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
| 281 uint32 port_index, | 281 uint32_t port_index, |
| 282 const std::vector<uint8>& data, | 282 const std::vector<uint8_t>& data, |
| 283 double timestamp) { | 283 double timestamp) { |
| 284 if (!send_thread_.IsRunning()) | 284 if (!send_thread_.IsRunning()) |
| 285 send_thread_.Start(); | 285 send_thread_.Start(); |
| 286 | 286 |
| 287 base::TimeDelta delay; | 287 base::TimeDelta delay; |
| 288 if (timestamp != 0.0) { | 288 if (timestamp != 0.0) { |
| 289 base::TimeTicks time_to_send = | 289 base::TimeTicks time_to_send = |
| 290 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 290 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
| 291 timestamp * base::Time::kMicrosecondsPerSecond); | 291 timestamp * base::Time::kMicrosecondsPerSecond); |
| 292 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 292 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 std::string json; | 392 std::string json; |
| 393 JSONStringValueSerializer serializer(&json); | 393 JSONStringValueSerializer serializer(&json); |
| 394 serializer.Serialize(*Value().get()); | 394 serializer.Serialize(*Value().get()); |
| 395 return json; | 395 return json; |
| 396 } | 396 } |
| 397 | 397 |
| 398 // TODO(agoode): Do not use SHA256 here. Instead store a persistent | 398 // TODO(agoode): Do not use SHA256 here. Instead store a persistent |
| 399 // mapping and just use a UUID or other random string. | 399 // mapping and just use a UUID or other random string. |
| 400 // http://crbug.com/465320 | 400 // http://crbug.com/465320 |
| 401 std::string MidiManagerAlsa::MidiPort::OpaqueKey() const { | 401 std::string MidiManagerAlsa::MidiPort::OpaqueKey() const { |
| 402 uint8 hash[crypto::kSHA256Length]; | 402 uint8_t hash[crypto::kSHA256Length]; |
| 403 crypto::SHA256HashString(JSONValue(), &hash, sizeof(hash)); | 403 crypto::SHA256HashString(JSONValue(), &hash, sizeof(hash)); |
| 404 return base::HexEncode(&hash, sizeof(hash)); | 404 return base::HexEncode(&hash, sizeof(hash)); |
| 405 } | 405 } |
| 406 | 406 |
| 407 bool MidiManagerAlsa::MidiPort::MatchConnected(const MidiPort& query) const { | 407 bool MidiManagerAlsa::MidiPort::MatchConnected(const MidiPort& query) const { |
| 408 // Matches on: | 408 // Matches on: |
| 409 // connected == true | 409 // connected == true |
| 410 // type | 410 // type |
| 411 // path | 411 // path |
| 412 // id | 412 // id |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 } | 557 } |
| 558 | 558 |
| 559 // No match. | 559 // No match. |
| 560 return ports_.end(); | 560 return ports_.end(); |
| 561 } | 561 } |
| 562 | 562 |
| 563 MidiManagerAlsa::MidiPortStateBase::MidiPortStateBase() = default; | 563 MidiManagerAlsa::MidiPortStateBase::MidiPortStateBase() = default; |
| 564 | 564 |
| 565 MidiManagerAlsa::MidiPortState::MidiPortState() = default; | 565 MidiManagerAlsa::MidiPortState::MidiPortState() = default; |
| 566 | 566 |
| 567 uint32 MidiManagerAlsa::MidiPortState::push_back(scoped_ptr<MidiPort> port) { | 567 uint32_t MidiManagerAlsa::MidiPortState::push_back(scoped_ptr<MidiPort> port) { |
| 568 // Add the web midi index. | 568 // Add the web midi index. |
| 569 uint32 web_port_index = 0; | 569 uint32_t web_port_index = 0; |
| 570 switch (port->type()) { | 570 switch (port->type()) { |
| 571 case MidiPort::Type::kInput: | 571 case MidiPort::Type::kInput: |
| 572 web_port_index = num_input_ports_++; | 572 web_port_index = num_input_ports_++; |
| 573 break; | 573 break; |
| 574 case MidiPort::Type::kOutput: | 574 case MidiPort::Type::kOutput: |
| 575 web_port_index = num_output_ports_++; | 575 web_port_index = num_output_ports_++; |
| 576 break; | 576 break; |
| 577 } | 577 } |
| 578 port->set_web_port_index(web_port_index); | 578 port->set_web_port_index(web_port_index); |
| 579 MidiPortStateBase::push_back(port.Pass()); | 579 MidiPortStateBase::push_back(port.Pass()); |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 if (at_index && at_index != std::string::npos) { | 803 if (at_index && at_index != std::string::npos) { |
| 804 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); | 804 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
| 805 if (name_index && name_index != std::string::npos) | 805 if (name_index && name_index != std::string::npos) |
| 806 return alsa_longname.substr(0, name_index - 1); | 806 return alsa_longname.substr(0, name_index - 1); |
| 807 } | 807 } |
| 808 | 808 |
| 809 // Failure. | 809 // Failure. |
| 810 return ""; | 810 return ""; |
| 811 } | 811 } |
| 812 | 812 |
| 813 void MidiManagerAlsa::SendMidiData(uint32 port_index, | 813 void MidiManagerAlsa::SendMidiData(uint32_t port_index, |
| 814 const std::vector<uint8>& data) { | 814 const std::vector<uint8_t>& data) { |
| 815 DCHECK(send_thread_.task_runner()->BelongsToCurrentThread()); | 815 DCHECK(send_thread_.task_runner()->BelongsToCurrentThread()); |
| 816 | 816 |
| 817 snd_midi_event_t* encoder; | 817 snd_midi_event_t* encoder; |
| 818 snd_midi_event_new(kSendBufferSize, &encoder); | 818 snd_midi_event_new(kSendBufferSize, &encoder); |
| 819 for (const auto datum : data) { | 819 for (const auto datum : data) { |
| 820 snd_seq_event_t event; | 820 snd_seq_event_t event; |
| 821 int result = snd_midi_event_encode_byte(encoder, datum, &event); | 821 int result = snd_midi_event_encode_byte(encoder, datum, &event); |
| 822 if (result == 1) { | 822 if (result == 1) { |
| 823 // Full event, send it. | 823 // Full event, send it. |
| 824 base::AutoLock lock(out_ports_lock_); | 824 base::AutoLock lock(out_ports_lock_); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 // Do again. | 921 // Do again. |
| 922 if (loop_again) | 922 if (loop_again) |
| 923 ScheduleEventLoop(); | 923 ScheduleEventLoop(); |
| 924 } | 924 } |
| 925 | 925 |
| 926 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, | 926 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, |
| 927 double timestamp) { | 927 double timestamp) { |
| 928 auto source_it = | 928 auto source_it = |
| 929 source_map_.find(AddrToInt(event->source.client, event->source.port)); | 929 source_map_.find(AddrToInt(event->source.client, event->source.port)); |
| 930 if (source_it != source_map_.end()) { | 930 if (source_it != source_map_.end()) { |
| 931 uint32 source = source_it->second; | 931 uint32_t source = source_it->second; |
| 932 if (event->type == SND_SEQ_EVENT_SYSEX) { | 932 if (event->type == SND_SEQ_EVENT_SYSEX) { |
| 933 // Special! Variable-length sysex. | 933 // Special! Variable-length sysex. |
| 934 ReceiveMidiData(source, static_cast<const uint8*>(event->data.ext.ptr), | 934 ReceiveMidiData(source, static_cast<const uint8_t*>(event->data.ext.ptr), |
| 935 event->data.ext.len, timestamp); | 935 event->data.ext.len, timestamp); |
| 936 } else { | 936 } else { |
| 937 // Otherwise, decode this and send that on. | 937 // Otherwise, decode this and send that on. |
| 938 unsigned char buf[12]; | 938 unsigned char buf[12]; |
| 939 long count = | 939 long count = |
| 940 snd_midi_event_decode(decoder_.get(), buf, sizeof(buf), event); | 940 snd_midi_event_decode(decoder_.get(), buf, sizeof(buf), event); |
| 941 if (count <= 0) { | 941 if (count <= 0) { |
| 942 if (count != -ENOENT) { | 942 if (count != -ENOENT) { |
| 943 // ENOENT means that it's not a MIDI message, which is not an | 943 // ENOENT means that it's not a MIDI message, which is not an |
| 944 // error, but other negative values are errors for us. | 944 // error, but other negative values are errors for us. |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 return; | 1137 return; |
| 1138 | 1138 |
| 1139 // Generate new port state. | 1139 // Generate new port state. |
| 1140 auto new_port_state = alsa_seq_state_.ToMidiPortState(alsa_cards_); | 1140 auto new_port_state = alsa_seq_state_.ToMidiPortState(alsa_cards_); |
| 1141 | 1141 |
| 1142 // Disconnect any connected old ports that are now missing. | 1142 // Disconnect any connected old ports that are now missing. |
| 1143 for (auto& old_port : port_state_) { | 1143 for (auto& old_port : port_state_) { |
| 1144 if (old_port->connected() && | 1144 if (old_port->connected() && |
| 1145 (new_port_state->FindConnected(*old_port) == new_port_state->end())) { | 1145 (new_port_state->FindConnected(*old_port) == new_port_state->end())) { |
| 1146 old_port->set_connected(false); | 1146 old_port->set_connected(false); |
| 1147 uint32 web_port_index = old_port->web_port_index(); | 1147 uint32_t web_port_index = old_port->web_port_index(); |
| 1148 switch (old_port->type()) { | 1148 switch (old_port->type()) { |
| 1149 case MidiPort::Type::kInput: | 1149 case MidiPort::Type::kInput: |
| 1150 source_map_.erase( | 1150 source_map_.erase( |
| 1151 AddrToInt(old_port->client_id(), old_port->port_id())); | 1151 AddrToInt(old_port->client_id(), old_port->port_id())); |
| 1152 SetInputPortState(web_port_index, MIDI_PORT_DISCONNECTED); | 1152 SetInputPortState(web_port_index, MIDI_PORT_DISCONNECTED); |
| 1153 break; | 1153 break; |
| 1154 case MidiPort::Type::kOutput: | 1154 case MidiPort::Type::kOutput: |
| 1155 DeleteAlsaOutputPort(web_port_index); | 1155 DeleteAlsaOutputPort(web_port_index); |
| 1156 SetOutputPortState(web_port_index, MIDI_PORT_DISCONNECTED); | 1156 SetOutputPortState(web_port_index, MIDI_PORT_DISCONNECTED); |
| 1157 break; | 1157 break; |
| 1158 } | 1158 } |
| 1159 } | 1159 } |
| 1160 } | 1160 } |
| 1161 | 1161 |
| 1162 // Reconnect or add new ports. | 1162 // Reconnect or add new ports. |
| 1163 auto it = new_port_state->begin(); | 1163 auto it = new_port_state->begin(); |
| 1164 while (it != new_port_state->end()) { | 1164 while (it != new_port_state->end()) { |
| 1165 auto& new_port = *it; | 1165 auto& new_port = *it; |
| 1166 auto old_port = port_state_.Find(*new_port); | 1166 auto old_port = port_state_.Find(*new_port); |
| 1167 if (old_port == port_state_.end()) { | 1167 if (old_port == port_state_.end()) { |
| 1168 // Add new port. | 1168 // Add new port. |
| 1169 const auto& opaque_key = new_port->OpaqueKey(); | 1169 const auto& opaque_key = new_port->OpaqueKey(); |
| 1170 const auto& manufacturer = new_port->manufacturer(); | 1170 const auto& manufacturer = new_port->manufacturer(); |
| 1171 const auto& port_name = new_port->port_name(); | 1171 const auto& port_name = new_port->port_name(); |
| 1172 const auto& version = new_port->version(); | 1172 const auto& version = new_port->version(); |
| 1173 const auto& type = new_port->type(); | 1173 const auto& type = new_port->type(); |
| 1174 const auto& client_id = new_port->client_id(); | 1174 const auto& client_id = new_port->client_id(); |
| 1175 const auto& port_id = new_port->port_id(); | 1175 const auto& port_id = new_port->port_id(); |
| 1176 | 1176 |
| 1177 uint32 web_port_index = port_state_.push_back(new_port.Pass()); | 1177 uint32_t web_port_index = port_state_.push_back(new_port.Pass()); |
| 1178 it = new_port_state->erase(it); | 1178 it = new_port_state->erase(it); |
| 1179 | 1179 |
| 1180 MidiPortInfo info(opaque_key, manufacturer, port_name, version, | 1180 MidiPortInfo info(opaque_key, manufacturer, port_name, version, |
| 1181 MIDI_PORT_OPENED); | 1181 MIDI_PORT_OPENED); |
| 1182 switch (type) { | 1182 switch (type) { |
| 1183 case MidiPort::Type::kInput: | 1183 case MidiPort::Type::kInput: |
| 1184 if (Subscribe(web_port_index, client_id, port_id)) | 1184 if (Subscribe(web_port_index, client_id, port_id)) |
| 1185 AddInputPort(info); | 1185 AddInputPort(info); |
| 1186 break; | 1186 break; |
| 1187 case MidiPort::Type::kOutput: | 1187 case MidiPort::Type::kOutput: |
| 1188 if (CreateAlsaOutputPort(web_port_index, client_id, port_id)) | 1188 if (CreateAlsaOutputPort(web_port_index, client_id, port_id)) |
| 1189 AddOutputPort(info); | 1189 AddOutputPort(info); |
| 1190 break; | 1190 break; |
| 1191 } | 1191 } |
| 1192 } else if (!(*old_port)->connected()) { | 1192 } else if (!(*old_port)->connected()) { |
| 1193 // Reconnect. | 1193 // Reconnect. |
| 1194 uint32 web_port_index = (*old_port)->web_port_index(); | 1194 uint32_t web_port_index = (*old_port)->web_port_index(); |
| 1195 (*old_port)->Update(new_port->path(), new_port->client_id(), | 1195 (*old_port)->Update(new_port->path(), new_port->client_id(), |
| 1196 new_port->port_id(), new_port->client_name(), | 1196 new_port->port_id(), new_port->client_name(), |
| 1197 new_port->port_name(), new_port->manufacturer(), | 1197 new_port->port_name(), new_port->manufacturer(), |
| 1198 new_port->version()); | 1198 new_port->version()); |
| 1199 switch ((*old_port)->type()) { | 1199 switch ((*old_port)->type()) { |
| 1200 case MidiPort::Type::kInput: | 1200 case MidiPort::Type::kInput: |
| 1201 if (Subscribe(web_port_index, (*old_port)->client_id(), | 1201 if (Subscribe(web_port_index, (*old_port)->client_id(), |
| 1202 (*old_port)->port_id())) | 1202 (*old_port)->port_id())) |
| 1203 SetInputPortState(web_port_index, MIDI_PORT_OPENED); | 1203 SetInputPortState(web_port_index, MIDI_PORT_OPENED); |
| 1204 break; | 1204 break; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1270 const char* path = device::udev_list_entry_get_name(list_entry); | 1270 const char* path = device::udev_list_entry_get_name(list_entry); |
| 1271 device::ScopedUdevDevicePtr dev( | 1271 device::ScopedUdevDevicePtr dev( |
| 1272 device::udev_device_new_from_syspath(udev_.get(), path)); | 1272 device::udev_device_new_from_syspath(udev_.get(), path)); |
| 1273 if (dev.get()) | 1273 if (dev.get()) |
| 1274 ProcessUdevEvent(dev.get()); | 1274 ProcessUdevEvent(dev.get()); |
| 1275 } | 1275 } |
| 1276 | 1276 |
| 1277 return true; | 1277 return true; |
| 1278 } | 1278 } |
| 1279 | 1279 |
| 1280 bool MidiManagerAlsa::CreateAlsaOutputPort(uint32 port_index, | 1280 bool MidiManagerAlsa::CreateAlsaOutputPort(uint32_t port_index, |
| 1281 int client_id, | 1281 int client_id, |
| 1282 int port_id) { | 1282 int port_id) { |
| 1283 // Create the port. | 1283 // Create the port. |
| 1284 int out_port = snd_seq_create_simple_port( | 1284 int out_port = snd_seq_create_simple_port( |
| 1285 out_client_.get(), NULL, kCreateOutputPortCaps, kCreatePortType); | 1285 out_client_.get(), NULL, kCreateOutputPortCaps, kCreatePortType); |
| 1286 if (out_port < 0) { | 1286 if (out_port < 0) { |
| 1287 VLOG(1) << "snd_seq_create_simple_port fails: " << snd_strerror(out_port); | 1287 VLOG(1) << "snd_seq_create_simple_port fails: " << snd_strerror(out_port); |
| 1288 return false; | 1288 return false; |
| 1289 } | 1289 } |
| 1290 // Activate port subscription. | 1290 // Activate port subscription. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1304 snd_seq_delete_simple_port(out_client_.get(), out_port); | 1304 snd_seq_delete_simple_port(out_client_.get(), out_port); |
| 1305 return false; | 1305 return false; |
| 1306 } | 1306 } |
| 1307 | 1307 |
| 1308 // Update our map. | 1308 // Update our map. |
| 1309 base::AutoLock lock(out_ports_lock_); | 1309 base::AutoLock lock(out_ports_lock_); |
| 1310 out_ports_[port_index] = out_port; | 1310 out_ports_[port_index] = out_port; |
| 1311 return true; | 1311 return true; |
| 1312 } | 1312 } |
| 1313 | 1313 |
| 1314 void MidiManagerAlsa::DeleteAlsaOutputPort(uint32 port_index) { | 1314 void MidiManagerAlsa::DeleteAlsaOutputPort(uint32_t port_index) { |
| 1315 base::AutoLock lock(out_ports_lock_); | 1315 base::AutoLock lock(out_ports_lock_); |
| 1316 auto it = out_ports_.find(port_index); | 1316 auto it = out_ports_.find(port_index); |
| 1317 if (it == out_ports_.end()) | 1317 if (it == out_ports_.end()) |
| 1318 return; | 1318 return; |
| 1319 | 1319 |
| 1320 int alsa_port = it->second; | 1320 int alsa_port = it->second; |
| 1321 snd_seq_delete_simple_port(out_client_.get(), alsa_port); | 1321 snd_seq_delete_simple_port(out_client_.get(), alsa_port); |
| 1322 out_ports_.erase(it); | 1322 out_ports_.erase(it); |
| 1323 } | 1323 } |
| 1324 | 1324 |
| 1325 bool MidiManagerAlsa::Subscribe(uint32 port_index, int client_id, int port_id) { | 1325 bool MidiManagerAlsa::Subscribe(uint32_t port_index, |
| 1326 int client_id, |
| 1327 int port_id) { |
| 1326 // Activate port subscription. | 1328 // Activate port subscription. |
| 1327 snd_seq_port_subscribe_t* subs; | 1329 snd_seq_port_subscribe_t* subs; |
| 1328 snd_seq_port_subscribe_alloca(&subs); | 1330 snd_seq_port_subscribe_alloca(&subs); |
| 1329 snd_seq_addr_t sender; | 1331 snd_seq_addr_t sender; |
| 1330 sender.client = client_id; | 1332 sender.client = client_id; |
| 1331 sender.port = port_id; | 1333 sender.port = port_id; |
| 1332 snd_seq_port_subscribe_set_sender(subs, &sender); | 1334 snd_seq_port_subscribe_set_sender(subs, &sender); |
| 1333 snd_seq_addr_t dest; | 1335 snd_seq_addr_t dest; |
| 1334 dest.client = in_client_id_; | 1336 dest.client = in_client_id_; |
| 1335 dest.port = in_port_id_; | 1337 dest.port = in_port_id_; |
| 1336 snd_seq_port_subscribe_set_dest(subs, &dest); | 1338 snd_seq_port_subscribe_set_dest(subs, &dest); |
| 1337 int err = snd_seq_subscribe_port(in_client_.get(), subs); | 1339 int err = snd_seq_subscribe_port(in_client_.get(), subs); |
| 1338 if (err != 0) { | 1340 if (err != 0) { |
| 1339 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); | 1341 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); |
| 1340 return false; | 1342 return false; |
| 1341 } | 1343 } |
| 1342 | 1344 |
| 1343 // Update our map. | 1345 // Update our map. |
| 1344 source_map_[AddrToInt(client_id, port_id)] = port_index; | 1346 source_map_[AddrToInt(client_id, port_id)] = port_index; |
| 1345 return true; | 1347 return true; |
| 1346 } | 1348 } |
| 1347 | 1349 |
| 1348 MidiManager* MidiManager::Create() { | 1350 MidiManager* MidiManager::Create() { |
| 1349 return new MidiManagerAlsa(); | 1351 return new MidiManagerAlsa(); |
| 1350 } | 1352 } |
| 1351 | 1353 |
| 1352 } // namespace midi | 1354 } // namespace midi |
| 1353 } // namespace media | 1355 } // namespace media |
| OLD | NEW |