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 <base/sys_byteorder.h>
20 #include <bluetooth/log.h>
21 
22 #include "internal_include/bt_trace.h"
23 
24 namespace bluetooth {
25 namespace avrcp {
26 
IsInterim() const27 bool RegisterNotificationResponse::IsInterim() const { return GetCType() == CType::INTERIM; }
28 
GetEvent() const29 Event RegisterNotificationResponse::GetEvent() const {
30   auto value = *(begin() + VendorPacket::kMinSize());
31   return static_cast<Event>(value);
32 }
33 
GetVolume() const34 uint8_t RegisterNotificationResponse::GetVolume() const {
35   log::assert_that(GetEvent() == Event::VOLUME_CHANGED,
36                    "assert failed: GetEvent() == Event::VOLUME_CHANGED");
37   auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
38   return *it;
39 }
40 
IsValid() const41 bool RegisterNotificationResponse::IsValid() const {
42   if (!VendorPacket::IsValid()) {
43     return false;
44   }
45   if (size() < kMinSize()) {
46     return false;
47   }
48   // Rejected type packets is not followed by event, but by error code instead.
49   if (GetCType() == CType::REJECTED) {
50     return true;
51   }
52   if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED) {
53     return false;
54   }
55 
56   switch (GetEvent()) {
57     case Event::VOLUME_CHANGED:
58       return size() == (kMinSize() + 1);
59     default:
60       // TODO (apanicke): Add the remaining events when implementing AVRCP
61       // Controller
62       return false;
63   }
64 }
65 
ToString() const66 std::string RegisterNotificationResponse::ToString() const {
67   std::stringstream ss;
68   ss << "RegisterNotificationResponse: " << std::endl;
69   ss << "  └ cType = " << GetCType() << std::endl;
70   ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
71   ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
72   ss << "  └ OpCode = " << GetOpcode() << std::endl;
73   ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
74   ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
75   ss << "  └ PacketType = " << GetPacketType() << std::endl;
76   ss << "  └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
77   ss << "  └ Event Registered = " << GetEvent() << std::endl;
78   ss << std::endl;
79 
80   return ss.str();
81 }
82 
83 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackStatusBuilder(bool interim,uint8_t play_status)84 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(bool interim, uint8_t play_status) {
85   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
86           new RegisterNotificationResponseBuilder(interim, Event::PLAYBACK_STATUS_CHANGED));
87   builder->data_union_.play_status = play_status;
88   return builder;
89 }
90 
91 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeTrackChangedBuilder(bool interim,uint64_t track_uid)92 RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(bool interim, uint64_t track_uid) {
93   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
94           new RegisterNotificationResponseBuilder(interim, Event::TRACK_CHANGED));
95   builder->data_union_.track_uid = track_uid;
96   return builder;
97 }
98 
99 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlaybackPositionBuilder(bool interim,uint32_t playback_pos)100 RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(bool interim,
101                                                                  uint32_t playback_pos) {
102   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
103           new RegisterNotificationResponseBuilder(interim, Event::PLAYBACK_POS_CHANGED));
104   builder->data_union_.playback_pos = playback_pos;
105   return builder;
106 }
107 
108 std::unique_ptr<RegisterNotificationResponseBuilder>
MakePlayerSettingChangedBuilder(bool interim,std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values)109 RegisterNotificationResponseBuilder::MakePlayerSettingChangedBuilder(
110         bool interim, std::vector<PlayerAttribute> attributes, std::vector<uint8_t> values) {
111   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
112           new RegisterNotificationResponseBuilder(interim,
113                                                   Event::PLAYER_APPLICATION_SETTING_CHANGED));
114   builder->data_union_.player_settings.number_of_attributes =
115           static_cast<uint8_t>(attributes.size());
116   for (int i = 0; i < builder->data_union_.player_settings.number_of_attributes; i++) {
117     builder->data_union_.player_settings.attributes[i] = attributes.at(i);
118     builder->data_union_.player_settings.values[i] = values.at(i);
119   }
120   return builder;
121 }
122 
123 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeNowPlayingBuilder(bool interim)124 RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(bool interim) {
125   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
126           new RegisterNotificationResponseBuilder(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(interim, Event::AVAILABLE_PLAYERS_CHANGED));
134   return builder;
135 }
136 
137 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeAddressedPlayerBuilder(bool interim,uint16_t player_id,uint16_t uid_counter)138 RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(bool interim, uint16_t player_id,
139                                                                 uint16_t uid_counter) {
140   std::unique_ptr<RegisterNotificationResponseBuilder> builder(
141           new RegisterNotificationResponseBuilder(interim, Event::ADDRESSED_PLAYER_CHANGED));
142   builder->data_union_.addressed_player.player_id = player_id;
143   builder->data_union_.addressed_player.uid_counter = uid_counter;
144   return builder;
145 }
146 
147 std::unique_ptr<RegisterNotificationResponseBuilder>
MakeUidsChangedBuilder(bool interim,uint16_t uid_counter)148 RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(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 * sizeof(uint8_t);
173       break;
174     case Event::NOW_PLAYING_CONTENT_CHANGED:
175       data_size = 0;
176       break;
177     case Event::AVAILABLE_PLAYERS_CHANGED:
178       data_size = 0;
179       break;
180     case Event::ADDRESSED_PLAYER_CHANGED:
181       data_size = 4;
182       break;
183     case Event::UIDS_CHANGED:
184       data_size = 2;
185       break;
186     case Event::VOLUME_CHANGED:
187       log::fatal("Volume Changed Notification Not Implemented");
188       break;
189   }
190 
191   return VendorPacket::kMinSize() + 1 + data_size;
192 }
193 
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)194 bool RegisterNotificationResponseBuilder::Serialize(
195         const std::shared_ptr<::bluetooth::Packet>& pkt) {
196   ReserveSpace(pkt, size());
197 
198   PacketBuilder::PushHeader(pkt);
199 
200   VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
201 
202   AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
203   switch (event_) {
204     case Event::PLAYBACK_STATUS_CHANGED: {
205       AddPayloadOctets1(pkt, data_union_.play_status);
206       break;
207     }
208     case Event::TRACK_CHANGED: {
209       AddPayloadOctets8(pkt, base::ByteSwap(data_union_.track_uid));
210       break;
211     }
212     case Event::PLAYBACK_POS_CHANGED: {
213       AddPayloadOctets4(pkt, base::ByteSwap(data_union_.playback_pos));
214       break;
215     }
216     case Event::PLAYER_APPLICATION_SETTING_CHANGED: {
217       AddPayloadOctets1(pkt, data_union_.player_settings.number_of_attributes);
218       for (int i = 0; i < data_union_.player_settings.number_of_attributes; i++) {
219         AddPayloadOctets1(pkt, static_cast<uint8_t>(data_union_.player_settings.attributes[i]));
220         AddPayloadOctets1(pkt, data_union_.player_settings.values[i]);
221       }
222       break;  // No additional data
223     }
224     case Event::NOW_PLAYING_CONTENT_CHANGED:
225       break;  // No additional data
226     case Event::AVAILABLE_PLAYERS_CHANGED:
227       break;  // No additional data
228     case Event::ADDRESSED_PLAYER_CHANGED: {
229       AddPayloadOctets2(pkt, base::ByteSwap(data_union_.addressed_player.player_id));
230       AddPayloadOctets2(pkt, base::ByteSwap(data_union_.addressed_player.uid_counter));
231       break;
232     }
233     case Event::UIDS_CHANGED: {
234       AddPayloadOctets2(pkt, base::ByteSwap(data_union_.uid_counter));
235       break;
236     }
237     case Event::VOLUME_CHANGED:
238       // TODO (apanicke): Add Volume Changed builder for when we are controller.
239       log::fatal("Volume Changed Notification Not Implemented");
240       break;
241   }
242 
243   return true;
244 }
245 
GetEventRegistered() const246 Event RegisterNotificationRequest::GetEventRegistered() const {
247   auto value = *(begin() + VendorPacket::kMinSize());
248   return static_cast<Event>(value);
249 }
250 
GetInterval() const251 uint32_t RegisterNotificationRequest::GetInterval() const {
252   auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
253   return it.extractBE<uint32_t>();
254 }
255 
IsValid() const256 bool RegisterNotificationRequest::IsValid() const { return size() == kMinSize(); }
257 
ToString() const258 std::string RegisterNotificationRequest::ToString() const {
259   std::stringstream ss;
260   ss << "RegisterNotificationPacket: " << std::endl;
261   ss << "  └ cType = " << GetCType() << std::endl;
262   ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
263   ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
264   ss << "  └ OpCode = " << GetOpcode() << std::endl;
265   ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
266   ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
267   ss << "  └ PacketType = " << GetPacketType() << std::endl;
268   ss << "  └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
269   ss << "  └ Event Registered = " << GetEventRegistered() << std::endl;
270   ss << "  └ Interval = " << loghex(GetInterval()) << std::endl;
271   ss << std::endl;
272 
273   return ss.str();
274 }
275 
MakeBuilder(Event event,uint32_t interval)276 std::unique_ptr<RegisterNotificationRequestBuilder> RegisterNotificationRequestBuilder::MakeBuilder(
277         Event event, uint32_t interval) {
278   std::unique_ptr<RegisterNotificationRequestBuilder> builder(
279           new RegisterNotificationRequestBuilder(event, interval));
280 
281   return builder;
282 }
283 
size() const284 size_t RegisterNotificationRequestBuilder::size() const {
285   return RegisterNotificationRequest::kMinSize();
286 }
287 
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)288 bool RegisterNotificationRequestBuilder::Serialize(
289         const std::shared_ptr<::bluetooth::Packet>& pkt) {
290   ReserveSpace(pkt, size());
291 
292   PacketBuilder::PushHeader(pkt);
293 
294   VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
295 
296   AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
297 
298   AddPayloadOctets4(pkt, base::ByteSwap(interval_));
299 
300   return true;
301 }
302 
303 }  // namespace avrcp
304 }  // namespace bluetooth
305