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
3 // found in the LICENSE file.
5 #include "media/midi/midi_manager_android.h"
7 #include "base/android/build_info.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/stringprintf.h"
11 #include "jni/MidiManagerAndroid_jni.h"
12 #include "media/midi/midi_device_android.h"
13 #include "media/midi/midi_manager_usb.h"
14 #include "media/midi/midi_output_port_android.h"
15 #include "media/midi/midi_switches.h"
16 #include "media/midi/usb_midi_device_factory_android.h"
21 MidiManager
* MidiManager::Create() {
22 auto sdk_version
= base::android::BuildInfo::GetInstance()->sdk_int();
23 if (sdk_version
<= base::android::SDK_VERSION_LOLLIPOP_MR1
||
24 !base::CommandLine::ForCurrentProcess()->HasSwitch(
25 switches::kUseAndroidMidiApi
)) {
26 return new MidiManagerUsb(
27 scoped_ptr
<UsbMidiDevice::Factory
>(new UsbMidiDeviceFactoryAndroid
));
30 return new MidiManagerAndroid();
33 MidiManagerAndroid::MidiManagerAndroid() {}
35 MidiManagerAndroid::~MidiManagerAndroid() {}
37 void MidiManagerAndroid::StartInitialization() {
38 JNIEnv
* env
= base::android::AttachCurrentThread();
40 uintptr_t pointer
= reinterpret_cast<uintptr_t>(this);
41 raw_manager_
.Reset(Java_MidiManagerAndroid_create(
42 env
, base::android::GetApplicationContext(), pointer
));
43 scheduler_
.reset(new MidiScheduler(this));
44 Java_MidiManagerAndroid_initialize(env
, raw_manager_
.obj());
47 void MidiManagerAndroid::DispatchSendMidiData(MidiManagerClient
* client
,
49 const std::vector
<uint8
>& data
,
51 if (port_index
>= all_output_ports_
.size()) {
52 // |port_index| is provided by a renderer so we can't believe that it is
53 // in the valid range.
56 DCHECK_EQ(output_ports().size(), all_output_ports_
.size());
57 if (output_ports()[port_index
].state
== MIDI_PORT_CONNECTED
) {
58 // We treat send call as implicit open.
59 // TODO(yhirano): Implement explicit open operation from the renderer.
60 if (all_output_ports_
[port_index
]->Open()) {
61 SetOutputPortState(port_index
, MIDI_PORT_OPENED
);
63 // We cannot open the port. It's useless to send data to such a port.
68 // output_streams_[port_index] is alive unless MidiManagerUsb is deleted.
69 // The task posted to the MidiScheduler will be disposed safely on deleting
71 scheduler_
->PostSendDataTask(
72 client
, data
.size(), timestamp
,
73 base::Bind(&MidiOutputPortAndroid::Send
,
74 base::Unretained(all_output_ports_
[port_index
]), data
));
77 void MidiManagerAndroid::OnReceivedData(MidiInputPortAndroid
* port
,
80 base::TimeTicks timestamp
) {
81 const auto i
= input_port_to_index_
.find(port
);
82 DCHECK(input_port_to_index_
.end() != i
);
83 ReceiveMidiData(i
->second
, data
, size
, timestamp
);
86 void MidiManagerAndroid::OnInitialized(JNIEnv
* env
,
88 jobjectArray devices
) {
89 jsize length
= env
->GetArrayLength(devices
);
91 for (jsize i
= 0; i
< length
; ++i
) {
92 jobject raw_device
= env
->GetObjectArrayElement(devices
, i
);
93 AddDevice(make_scoped_ptr(new MidiDeviceAndroid(env
, raw_device
, this)));
95 CompleteInitialization(Result::OK
);
98 void MidiManagerAndroid::OnAttached(JNIEnv
* env
,
100 jobject raw_device
) {
101 AddDevice(make_scoped_ptr(new MidiDeviceAndroid(env
, raw_device
, this)));
104 void MidiManagerAndroid::OnDetached(JNIEnv
* env
,
106 jobject raw_device
) {
107 for (const auto& device
: devices_
) {
108 if (device
->HasRawDevice(env
, raw_device
)) {
109 for (const auto& port
: device
->input_ports()) {
110 DCHECK(input_port_to_index_
.end() != input_port_to_index_
.find(port
));
111 size_t index
= input_port_to_index_
[port
];
112 SetInputPortState(index
, MIDI_PORT_DISCONNECTED
);
114 for (const auto& port
: device
->output_ports()) {
115 DCHECK(output_port_to_index_
.end() != output_port_to_index_
.find(port
));
116 size_t index
= output_port_to_index_
[port
];
117 SetOutputPortState(index
, MIDI_PORT_DISCONNECTED
);
123 void MidiManagerAndroid::AddDevice(scoped_ptr
<MidiDeviceAndroid
> device
) {
124 for (auto& port
: device
->input_ports()) {
125 // We implicitly open input ports here, because there are no signal
126 // from the renderer when to open.
127 // TODO(yhirano): Implement open operation in Blink.
128 MidiPortState state
= port
->Open() ? MIDI_PORT_OPENED
: MIDI_PORT_CONNECTED
;
130 const size_t index
= all_input_ports_
.size();
131 all_input_ports_
.push_back(port
);
132 // Port ID must be unique in a MIDI manager. This ID setting is
133 // sufficiently unique although there is no user-friendly meaning.
134 // TODO(yhirano): Use a hashed string as ID.
135 const std::string
id(
136 base::StringPrintf("native:port-in-%ld", static_cast<long>(index
)));
138 input_port_to_index_
.insert(std::make_pair(port
, index
));
139 AddInputPort(MidiPortInfo(id
, device
->GetManufacturer(),
140 device
->GetProductName(),
141 device
->GetDeviceVersion(), state
));
143 for (const auto& port
: device
->output_ports()) {
144 const size_t index
= all_output_ports_
.size();
145 all_output_ports_
.push_back(port
);
147 // Port ID must be unique in a MIDI manager. This ID setting is
148 // sufficiently unique although there is no user-friendly meaning.
149 // TODO(yhirano): Use a hashed string as ID.
150 const std::string
id(
151 base::StringPrintf("native:port-out-%ld", static_cast<long>(index
)));
153 output_port_to_index_
.insert(std::make_pair(port
, index
));
155 MidiPortInfo(id
, device
->GetManufacturer(), device
->GetProductName(),
156 device
->GetDeviceVersion(), MIDI_PORT_CONNECTED
));
158 devices_
.push_back(device
.release());
161 bool MidiManagerAndroid::Register(JNIEnv
* env
) {
162 return RegisterNativesImpl(env
);