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 "register_notification_packet.h"
18
19 #include <bluetooth/log.h>
20
21 #include "internal_include/bt_trace.h"
22
23 namespace bluetooth {
24 namespace avrcp {
25
IsInterim() const26 bool RegisterNotificationResponse::IsInterim() const {
27 return GetCType() == CType::INTERIM;
28 }
29
GetEvent() const30 Event RegisterNotificationResponse::GetEvent() const {
31 auto value = *(begin() + VendorPacket::kMinSize());
32 return static_cast<Event>(value);
33 }
34
GetVolume() const35 uint8_t RegisterNotificationResponse::GetVolume() const {
36 log::assert_that(GetEvent() == Event::VOLUME_CHANGED,
37 "assert failed: GetEvent() == Event::VOLUME_CHANGED");
38 auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
39 return *it;
40 }
41
IsValid() const42 bool RegisterNotificationResponse::IsValid() const {
43 if (!VendorPacket::IsValid()) return false;
44 if (size() < kMinSize()) return false;
45 if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED && GetCType() != CType::REJECTED) {
46 return false;
47 }
48
49 switch (GetEvent()) {
50 case Event::VOLUME_CHANGED:
51 return size() == (kMinSize() + 1);
52 default:
53 // TODO (apanicke): Add the remaining events when implementing AVRCP
54 // Controller
55 return false;
56 }
57 }
58
ToString() const59 std::string RegisterNotificationResponse::ToString() const {
60 std::stringstream ss;
61 ss << "RegisterNotificationResponse: " << std::endl;
62 ss << " └ cType = " << GetCType() << std::endl;
63 ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
64 ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
65 ss << " └ OpCode = " << GetOpcode() << std::endl;
66 ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
67 ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
68 ss << " └ PacketType = " << GetPacketType() << std::endl;
69 ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
70 ss << " └ Event Registered = " << GetEvent() << std::endl;
71 ss << std::endl;
72
73 return ss.str();
74 }
75
76 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackStatusBuilder(bool interim,uint8_t play_status)77 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
78 bool interim, uint8_t play_status) {
79 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
80 new RegisterNotificationResponseBuilder(interim,
81 Event::PLAYBACK_STATUS_CHANGED));
82 builder->data_union_.play_status = play_status;
83 return builder;
84 }
85
86 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeTrackChangedBuilder(bool interim,uint64_t track_uid)87 RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
88 bool interim, uint64_t track_uid) {
89 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
90 new RegisterNotificationResponseBuilder(interim, Event::TRACK_CHANGED));
91 builder->data_union_.track_uid = track_uid;
92 return builder;
93 }
94
95 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackPositionBuilder(bool interim,uint32_t playback_pos)96 RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
97 bool interim, uint32_t playback_pos) {
98 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
99 new RegisterNotificationResponseBuilder(interim,
100 Event::PLAYBACK_POS_CHANGED));
101 builder->data_union_.playback_pos = playback_pos;
102 return builder;
103 }
104
105 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlayerSettingChangedBuilder(bool interim,std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)106 RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
107 bool interim, std::vector<PlayerAttribute> attributes,
108 std::vector<uint8_t> values) {
109 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
110 new RegisterNotificationResponseBuilder(
111 interim, Event::PLAYER_APPLICATION_SETTING_CHANGED));
112 builder->data_union_.player_settings.number_of_attributes =
113 static_cast<uint8_t>(attributes.size());
114 for (int i = 0; i < builder->data_union_.player_settings.number_of_attributes;
115 i++) {
116 builder->data_union_.player_settings.attributes[i] = attributes.at(i);
117 builder->data_union_.player_settings.values[i] = values.at(i);
118 }
119 return builder;
120 }
121
122 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeNowPlayingBuilder(bool interim)123 RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(bool interim) {
124 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
125 new RegisterNotificationResponseBuilder(
126 interim, Event::NOW_PLAYING_CONTENT_CHANGED));
127 return builder;
128 }
129
130 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeAvailablePlayersBuilder(bool interim)131 RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(bool interim) {
132 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
133 new RegisterNotificationResponseBuilder(
134 interim, Event::AVAILABLE_PLAYERS_CHANGED));
135 return builder;
136 }
137
138 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeAddressedPlayerBuilder(bool interim,uint16_t player_id,uint16_t uid_counter)139 RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
140 bool interim, uint16_t player_id, uint16_t uid_counter) {
141 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
142 new RegisterNotificationResponseBuilder(interim,
143 Event::ADDRESSED_PLAYER_CHANGED));
144 builder->data_union_.addressed_player.player_id = player_id;
145 builder->data_union_.addressed_player.uid_counter = uid_counter;
146 return builder;
147 }
148
149 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeUidsChangedBuilder(bool interim,uint16_t uid_counter)150 RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(
151 bool interim, uint16_t uid_counter) {
152 std::unique_ptr<RegisterNotificationResponseBuilder> builder(
153 new RegisterNotificationResponseBuilder(interim, Event::UIDS_CHANGED));
154 builder->data_union_.uid_counter = uid_counter;
155 return builder;
156 }
157
size() const158 size_t RegisterNotificationResponseBuilder::size() const {
159 size_t data_size = 0;
160
161 // We specifically avoid having a default case here in order to ensure that
162 // there is an error in case an event isn't handled.
163 switch (event_) {
164 case Event::PLAYBACK_STATUS_CHANGED:
165 data_size = 1;
166 break;
167 case Event::TRACK_CHANGED:
168 data_size = 8;
169 break;
170 case Event::PLAYBACK_POS_CHANGED:
171 data_size = 4;
172 break;
173 case Event::PLAYER_APPLICATION_SETTING_CHANGED:
174 data_size = sizeof(uint8_t) +
175 2 * data_union_.player_settings.number_of_attributes *
176 sizeof(uint8_t);
177 break;
178 case Event::NOW_PLAYING_CONTENT_CHANGED:
179 data_size = 0;
180 break;
181 case Event::AVAILABLE_PLAYERS_CHANGED:
182 data_size = 0;
183 break;
184 case Event::ADDRESSED_PLAYER_CHANGED:
185 data_size = 4;
186 break;
187 case Event::UIDS_CHANGED:
188 data_size = 2;
189 break;
190 case Event::VOLUME_CHANGED:
191 log::fatal("Volume Changed Notification Not Implemented");
192 break;
193 }
194
195 return VendorPacket::kMinSize() + 1 + data_size;
196 }
197
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)198 bool RegisterNotificationResponseBuilder::Serialize(
199 const std::shared_ptr<::bluetooth::Packet>& pkt) {
200 ReserveSpace(pkt, size());
201
202 PacketBuilder::PushHeader(pkt);
203
204 VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
205
206 AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
207 switch (event_) {
208 case Event::PLAYBACK_STATUS_CHANGED: {
209 AddPayloadOctets1(pkt, data_union_.play_status);
210 break;
211 }
212 case Event::TRACK_CHANGED: {
213 AddPayloadOctets8(pkt, base::ByteSwap(data_union_.track_uid));
214 break;
215 }
216 case Event::PLAYBACK_POS_CHANGED: {
217 AddPayloadOctets4(pkt, base::ByteSwap(data_union_.playback_pos));
218 break;
219 }
220 case Event::PLAYER_APPLICATION_SETTING_CHANGED: {
221 AddPayloadOctets1(pkt, data_union_.player_settings.number_of_attributes);
222 for (int i = 0; i < data_union_.player_settings.number_of_attributes;
223 i++) {
224 AddPayloadOctets1(pkt, static_cast<uint8_t>(
225 data_union_.player_settings.attributes[i]));
226 AddPayloadOctets1(pkt, data_union_.player_settings.values[i]);
227 }
228 break; // No additional data
229 }
230 case Event::NOW_PLAYING_CONTENT_CHANGED:
231 break; // No additional data
232 case Event::AVAILABLE_PLAYERS_CHANGED:
233 break; // No additional data
234 case Event::ADDRESSED_PLAYER_CHANGED: {
235 AddPayloadOctets2(pkt,
236 base::ByteSwap(data_union_.addressed_player.player_id));
237 AddPayloadOctets2(
238 pkt, base::ByteSwap(data_union_.addressed_player.uid_counter));
239 break;
240 }
241 case Event::UIDS_CHANGED: {
242 AddPayloadOctets2(pkt, base::ByteSwap(data_union_.uid_counter));
243 break;
244 }
245 case Event::VOLUME_CHANGED:
246 // TODO (apanicke): Add Volume Changed builder for when we are controller.
247 log::fatal("Volume Changed Notification Not Implemented");
248 break;
249 }
250
251 return true;
252 }
253
GetEventRegistered() const254 Event RegisterNotificationRequest::GetEventRegistered() const {
255 auto value = *(begin() + VendorPacket::kMinSize());
256 return static_cast<Event>(value);
257 }
258
GetInterval() const259 uint32_t RegisterNotificationRequest::GetInterval() const {
260 auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
261 return it.extractBE<uint32_t>();
262 }
263
IsValid() const264 bool RegisterNotificationRequest::IsValid() const {
265 return (size() == kMinSize());
266 }
267
ToString() const268 std::string RegisterNotificationRequest::ToString() const {
269 std::stringstream ss;
270 ss << "RegisterNotificationPacket: " << std::endl;
271 ss << " └ cType = " << GetCType() << std::endl;
272 ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
273 ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
274 ss << " └ OpCode = " << GetOpcode() << std::endl;
275 ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
276 ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
277 ss << " └ PacketType = " << GetPacketType() << std::endl;
278 ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
279 ss << " └ Event Registered = " << GetEventRegistered() << std::endl;
280 ss << " └ Interval = " << loghex(GetInterval()) << std::endl;
281 ss << std::endl;
282
283 return ss.str();
284 }
285
286 std::unique_ptr<RegisterNotificationRequestBuilder>
MakeBuilder(Event event,uint32_t interval)287 RegisterNotificationRequestBuilder::MakeBuilder(Event event,
288 uint32_t interval) {
289 std::unique_ptr<RegisterNotificationRequestBuilder> builder(
290 new RegisterNotificationRequestBuilder(event, interval));
291
292 return builder;
293 }
294
size() const295 size_t RegisterNotificationRequestBuilder::size() const {
296 return RegisterNotificationRequest::kMinSize();
297 }
298
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)299 bool RegisterNotificationRequestBuilder::Serialize(
300 const std::shared_ptr<::bluetooth::Packet>& pkt) {
301 ReserveSpace(pkt, size());
302
303 PacketBuilder::PushHeader(pkt);
304
305 VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
306
307 AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
308
309 AddPayloadOctets4(pkt, base::ByteSwap(interval_));
310
311 return true;
312 }
313
314 } // namespace avrcp
315 } // namespace bluetooth
316