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 |