Chromium Code Reviews| 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 <stddef.h> | 9 #include <stddef.h> |
| 10 #include <stdlib.h> | 10 #include <stdlib.h> |
| 11 | 11 |
| 12 #include <algorithm> | 12 #include <algorithm> |
| 13 #include <string> | 13 #include <string> |
| 14 #include <utility> | 14 #include <utility> |
| 15 | 15 |
| 16 #include "base/bind.h" | 16 #include "base/bind.h" |
| 17 #include "base/json/json_string_value_serializer.h" | 17 #include "base/json/json_string_value_serializer.h" |
| 18 #include "base/lazy_instance.h" | |
| 18 #include "base/logging.h" | 19 #include "base/logging.h" |
| 19 #include "base/macros.h" | 20 #include "base/macros.h" |
| 20 #include "base/memory/ptr_util.h" | 21 #include "base/memory/ptr_util.h" |
| 21 #include "base/message_loop/message_loop.h" | 22 #include "base/message_loop/message_loop.h" |
| 22 #include "base/posix/eintr_wrapper.h" | 23 #include "base/posix/eintr_wrapper.h" |
| 23 #include "base/posix/safe_strerror.h" | 24 #include "base/posix/safe_strerror.h" |
| 24 #include "base/single_thread_task_runner.h" | 25 #include "base/single_thread_task_runner.h" |
| 25 #include "base/strings/string_number_conversions.h" | 26 #include "base/strings/string_number_conversions.h" |
| 26 #include "base/strings/stringprintf.h" | 27 #include "base/strings/stringprintf.h" |
| 27 #include "base/time/time.h" | 28 #include "base/time/time.h" |
| 28 #include "crypto/sha2.h" | 29 #include "crypto/sha2.h" |
| 29 #include "media/midi/midi_port_info.h" | 30 #include "media/midi/midi_port_info.h" |
| 31 #include "media/midi/midi_service.h" | |
| 30 | 32 |
| 31 namespace midi { | 33 namespace midi { |
| 32 | 34 |
| 33 namespace { | 35 namespace { |
| 34 | 36 |
| 35 using mojom::PortState; | 37 using mojom::PortState; |
| 36 using mojom::Result; | 38 using mojom::Result; |
| 37 | 39 |
| 40 // TODO(toyoshim): use constexpr for following const values. | |
| 41 const int kEventTaskRunner = 0; | |
| 42 const int kSendTaskRunner = 1; | |
| 43 | |
| 38 // Per-output buffer. This can be smaller, but then large sysex messages | 44 // Per-output buffer. This can be smaller, but then large sysex messages |
| 39 // will be (harmlessly) split across multiple seq events. This should | 45 // will be (harmlessly) split across multiple seq events. This should |
| 40 // not have any real practical effect, except perhaps to slightly reorder | 46 // not have any real practical effect, except perhaps to slightly reorder |
| 41 // realtime messages with respect to sysex. | 47 // realtime messages with respect to sysex. |
| 42 const size_t kSendBufferSize = 256; | 48 const size_t kSendBufferSize = 256; |
| 43 | 49 |
| 44 // Minimum client id for which we will have ALSA card devices for. When we | 50 // Minimum client id for which we will have ALSA card devices for. When we |
| 45 // are searching for card devices (used to get the path, id, and manufacturer), | 51 // are searching for card devices (used to get the path, id, and manufacturer), |
| 46 // we don't want to get confused by kernel clients that do not have a card. | 52 // we don't want to get confused by kernel clients that do not have a card. |
| 47 // See seq_clientmgr.c in the ALSA code for this. | 53 // See seq_clientmgr.c in the ALSA code for this. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 const unsigned int kRequiredOutputPortCaps = | 89 const unsigned int kRequiredOutputPortCaps = |
| 84 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; | 90 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; |
| 85 | 91 |
| 86 const unsigned int kCreateOutputPortCaps = | 92 const unsigned int kCreateOutputPortCaps = |
| 87 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; | 93 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 88 const unsigned int kCreateInputPortCaps = | 94 const unsigned int kCreateInputPortCaps = |
| 89 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; | 95 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 90 const unsigned int kCreatePortType = | 96 const unsigned int kCreatePortType = |
| 91 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; | 97 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; |
| 92 | 98 |
| 99 // Global variables to identify MidiManagerAlsa instance. | |
| 100 const int kInvalidInstanceId = -1; | |
| 101 int g_active_instance_id = kInvalidInstanceId; | |
| 102 int g_next_instance_id = 0; | |
| 103 base::LazyInstance<base::Lock> g_instance_id_lock = LAZY_INSTANCE_INITIALIZER; | |
| 104 | |
| 105 // Prevent current instance from quiting Finalize() while tasks run on external | |
| 106 // TaskRunners. | |
| 107 base::LazyInstance<base::Lock> g_event_task_lock = LAZY_INSTANCE_INITIALIZER; | |
| 108 base::LazyInstance<base::Lock> g_send_task_lock = LAZY_INSTANCE_INITIALIZER; | |
| 109 | |
| 93 int AddrToInt(int client, int port) { | 110 int AddrToInt(int client, int port) { |
| 94 return (client << 8) | port; | 111 return (client << 8) | port; |
| 95 } | 112 } |
| 96 | 113 |
| 97 // Returns true if this client has an ALSA card associated with it. | 114 // Returns true if this client has an ALSA card associated with it. |
| 98 bool IsCardClient(snd_seq_client_type_t type, int client_id) { | 115 bool IsCardClient(snd_seq_client_type_t type, int client_id) { |
| 99 return (type == SND_SEQ_KERNEL_CLIENT) && | 116 return (type == SND_SEQ_KERNEL_CLIENT) && |
| 100 (client_id >= kMinimumClientIdForCards); | 117 (client_id >= kMinimumClientIdForCards); |
| 101 } | 118 } |
| 102 | 119 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 | 163 |
| 147 void SetStringIfNonEmpty(base::DictionaryValue* value, | 164 void SetStringIfNonEmpty(base::DictionaryValue* value, |
| 148 const std::string& path, | 165 const std::string& path, |
| 149 const std::string& in_value) { | 166 const std::string& in_value) { |
| 150 if (!in_value.empty()) | 167 if (!in_value.empty()) |
| 151 value->SetString(path, in_value); | 168 value->SetString(path, in_value); |
| 152 } | 169 } |
| 153 | 170 |
| 154 } // namespace | 171 } // namespace |
| 155 | 172 |
| 156 MidiManagerAlsa::MidiManagerAlsa() | 173 MidiManagerAlsa::MidiManagerAlsa(MidiService* service) : MidiManager(service) { |
| 157 : event_thread_("MidiEventThread"), send_thread_("MidiSendThread") {} | 174 base::AutoLock lock(g_instance_id_lock.Get()); |
| 175 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); | |
| 176 instance_id_ = g_next_instance_id++; | |
| 177 g_active_instance_id = instance_id_; | |
| 178 } | |
| 158 | 179 |
| 159 MidiManagerAlsa::~MidiManagerAlsa() { | 180 MidiManagerAlsa::~MidiManagerAlsa() { |
| 160 // Take lock to ensure that the members initialized on the IO thread | 181 // Take lock to ensure that the members initialized on the IO thread |
| 161 // are not destructed here. | 182 // are not destructed here. |
| 162 base::AutoLock lock(lazy_init_member_lock_); | 183 base::AutoLock lock(lazy_init_member_lock_); |
| 163 | 184 |
| 164 // Extra CHECK to verify all members are already reset. | 185 // Extra CHECK to verify all members are already reset. |
| 165 CHECK(!initialization_thread_checker_); | 186 CHECK(!initialization_thread_checker_); |
| 166 CHECK(!in_client_); | 187 CHECK(!in_client_); |
| 167 CHECK(!out_client_); | 188 CHECK(!out_client_); |
| 168 CHECK(!decoder_); | 189 CHECK(!decoder_); |
| 169 CHECK(!udev_); | 190 CHECK(!udev_); |
| 170 CHECK(!udev_monitor_); | 191 CHECK(!udev_monitor_); |
| 171 | 192 |
| 172 CHECK(!send_thread_.IsRunning()); | 193 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); |
| 173 CHECK(!event_thread_.IsRunning()); | 194 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); |
| 174 } | 195 } |
| 175 | 196 |
| 176 void MidiManagerAlsa::StartInitialization() { | 197 void MidiManagerAlsa::StartInitialization() { |
| 177 base::AutoLock lock(lazy_init_member_lock_); | 198 base::AutoLock lock(lazy_init_member_lock_); |
| 178 | 199 |
| 179 initialization_thread_checker_.reset(new base::ThreadChecker()); | 200 initialization_thread_checker_.reset(new base::ThreadChecker()); |
| 180 | 201 |
| 181 // Create client handles. | 202 // Create client handles. |
| 182 snd_seq_t* tmp_seq = nullptr; | 203 snd_seq_t* tmp_seq = nullptr; |
| 183 int err = | 204 int err = |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 // TODO(agoode): Check the return value for failure. | 302 // TODO(agoode): Check the return value for failure. |
| 282 EnumerateAlsaPorts(); | 303 EnumerateAlsaPorts(); |
| 283 | 304 |
| 284 // Generate hotplug events for existing udev devices. This must be done | 305 // Generate hotplug events for existing udev devices. This must be done |
| 285 // after udev_monitor_enable_receiving() is called. See the algorithm | 306 // after udev_monitor_enable_receiving() is called. See the algorithm |
| 286 // at http://www.signal11.us/oss/udev/. | 307 // at http://www.signal11.us/oss/udev/. |
| 287 EnumerateUdevCards(); | 308 EnumerateUdevCards(); |
| 288 | 309 |
| 289 // Start processing events. Don't do this before enumeration of both | 310 // Start processing events. Don't do this before enumeration of both |
| 290 // ALSA and udev. | 311 // ALSA and udev. |
| 291 event_thread_.Start(); | 312 service() |
| 292 event_thread_.task_runner()->PostTask( | 313 ->GetTaskRunner(kEventTaskRunner) |
| 293 FROM_HERE, | 314 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, |
| 294 base::Bind(&MidiManagerAlsa::ScheduleEventLoop, base::Unretained(this))); | 315 base::Unretained(this), instance_id_)); |
| 295 send_thread_.Start(); | |
| 296 | 316 |
| 297 CompleteInitialization(Result::OK); | 317 CompleteInitialization(Result::OK); |
| 298 } | 318 } |
| 299 | 319 |
| 300 void MidiManagerAlsa::Finalize() { | 320 void MidiManagerAlsa::Finalize() { |
| 301 base::AutoLock lock(lazy_init_member_lock_); | 321 base::AutoLock lock(lazy_init_member_lock_); |
| 302 DCHECK(initialization_thread_checker_->CalledOnValidThread()); | 322 DCHECK(initialization_thread_checker_->CalledOnValidThread()); |
| 303 | 323 |
| 304 // Tell the event thread it will soon be time to shut down. This gives | 324 // Tell tasks running on TaskRunners it will soon be time to shut down. This |
| 305 // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT | 325 // gives us assurance a task running on kEventTaskRunner will stop in case the |
| 306 // message is lost. | 326 // SND_SEQ_EVENT_CLIENT_EXIT message is lost. |
| 307 { | 327 { |
| 308 base::AutoLock lock(shutdown_lock_); | 328 base::AutoLock lock(g_instance_id_lock.Get()); |
| 309 event_thread_shutdown_ = true; | 329 CHECK_EQ(instance_id_, g_active_instance_id); |
| 330 g_active_instance_id = kInvalidInstanceId; | |
| 310 } | 331 } |
| 311 | 332 |
| 312 // Stop the send thread. | 333 // Ensure that no tasks run on kSendTaskRunner. |
| 313 send_thread_.Stop(); | 334 base::AutoLock send_runner_lock(g_send_task_lock.Get()); |
| 314 | 335 |
| 315 // Close the out client. This will trigger the event thread to stop, | 336 // Close the out client. This will trigger the event thread to stop, |
| 316 // because of SND_SEQ_EVENT_CLIENT_EXIT. | 337 // because of SND_SEQ_EVENT_CLIENT_EXIT. |
| 317 out_client_.reset(); | 338 out_client_.reset(); |
| 318 | 339 |
| 319 // Wait for the event thread to stop. | 340 // Ensure that no tasks run on kEventTaskRunner. |
| 320 event_thread_.Stop(); | 341 base::AutoLock event_runner_lock(g_event_task_lock.Get()); |
| 321 | 342 |
| 322 // Destruct the other stuff we initialized in StartInitialization(). | 343 // Destruct the other stuff we initialized in StartInitialization(). |
| 323 udev_monitor_.reset(); | 344 udev_monitor_.reset(); |
| 324 udev_.reset(); | 345 udev_.reset(); |
| 325 decoder_.reset(); | 346 decoder_.reset(); |
| 326 in_client_.reset(); | 347 in_client_.reset(); |
| 327 initialization_thread_checker_.reset(); | 348 initialization_thread_checker_.reset(); |
| 328 } | 349 } |
| 329 | 350 |
| 330 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, | 351 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
| 331 uint32_t port_index, | 352 uint32_t port_index, |
| 332 const std::vector<uint8_t>& data, | 353 const std::vector<uint8_t>& data, |
| 333 double timestamp) { | 354 double timestamp) { |
| 334 base::TimeDelta delay; | 355 base::TimeDelta delay; |
| 335 if (timestamp != 0.0) { | 356 if (timestamp != 0.0) { |
| 336 base::TimeTicks time_to_send = | 357 base::TimeTicks time_to_send = |
| 337 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 358 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
| 338 timestamp * base::Time::kMicrosecondsPerSecond); | 359 timestamp * base::Time::kMicrosecondsPerSecond); |
| 339 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 360 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
| 340 } | 361 } |
| 341 | 362 |
| 342 send_thread_.task_runner()->PostDelayedTask( | 363 service() |
| 343 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData, | 364 ->GetTaskRunner(kSendTaskRunner) |
| 344 base::Unretained(this), port_index, data), | 365 ->PostDelayedTask( |
| 345 delay); | 366 FROM_HERE, |
| 346 | 367 base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this), |
| 347 // Acknowledge send. | 368 instance_id_, client, port_index, data), |
| 348 send_thread_.task_runner()->PostTask( | 369 delay); |
| 349 FROM_HERE, base::Bind(&MidiManagerAlsa::AccumulateMidiBytesSent, | |
| 350 base::Unretained(this), client, data.size())); | |
| 351 } | 370 } |
| 352 | 371 |
| 353 MidiManagerAlsa::MidiPort::Id::Id() = default; | 372 MidiManagerAlsa::MidiPort::Id::Id() = default; |
| 354 | 373 |
| 355 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus, | 374 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus, |
| 356 const std::string& vendor_id, | 375 const std::string& vendor_id, |
| 357 const std::string& model_id, | 376 const std::string& model_id, |
| 358 const std::string& usb_interface_num, | 377 const std::string& usb_interface_num, |
| 359 const std::string& serial) | 378 const std::string& serial) |
| 360 : bus_(bus), | 379 : bus_(bus), |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 if (at_index && at_index != std::string::npos) { | 876 if (at_index && at_index != std::string::npos) { |
| 858 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); | 877 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
| 859 if (name_index && name_index != std::string::npos) | 878 if (name_index && name_index != std::string::npos) |
| 860 return alsa_longname.substr(0, name_index - 1); | 879 return alsa_longname.substr(0, name_index - 1); |
| 861 } | 880 } |
| 862 | 881 |
| 863 // Failure. | 882 // Failure. |
| 864 return ""; | 883 return ""; |
| 865 } | 884 } |
| 866 | 885 |
| 867 void MidiManagerAlsa::SendMidiData(uint32_t port_index, | 886 void MidiManagerAlsa::SendMidiData(int instance_id, |
| 887 MidiManagerClient* client, | |
| 888 uint32_t port_index, | |
| 868 const std::vector<uint8_t>& data) { | 889 const std::vector<uint8_t>& data) { |
| 869 DCHECK(send_thread_.task_runner()->BelongsToCurrentThread()); | 890 DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread()); |
| 891 | |
| 892 // Obtain the lock so that the instance could not be destructed while this | |
| 893 // method is running on the kSendTaskRunner. | |
| 894 base::AutoLock lock(g_send_task_lock.Get()); | |
|
yhirano
2017/02/08 10:04:37
I think moving this below the instance id check is
Takashi Toyoshima
2017/02/08 11:08:55
If this lock is created after the instance id chec
| |
| 895 { | |
| 896 // Check if Finalize() already runs. After this check, we can access |this| | |
| 897 // safely on the kEventTaskRunner. | |
| 898 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | |
| 899 if (instance_id != g_active_instance_id) | |
| 900 return; | |
| 901 } | |
| 870 | 902 |
| 871 snd_midi_event_t* encoder; | 903 snd_midi_event_t* encoder; |
| 872 snd_midi_event_new(kSendBufferSize, &encoder); | 904 snd_midi_event_new(kSendBufferSize, &encoder); |
| 873 for (const auto datum : data) { | 905 for (const auto datum : data) { |
| 874 snd_seq_event_t event; | 906 snd_seq_event_t event; |
| 875 int result = snd_midi_event_encode_byte(encoder, datum, &event); | 907 int result = snd_midi_event_encode_byte(encoder, datum, &event); |
| 876 if (result == 1) { | 908 if (result == 1) { |
| 877 // Full event, send it. | 909 // Full event, send it. |
| 878 base::AutoLock lock(out_ports_lock_); | 910 base::AutoLock lock(out_ports_lock_); |
| 879 auto it = out_ports_.find(port_index); | 911 auto it = out_ports_.find(port_index); |
| 880 if (it != out_ports_.end()) { | 912 if (it != out_ports_.end()) { |
| 881 snd_seq_ev_set_source(&event, it->second); | 913 snd_seq_ev_set_source(&event, it->second); |
| 882 snd_seq_ev_set_subs(&event); | 914 snd_seq_ev_set_subs(&event); |
| 883 snd_seq_ev_set_direct(&event); | 915 snd_seq_ev_set_direct(&event); |
| 884 snd_seq_event_output_direct(out_client_.get(), &event); | 916 snd_seq_event_output_direct(out_client_.get(), &event); |
| 885 } | 917 } |
| 886 } | 918 } |
| 887 } | 919 } |
| 888 snd_midi_event_free(encoder); | 920 snd_midi_event_free(encoder); |
| 921 | |
| 922 // Acknowledge send. | |
| 923 AccumulateMidiBytesSent(client, data.size()); | |
| 889 } | 924 } |
| 890 | 925 |
| 891 void MidiManagerAlsa::ScheduleEventLoop() { | 926 void MidiManagerAlsa::EventLoop(int instance_id) { |
| 892 event_thread_.task_runner()->PostTask( | 927 // Obtain the lock so that the instance could not be destructed while this |
| 893 FROM_HERE, | 928 // method is running on the kEventTaskRunner. |
| 894 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); | 929 base::AutoLock lock(g_event_task_lock.Get()); |
|
yhirano
2017/02/08 10:04:37
I think moving this below the instance id check is
Takashi Toyoshima
2017/02/08 11:08:55
same
| |
| 895 } | 930 { |
| 931 // Check if Finalize() already runs. After this check, we can access |this| | |
| 932 // safely on the kEventTaskRunner. | |
| 933 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | |
| 934 if (instance_id != g_active_instance_id) | |
| 935 return; | |
| 936 } | |
| 896 | 937 |
| 897 void MidiManagerAlsa::EventLoop() { | |
| 898 bool loop_again = true; | 938 bool loop_again = true; |
| 899 | 939 |
| 900 struct pollfd pfd[2]; | 940 struct pollfd pfd[2]; |
| 901 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); | 941 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); |
| 902 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); | 942 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); |
| 903 pfd[1].events = POLLIN; | 943 pfd[1].events = POLLIN; |
| 904 | 944 |
| 905 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1)); | 945 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1)); |
| 906 if (err < 0) { | 946 if (err < 0) { |
| 907 VLOG(1) << "poll fails: " << base::safe_strerror(errno); | 947 VLOG(1) << "poll fails: " << base::safe_strerror(errno); |
| 908 loop_again = false; | 948 loop_again = false; |
| 909 } else { | 949 } else { |
| 910 if (pfd[0].revents & POLLIN) { | 950 if (pfd[0].revents & POLLIN) { |
| 911 // Read available incoming MIDI data. | 951 // Read available incoming MIDI data. |
| 912 int remaining; | 952 int remaining; |
| 913 double timestamp = | 953 double timestamp = |
| 914 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); | 954 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); |
| 915 do { | 955 do { |
| 916 snd_seq_event_t* event; | 956 snd_seq_event_t* event; |
| 917 err = snd_seq_event_input(in_client_.get(), &event); | 957 err = snd_seq_event_input(in_client_.get(), &event); |
| 918 remaining = snd_seq_event_input_pending(in_client_.get(), 0); | 958 remaining = snd_seq_event_input_pending(in_client_.get(), 0); |
| 919 | 959 |
| 920 if (err == -ENOSPC) { | 960 if (err == -ENOSPC) { |
| 921 // Handle out of space error. | 961 // Handle out of space error. |
| 922 VLOG(1) << "snd_seq_event_input detected buffer overrun"; | 962 VLOG(1) << "snd_seq_event_input detected buffer overrun"; |
| 923 // We've lost events: check another way to see if we need to shut | 963 // We've lost events: check another way to see if we need to shut |
| 924 // down. | 964 // down. |
| 925 base::AutoLock lock(shutdown_lock_); | |
| 926 if (event_thread_shutdown_) | |
| 927 loop_again = false; | |
| 928 } else if (err == -EAGAIN) { | 965 } else if (err == -EAGAIN) { |
| 929 // We've read all the data. | 966 // We've read all the data. |
| 930 } else if (err < 0) { | 967 } else if (err < 0) { |
| 931 // Handle other errors. | 968 // Handle other errors. |
| 932 VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err); | 969 VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err); |
| 933 // TODO(agoode): Use RecordAction() or similar to log this. | 970 // TODO(agoode): Use RecordAction() or similar to log this. |
| 934 loop_again = false; | 971 loop_again = false; |
| 935 } else if (event->source.client == SND_SEQ_CLIENT_SYSTEM && | 972 } else if (event->source.client == SND_SEQ_CLIENT_SYSTEM && |
| 936 event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) { | 973 event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) { |
| 937 // Handle announce events. | 974 // Handle announce events. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 966 device::ScopedUdevDevicePtr dev( | 1003 device::ScopedUdevDevicePtr dev( |
| 967 device::udev_monitor_receive_device(udev_monitor_.get())); | 1004 device::udev_monitor_receive_device(udev_monitor_.get())); |
| 968 if (dev.get()) | 1005 if (dev.get()) |
| 969 ProcessUdevEvent(dev.get()); | 1006 ProcessUdevEvent(dev.get()); |
| 970 else | 1007 else |
| 971 VLOG(1) << "udev_monitor_receive_device fails"; | 1008 VLOG(1) << "udev_monitor_receive_device fails"; |
| 972 } | 1009 } |
| 973 } | 1010 } |
| 974 | 1011 |
| 975 // Do again. | 1012 // Do again. |
| 976 if (loop_again) | 1013 if (loop_again) { |
| 977 ScheduleEventLoop(); | 1014 service() |
| 1015 ->GetTaskRunner(kEventTaskRunner) | |
| 1016 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, | |
| 1017 base::Unretained(this), instance_id)); | |
| 1018 } | |
| 978 } | 1019 } |
| 979 | 1020 |
| 980 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, | 1021 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, |
| 981 double timestamp) { | 1022 double timestamp) { |
| 982 auto source_it = | 1023 auto source_it = |
| 983 source_map_.find(AddrToInt(event->source.client, event->source.port)); | 1024 source_map_.find(AddrToInt(event->source.client, event->source.port)); |
| 984 if (source_it != source_map_.end()) { | 1025 if (source_it != source_map_.end()) { |
| 985 uint32_t source = source_it->second; | 1026 uint32_t source = source_it->second; |
| 986 if (event->type == SND_SEQ_EVENT_SYSEX) { | 1027 if (event->type == SND_SEQ_EVENT_SYSEX) { |
| 987 // Special! Variable-length sysex. | 1028 // Special! Variable-length sysex. |
| (...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1394 if (err != 0) { | 1435 if (err != 0) { |
| 1395 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); | 1436 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); |
| 1396 return false; | 1437 return false; |
| 1397 } | 1438 } |
| 1398 | 1439 |
| 1399 // Update our map. | 1440 // Update our map. |
| 1400 source_map_[AddrToInt(client_id, port_id)] = port_index; | 1441 source_map_[AddrToInt(client_id, port_id)] = port_index; |
| 1401 return true; | 1442 return true; |
| 1402 } | 1443 } |
| 1403 | 1444 |
| 1404 MidiManager* MidiManager::Create() { | 1445 MidiManager* MidiManager::Create(MidiService* service) { |
| 1405 return new MidiManagerAlsa(); | 1446 return new MidiManagerAlsa(service); |
| 1406 } | 1447 } |
| 1407 | 1448 |
| 1408 } // namespace midi | 1449 } // namespace midi |
| OLD | NEW |