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