Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(591)

Side by Side Diff: media/midi/midi_manager_alsa.cc

Issue 2923163003: Web MIDI: use midi::TaskService in MidiManagerAlsa (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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>
(...skipping 10 matching lines...) Expand all
21 #include "base/message_loop/message_loop.h" 21 #include "base/message_loop/message_loop.h"
22 #include "base/posix/eintr_wrapper.h" 22 #include "base/posix/eintr_wrapper.h"
23 #include "base/posix/safe_strerror.h" 23 #include "base/posix/safe_strerror.h"
24 #include "base/single_thread_task_runner.h" 24 #include "base/single_thread_task_runner.h"
25 #include "base/strings/string_number_conversions.h" 25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/stringprintf.h" 26 #include "base/strings/stringprintf.h"
27 #include "base/time/time.h" 27 #include "base/time/time.h"
28 #include "crypto/sha2.h" 28 #include "crypto/sha2.h"
29 #include "media/midi/midi_port_info.h" 29 #include "media/midi/midi_port_info.h"
30 #include "media/midi/midi_service.h" 30 #include "media/midi/midi_service.h"
31 #include "media/midi/task_service.h"
31 32
32 namespace midi { 33 namespace midi {
33 34
34 namespace { 35 namespace {
35 36
36 using mojom::PortState; 37 using mojom::PortState;
37 using mojom::Result; 38 using mojom::Result;
38 39
39 // TODO(toyoshim): use constexpr for following const values. 40 enum {
40 const int kEventTaskRunner = 0; 41 kDefaultRunnerNotUsedOnAlsa = TaskService::kDefaultRunnerId,
41 const int kSendTaskRunner = 1; 42 kEventTaskRunner,
43 kSendTaskRunner
44 };
42 45
43 // Per-output buffer. This can be smaller, but then large sysex messages 46 // Per-output buffer. This can be smaller, but then large sysex messages
44 // will be (harmlessly) split across multiple seq events. This should 47 // will be (harmlessly) split across multiple seq events. This should
45 // not have any real practical effect, except perhaps to slightly reorder 48 // not have any real practical effect, except perhaps to slightly reorder
46 // realtime messages with respect to sysex. 49 // realtime messages with respect to sysex.
47 const size_t kSendBufferSize = 256; 50 constexpr size_t kSendBufferSize = 256;
48 51
49 // Minimum client id for which we will have ALSA card devices for. When we 52 // Minimum client id for which we will have ALSA card devices for. When we
50 // are searching for card devices (used to get the path, id, and manufacturer), 53 // are searching for card devices (used to get the path, id, and manufacturer),
51 // we don't want to get confused by kernel clients that do not have a card. 54 // we don't want to get confused by kernel clients that do not have a card.
52 // See seq_clientmgr.c in the ALSA code for this. 55 // See seq_clientmgr.c in the ALSA code for this.
53 // TODO(agoode): Add proper client -> card export from the kernel to avoid 56 // TODO(agoode): Add proper client -> card export from the kernel to avoid
54 // hardcoding. 57 // hardcoding.
55 const int kMinimumClientIdForCards = 16; 58 constexpr int kMinimumClientIdForCards = 16;
56 59
57 // ALSA constants. 60 // ALSA constants.
58 const char kAlsaHw[] = "hw"; 61 const char kAlsaHw[] = "hw";
59 62
60 // udev constants. 63 // udev constants.
61 const char kUdev[] = "udev"; 64 const char kUdev[] = "udev";
62 const char kUdevSubsystemSound[] = "sound"; 65 const char kUdevSubsystemSound[] = "sound";
63 const char kUdevPropertySoundInitialized[] = "SOUND_INITIALIZED"; 66 const char kUdevPropertySoundInitialized[] = "SOUND_INITIALIZED";
64 const char kUdevActionChange[] = "change"; 67 const char kUdevActionChange[] = "change";
65 const char kUdevActionRemove[] = "remove"; 68 const char kUdevActionRemove[] = "remove";
(...skipping 10 matching lines...) Expand all
76 79
77 const char kSysattrVendorName[] = "vendor_name"; 80 const char kSysattrVendorName[] = "vendor_name";
78 const char kSysattrVendor[] = "vendor"; 81 const char kSysattrVendor[] = "vendor";
79 const char kSysattrModel[] = "model"; 82 const char kSysattrModel[] = "model";
80 const char kSysattrGuid[] = "guid"; 83 const char kSysattrGuid[] = "guid";
81 84
82 const char kCardSyspath[] = "/card"; 85 const char kCardSyspath[] = "/card";
83 86
84 // Constants for the capabilities we search for in inputs and outputs. 87 // Constants for the capabilities we search for in inputs and outputs.
85 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. 88 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html.
86 const unsigned int kRequiredInputPortCaps = 89 constexpr unsigned int kRequiredInputPortCaps =
87 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; 90 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
88 const unsigned int kRequiredOutputPortCaps = 91 constexpr unsigned int kRequiredOutputPortCaps =
89 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; 92 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
90 93
91 const unsigned int kCreateOutputPortCaps = 94 constexpr unsigned int kCreateOutputPortCaps =
92 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; 95 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT;
93 const unsigned int kCreateInputPortCaps = 96 constexpr unsigned int kCreateInputPortCaps =
94 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; 97 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT;
95 const unsigned int kCreatePortType = 98 constexpr unsigned int kCreatePortType =
96 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; 99 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION;
97 100
98 // Global variables to identify MidiManagerAlsa instance.
99 const int kInvalidInstanceId = -1;
100 int g_active_instance_id = kInvalidInstanceId;
101 int g_next_instance_id = 0;
102
103 struct MidiManagerLockHelper {
104 base::Lock instance_id_lock;
105
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 }
116
117 int AddrToInt(int client, int port) { 101 int AddrToInt(int client, int port) {
118 return (client << 8) | port; 102 return (client << 8) | port;
119 } 103 }
120 104
121 // Returns true if this client has an ALSA card associated with it. 105 // Returns true if this client has an ALSA card associated with it.
122 bool IsCardClient(snd_seq_client_type_t type, int client_id) { 106 bool IsCardClient(snd_seq_client_type_t type, int client_id) {
123 return (type == SND_SEQ_KERNEL_CLIENT) && 107 return (type == SND_SEQ_KERNEL_CLIENT) &&
124 (client_id >= kMinimumClientIdForCards); 108 (client_id >= kMinimumClientIdForCards);
125 } 109 }
126 110
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 const std::string& in_value) { 157 const std::string& in_value) {
174 if (!in_value.empty()) 158 if (!in_value.empty())
175 value->SetString(path, in_value); 159 value->SetString(path, in_value);
176 } 160 }
177 161
178 } // namespace 162 } // namespace
179 163
180 MidiManagerAlsa::MidiManagerAlsa(MidiService* service) : MidiManager(service) {} 164 MidiManagerAlsa::MidiManagerAlsa(MidiService* service) : MidiManager(service) {}
181 165
182 MidiManagerAlsa::~MidiManagerAlsa() { 166 MidiManagerAlsa::~MidiManagerAlsa() {
183 // Take lock to ensure that the members initialized on the IO thread
184 // are not destructed here.
185 base::AutoLock lock(lazy_init_member_lock_);
186
187 // Extra CHECK to verify all members are already reset. 167 // Extra CHECK to verify all members are already reset.
188 CHECK(!initialization_thread_checker_);
189 CHECK(!in_client_); 168 CHECK(!in_client_);
190 CHECK(!out_client_); 169 CHECK(!out_client_);
191 CHECK(!decoder_); 170 CHECK(!decoder_);
192 CHECK(!udev_); 171 CHECK(!udev_);
193 CHECK(!udev_monitor_); 172 CHECK(!udev_monitor_);
194
195 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock);
196 CHECK_EQ(kInvalidInstanceId, g_active_instance_id);
197 } 173 }
198 174
199 void MidiManagerAlsa::StartInitialization() { 175 void MidiManagerAlsa::StartInitialization() {
200 { 176 if (!service()->task_service()->BindInstance()) {
201 base::AutoLock lock(GetLockHelper()->instance_id_lock); 177 NOTREACHED();
202 CHECK_EQ(kInvalidInstanceId, g_active_instance_id); 178 return CompleteInitialization(Result::INITIALIZATION_ERROR);
203 instance_id_ = g_next_instance_id++;
204 g_active_instance_id = instance_id_;
205 } 179 }
206 180
207 base::AutoLock lock(lazy_init_member_lock_);
208
209 initialization_thread_checker_.reset(new base::ThreadChecker());
210
211 // Create client handles. 181 // Create client handles.
212 snd_seq_t* tmp_seq = nullptr; 182 snd_seq_t* tmp_seq = nullptr;
213 int err = 183 int err =
214 snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK); 184 snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK);
215 if (err != 0) { 185 if (err != 0) {
216 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); 186 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err);
217 return CompleteInitialization(Result::INITIALIZATION_ERROR); 187 return CompleteInitialization(Result::INITIALIZATION_ERROR);
218 } 188 }
219 ScopedSndSeqPtr in_client(tmp_seq); 189 ScopedSndSeqPtr in_client(tmp_seq);
220 tmp_seq = nullptr; 190 tmp_seq = nullptr;
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 // TODO(agoode): Check the return value for failure. 281 // TODO(agoode): Check the return value for failure.
312 EnumerateAlsaPorts(); 282 EnumerateAlsaPorts();
313 283
314 // Generate hotplug events for existing udev devices. This must be done 284 // Generate hotplug events for existing udev devices. This must be done
315 // after udev_monitor_enable_receiving() is called. See the algorithm 285 // after udev_monitor_enable_receiving() is called. See the algorithm
316 // at http://www.signal11.us/oss/udev/. 286 // at http://www.signal11.us/oss/udev/.
317 EnumerateUdevCards(); 287 EnumerateUdevCards();
318 288
319 // Start processing events. Don't do this before enumeration of both 289 // Start processing events. Don't do this before enumeration of both
320 // ALSA and udev. 290 // ALSA and udev.
321 service() 291 service()->task_service()->PostBoundTask(
322 ->GetTaskRunner(kEventTaskRunner) 292 kEventTaskRunner,
323 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, 293 base::BindOnce(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
324 base::Unretained(this), instance_id_));
325 294
326 CompleteInitialization(Result::OK); 295 CompleteInitialization(Result::OK);
327 } 296 }
328 297
329 void MidiManagerAlsa::Finalize() { 298 void MidiManagerAlsa::Finalize() {
330 base::AutoLock lock(lazy_init_member_lock_);
331 DCHECK(initialization_thread_checker_->CalledOnValidThread());
332
333 // Tell tasks running on TaskRunners it will soon be time to shut down. This
334 // gives us assurance a task running on kEventTaskRunner will stop in case the
335 // SND_SEQ_EVENT_CLIENT_EXIT message is lost.
336 {
337 base::AutoLock lock(GetLockHelper()->instance_id_lock);
338 CHECK_EQ(instance_id_, g_active_instance_id);
339 g_active_instance_id = kInvalidInstanceId;
340 }
341
342 // Ensure that no tasks run on kSendTaskRunner.
343 base::AutoLock send_runner_lock(GetLockHelper()->send_task_lock);
344
345 // Close the out client. This will trigger the event thread to stop, 299 // Close the out client. This will trigger the event thread to stop,
346 // because of SND_SEQ_EVENT_CLIENT_EXIT. 300 // because of SND_SEQ_EVENT_CLIENT_EXIT.
347 out_client_.reset(); 301 out_client_.reset();
348 302
349 // Ensure that no tasks run on kEventTaskRunner. 303 // Ensure that no task is running any more.
350 base::AutoLock event_runner_lock(GetLockHelper()->event_task_lock); 304 bool result = service()->task_service()->UnbindInstance();
305 CHECK(result);
351 306
352 // Destruct the other stuff we initialized in StartInitialization(). 307 // Destruct the other stuff we initialized in StartInitialization().
353 udev_monitor_.reset(); 308 udev_monitor_.reset();
354 udev_.reset(); 309 udev_.reset();
355 decoder_.reset(); 310 decoder_.reset();
356 in_client_.reset(); 311 in_client_.reset();
357 initialization_thread_checker_.reset();
358 } 312 }
359 313
360 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, 314 void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client,
361 uint32_t port_index, 315 uint32_t port_index,
362 const std::vector<uint8_t>& data, 316 const std::vector<uint8_t>& data,
363 double timestamp) { 317 double timestamp) {
364 base::TimeDelta delay; 318 base::TimeDelta delay;
365 if (timestamp != 0.0) { 319 if (timestamp != 0.0) {
366 base::TimeTicks time_to_send = 320 base::TimeTicks time_to_send =
367 base::TimeTicks() + base::TimeDelta::FromMicroseconds( 321 base::TimeTicks() + base::TimeDelta::FromMicroseconds(
368 timestamp * base::Time::kMicrosecondsPerSecond); 322 timestamp * base::Time::kMicrosecondsPerSecond);
369 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); 323 delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta());
370 } 324 }
371 325
372 service() 326 service()->task_service()->PostBoundDelayedTask(
373 ->GetTaskRunner(kSendTaskRunner) 327 kSendTaskRunner,
374 ->PostDelayedTask( 328 base::BindOnce(&MidiManagerAlsa::SendMidiData, base::Unretained(this),
375 FROM_HERE, 329 client, port_index, data),
376 base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this), 330 delay);
377 instance_id_, client, port_index, data),
378 delay);
379 } 331 }
380 332
381 MidiManagerAlsa::MidiPort::Id::Id() = default; 333 MidiManagerAlsa::MidiPort::Id::Id() = default;
382 334
383 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus, 335 MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus,
384 const std::string& vendor_id, 336 const std::string& vendor_id,
385 const std::string& model_id, 337 const std::string& model_id,
386 const std::string& usb_interface_num, 338 const std::string& usb_interface_num,
387 const std::string& serial) 339 const std::string& serial)
388 : bus_(bus), 340 : bus_(bus),
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 if (at_index && at_index != std::string::npos) { 837 if (at_index && at_index != std::string::npos) {
886 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); 838 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1);
887 if (name_index && name_index != std::string::npos) 839 if (name_index && name_index != std::string::npos)
888 return alsa_longname.substr(0, name_index - 1); 840 return alsa_longname.substr(0, name_index - 1);
889 } 841 }
890 842
891 // Failure. 843 // Failure.
892 return ""; 844 return "";
893 } 845 }
894 846
895 void MidiManagerAlsa::SendMidiData(int instance_id, 847 void MidiManagerAlsa::SendMidiData(MidiManagerClient* client,
896 MidiManagerClient* client,
897 uint32_t port_index, 848 uint32_t port_index,
898 const std::vector<uint8_t>& data) { 849 const std::vector<uint8_t>& data) {
899 DCHECK(service()->GetTaskRunner(kSendTaskRunner)->BelongsToCurrentThread());
900
901 // Obtain the lock so that the instance could not be destructed while this
902 // method is running on the kSendTaskRunner.
903 base::AutoLock lock(GetLockHelper()->send_task_lock);
904 {
905 // Check if Finalize() already runs. After this check, we can access |this|
906 // safely on the kEventTaskRunner.
907 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock);
908 if (instance_id != g_active_instance_id)
909 return;
910 }
911
912 snd_midi_event_t* encoder; 850 snd_midi_event_t* encoder;
913 snd_midi_event_new(kSendBufferSize, &encoder); 851 snd_midi_event_new(kSendBufferSize, &encoder);
914 for (const auto datum : data) { 852 for (const auto datum : data) {
915 snd_seq_event_t event; 853 snd_seq_event_t event;
916 int result = snd_midi_event_encode_byte(encoder, datum, &event); 854 int result = snd_midi_event_encode_byte(encoder, datum, &event);
917 if (result == 1) { 855 if (result == 1) {
918 // Full event, send it. 856 // Full event, send it.
919 base::AutoLock lock(out_ports_lock_); 857 base::AutoLock lock(out_ports_lock_);
920 auto it = out_ports_.find(port_index); 858 auto it = out_ports_.find(port_index);
921 if (it != out_ports_.end()) { 859 if (it != out_ports_.end()) {
922 snd_seq_ev_set_source(&event, it->second); 860 snd_seq_ev_set_source(&event, it->second);
923 snd_seq_ev_set_subs(&event); 861 snd_seq_ev_set_subs(&event);
924 snd_seq_ev_set_direct(&event); 862 snd_seq_ev_set_direct(&event);
925 snd_seq_event_output_direct(out_client_.get(), &event); 863 snd_seq_event_output_direct(out_client_.get(), &event);
926 } 864 }
927 } 865 }
928 } 866 }
929 snd_midi_event_free(encoder); 867 snd_midi_event_free(encoder);
930 868
931 // Acknowledge send. 869 // Acknowledge send.
932 AccumulateMidiBytesSent(client, data.size()); 870 AccumulateMidiBytesSent(client, data.size());
933 } 871 }
934 872
935 void MidiManagerAlsa::EventLoop(int instance_id) { 873 void MidiManagerAlsa::EventLoop() {
936 // Obtain the lock so that the instance could not be destructed while this
937 // method is running on the kEventTaskRunner.
938 base::AutoLock lock(GetLockHelper()->event_task_lock);
939 {
940 // Check if Finalize() already runs. After this check, we can access |this|
941 // safely on the kEventTaskRunner.
942 base::AutoLock instance_id_lock(GetLockHelper()->instance_id_lock);
943 if (instance_id != g_active_instance_id)
944 return;
945 }
946
947 bool loop_again = true; 874 bool loop_again = true;
948 875
949 struct pollfd pfd[2]; 876 struct pollfd pfd[2];
950 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN); 877 snd_seq_poll_descriptors(in_client_.get(), &pfd[0], 1, POLLIN);
951 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get()); 878 pfd[1].fd = device::udev_monitor_get_fd(udev_monitor_.get());
952 pfd[1].events = POLLIN; 879 pfd[1].events = POLLIN;
953 880
954 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1)); 881 int err = HANDLE_EINTR(poll(pfd, arraysize(pfd), -1));
955 if (err < 0) { 882 if (err < 0) {
956 VLOG(1) << "poll fails: " << base::safe_strerror(errno); 883 VLOG(1) << "poll fails: " << base::safe_strerror(errno);
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1013 device::udev_monitor_receive_device(udev_monitor_.get())); 940 device::udev_monitor_receive_device(udev_monitor_.get()));
1014 if (dev.get()) 941 if (dev.get())
1015 ProcessUdevEvent(dev.get()); 942 ProcessUdevEvent(dev.get());
1016 else 943 else
1017 VLOG(1) << "udev_monitor_receive_device fails"; 944 VLOG(1) << "udev_monitor_receive_device fails";
1018 } 945 }
1019 } 946 }
1020 947
1021 // Do again. 948 // Do again.
1022 if (loop_again) { 949 if (loop_again) {
1023 service() 950 service()->task_service()->PostBoundTask(
1024 ->GetTaskRunner(kEventTaskRunner) 951 kEventTaskRunner,
1025 ->PostTask(FROM_HERE, base::Bind(&MidiManagerAlsa::EventLoop, 952 base::BindOnce(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
1026 base::Unretained(this), instance_id));
1027 } 953 }
1028 } 954 }
1029 955
1030 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event, 956 void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event,
1031 double timestamp) { 957 double timestamp) {
1032 auto source_it = 958 auto source_it =
1033 source_map_.find(AddrToInt(event->source.client, event->source.port)); 959 source_map_.find(AddrToInt(event->source.client, event->source.port));
1034 if (source_it != source_map_.end()) { 960 if (source_it != source_map_.end()) {
1035 uint32_t source = source_it->second; 961 uint32_t source = source_it->second;
1036 if (event->type == SND_SEQ_EVENT_SYSEX) { 962 if (event->type == SND_SEQ_EVENT_SYSEX) {
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
1449 // Update our map. 1375 // Update our map.
1450 source_map_[AddrToInt(client_id, port_id)] = port_index; 1376 source_map_[AddrToInt(client_id, port_id)] = port_index;
1451 return true; 1377 return true;
1452 } 1378 }
1453 1379
1454 MidiManager* MidiManager::Create(MidiService* service) { 1380 MidiManager* MidiManager::Create(MidiService* service) {
1455 return new MidiManagerAlsa(service); 1381 return new MidiManagerAlsa(service);
1456 } 1382 }
1457 1383
1458 } // namespace midi 1384 } // namespace midi
OLDNEW
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698