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") {} | |
158 | 174 |
159 MidiManagerAlsa::~MidiManagerAlsa() { | 175 MidiManagerAlsa::~MidiManagerAlsa() { |
160 // Take lock to ensure that the members initialized on the IO thread | 176 // Take lock to ensure that the members initialized on the IO thread |
161 // are not destructed here. | 177 // are not destructed here. |
162 base::AutoLock lock(lazy_init_member_lock_); | 178 base::AutoLock lock(lazy_init_member_lock_); |
163 | 179 |
164 // Extra CHECK to verify all members are already reset. | 180 // Extra CHECK to verify all members are already reset. |
165 CHECK(!initialization_thread_checker_); | 181 CHECK(!initialization_thread_checker_); |
166 CHECK(!in_client_); | 182 CHECK(!in_client_); |
167 CHECK(!out_client_); | 183 CHECK(!out_client_); |
168 CHECK(!decoder_); | 184 CHECK(!decoder_); |
169 CHECK(!udev_); | 185 CHECK(!udev_); |
170 CHECK(!udev_monitor_); | 186 CHECK(!udev_monitor_); |
171 | 187 |
172 CHECK(!send_thread_.IsRunning()); | 188 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); |
173 CHECK(!event_thread_.IsRunning()); | 189 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); |
174 } | 190 } |
175 | 191 |
176 void MidiManagerAlsa::StartInitialization() { | 192 void MidiManagerAlsa::StartInitialization() { |
193 { | |
Takashi Toyoshima
2017/02/08 12:56:13
Since Finalize() is called only when StartInitiali
| |
194 base::AutoLock lock(g_instance_id_lock.Get()); | |
195 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); | |
196 instance_id_ = g_next_instance_id++; | |
197 g_active_instance_id = instance_id_; | |
198 } | |
199 | |
177 base::AutoLock lock(lazy_init_member_lock_); | 200 base::AutoLock lock(lazy_init_member_lock_); |
178 | 201 |
179 initialization_thread_checker_.reset(new base::ThreadChecker()); | 202 initialization_thread_checker_.reset(new base::ThreadChecker()); |
180 | 203 |
181 // Create client handles. | 204 // Create client handles. |
182 snd_seq_t* tmp_seq = nullptr; | 205 snd_seq_t* tmp_seq = nullptr; |
183 int err = | 206 int err = |
184 snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK); | 207 snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK); |
185 if (err != 0) { | 208 if (err != 0) { |
186 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); | 209 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 // TODO(agoode): Check the return value for failure. | 304 // TODO(agoode): Check the return value for failure. |
282 EnumerateAlsaPorts(); | 305 EnumerateAlsaPorts(); |
283 | 306 |
284 // Generate hotplug events for existing udev devices. This must be done | 307 // Generate hotplug events for existing udev devices. This must be done |
285 // after udev_monitor_enable_receiving() is called. See the algorithm | 308 // after udev_monitor_enable_receiving() is called. See the algorithm |
286 // at http://www.signal11.us/oss/udev/. | 309 // at http://www.signal11.us/oss/udev/. |
287 EnumerateUdevCards(); | 310 EnumerateUdevCards(); |
288 | 311 |
289 // Start processing events. Don't do this before enumeration of both | 312 // Start processing events. Don't do this before enumeration of both |
290 // ALSA and udev. | 313 // ALSA and udev. |
291 event_thread_.Start(); | 314 service() |
292 event_thread_.task_runner()->PostTask( | 315 ->GetTaskRunner(kEventTaskRunner) |
293 FROM_HERE, | 316 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, |
294 base::Bind(&MidiManagerAlsa::ScheduleEventLoop, base::Unretained(this))); | 317 base::Unretained(this), instance_id_)); |
295 send_thread_.Start(); | |
296 | 318 |
297 CompleteInitialization(Result::OK); | 319 CompleteInitialization(Result::OK); |
298 } | 320 } |
299 | 321 |
300 void MidiManagerAlsa::Finalize() { | 322 void MidiManagerAlsa::Finalize() { |
301 base::AutoLock lock(lazy_init_member_lock_); | 323 base::AutoLock lock(lazy_init_member_lock_); |
302 DCHECK(initialization_thread_checker_->CalledOnValidThread()); | 324 DCHECK(initialization_thread_checker_->CalledOnValidThread()); |
303 | 325 |
304 // Tell the event thread it will soon be time to shut down. This gives | 326 // 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 | 327 // gives us assurance a task running on kEventTaskRunner will stop in case the |
306 // message is lost. | 328 // SND_SEQ_EVENT_CLIENT_EXIT message is lost. |
307 { | 329 { |
308 base::AutoLock lock(shutdown_lock_); | 330 base::AutoLock lock(g_instance_id_lock.Get()); |
309 event_thread_shutdown_ = true; | 331 CHECK_EQ(instance_id_, g_active_instance_id); |
332 g_active_instance_id = kInvalidInstanceId; | |
310 } | 333 } |
311 | 334 |
312 // Stop the send thread. | 335 // Ensure that no tasks run on kSendTaskRunner. |
313 send_thread_.Stop(); | 336 base::AutoLock send_runner_lock(g_send_task_lock.Get()); |
314 | 337 |
315 // Close the out client. This will trigger the event thread to stop, | 338 // Close the out client. This will trigger the event thread to stop, |
316 // because of SND_SEQ_EVENT_CLIENT_EXIT. | 339 // because of SND_SEQ_EVENT_CLIENT_EXIT. |
317 out_client_.reset(); | 340 out_client_.reset(); |
318 | 341 |
319 // Wait for the event thread to stop. | 342 // Ensure that no tasks run on kEventTaskRunner. |
320 event_thread_.Stop(); | 343 base::AutoLock event_runner_lock(g_event_task_lock.Get()); |
321 | 344 |
322 // Destruct the other stuff we initialized in StartInitialization(). | 345 // Destruct the other stuff we initialized in StartInitialization(). |
323 udev_monitor_.reset(); | 346 udev_monitor_.reset(); |
324 udev_.reset(); | 347 udev_.reset(); |
325 decoder_.reset(); | 348 decoder_.reset(); |
326 in_client_.reset(); | 349 in_client_.reset(); |
327 initialization_thread_checker_.reset(); | 350 initialization_thread_checker_.reset(); |
328 } | 351 } |
329 | 352 |
330 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, | 353 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
331 uint32_t port_index, | 354 uint32_t port_index, |
332 const std::vector<uint8_t>& data, | 355 const std::vector<uint8_t>& data, |
333 double timestamp) { | 356 double timestamp) { |
334 base::TimeDelta delay; | 357 base::TimeDelta delay; |
335 if (timestamp != 0.0) { | 358 if (timestamp != 0.0) { |
336 base::TimeTicks time_to_send = | 359 base::TimeTicks time_to_send = |
337 base::TimeTicks() + base::TimeDelta::FromMicroseconds( | 360 base::TimeTicks() + base::TimeDelta::FromMicroseconds( |
338 timestamp * base::Time::kMicrosecondsPerSecond); | 361 timestamp * base::Time::kMicrosecondsPerSecond); |
339 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); | 362 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); |
340 } | 363 } |
341 | 364 |
342 send_thread_.task_runner()->PostDelayedTask( | 365 service() |
343 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData, | 366 ->GetTaskRunner(kSendTaskRunner) |
344 base::Unretained(this), port_index, data), | 367 ->PostDelayedTask( |
345 delay); | 368 FROM_HERE, |
346 | 369 base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this), |
347 // Acknowledge send. | 370 instance_id_, client, port_index, data), |
348 send_thread_.task_runner()->PostTask( | 371 delay); |
349 FROM_HERE, base::Bind(&MidiManagerAlsa::AccumulateMidiBytesSent, | |
350 base::Unretained(this), client, data.size())); | |
351 } | 372 } |
352 | 373 |
353 MidiManagerAlsa::MidiPort::Id::Id() = default; | 374 MidiManagerAlsa::MidiPort::Id::Id() = default; |
354 | 375 |
355 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus, | 376 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus, |
356 const std::string& vendor_id, | 377 const std::string& vendor_id, |
357 const std::string& model_id, | 378 const std::string& model_id, |
358 const std::string& usb_interface_num, | 379 const std::string& usb_interface_num, |
359 const std::string& serial) | 380 const std::string& serial) |
360 : bus_(bus), | 381 : bus_(bus), |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
857 if (at_index && at_index != std::string::npos) { | 878 if (at_index && at_index != std::string::npos) { |
858 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); | 879 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
859 if (name_index && name_index != std::string::npos) | 880 if (name_index && name_index != std::string::npos) |
860 return alsa_longname.substr(0, name_index - 1); | 881 return alsa_longname.substr(0, name_index - 1); |
861 } | 882 } |
862 | 883 |
863 // Failure. | 884 // Failure. |
864 return ""; | 885 return ""; |
865 } | 886 } |
866 | 887 |
867 void MidiManagerAlsa::SendMidiData(uint32_t port_index, | 888 void MidiManagerAlsa::SendMidiData(int instance_id, |
889 MidiManagerClient* client, | |
890 uint32_t port_index, | |
868 const std::vector<uint8_t>& data) { | 891 const std::vector<uint8_t>& data) { |
869 DCHECK(send_thread_.task_runner()->BelongsToCurrentThread()); | 892 DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread()); |
893 | |
894 // Obtain the lock so that the instance could not be destructed while this | |
895 // method is running on the kSendTaskRunner. | |
896 base::AutoLock lock(g_send_task_lock.Get()); | |
897 { | |
898 // Check if Finalize() already runs. After this check, we can access |this| | |
899 // safely on the kEventTaskRunner. | |
900 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | |
901 if (instance_id != g_active_instance_id) | |
902 return; | |
903 } | |
870 | 904 |
871 snd_midi_event_t* encoder; | 905 snd_midi_event_t* encoder; |
872 snd_midi_event_new(kSendBufferSize, &encoder); | 906 snd_midi_event_new(kSendBufferSize, &encoder); |
873 for (const auto datum : data) { | 907 for (const auto datum : data) { |
874 snd_seq_event_t event; | 908 snd_seq_event_t event; |
875 int result = snd_midi_event_encode_byte(encoder, datum, &event); | 909 int result = snd_midi_event_encode_byte(encoder, datum, &event); |
876 if (result == 1) { | 910 if (result == 1) { |
877 // Full event, send it. | 911 // Full event, send it. |
878 base::AutoLock lock(out_ports_lock_); | 912 base::AutoLock lock(out_ports_lock_); |
879 auto it = out_ports_.find(port_index); | 913 auto it = out_ports_.find(port_index); |
880 if (it != out_ports_.end()) { | 914 if (it != out_ports_.end()) { |
881 snd_seq_ev_set_source(&event, it->second); | 915 snd_seq_ev_set_source(&event, it->second); |
882 snd_seq_ev_set_subs(&event); | 916 snd_seq_ev_set_subs(&event); |
883 snd_seq_ev_set_direct(&event); | 917 snd_seq_ev_set_direct(&event); |
884 snd_seq_event_output_direct(out_client_.get(), &event); | 918 snd_seq_event_output_direct(out_client_.get(), &event); |
885 } | 919 } |
886 } | 920 } |
887 } | 921 } |
888 snd_midi_event_free(encoder); | 922 snd_midi_event_free(encoder); |
923 | |
924 // Acknowledge send. | |
925 AccumulateMidiBytesSent(client, data.size()); | |
889 } | 926 } |
890 | 927 |
891 void MidiManagerAlsa::ScheduleEventLoop() { | 928 void MidiManagerAlsa::EventLoop(int instance_id) { |
892 event_thread_.task_runner()->PostTask( | 929 // Obtain the lock so that the instance could not be destructed while this |
893 FROM_HERE, | 930 // method is running on the kEventTaskRunner. |
894 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); | 931 base::AutoLock lock(g_event_task_lock.Get()); |
895 } | 932 { |
933 // Check if Finalize() already runs. After this check, we can access |this| | |
934 // safely on the kEventTaskRunner. | |
935 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | |
936 if (instance_id != g_active_instance_id) | |
937 return; | |
938 } | |
896 | 939 |
897 void MidiManagerAlsa::EventLoop() { | |
898 bool loop_again = true; | 940 bool loop_again = true; |
899 | 941 |
900 struct pollfd pfd[2]; | 942 struct pollfd pfd[2]; |
901 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); | 943 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); |
902 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); | 944 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); |
903 pfd[1].events = POLLIN; | 945 pfd[1].events = POLLIN; |
904 | 946 |
905 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1)); | 947 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1)); |
906 if (err < 0) { | 948 if (err < 0) { |
907 VLOG(1) << "poll fails: " << base::safe_strerror(errno); | 949 VLOG(1) << "poll fails: " << base::safe_strerror(errno); |
908 loop_again = false; | 950 loop_again = false; |
909 } else { | 951 } else { |
910 if (pfd[0].revents & POLLIN) { | 952 if (pfd[0].revents & POLLIN) { |
911 // Read available incoming MIDI data. | 953 // Read available incoming MIDI data. |
912 int remaining; | 954 int remaining; |
913 double timestamp = | 955 double timestamp = |
914 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); | 956 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); |
915 do { | 957 do { |
916 snd_seq_event_t* event; | 958 snd_seq_event_t* event; |
917 err = snd_seq_event_input(in_client_.get(), &event); | 959 err = snd_seq_event_input(in_client_.get(), &event); |
918 remaining = snd_seq_event_input_pending(in_client_.get(), 0); | 960 remaining = snd_seq_event_input_pending(in_client_.get(), 0); |
919 | 961 |
920 if (err == -ENOSPC) { | 962 if (err == -ENOSPC) { |
921 // Handle out of space error. | 963 // Handle out of space error. |
922 VLOG(1) << "snd_seq_event_input detected buffer overrun"; | 964 VLOG(1) << "snd_seq_event_input detected buffer overrun"; |
923 // We've lost events: check another way to see if we need to shut | 965 // We've lost events: check another way to see if we need to shut |
924 // down. | 966 // down. |
925 base::AutoLock lock(shutdown_lock_); | |
926 if (event_thread_shutdown_) | |
927 loop_again = false; | |
928 } else if (err == -EAGAIN) { | 967 } else if (err == -EAGAIN) { |
929 // We've read all the data. | 968 // We've read all the data. |
930 } else if (err < 0) { | 969 } else if (err < 0) { |
931 // Handle other errors. | 970 // Handle other errors. |
932 VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err); | 971 VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err); |
933 // TODO(agoode): Use RecordAction() or similar to log this. | 972 // TODO(agoode): Use RecordAction() or similar to log this. |
934 loop_again = false; | 973 loop_again = false; |
935 } else if (event->source.client == SND_SEQ_CLIENT_SYSTEM && | 974 } else if (event->source.client == SND_SEQ_CLIENT_SYSTEM && |
936 event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) { | 975 event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) { |
937 // Handle announce events. | 976 // Handle announce events. |
(...skipping 28 matching lines...) Expand all Loading... | |
966 device::ScopedUdevDevicePtr dev( | 1005 device::ScopedUdevDevicePtr dev( |
967 device::udev_monitor_receive_device(udev_monitor_.get())); | 1006 device::udev_monitor_receive_device(udev_monitor_.get())); |
968 if (dev.get()) | 1007 if (dev.get()) |
969 ProcessUdevEvent(dev.get()); | 1008 ProcessUdevEvent(dev.get()); |
970 else | 1009 else |
971 VLOG(1) << "udev_monitor_receive_device fails"; | 1010 VLOG(1) << "udev_monitor_receive_device fails"; |
972 } | 1011 } |
973 } | 1012 } |
974 | 1013 |
975 // Do again. | 1014 // Do again. |
976 if (loop_again) | 1015 if (loop_again) { |
977 ScheduleEventLoop(); | 1016 service() |
1017 ->GetTaskRunner(kEventTaskRunner) | |
1018 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, | |
1019 base::Unretained(this), instance_id)); | |
1020 } | |
978 } | 1021 } |
979 | 1022 |
980 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, | 1023 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, |
981 double timestamp) { | 1024 double timestamp) { |
982 auto source_it = | 1025 auto source_it = |
983 source_map_.find(AddrToInt(event->source.client, event->source.port)); | 1026 source_map_.find(AddrToInt(event->source.client, event->source.port)); |
984 if (source_it != source_map_.end()) { | 1027 if (source_it != source_map_.end()) { |
985 uint32_t source = source_it->second; | 1028 uint32_t source = source_it->second; |
986 if (event->type == SND_SEQ_EVENT_SYSEX) { | 1029 if (event->type == SND_SEQ_EVENT_SYSEX) { |
987 // Special! Variable-length sysex. | 1030 // Special! Variable-length sysex. |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1394 if (err != 0) { | 1437 if (err != 0) { |
1395 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); | 1438 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); |
1396 return false; | 1439 return false; |
1397 } | 1440 } |
1398 | 1441 |
1399 // Update our map. | 1442 // Update our map. |
1400 source_map_[AddrToInt(client_id, port_id)] = port_index; | 1443 source_map_[AddrToInt(client_id, port_id)] = port_index; |
1401 return true; | 1444 return true; |
1402 } | 1445 } |
1403 | 1446 |
1404 MidiManager* MidiManager::Create() { | 1447 MidiManager* MidiManager::Create(MidiService* service) { |
1405 return new MidiManagerAlsa(); | 1448 return new MidiManagerAlsa(service); |
1406 } | 1449 } |
1407 | 1450 |
1408 } // namespace midi | 1451 } // namespace midi |
OLD | NEW |