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 "chromeos/dbus/fake_bluetooth_media_transport_client.h"
8 #include <sys/socket.h>
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"
21 using dbus::ObjectPath
;
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";
32 const int kInvalidFd
= -1;
34 ObjectPath
GenerateTransportPath() {
35 static unsigned int sequence_number
= 0;
37 std::stringstream path
;
38 path
<< chromeos::FakeBluetoothAdapterClient::kAdapterPath
39 << chromeos::FakeBluetoothMediaTransportClient::kTransportDevicePath
40 << "/fd" << sequence_number
;
41 return ObjectPath(path
.str());
49 const char FakeBluetoothMediaTransportClient::kTransportDevicePath
[] =
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;
60 FakeBluetoothMediaTransportClient::Properties::Properties(
61 const PropertyChangedCallback
& callback
)
62 : BluetoothMediaTransportClient::Properties(
64 kBluetoothMediaTransportInterface
,
68 FakeBluetoothMediaTransportClient::Properties::~Properties() {
71 void FakeBluetoothMediaTransportClient::Properties::Get(
72 dbus::PropertyBase
* property
,
73 dbus::PropertySet::GetCallback callback
) {
74 VLOG(1) << "Get " << property
->name();
78 void FakeBluetoothMediaTransportClient::Properties::GetAll() {
79 VLOG(1) << "GetAll called.";
82 void FakeBluetoothMediaTransportClient::Properties::Set(
83 dbus::PropertyBase
* property
,
84 dbus::PropertySet::SetCallback callback
) {
85 VLOG(1) << "Set " << property
->name();
89 FakeBluetoothMediaTransportClient::Transport::Transport(
90 const ObjectPath
& transport_path
,
91 Properties
* transport_properties
)
92 : path(transport_path
) {
93 properties
.reset(transport_properties
);
96 FakeBluetoothMediaTransportClient::Transport::~Transport() {
99 FakeBluetoothMediaTransportClient::FakeBluetoothMediaTransportClient() {
102 FakeBluetoothMediaTransportClient::~FakeBluetoothMediaTransportClient() {
103 STLDeleteValues(&endpoint_to_transport_map_
);
106 // DBusClient override.
107 void FakeBluetoothMediaTransportClient::Init(dbus::Bus
* bus
) {
110 void FakeBluetoothMediaTransportClient::AddObserver(
111 BluetoothMediaTransportClient::Observer
* observer
) {
112 observers_
.AddObserver(observer
);
115 void FakeBluetoothMediaTransportClient::RemoveObserver(
116 BluetoothMediaTransportClient::Observer
* observer
) {
117 observers_
.RemoveObserver(observer
);
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
);
127 return transport
->properties
.get();
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
);
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
);
146 void FakeBluetoothMediaTransportClient::Release(
147 const ObjectPath
& object_path
,
148 const base::Closure
& callback
,
149 const ErrorCallback
& error_callback
) {
150 error_callback
.Run(kNotImplemented
, "");
153 void FakeBluetoothMediaTransportClient::SetValid(
154 FakeBluetoothMediaEndpointServiceProvider
* endpoint
,
156 FakeBluetoothMediaClient
* media
= static_cast<FakeBluetoothMediaClient
*>(
157 DBusThreadManager::Get()->GetBluetoothMediaClient());
160 ObjectPath
endpoint_path(endpoint
->object_path());
161 if (!media
->IsRegistered(endpoint_path
))
165 ObjectPath transport_path
= GenerateTransportPath();
166 VLOG(1) << "New transport, " << transport_path
.value()
167 << " is created for endpoint " << endpoint_path
.value();
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
);
182 endpoint_to_transport_map_
[endpoint_path
] =
183 new Transport(transport_path
, properties
.release());
184 transport_to_endpoint_map_
[transport_path
] = endpoint_path
;
188 Transport
* transport
= GetTransport(endpoint_path
);
191 ObjectPath transport_path
= transport
->path
;
193 // Notifies observers about the state change of the transport.
194 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer
, observers_
,
195 MediaTransportRemoved(transport_path
));
197 endpoint
->ClearConfiguration(transport_path
);
199 endpoint_to_transport_map_
.erase(endpoint_path
);
200 transport_to_endpoint_map_
.erase(transport_path
);
203 void FakeBluetoothMediaTransportClient::SetState(
204 const ObjectPath
& endpoint_path
,
205 const std::string
& state
) {
206 VLOG(1) << "SetState - state: " << state
;
208 Transport
* transport
= GetTransport(endpoint_path
);
212 transport
->properties
->state
.ReplaceValue(state
);
213 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer
, observers_
,
214 MediaTransportPropertyChanged(
216 BluetoothMediaTransportClient::kStateProperty
));
219 void FakeBluetoothMediaTransportClient::SetVolume(
220 const ObjectPath
& endpoint_path
,
221 const uint16_t& volume
) {
222 Transport
* transport
= GetTransport(endpoint_path
);
226 transport
->properties
->volume
.ReplaceValue(volume
);
227 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer
, observers_
,
228 MediaTransportPropertyChanged(
230 BluetoothMediaTransportClient::kVolumeProperty
));
233 void FakeBluetoothMediaTransportClient::WriteData(
234 const ObjectPath
& endpoint_path
, const std::vector
<char>& bytes
) {
235 VLOG(1) << "WriteData - write " << bytes
.size() << " bytes";
237 Transport
* transport
= GetTransport(endpoint_path
);
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();
245 if (!transport
->input_fd
.get()) {
246 VLOG(1) << "WriteData - invalid input file descriptor";
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";
257 VLOG(1) << "WriteData - wrote " << written_len
<< " bytes to the socket";
260 ObjectPath
FakeBluetoothMediaTransportClient::GetTransportPath(
261 const ObjectPath
& endpoint_path
) {
262 Transport
* transport
= GetTransport(endpoint_path
);
263 return transport
? transport
->path
: ObjectPath("");
266 void FakeBluetoothMediaTransportClient::OnPropertyChanged(
267 const std::string
& property_name
) {
268 VLOG(1) << "Property " << property_name
<< " changed";
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("");
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;
284 FakeBluetoothMediaTransportClient::Transport
*
285 FakeBluetoothMediaTransportClient::GetTransportByPath(
286 const dbus::ObjectPath
& transport_path
) {
287 return GetTransport(GetEndpointPath(transport_path
));
290 void FakeBluetoothMediaTransportClient::AcquireInternal(
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
);
298 error_callback
.Run(kFailed
, "");
302 std::string state
= transport
->properties
->state
.value();
303 if (state
== "active") {
304 error_callback
.Run(kNotAuthorized
, "");
307 if (state
!= "pending") {
308 error_callback
.Run(try_flag
? kNotAvailable
: kFailed
, "");
313 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, fds
) < 0) {
314 transport
->input_fd
.reset();
315 error_callback
.Run(kFailed
, "");
318 DCHECK((fds
[0] > kInvalidFd
) && (fds
[1] > kInvalidFd
));
319 transport
->input_fd
.reset(new base::File(fds
[0]));
321 dbus::FileDescriptor
out_fd(fds
[1]);
322 callback
.Run(&out_fd
, kDefaultReadMtu
, kDefaultWriteMtu
);
323 SetState(endpoint_path
, "active");
326 } // namespace chromeos