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