Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / midi / midi_manager_android.cc
blob19140e5acc4edeaa8ff12179ac200ec2e6ea3fed
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"
18 namespace media {
19 namespace midi {
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,
48 uint32 port_index,
49 const std::vector<uint8>& data,
50 double timestamp) {
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.
54 return;
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);
62 } else {
63 // We cannot open the port. It's useless to send data to such a port.
64 return;
68 // output_streams_[port_index] is alive unless MidiManagerUsb is deleted.
69 // The task posted to the MidiScheduler will be disposed safely on deleting
70 // the scheduler.
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,
78 const uint8* data,
79 size_t size,
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,
87 jobject caller,
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,
99 jobject caller,
100 jobject raw_device) {
101 AddDevice(make_scoped_ptr(new MidiDeviceAndroid(env, raw_device, this)));
104 void MidiManagerAndroid::OnDetached(JNIEnv* env,
105 jobject caller,
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));
154 AddOutputPort(
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);
165 } // namespace midi
166 } // namespace media