| 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" | |
| 19 #include "base/logging.h" | 18 #include "base/logging.h" |
| 20 #include "base/macros.h" | 19 #include "base/macros.h" |
| 21 #include "base/memory/ptr_util.h" | 20 #include "base/memory/ptr_util.h" |
| 22 #include "base/message_loop/message_loop.h" | 21 #include "base/message_loop/message_loop.h" |
| 23 #include "base/posix/eintr_wrapper.h" | 22 #include "base/posix/eintr_wrapper.h" |
| 24 #include "base/posix/safe_strerror.h" | 23 #include "base/posix/safe_strerror.h" |
| 25 #include "base/single_thread_task_runner.h" | 24 #include "base/single_thread_task_runner.h" |
| 26 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
| 27 #include "base/strings/stringprintf.h" | 26 #include "base/strings/stringprintf.h" |
| 28 #include "base/time/time.h" | 27 #include "base/time/time.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; | 92 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 94 const unsigned int kCreateInputPortCaps = | 93 const unsigned int kCreateInputPortCaps = |
| 95 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; | 94 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 96 const unsigned int kCreatePortType = | 95 const unsigned int kCreatePortType = |
| 97 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; | 96 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; |
| 98 | 97 |
| 99 // Global variables to identify MidiManagerAlsa instance. | 98 // Global variables to identify MidiManagerAlsa instance. |
| 100 const int kInvalidInstanceId = -1; | 99 const int kInvalidInstanceId = -1; |
| 101 int g_active_instance_id = kInvalidInstanceId; | 100 int g_active_instance_id = kInvalidInstanceId; |
| 102 int g_next_instance_id = 0; | 101 int g_next_instance_id = 0; |
| 103 base::LazyInstance<base::Lock> g_instance_id_lock = LAZY_INSTANCE_INITIALIZER; | |
| 104 | 102 |
| 105 // Prevent current instance from quiting Finalize() while tasks run on external | 103 struct MidiManagerLockHelper { |
| 106 // TaskRunners. | 104 base::Lock instance_id_lock; |
| 107 base::LazyInstance<base::Lock> g_event_task_lock = LAZY_INSTANCE_INITIALIZER; | 105 |
| 108 base::LazyInstance<base::Lock> g_send_task_lock = LAZY_INSTANCE_INITIALIZER; | 106 // Prevent current instance from quiting Finalize() while tasks run on |
| 107 // external TaskRunners. |
| 108 base::Lock event_task_lock; |
| 109 base::Lock send_task_lock; |
| 110 }; |
| 111 |
| 112 MidiManagerLockHelper* GetLockHelper() { |
| 113 static MidiManagerLockHelper* lock_helper = new MidiManagerLockHelper(); |
| 114 return lock_helper; |
| 115 } |
| 109 | 116 |
| 110 int AddrToInt(int client, int port) { | 117 int AddrToInt(int client, int port) { |
| 111 return (client << 8) | port; | 118 return (client << 8) | port; |
| 112 } | 119 } |
| 113 | 120 |
| 114 // Returns true if this client has an ALSA card associated with it. | 121 // Returns true if this client has an ALSA card associated with it. |
| 115 bool IsCardClient(snd_seq_client_type_t type, int client_id) { | 122 bool IsCardClient(snd_seq_client_type_t type, int client_id) { |
| 116 return (type == SND_SEQ_KERNEL_CLIENT) && | 123 return (type == SND_SEQ_KERNEL_CLIENT) && |
| 117 (client_id >= kMinimumClientIdForCards); | 124 (client_id >= kMinimumClientIdForCards); |
| 118 } | 125 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 base::AutoLock lock(lazy_init_member_lock_); | 185 base::AutoLock lock(lazy_init_member_lock_); |
| 179 | 186 |
| 180 // Extra CHECK to verify all members are already reset. | 187 // Extra CHECK to verify all members are already reset. |
| 181 CHECK(!initialization_thread_checker_); | 188 CHECK(!initialization_thread_checker_); |
| 182 CHECK(!in_client_); | 189 CHECK(!in_client_); |
| 183 CHECK(!out_client_); | 190 CHECK(!out_client_); |
| 184 CHECK(!decoder_); | 191 CHECK(!decoder_); |
| 185 CHECK(!udev_); | 192 CHECK(!udev_); |
| 186 CHECK(!udev_monitor_); | 193 CHECK(!udev_monitor_); |
| 187 | 194 |
| 188 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | 195 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock); |
| 189 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); | 196 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); |
| 190 } | 197 } |
| 191 | 198 |
| 192 void MidiManagerAlsa::StartInitialization() { | 199 void MidiManagerAlsa::StartInitialization() { |
| 193 { | 200 { |
| 194 base::AutoLock lock(g_instance_id_lock.Get()); | 201 base::AutoLock lock(GetLockHelper()->instance_id_lock); |
| 195 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); | 202 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); |
| 196 instance_id_ = g_next_instance_id++; | 203 instance_id_ = g_next_instance_id++; |
| 197 g_active_instance_id = instance_id_; | 204 g_active_instance_id = instance_id_; |
| 198 } | 205 } |
| 199 | 206 |
| 200 base::AutoLock lock(lazy_init_member_lock_); | 207 base::AutoLock lock(lazy_init_member_lock_); |
| 201 | 208 |
| 202 initialization_thread_checker_.reset(new base::ThreadChecker()); | 209 initialization_thread_checker_.reset(new base::ThreadChecker()); |
| 203 | 210 |
| 204 // Create client handles. | 211 // Create client handles. |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 } | 327 } |
| 321 | 328 |
| 322 void MidiManagerAlsa::Finalize() { | 329 void MidiManagerAlsa::Finalize() { |
| 323 base::AutoLock lock(lazy_init_member_lock_); | 330 base::AutoLock lock(lazy_init_member_lock_); |
| 324 DCHECK(initialization_thread_checker_->CalledOnValidThread()); | 331 DCHECK(initialization_thread_checker_->CalledOnValidThread()); |
| 325 | 332 |
| 326 // Tell tasks running on TaskRunners it will soon be time to shut down. This | 333 // Tell tasks running on TaskRunners it will soon be time to shut down. This |
| 327 // gives us assurance a task running on kEventTaskRunner will stop in case the | 334 // gives us assurance a task running on kEventTaskRunner will stop in case the |
| 328 // SND_SEQ_EVENT_CLIENT_EXIT message is lost. | 335 // SND_SEQ_EVENT_CLIENT_EXIT message is lost. |
| 329 { | 336 { |
| 330 base::AutoLock lock(g_instance_id_lock.Get()); | 337 base::AutoLock lock(GetLockHelper()->instance_id_lock); |
| 331 CHECK_EQ(instance_id_, g_active_instance_id); | 338 CHECK_EQ(instance_id_, g_active_instance_id); |
| 332 g_active_instance_id = kInvalidInstanceId; | 339 g_active_instance_id = kInvalidInstanceId; |
| 333 } | 340 } |
| 334 | 341 |
| 335 // Ensure that no tasks run on kSendTaskRunner. | 342 // Ensure that no tasks run on kSendTaskRunner. |
| 336 base::AutoLock send_runner_lock(g_send_task_lock.Get()); | 343 base::AutoLock send_runner_lock(GetLockHelper()->send_task_lock); |
| 337 | 344 |
| 338 // Close the out client. This will trigger the event thread to stop, | 345 // Close the out client. This will trigger the event thread to stop, |
| 339 // because of SND_SEQ_EVENT_CLIENT_EXIT. | 346 // because of SND_SEQ_EVENT_CLIENT_EXIT. |
| 340 out_client_.reset(); | 347 out_client_.reset(); |
| 341 | 348 |
| 342 // Ensure that no tasks run on kEventTaskRunner. | 349 // Ensure that no tasks run on kEventTaskRunner. |
| 343 base::AutoLock event_runner_lock(g_event_task_lock.Get()); | 350 base::AutoLock event_runner_lock(GetLockHelper()->event_task_lock); |
| 344 | 351 |
| 345 // Destruct the other stuff we initialized in StartInitialization(). | 352 // Destruct the other stuff we initialized in StartInitialization(). |
| 346 udev_monitor_.reset(); | 353 udev_monitor_.reset(); |
| 347 udev_.reset(); | 354 udev_.reset(); |
| 348 decoder_.reset(); | 355 decoder_.reset(); |
| 349 in_client_.reset(); | 356 in_client_.reset(); |
| 350 initialization_thread_checker_.reset(); | 357 initialization_thread_checker_.reset(); |
| 351 } | 358 } |
| 352 | 359 |
| 353 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, | 360 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, |
| (...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 } | 893 } |
| 887 | 894 |
| 888 void MidiManagerAlsa::SendMidiData(int instance_id, | 895 void MidiManagerAlsa::SendMidiData(int instance_id, |
| 889 MidiManagerClient* client, | 896 MidiManagerClient* client, |
| 890 uint32_t port_index, | 897 uint32_t port_index, |
| 891 const std::vector<uint8_t>& data) { | 898 const std::vector<uint8_t>& data) { |
| 892 DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread()); | 899 DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread()); |
| 893 | 900 |
| 894 // Obtain the lock so that the instance could not be destructed while this | 901 // Obtain the lock so that the instance could not be destructed while this |
| 895 // method is running on the kSendTaskRunner. | 902 // method is running on the kSendTaskRunner. |
| 896 base::AutoLock lock(g_send_task_lock.Get()); | 903 base::AutoLock lock(GetLockHelper()->send_task_lock); |
| 897 { | 904 { |
| 898 // Check if Finalize() already runs. After this check, we can access |this| | 905 // Check if Finalize() already runs. After this check, we can access |this| |
| 899 // safely on the kEventTaskRunner. | 906 // safely on the kEventTaskRunner. |
| 900 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | 907 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock); |
| 901 if (instance_id != g_active_instance_id) | 908 if (instance_id != g_active_instance_id) |
| 902 return; | 909 return; |
| 903 } | 910 } |
| 904 | 911 |
| 905 snd_midi_event_t* encoder; | 912 snd_midi_event_t* encoder; |
| 906 snd_midi_event_new(kSendBufferSize, &encoder); | 913 snd_midi_event_new(kSendBufferSize, &encoder); |
| 907 for (const auto datum : data) { | 914 for (const auto datum : data) { |
| 908 snd_seq_event_t event; | 915 snd_seq_event_t event; |
| 909 int result = snd_midi_event_encode_byte(encoder, datum, &event); | 916 int result = snd_midi_event_encode_byte(encoder, datum, &event); |
| 910 if (result == 1) { | 917 if (result == 1) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 921 } | 928 } |
| 922 snd_midi_event_free(encoder); | 929 snd_midi_event_free(encoder); |
| 923 | 930 |
| 924 // Acknowledge send. | 931 // Acknowledge send. |
| 925 AccumulateMidiBytesSent(client, data.size()); | 932 AccumulateMidiBytesSent(client, data.size()); |
| 926 } | 933 } |
| 927 | 934 |
| 928 void MidiManagerAlsa::EventLoop(int instance_id) { | 935 void MidiManagerAlsa::EventLoop(int instance_id) { |
| 929 // Obtain the lock so that the instance could not be destructed while this | 936 // Obtain the lock so that the instance could not be destructed while this |
| 930 // method is running on the kEventTaskRunner. | 937 // method is running on the kEventTaskRunner. |
| 931 base::AutoLock lock(g_event_task_lock.Get()); | 938 base::AutoLock lock(GetLockHelper()->event_task_lock); |
| 932 { | 939 { |
| 933 // Check if Finalize() already runs. After this check, we can access |this| | 940 // Check if Finalize() already runs. After this check, we can access |this| |
| 934 // safely on the kEventTaskRunner. | 941 // safely on the kEventTaskRunner. |
| 935 base::AutoLock instance_id_lock(g_instance_id_lock.Get()); | 942 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock); |
| 936 if (instance_id != g_active_instance_id) | 943 if (instance_id != g_active_instance_id) |
| 937 return; | 944 return; |
| 938 } | 945 } |
| 939 | 946 |
| 940 bool loop_again = true; | 947 bool loop_again = true; |
| 941 | 948 |
| 942 struct pollfd pfd[2]; | 949 struct pollfd pfd[2]; |
| 943 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); | 950 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); |
| 944 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); | 951 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); |
| 945 pfd[1].events = POLLIN; | 952 pfd[1].events = POLLIN; |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1442 // Update our map. | 1449 // Update our map. |
| 1443 source_map_[AddrToInt(client_id, port_id)] = port_index; | 1450 source_map_[AddrToInt(client_id, port_id)] = port_index; |
| 1444 return true; | 1451 return true; |
| 1445 } | 1452 } |
| 1446 | 1453 |
| 1447 MidiManager* MidiManager::Create(MidiService* service) { | 1454 MidiManager* MidiManager::Create(MidiService* service) { |
| 1448 return new MidiManagerAlsa(service); | 1455 return new MidiManagerAlsa(service); |
| 1449 } | 1456 } |
| 1450 | 1457 |
| 1451 } // namespace midi | 1458 } // namespace midi |
| OLD | NEW |