Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / chromeos / dbus / fake_bluetooth_media_transport_client.cc
blob441a66bca4af4148620ddfe03bb4d02b018829b4
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"
7 #include <unistd.h>
8 #include <sys/socket.h>
10 #include <sstream>
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;
23 namespace {
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;
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());
44 } // namespace
46 namespace chromeos {
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;
60 FakeBluetoothMediaTransportClient::Properties::Properties(
61 const PropertyChangedCallback& callback)
62 : BluetoothMediaTransportClient::Properties(
63 nullptr,
64 kBluetoothMediaTransportInterface,
65 callback) {
68 FakeBluetoothMediaTransportClient::Properties::~Properties() {
71 void FakeBluetoothMediaTransportClient::Properties::Get(
72 dbus::PropertyBase* property,
73 dbus::PropertySet::GetCallback callback) {
74 VLOG(1) << "Get " << property->name();
75 callback.Run(false);
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();
86 callback.Run(false);
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);
125 if (!transport)
126 return nullptr;
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,
155 bool valid) {
156 FakeBluetoothMediaClient* media = static_cast<FakeBluetoothMediaClient*>(
157 DBusThreadManager::Get()->GetBluetoothMediaClient());
158 DCHECK(media);
160 ObjectPath endpoint_path(endpoint->object_path());
161 if (!media->IsRegistered(endpoint_path))
162 return;
164 if (valid) {
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;
185 return;
188 Transport* transport = GetTransport(endpoint_path);
189 if (!transport)
190 return;
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);
198 delete transport;
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);
209 if (!transport)
210 return;
212 transport->properties->state.ReplaceValue(state);
213 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_,
214 MediaTransportPropertyChanged(
215 transport->path,
216 BluetoothMediaTransportClient::kStateProperty));
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;
226 transport->properties->volume.ReplaceValue(volume);
227 FOR_EACH_OBSERVER(BluetoothMediaTransportClient::Observer, observers_,
228 MediaTransportPropertyChanged(
229 transport->path,
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();
242 return;
245 if (!transport->input_fd.get()) {
246 VLOG(1) << "WriteData - invalid input file descriptor";
247 return;
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;
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(
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;
302 std::string state = transport->properties->state.value();
303 if (state == "active") {
304 error_callback.Run(kNotAuthorized, "");
305 return;
307 if (state != "pending") {
308 error_callback.Run(try_flag ? kNotAvailable : kFailed, "");
309 return;
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;
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