1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <base/logging.h>
18
19 #include "register_notification_packet.h"
20
21 namespace bluetooth {
22 namespace avrcp {
23
IsInterim() const24 bool RegisterNotificationResponse::IsInterim() const {
25 return GetCType() == CType::INTERIM;
26 }
27
GetEvent() const28 Event RegisterNotificationResponse::GetEvent() const {
29 auto value = *(begin() + VendorPacket::kMinSize());
30 return static_cast<Event>(value);
31 }
32
GetVolume() const33 uint8_t RegisterNotificationResponse::GetVolume() const {
34 CHECK(GetEvent() == Event::VOLUME_CHANGED);
35 auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
36 return *it;
37 }
38
IsValid() const39 bool RegisterNotificationResponse::IsValid() const {
40 if (!VendorPacket::IsValid()) return false;
41 if (size() < kMinSize()) return false;
42 if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED && GetCType() != CType::REJECTED) {
43 return false;
44 }
45
46 switch (GetEvent()) {
47 case Event::VOLUME_CHANGED:
48 return size() == (kMinSize() + 1);
49 default:
50 // TODO (apanicke): Add the remaining events when implementing AVRCP
51 // Controller
52 return false;
53 }
54 }
55
ToString() const56 std::string RegisterNotificationResponse::ToString() const {
57 std::stringstream ss;
58 ss << "RegisterNotificationResponse: " << std::endl;
59 ss << " └ cType = " << GetCType() << std::endl;
60 ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
61 ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
62 ss << " └ OpCode = " << GetOpcode() << std::endl;
63 ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
64 ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
65 ss << " └ PacketType = " << GetPacketType() << std::endl;
66 ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
67 ss << " └ Event Registered = " << GetEvent() << std::endl;
68 ss << std::endl;
69
70 return ss.str();
71 }
72
73 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackStatusBuilder(bool interim,uint8_t play_status)74 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
75 bool interim, uint8_t play_status) {
76 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
77 new RegisterNotificationResponseBuilder(interim,
78 Event::PLAYBACK_STATUS_CHANGED));
79 builder->data_union_.play_status = play_status;
80 return builder;
81 }
82
83 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeTrackChangedBuilder(bool interim,uint64_t track_uid)84 RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
85 bool interim, uint64_t track_uid) {
86 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
87 new RegisterNotificationResponseBuilder(interim, Event::TRACK_CHANGED));
88 builder->data_union_.track_uid = track_uid;
89 return builder;
90 }
91
92 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackPositionBuilder(bool interim,uint32_t playback_pos)93 RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
94 bool interim, uint32_t playback_pos) {
95 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
96 new RegisterNotificationResponseBuilder(interim,
97 Event::PLAYBACK_POS_CHANGED));
98 builder->data_union_.playback_pos = playback_pos;
99 return builder;
100 }
101
102 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlayerSettingChangedBuilder(bool interim,std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)103 RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
104 bool interim, std::vector<PlayerAttribute> attributes,
105 std::vector<uint8_t> values) {
106 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
107 new RegisterNotificationResponseBuilder(
108 interim, Event::PLAYER_APPLICATION_SETTING_CHANGED));
109 builder->data_union_.player_settings.number_of_attributes =
110 static_cast<uint8_t>(attributes.size());
111 for (int i = 0; i < builder->data_union_.player_settings.number_of_attributes;
112 i++) {
113 builder->data_union_.player_settings.attributes[i] = attributes.at(i);
114 builder->data_union_.player_settings.values[i] = values.at(i);
115 }
116 return builder;
117 }
118
119 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeNowPlayingBuilder(bool interim)120 RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(bool interim) {
121 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
122 new RegisterNotificationResponseBuilder(
123 interim, Event::NOW_PLAYING_CONTENT_CHANGED));
124 return builder;
125 }
126
127 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeAvailablePlayersBuilder(bool interim)128 RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(bool interim) {
129 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
130 new RegisterNotificationResponseBuilder(
131 interim, Event::AVAILABLE_PLAYERS_CHANGED));
132 return builder;
133 }
134
135 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeAddressedPlayerBuilder(bool interim,uint16_t player_id,uint16_t uid_counter)136 RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
137 bool interim, uint16_t player_id, uint16_t uid_counter) {
138 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
139 new RegisterNotificationResponseBuilder(interim,
140 Event::ADDRESSED_PLAYER_CHANGED));
141 builder->data_union_.addressed_player.player_id = player_id;
142 builder->data_union_.addressed_player.uid_counter = uid_counter;
143 return builder;
144 }
145
146 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeUidsChangedBuilder(bool interim,uint16_t uid_counter)147 RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(
148 bool interim, uint16_t uid_counter) {
149 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
150 new RegisterNotificationResponseBuilder(interim, Event::UIDS_CHANGED));
151 builder->data_union_.uid_counter = uid_counter;
152 return builder;
153 }
154
size() const155 size_t RegisterNotificationResponseBuilder::size() const {
156 size_t data_size = 0;
157
158 // We specifically avoid having a default case here in order to ensure that
159 // there is an error in case an event isn't handled.
160 switch (event_) {
161 case Event::PLAYBACK_STATUS_CHANGED:
162 data_size = 1;
163 break;
164 case Event::TRACK_CHANGED:
165 data_size = 8;
166 break;
167 case Event::PLAYBACK_POS_CHANGED:
168 data_size = 4;
169 break;
170 case Event::PLAYER_APPLICATION_SETTING_CHANGED:
171 data_size = sizeof(uint8_t) +
172 2 * data_union_.player_settings.number_of_attributes *
173 sizeof(uint8_t);
174 break;
175 case Event::NOW_PLAYING_CONTENT_CHANGED:
176 data_size = 0;
177 break;
178 case Event::AVAILABLE_PLAYERS_CHANGED:
179 data_size = 0;
180 break;
181 case Event::ADDRESSED_PLAYER_CHANGED:
182 data_size = 4;
183 break;
184 case Event::UIDS_CHANGED:
185 data_size = 2;
186 break;
187 case Event::VOLUME_CHANGED:
188 LOG(FATAL) << "Volume Changed Notification Not Implemented";
189 break;
190 }
191
192 return VendorPacket::kMinSize() + 1 + data_size;
193 }
194
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)195 bool RegisterNotificationResponseBuilder::Serialize(
196 const std::shared_ptr<::bluetooth::Packet>& pkt) {
197 ReserveSpace(pkt, size());
198
199 PacketBuilder::PushHeader(pkt);
200
201 VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
202
203 AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
204 switch (event_) {
205 case Event::PLAYBACK_STATUS_CHANGED: {
206 AddPayloadOctets1(pkt, data_union_.play_status);
207 break;
208 }
209 case Event::TRACK_CHANGED: {
210 AddPayloadOctets8(pkt, base::ByteSwap(data_union_.track_uid));
211 break;
212 }
213 case Event::PLAYBACK_POS_CHANGED: {
214 AddPayloadOctets4(pkt, base::ByteSwap(data_union_.playback_pos));
215 break;
216 }
217 case Event::PLAYER_APPLICATION_SETTING_CHANGED: {
218 AddPayloadOctets1(pkt, data_union_.player_settings.number_of_attributes);
219 for (int i = 0; i < data_union_.player_settings.number_of_attributes;
220 i++) {
221 AddPayloadOctets1(pkt, static_cast<uint8_t>(
222 data_union_.player_settings.attributes[i]));
223 AddPayloadOctets1(pkt, data_union_.player_settings.values[i]);
224 }
225 break; // No additional data
226 }
227 case Event::NOW_PLAYING_CONTENT_CHANGED:
228 break; // No additional data
229 case Event::AVAILABLE_PLAYERS_CHANGED:
230 break; // No additional data
231 case Event::ADDRESSED_PLAYER_CHANGED: {
232 AddPayloadOctets2(pkt,
233 base::ByteSwap(data_union_.addressed_player.player_id));
234 AddPayloadOctets2(
235 pkt, base::ByteSwap(data_union_.addressed_player.uid_counter));
236 break;
237 }
238 case Event::UIDS_CHANGED: {
239 AddPayloadOctets2(pkt, base::ByteSwap(data_union_.uid_counter));
240 break;
241 }
242 case Event::VOLUME_CHANGED:
243 // TODO (apanicke): Add Volume Changed builder for when we are controller.
244 LOG(FATAL) << "Volume Changed Notification Not Implemented";
245 break;
246 }
247
248 return true;
249 }
250
GetEventRegistered() const251 Event RegisterNotificationRequest::GetEventRegistered() const {
252 auto value = *(begin() + VendorPacket::kMinSize());
253 return static_cast<Event>(value);
254 }
255
GetInterval() const256 uint32_t RegisterNotificationRequest::GetInterval() const {
257 auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
258 return it.extractBE<uint32_t>();
259 }
260
IsValid() const261 bool RegisterNotificationRequest::IsValid() const {
262 return (size() == kMinSize());
263 }
264
ToString() const265 std::string RegisterNotificationRequest::ToString() const {
266 std::stringstream ss;
267 ss << "RegisterNotificationPacket: " << std::endl;
268 ss << " └ cType = " << GetCType() << std::endl;
269 ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
270 ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
271 ss << " └ OpCode = " << GetOpcode() << std::endl;
272 ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
273 ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
274 ss << " └ PacketType = " << GetPacketType() << std::endl;
275 ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
276 ss << " └ Event Registered = " << GetEventRegistered() << std::endl;
277 ss << " └ Interval = " << loghex(GetInterval()) << std::endl;
278 ss << std::endl;
279
280 return ss.str();
281 }
282
283 std::unique_ptr<RegisterNotificationRequestBuilder>
MakeBuilder(Event event,uint32_t interval)284 RegisterNotificationRequestBuilder::MakeBuilder(Event event,
285 uint32_t interval) {
286 std::unique_ptr<RegisterNotificationRequestBuilder> builder(
287 new RegisterNotificationRequestBuilder(event, interval));
288
289 return builder;
290 }
291
size() const292 size_t RegisterNotificationRequestBuilder::size() const {
293 return RegisterNotificationRequest::kMinSize();
294 }
295
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)296 bool RegisterNotificationRequestBuilder::Serialize(
297 const std::shared_ptr<::bluetooth::Packet>& pkt) {
298 ReserveSpace(pkt, size());
299
300 PacketBuilder::PushHeader(pkt);
301
302 VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
303
304 AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
305
306 AddPayloadOctets4(pkt, base::ByteSwap(interval_));
307
308 return true;
309 }
310
311 } // namespace avrcp
312 } // namespace bluetooth
313