OSDN Git Service

Add packet classes needed for AVRCP Absolute Volume
authorAjay Panicker <apanicke@google.com>
Sat, 17 Feb 2018 19:22:48 +0000 (11:22 -0800)
committerAjay Panicker <apanicke@google.com>
Tue, 20 Feb 2018 18:37:07 +0000 (10:37 -0800)
Add the Register Notification Request packet as well as the
packets Set Absolute Volume packet.

Bug: 68854188
Test: run host native test net_test_packets
Change-Id: Ie0d1f1fb23254c1353b6a73529ca93e92f231ed5

packet/Android.bp
packet/avrcp/Android.bp
packet/avrcp/avrcp_common.h
packet/avrcp/register_notification_packet.cc
packet/avrcp/register_notification_packet.h
packet/avrcp/set_absolute_volume.cc [new file with mode: 0644]
packet/avrcp/set_absolute_volume.h [new file with mode: 0644]
packet/include/avrcp_packet.h
packet/tests/avrcp/avrcp_test_packets.h
packet/tests/avrcp/register_notification_packet_test.cc
packet/tests/avrcp/set_absolute_volume_packet_test.cc [new file with mode: 0644]

index ea0f2df..a10b975 100644 (file)
@@ -31,6 +31,7 @@ cc_test {
         "tests/avrcp/pass_through_packet_test.cc",
         "tests/avrcp/play_item_packet_test.cc",
         "tests/avrcp/register_notification_packet_test.cc",
+        "tests/avrcp/set_absolute_volume_packet_test.cc",
         "tests/avrcp/set_browsed_player_packet_test.cc",
         "tests/avrcp/vendor_packet_test.cc",
         "tests/base/iterator_test.cc",
index e621449..99c1bad 100644 (file)
@@ -17,6 +17,7 @@ cc_library_static {
         "pass_through_packet.cc",
         "play_item.cc",
         "register_notification_packet.cc",
+        "set_absolute_volume.cc",
         "set_browsed_player.cc",
         "vendor_packet.cc",
     ],
index 40e2546..c627ebd 100644 (file)
@@ -52,6 +52,7 @@ enum class CommandPdu : uint8_t {
   GET_ELEMENT_ATTRIBUTES = 0x20,
   GET_PLAY_STATUS = 0x30,
   REGISTER_NOTIFICATION = 0x31,
+  SET_ABSOLUTE_VOLUME = 0x50,
   SET_ADDRESSED_PLAYER = 0x60,
   PLAY_ITEM = 0x74,
 };
index 1bf2bf0..5131278 100644 (file)
 namespace bluetooth {
 namespace avrcp {
 
+bool RegisterNotificationResponse::IsInterim() const {
+  return GetCType() == CType::INTERIM;
+}
+
+Event RegisterNotificationResponse::GetEvent() const {
+  auto value = *(begin() + VendorPacket::kMinSize());
+  return static_cast<Event>(value);
+}
+
+uint8_t RegisterNotificationResponse::GetVolume() const {
+  CHECK(GetEvent() == Event::VOLUME_CHANGED);
+  auto it = begin() + VendorPacket::kMinSize() + static_cast<size_t>(1);
+  return *it;
+}
+
+bool RegisterNotificationResponse::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  if (size() < kMinSize()) return false;
+  if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED)
+    return false;
+
+  switch (GetEvent()) {
+    case Event::VOLUME_CHANGED:
+      return size() == (kMinSize() + 1);
+    default:
+      // TODO (apanicke): Add the remaining events when implementing AVRCP
+      // Controller
+      return false;
+  }
+}
+
+std::string RegisterNotificationResponse::ToString() const {
+  std::stringstream ss;
+  ss << "RegisterNotificationResponse: " << std::endl;
+  ss << "  └ cType = " << GetCType() << std::endl;
+  ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  └ OpCode = " << GetOpcode() << std::endl;
+  ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  └ PacketType = " << GetPacketType() << std::endl;
+  ss << "  └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  └ Event Registered = " << GetEvent() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
 std::unique_ptr<RegisterNotificationResponseBuilder>
 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
     bool interim, uint8_t play_status) {
@@ -124,22 +172,43 @@ bool RegisterNotificationResponseBuilder::Serialize(
   VendorPacketBuilder::PushHeader(pkt, 1 + data_size);
 
   AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
-  if (event_ == Event::PLAYBACK_STATUS_CHANGED) {
-    uint8_t playback_status = data_ & 0xFF;
-    AddPayloadOctets1(pkt, playback_status);
-  } else if (event_ == Event::TRACK_CHANGED) {
-    AddPayloadOctets8(pkt, base::ByteSwap(data_));
-  } else if (event_ == Event::PLAYBACK_POS_CHANGED) {
-    uint32_t playback_pos = data_ & 0xFFFFFFFF;
-    AddPayloadOctets4(pkt, base::ByteSwap(playback_pos));
-  } else if (event_ == Event::ADDRESSED_PLAYER_CHANGED) {
-    uint16_t uid_counter = data_ & 0xFFFF;
-    uint16_t player_id = (data_ >> 16) & 0xFFFF;
-    AddPayloadOctets2(pkt, base::ByteSwap(player_id));
-    AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
-  } else if (event_ == Event::UIDS_CHANGED) {
-    uint16_t uid_counter = data_ & 0xFFFF;
-    AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
+  switch (event_) {
+    case Event::PLAYBACK_STATUS_CHANGED: {
+      uint8_t playback_status = data_ & 0xFF;
+      AddPayloadOctets1(pkt, playback_status);
+      break;
+    }
+    case Event::TRACK_CHANGED: {
+      AddPayloadOctets8(pkt, base::ByteSwap(data_));
+      break;
+    }
+    case Event::PLAYBACK_POS_CHANGED: {
+      uint32_t playback_pos = data_ & 0xFFFFFFFF;
+      AddPayloadOctets4(pkt, base::ByteSwap(playback_pos));
+      break;
+    }
+    case Event::PLAYER_APPLICATION_SETTING_CHANGED:
+      break;  // No additional data
+    case Event::NOW_PLAYING_CONTENT_CHANGED:
+      break;  // No additional data
+    case Event::AVAILABLE_PLAYERS_CHANGED:
+      break;  // No additional data
+    case Event::ADDRESSED_PLAYER_CHANGED: {
+      uint16_t uid_counter = data_ & 0xFFFF;
+      uint16_t player_id = (data_ >> 16) & 0xFFFF;
+      AddPayloadOctets2(pkt, base::ByteSwap(player_id));
+      AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
+      break;
+    }
+    case Event::UIDS_CHANGED: {
+      uint16_t uid_counter = data_ & 0xFFFF;
+      AddPayloadOctets2(pkt, base::ByteSwap(uid_counter));
+      break;
+    }
+    default:
+      // TODO (apanicke): Add Volume Changed builder for when we are controller.
+      LOG(FATAL) << "Unhandled event for register notification";
+      break;
   }
 
   return true;
@@ -177,5 +246,33 @@ std::string RegisterNotificationRequest::ToString() const {
   return ss.str();
 }
 
+std::unique_ptr<RegisterNotificationRequestBuilder>
+RegisterNotificationRequestBuilder::MakeBuilder(Event event,
+                                                uint32_t interval) {
+  std::unique_ptr<RegisterNotificationRequestBuilder> builder(
+      new RegisterNotificationRequestBuilder(event, interval));
+
+  return builder;
+}
+
+size_t RegisterNotificationRequestBuilder::size() const {
+  return RegisterNotificationRequest::kMinSize();
+}
+
+bool RegisterNotificationRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, static_cast<uint8_t>(event_));
+
+  AddPayloadOctets4(pkt, base::ByteSwap(interval_));
+
+  return true;
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
index a22f177..53286c4 100644 (file)
 namespace bluetooth {
 namespace avrcp {
 
+class RegisterNotificationResponse : public VendorPacket {
+ public:
+  virtual ~RegisterNotificationResponse() = default;
+
+  /**
+   *  Register Notificaiton Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t param_length;
+   *   RegisterNotificationRequestPacket:
+   *     uint8_t event_id;
+   *     uint8_t[] data;  // Length changes based on the event_id
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; }
+
+  // TODO (apanicke): Add other getters when implementing AVRCP Controller
+  bool IsInterim() const;
+  Event GetEvent() const;
+  uint8_t GetVolume() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
 class RegisterNotificationResponseBuilder : public VendorPacketBuilder {
  public:
   virtual ~RegisterNotificationResponseBuilder() = default;
 
-  // Playback Status Changed Maker
   static std::unique_ptr<RegisterNotificationResponseBuilder>
   MakePlaybackStatusBuilder(bool interim, uint8_t play_status);
-  // Track Changed Maker
+
   static std::unique_ptr<RegisterNotificationResponseBuilder>
   MakeTrackChangedBuilder(bool interim, uint64_t track_uid);
-  // Playback Position Changed Maker
+
   static std::unique_ptr<RegisterNotificationResponseBuilder>
   MakePlaybackPositionBuilder(bool interim, uint32_t playback_pos);
 
@@ -97,5 +130,27 @@ class RegisterNotificationRequest : public VendorPacket {
   using VendorPacket::VendorPacket;
 };
 
+class RegisterNotificationRequestBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~RegisterNotificationRequestBuilder() = default;
+
+  static std::unique_ptr<RegisterNotificationRequestBuilder> MakeBuilder(
+      Event event, uint32_t interval);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  Event event_;
+  uint32_t interval_;
+
+  RegisterNotificationRequestBuilder(Event event, uint32_t interval)
+      : VendorPacketBuilder(CType::NOTIFY, CommandPdu::REGISTER_NOTIFICATION,
+                            PacketType::SINGLE),
+        event_(event),
+        interval_(interval){};
+};
+
 }  // namespace avrcp
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_absolute_volume.cc b/packet/avrcp/set_absolute_volume.cc
new file mode 100644 (file)
index 0000000..ff6b7ac
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "set_absolute_volume.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+std::unique_ptr<SetAbsoluteVolumeRequestBuilder>
+SetAbsoluteVolumeRequestBuilder::MakeBuilder(uint8_t volume) {
+  std::unique_ptr<SetAbsoluteVolumeRequestBuilder> builder(
+      new SetAbsoluteVolumeRequestBuilder(volume & 0x7F));
+
+  return builder;
+}
+
+size_t SetAbsoluteVolumeRequestBuilder::size() const {
+  return VendorPacket::kMinSize() + 1;
+}
+
+bool SetAbsoluteVolumeRequestBuilder::Serialize(
+    const std::shared_ptr<::bluetooth::Packet>& pkt) {
+  ReserveSpace(pkt, size());
+
+  PacketBuilder::PushHeader(pkt);
+
+  VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
+
+  AddPayloadOctets1(pkt, volume_);
+
+  return true;
+}
+
+uint8_t SetAbsoluteVolumeResponse::GetVolume() const {
+  auto it = begin() + VendorPacket::kMinSize();
+  return *it;
+}
+
+bool SetAbsoluteVolumeResponse::IsValid() const {
+  if (!VendorPacket::IsValid()) return false;
+  if (GetCType() != CType::ACCEPTED) return false;
+  return size() == kMinSize();
+}
+
+std::string SetAbsoluteVolumeResponse::ToString() const {
+  std::stringstream ss;
+  ss << "SetAbsoluteVolumeResponse: " << std::endl;
+  ss << "  └ cType = " << GetCType() << std::endl;
+  ss << "  └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
+  ss << "  └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
+  ss << "  └ OpCode = " << GetOpcode() << std::endl;
+  ss << "  └ Company ID = " << loghex(GetCompanyId()) << std::endl;
+  ss << "  └ Command PDU = " << GetCommandPdu() << std::endl;
+  ss << "  └ PacketType = " << GetPacketType() << std::endl;
+  ss << "  └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
+  ss << "  └ Volume = " << GetVolume() << std::endl;
+  ss << std::endl;
+
+  return ss.str();
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/packet/avrcp/set_absolute_volume.h b/packet/avrcp/set_absolute_volume.h
new file mode 100644 (file)
index 0000000..48cd388
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "vendor_packet.h"
+
+// TODO (apanicke): Set Absolute Volume request vs response have the same
+// packet structure, the only difference between the two is the CType.
+// Adding a passed flag as a parameter would be possible but I feel that
+// this would break the design pattern of request vs response. Look into
+// this for the future.
+
+namespace bluetooth {
+namespace avrcp {
+
+class SetAbsoluteVolumeRequestBuilder : public VendorPacketBuilder {
+ public:
+  virtual ~SetAbsoluteVolumeRequestBuilder() = default;
+
+  static std::unique_ptr<SetAbsoluteVolumeRequestBuilder> MakeBuilder(
+      uint8_t volume);
+
+  virtual size_t size() const override;
+  virtual bool Serialize(
+      const std::shared_ptr<::bluetooth::Packet>& pkt) override;
+
+ protected:
+  uint8_t volume_;
+
+  SetAbsoluteVolumeRequestBuilder(uint8_t volume)
+      : VendorPacketBuilder(CType::CONTROL, CommandPdu::SET_ABSOLUTE_VOLUME,
+                            PacketType::SINGLE),
+        volume_(volume){};
+};
+
+class SetAbsoluteVolumeResponse : public VendorPacket {
+ public:
+  virtual ~SetAbsoluteVolumeResponse() = default;
+
+  /**
+   * AVRCP Play Item Request Packet Layout
+   *   AvrcpPacket:
+   *     CType c_type_;
+   *     uint8_t subunit_type_ : 5;
+   *     uint8_t subunit_id_ : 3;
+   *     Opcode opcode_;
+   *   VendorPacket:
+   *     uint8_t company_id[3];
+   *     uint8_t command_pdu;
+   *     uint8_t packet_type;
+   *     uint16_t parameter_length;
+   *   SetAbsoluteVolumeResponse:
+   *     uint8_t volume;
+   */
+  static constexpr size_t kMinSize() { return VendorPacket::kMinSize() + 1; }
+
+  uint8_t GetVolume() const;
+
+  virtual bool IsValid() const override;
+  virtual std::string ToString() const override;
+
+ protected:
+  using VendorPacket::VendorPacket;
+};
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file
index 9aa37a4..54ec2c3 100644 (file)
@@ -31,4 +31,5 @@
 #include "avrcp/get_item_attributes.h"
 #include "avrcp/get_total_number_of_items.h"
 #include "avrcp/play_item.h"
+#include "avrcp/set_absolute_volume.h"
 #include "avrcp/set_browsed_player.h"
\ No newline at end of file
index 2a822c1..e40fab2 100644 (file)
@@ -92,6 +92,11 @@ std::vector<uint8_t> register_play_status_notification = {
     0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
     0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x05};
 
+// AVRCP Register Volume Changed Notification
+std::vector<uint8_t> register_volume_changed_notification = {
+    0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
+    0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x00};
+
 // AVRCP Interim Playback Status Notification
 std::vector<uint8_t> interim_play_status_notification = {
     0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x01, 0x00};
@@ -106,6 +111,10 @@ std::vector<uint8_t> changed_play_pos_notification = {
     0x0d, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00,
     0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00};
 
+// AVRCP Interim Volume Changed Notification with volume at 55% (0x47)
+std::vector<uint8_t> interim_volume_changed_notification = {
+    0x0f, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x02, 0x0d, 0x47};
+
 // AVRCP Reject List Player Application Settings Response
 std::vector<uint8_t> reject_player_app_settings_response = {
     0x0a, 0x48, 0x00, 0x00, 0x19, 0x58, 0x11, 0x00, 0x00, 0x01, 0x00};
@@ -230,4 +239,12 @@ std::vector<uint8_t> play_item_request = {
 std::vector<uint8_t> play_item_response = {0x09, 0x48, 0x00, 0x00, 0x19, 0x58,
                                            0x74, 0x00, 0x00, 0x01, 0x04};
 
+// AVRCP Set Absolute Volume Request with volume at 56% (0x48)
+std::vector<uint8_t> set_absolute_volume_request = {
+    0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x48};
+
+// AVRCP Set Absolute Volume Response with voume at 52% (0x43)
+std::vector<uint8_t> set_absolute_volume_response = {
+    0x09, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x43};
+
 }  // namespace
\ No newline at end of file
index 7897587..79fb87b 100644 (file)
@@ -24,6 +24,7 @@ namespace bluetooth {
 namespace avrcp {
 
 using TestRegNotifReqPacket = TestPacketType<RegisterNotificationRequest>;
+using TestRegNotifRspPacket = TestPacketType<RegisterNotificationResponse>;
 
 TEST(RegisterNotificationRequestTest, getterTest) {
   auto test_packet =
@@ -50,7 +51,58 @@ TEST(RegisterNotificationRequestTest, invalidTest) {
   ASSERT_FALSE(test_packet->IsValid());
 }
 
-TEST(RegisterNotificationResponseTest, playStatusBuilderTest) {
+TEST(RegisterNotificationRequestBuilderTest, builderTest) {
+  auto builder =
+      RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0);
+  ASSERT_EQ(builder->size(), register_volume_changed_notification.size());
+
+  auto test_packet = TestRegNotifReqPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), register_volume_changed_notification);
+}
+
+TEST(RegisterNotificationResponseTest, volumeGetterTest) {
+  auto test_packet =
+      TestRegNotifRspPacket::Make(interim_volume_changed_notification);
+
+  ASSERT_TRUE(test_packet->IsInterim());
+  ASSERT_EQ(test_packet->GetEvent(), Event::VOLUME_CHANGED);
+  ASSERT_EQ(test_packet->GetVolume(), 0x47);
+}
+
+TEST(RegisterNotificationResponseTest, validTest) {
+  auto test_packet =
+      TestRegNotifRspPacket::Make(interim_volume_changed_notification);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationResponseTest, invalidTest) {
+  std::vector<uint8_t> packet_copy = interim_volume_changed_notification;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestRegNotifRspPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0, 1, 2, 3, 4};
+  test_packet = TestRegNotifRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  auto wrong_ctype = interim_volume_changed_notification;
+  wrong_ctype[0] = 0x00;
+  test_packet = TestRegNotifRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+TEST(RegisterNotificationResponseTest, wrongEventDeathTest) {
+  auto wrong_event = interim_volume_changed_notification;
+  wrong_event[10] = 0x00;
+  auto test_packet = TestRegNotifRspPacket::Make(wrong_event);
+
+  ASSERT_DEATH(test_packet->GetVolume(),
+               "GetEvent\\(\\) == Event::VOLUME_CHANGED");
+}
+
+TEST(RegisterNotificationResponseBuilderTest, playStatusBuilderTest) {
   auto builder = RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
       true, 0x00);
   ASSERT_EQ(builder->size(), interim_play_status_notification.size());
@@ -59,7 +111,7 @@ TEST(RegisterNotificationResponseTest, playStatusBuilderTest) {
   ASSERT_EQ(test_packet->GetData(), interim_play_status_notification);
 }
 
-TEST(RegisterNotificationResponseTest, trackChangedBuilderTest) {
+TEST(RegisterNotificationResponseBuilderTest, trackChangedBuilderTest) {
   auto builder = RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
       true, 0x0000000000000000);
   ASSERT_EQ(builder->size(), interim_track_changed_notification.size());
@@ -68,7 +120,7 @@ TEST(RegisterNotificationResponseTest, trackChangedBuilderTest) {
   ASSERT_EQ(test_packet->GetData(), interim_track_changed_notification);
 }
 
-TEST(RegisterNotificationResponseTest, playPositionBuilderTest) {
+TEST(RegisterNotificationResponseBuilderTest, playPositionBuilderTest) {
   auto builder =
       RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
           false, 0x00000000);
@@ -79,4 +131,4 @@ TEST(RegisterNotificationResponseTest, playPositionBuilderTest) {
 }
 
 }  // namespace avrcp
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/packet/tests/avrcp/set_absolute_volume_packet_test.cc b/packet/tests/avrcp/set_absolute_volume_packet_test.cc
new file mode 100644 (file)
index 0000000..8be462e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "avrcp_test_packets.h"
+#include "packet_test_helper.h"
+#include "set_absolute_volume.h"
+
+namespace bluetooth {
+namespace avrcp {
+
+using TestSetVolumeRspPacket = TestPacketType<SetAbsoluteVolumeResponse>;
+
+TEST(SetAbsoluteVolumeRequestBuilderTest, builderTest) {
+  auto builder = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x48);
+  ASSERT_EQ(builder->size(), set_absolute_volume_request.size());
+
+  auto test_packet = TestSetVolumeRspPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_absolute_volume_request);
+}
+
+// Test whether the volume field has the highest bit masked
+TEST(SetAbsoluteVolumeRequestBuilderTest, volumeMaskTest) {
+  auto builder = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0xc8);
+  auto test_packet = TestSetVolumeRspPacket::Make();
+  builder->Serialize(test_packet);
+  ASSERT_EQ(test_packet->GetData(), set_absolute_volume_request);
+}
+
+TEST(SetAbsoluteVolumeResponseTest, getterTest) {
+  auto test_packet = TestSetVolumeRspPacket::Make(set_absolute_volume_response);
+
+  ASSERT_EQ(test_packet->GetVolume(), 0x43);
+}
+
+TEST(SetAbsoluteVolumeResponseTest, validTest) {
+  auto test_packet = TestSetVolumeRspPacket::Make(set_absolute_volume_response);
+
+  ASSERT_TRUE(test_packet->IsValid());
+}
+
+TEST(SetAbsoluteVolumeResponseTest, invalidTest) {
+  auto packet_copy = set_absolute_volume_request;
+  packet_copy.push_back(0x00);
+  auto test_packet = TestSetVolumeRspPacket::Make(packet_copy);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  std::vector<uint8_t> short_packet = {0x00, 0x01, 0x02, 0x03, 0x04};
+  test_packet = TestSetVolumeRspPacket::Make(short_packet);
+  ASSERT_FALSE(test_packet->IsValid());
+
+  auto wrong_ctype = set_absolute_volume_request;
+  wrong_ctype[0] = 0x00;
+  test_packet = TestSetVolumeRspPacket::Make(wrong_ctype);
+  ASSERT_FALSE(test_packet->IsValid());
+}
+
+}  // namespace avrcp
+}  // namespace bluetooth
\ No newline at end of file