| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "chromeos/dbus/fake_bluetooth_media_transport_client.h" | |
| 6 | |
| 7 #include <unistd.h> | |
| 8 #include <sys/socket.h> | |
| 9 | |
| 10 #include <sstream> | |
| 11 | |
| 12 #include "base/bind.h" | |
| 13 #include "base/stl_util.h" | |
| 14 #include "chromeos/dbus/bluetooth_media_client.h" | |
| 15 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 16 #include "chromeos/dbus/fake_bluetooth_adapter_client.h" | |
| 17 #include "chromeos/dbus/fake_bluetooth_media_client.h" | |
| 18 #include "chromeos/dbus/fake_bluetooth_media_endpoint_service_provider.h" | |
| 19 #include "dbus/file_descriptor.h" | |
| 20 | |
| 21 using dbus::ObjectPath; | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // TODO(mcchou): Remove this constants once it is in cros_system_api. | |
| 26 const char kBluetoothMediaTransportInterface[] = "org.bluez.MediaTransport1"; | |
| 27 const char kNotImplemented[] = "org.bluez.NotImplemented"; | |
| 28 const char kNotAuthorized[] = "org.bluez.NotAuthorized"; | |
| 29 const char kFailed[] = "org.bluez.Failed"; | |
| 30 const char kNotAvailable[] = "org.bluez.NotAvailable"; | |
| 31 | |
| 32 const int kInvalidFd = -1; | |
| 33 | |
| 34 ObjectPath GenerateTransportPath() { | |
| 35 static unsigned int sequence_number = 0; | |
| 36 ++sequence_number; | |
| 37 std::stringstream path; | |
| 38 path << chromeos::FakeBluetoothAdapterClient::kAdapterPath | |
| 39 << chromeos::FakeBluetoothMediaTransportClient::kTransportDevicePath | |
| 40 << "/fd" << sequence_number; | |
| 41 return ObjectPath(path.str()); | |
| 42 } | |
| 43 | |
| 44 } // namespace | |
| 45 | |
| 46 namespace chromeos { | |
| 47 | |
| 48 // static | |
| 49 const char FakeBluetoothMediaTransportClient::kTransportDevicePath[] = | |
| 50 "/fake_audio_source"; | |
| 51 const uint8_t FakeBluetoothMediaTransportClient::kTransportCodec = 0x00; | |
| 52 const std::vector<uint8_t> | |
| 53 FakeBluetoothMediaTransportClient::kTransportConfiguration = { | |
| 54 0x21, 0x15, 0x33, 0x2C}; | |
| 55 const uint16_t FakeBluetoothMediaTransportClient::kTransportDelay = 5; | |
| 56 const uint16_t FakeBluetoothMediaTransportClient::kTransportVolume = 50; | |
| 57 const uint16_t FakeBluetoothMediaTransportClient::kDefaultReadMtu = 20; | |
| 58 const uint16_t FakeBluetoothMediaTransportClient::kDefaultWriteMtu = 25; | |
| 59 | |
| 60 FakeBluetoothMediaTransportClient::Properties::Properties( | |
| 61 const PropertyChangedCallback& callback) | |
| 62 : BluetoothMediaTransportClient::Properties( | |
| 63 nullptr, | |
| 64 kBluetoothMediaTransportInterface, | |
| 65 callback) { | |
| 66 } | |
| 67 | |
| 68 FakeBluetoothMediaTransportClient::Properties::~Properties() { | |
| 69 } | |
| 70 | |
| 71 void FakeBluetoothMediaTransportClient::Properties::Get( | |
| 72 dbus::PropertyBase* property, | |
| 73 dbus::PropertySet::GetCallback callback) { | |
| 74 VLOG(1) << "Get " << property->name(); | |
| 75 callback.Run(false); | |
| 76 } | |
| 77 | |
| 78 void FakeBluetoothMediaTransportClient::Properties::GetAll() { | |
| 79 VLOG(1) << "GetAll called."; | |
| 80 } | |
| 81 | |
| 82 void FakeBluetoothMediaTransportClient::Properties::Set( | |
| 83 dbus::PropertyBase* property, | |
| 84 dbus::PropertySet::SetCallback callback) { | |
| 85 VLOG(1) << "Set " << property->name(); | |
| 86 callback.Run(false); | |
| 87 } | |
| 88 | |
| 89 FakeBluetoothMediaTransportClient::Transport::Transport( | |
| 90 const ObjectPath& transport_path, | |
| 91 Properties* transport_properties) | |
| 92 : path(transport_path) { | |
| 93 properties.reset(transport_properties); | |
| 94 } | |
| 95 | |
| 96 FakeBluetoothMediaTransportClient::Transport::~Transport() { | |
| 97 } | |
| 98 | |
| 99 FakeBluetoothMediaTransportClient::FakeBluetoothMediaTransportClient() { | |
| 100 } | |
| 101 | |
| 102 FakeBluetoothMediaTransportClient::~FakeBluetoothMediaTransportClient() { | |
| 103 STLDeleteValues(&endpoint_to_transport_map_); | |
| 104 } | |
| 105 | |
| 106 // DBusClient override. | |
| 107 void FakeBluetoothMediaTransportClient::Init(dbus::Bus* bus) { | |
| 108 } | |
| 109 | |
| 110 void FakeBluetoothMediaTransportClient::AddObserver( | |
| 111 BluetoothMediaTransportClient::Observer* observer) { | |
| 112 observers_.AddObserver(observer); | |
| 113 } | |
| 114 | |
| 115 void FakeBluetoothMediaTransportClient::RemoveObserver( | |
| 116 BluetoothMediaTransportClient::Observer* observer) { | |
| 117 observers_.RemoveObserver(observer); | |
| 118 } | |
| 119 | |
| 120 FakeBluetoothMediaTransportClient::Properties* | |
| 121 FakeBluetoothMediaTransportClient::GetProperties( | |
| 122 const ObjectPath& object_path) { | |
| 123 const ObjectPath& endpoint_path = GetEndpointPath(object_path); | |
| 124 Transport* transport = GetTransport(endpoint_path); | |
| 125 if (!transport) | |
| 126 return nullptr; | |
| 127 return transport->properties.get(); | |
| 128 } | |
| 129 | |
| 130 void FakeBluetoothMediaTransportClient::Acquire( | |
| 131 const ObjectPath& object_path, | |
| 132 const AcquireCallback& callback, | |
| 133 const ErrorCallback& error_callback) { | |
| 134 VLOG(1) << "Acquire - transport path: " << object_path.value(); | |
| 135 AcquireInternal(false, object_path, callback, error_callback); | |
| 136 } | |
| 137 | |
| 138 void FakeBluetoothMediaTransportClient::TryAcquire( | |
| 139 const ObjectPath& object_path, | |
| 140 const AcquireCallback& callback, | |
| 141 const ErrorCallback& error_callback) { | |
| 142 VLOG(1) << "TryAcquire - transport path: " << object_path.value(); | |
| 143 AcquireInternal(true, object_path, callback, error_callback); | |
| 144 } | |
| 145 | |
| 146 void FakeBluetoothMediaTransportClient::Release( | |
| 147 const ObjectPath& object_path, | |
| 148 const base::Closure& callback, | |
| 149 const ErrorCallback& error_callback) { | |
| 150 error_callback.Run(kNotImplemented, ""); | |
| 151 } | |
| 152 | |
| 153 void FakeBluetoothMediaTransportClient::SetValid( | |
| 154 FakeBluetoothMediaEndpointServiceProvider* endpoint, | |
| 155 bool valid) { | |
| 156 FakeBluetoothMediaClient* media = static_cast<FakeBluetoothMediaClient*>( | |
| 157 DBusThreadManager::Get()->GetBluetoothMediaClient()); | |
| 158 DCHECK(media); | |
| 159 | |
| 160 ObjectPath endpoint_path(endpoint->object_path()); | |
| 161 if (!media->IsRegistered(endpoint_path)) | |
| 162 return; | |
| 163 | |
| 164 if (valid) { | |
| 165 ObjectPath transport_path = GenerateTransportPath(); | |
| 166 VLOG(1) << "New transport, " << transport_path.value() | |
| 167 << " is created for endpoint " << endpoint_path.value(); | |
| 168 | |
| 169 // Sets the fake property set with default values. | |
| 170 scoped_ptr<Properties> properties(new Properties( | |
| 171 base::Bind(&FakeBluetoothMediaTransportClient::OnPropertyChanged, | |
| 172 base::Unretained(this)))); | |
| 173 properties->device.ReplaceValue(ObjectPath(kTransportDevicePath)); | |
| 174 properties->uuid.ReplaceValue( | |
| 175 BluetoothMediaClient::kBluetoothAudioSinkUUID); | |
| 176 properties->codec.ReplaceValue(kTransportCodec); | |
| 177 properties->configuration.ReplaceValue(kTransportConfiguration); | |
| 178 properties->state.ReplaceValue(BluetoothMediaTransportClient::kStateIdle); | |
| 179 properties->delay.ReplaceValue(kTransportDelay); | |
| 180 properties->volume.ReplaceValue(kTransportVolume); | |
| 181 | |
| 182 endpoint_to_transport_map_[endpoint_path] = | |
| 183 new Transport(transport_path, properties.release()); | |
| 184 transport_to_endpoint_map_[transport_path] = endpoint_path; | |
| 185 return; | |
| 186 } | |
| 187 | |
| 188 Transport* transport = GetTransport(endpoint_path); | |
| 189 if (!transport) | |
| 190 return; | |
| 191 ObjectPath transport_path = transport->path; | |
| 192 | |
| 193 // Notifies observers about the state change of the transport. | |
| 194 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_, | |
| 195 MediaTransportRemoved(transport_path)); | |
| 196 | |
| 197 endpoint->ClearConfiguration(transport_path); | |
| 198 delete transport; | |
| 199 endpoint_to_transport_map_.erase(endpoint_path); | |
| 200 transport_to_endpoint_map_.erase(transport_path); | |
| 201 } | |
| 202 | |
| 203 void FakeBluetoothMediaTransportClient::SetState( | |
| 204 const ObjectPath& endpoint_path, | |
| 205 const std::string& state) { | |
| 206 VLOG(1) << "SetState - state: " << state; | |
| 207 | |
| 208 Transport* transport = GetTransport(endpoint_path); | |
| 209 if (!transport) | |
| 210 return; | |
| 211 | |
| 212 transport->properties->state.ReplaceValue(state); | |
| 213 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_, | |
| 214 MediaTransportPropertyChanged( | |
| 215 transport->path, | |
| 216 BluetoothMediaTransportClient::kStateProperty)); | |
| 217 } | |
| 218 | |
| 219 void FakeBluetoothMediaTransportClient::SetVolume( | |
| 220 const ObjectPath& endpoint_path, | |
| 221 const uint16_t& volume) { | |
| 222 Transport* transport = GetTransport(endpoint_path); | |
| 223 if (!transport) | |
| 224 return; | |
| 225 | |
| 226 transport->properties->volume.ReplaceValue(volume); | |
| 227 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_, | |
| 228 MediaTransportPropertyChanged( | |
| 229 transport->path, | |
| 230 BluetoothMediaTransportClient::kVolumeProperty)); | |
| 231 } | |
| 232 | |
| 233 void FakeBluetoothMediaTransportClient::WriteData( | |
| 234 const ObjectPath& endpoint_path, const std::vector<char>& bytes) { | |
| 235 VLOG(1) << "WriteData - write " << bytes.size() << " bytes"; | |
| 236 | |
| 237 Transport* transport = GetTransport(endpoint_path); | |
| 238 | |
| 239 if (!transport || transport->properties->state.value() != "active") { | |
| 240 VLOG(1) << "WriteData - write operation rejected, since the state isn't " | |
| 241 "active for endpoint: " << endpoint_path.value(); | |
| 242 return; | |
| 243 } | |
| 244 | |
| 245 if (!transport->input_fd.get()) { | |
| 246 VLOG(1) << "WriteData - invalid input file descriptor"; | |
| 247 return; | |
| 248 } | |
| 249 | |
| 250 ssize_t written_len = | |
| 251 write(transport->input_fd->GetPlatformFile(), bytes.data(), bytes.size()); | |
| 252 if (written_len < 0) { | |
| 253 VLOG(1) << "WriteData - failed to write to the socket"; | |
| 254 return; | |
| 255 } | |
| 256 | |
| 257 VLOG(1) << "WriteData - wrote " << written_len << " bytes to the socket"; | |
| 258 } | |
| 259 | |
| 260 ObjectPath FakeBluetoothMediaTransportClient::GetTransportPath( | |
| 261 const ObjectPath& endpoint_path) { | |
| 262 Transport* transport = GetTransport(endpoint_path); | |
| 263 return transport ? transport->path : ObjectPath(""); | |
| 264 } | |
| 265 | |
| 266 void FakeBluetoothMediaTransportClient::OnPropertyChanged( | |
| 267 const std::string& property_name) { | |
| 268 VLOG(1) << "Property " << property_name << " changed"; | |
| 269 } | |
| 270 | |
| 271 ObjectPath FakeBluetoothMediaTransportClient::GetEndpointPath( | |
| 272 const ObjectPath& transport_path) { | |
| 273 const auto& it = transport_to_endpoint_map_.find(transport_path); | |
| 274 return it != transport_to_endpoint_map_.end() ? it->second : ObjectPath(""); | |
| 275 } | |
| 276 | |
| 277 FakeBluetoothMediaTransportClient::Transport* | |
| 278 FakeBluetoothMediaTransportClient::GetTransport( | |
| 279 const ObjectPath& endpoint_path) { | |
| 280 const auto& it = endpoint_to_transport_map_.find(endpoint_path); | |
| 281 return (it != endpoint_to_transport_map_.end()) ? it->second : nullptr; | |
| 282 } | |
| 283 | |
| 284 FakeBluetoothMediaTransportClient::Transport* | |
| 285 FakeBluetoothMediaTransportClient::GetTransportByPath( | |
| 286 const dbus::ObjectPath& transport_path) { | |
| 287 return GetTransport(GetEndpointPath(transport_path)); | |
| 288 } | |
| 289 | |
| 290 void FakeBluetoothMediaTransportClient::AcquireInternal( | |
| 291 bool try_flag, | |
| 292 const ObjectPath& object_path, | |
| 293 const AcquireCallback& callback, | |
| 294 const ErrorCallback& error_callback) { | |
| 295 const ObjectPath& endpoint_path = GetEndpointPath(object_path); | |
| 296 Transport* transport = GetTransport(endpoint_path); | |
| 297 if (!transport) { | |
| 298 error_callback.Run(kFailed, ""); | |
| 299 return; | |
| 300 } | |
| 301 | |
| 302 std::string state = transport->properties->state.value(); | |
| 303 if (state == "active") { | |
| 304 error_callback.Run(kNotAuthorized, ""); | |
| 305 return; | |
| 306 } | |
| 307 if (state != "pending") { | |
| 308 error_callback.Run(try_flag ? kNotAvailable : kFailed, ""); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 int fds[2]; | |
| 313 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { | |
| 314 transport->input_fd.reset(); | |
| 315 error_callback.Run(kFailed, ""); | |
| 316 return; | |
| 317 } | |
| 318 DCHECK((fds[0] > kInvalidFd) && (fds[1] > kInvalidFd)); | |
| 319 transport->input_fd.reset(new base::File(fds[0])); | |
| 320 | |
| 321 dbus::FileDescriptor out_fd(fds[1]); | |
| 322 callback.Run(&out_fd, kDefaultReadMtu, kDefaultWriteMtu); | |
| 323 SetState(endpoint_path, "active"); | |
| 324 } | |
| 325 | |
| 326 } // namespace chromeos | |
| OLD | NEW |