/*
* 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
#include "register_notification_packet.h"
namespace bluetooth {
namespace avrcp {
bool RegisterNotificationResponse::IsInterim() const {
return GetCType() == CType::INTERIM;
}
Event RegisterNotificationResponse::GetEvent() const {
auto value = *(begin() + VendorPacket::kMinSize());
return static_cast(value);
}
uint8_t RegisterNotificationResponse::GetVolume() const {
CHECK(GetEvent() == Event::VOLUME_CHANGED);
auto it = begin() + VendorPacket::kMinSize() + static_cast(1);
return *it;
}
bool RegisterNotificationResponse::IsValid() const {
if (!VendorPacket::IsValid()) return false;
if (size() < kMinSize()) return false;
if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED && GetCType() != CType::REJECTED) {
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::MakePlaybackStatusBuilder(
bool interim, uint8_t play_status) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(interim,
Event::PLAYBACK_STATUS_CHANGED));
builder->data_ = play_status;
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(
bool interim, uint64_t track_uid) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(interim, Event::TRACK_CHANGED));
builder->data_ = track_uid;
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(
bool interim, uint32_t playback_pos) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(interim,
Event::PLAYBACK_POS_CHANGED));
builder->data_ = playback_pos;
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(bool interim) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(
interim, Event::NOW_PLAYING_CONTENT_CHANGED));
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakeAvailablePlayersBuilder(bool interim) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(
interim, Event::AVAILABLE_PLAYERS_CHANGED));
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(
bool interim, uint16_t player_id, uint16_t uid_counter) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(interim,
Event::ADDRESSED_PLAYER_CHANGED));
builder->data_ = ((uint32_t)player_id) << 16;
builder->data_ |= uid_counter;
return builder;
}
std::unique_ptr
RegisterNotificationResponseBuilder::MakeUidsChangedBuilder(
bool interim, uint16_t uid_counter) {
std::unique_ptr builder(
new RegisterNotificationResponseBuilder(interim, Event::UIDS_CHANGED));
builder->data_ = uid_counter;
return builder;
}
size_t RegisterNotificationResponseBuilder::size() const {
size_t data_size = 0;
// We specifically avoid having a default case here in order to ensure that
// there is an error in case an event isn't handled.
switch (event_) {
case Event::PLAYBACK_STATUS_CHANGED:
data_size = 1;
break;
case Event::TRACK_CHANGED:
data_size = 8;
break;
case Event::PLAYBACK_POS_CHANGED:
data_size = 4;
break;
case Event::PLAYER_APPLICATION_SETTING_CHANGED:
LOG(FATAL) << "Player Application Notification Not Implemented";
break;
case Event::NOW_PLAYING_CONTENT_CHANGED:
data_size = 0;
break;
case Event::AVAILABLE_PLAYERS_CHANGED:
data_size = 0;
break;
case Event::ADDRESSED_PLAYER_CHANGED:
data_size = 4;
break;
case Event::UIDS_CHANGED:
data_size = 2;
break;
case Event::VOLUME_CHANGED:
LOG(FATAL) << "Volume Changed Notification Not Implemented";
break;
}
return VendorPacket::kMinSize() + 1 + data_size;
}
bool RegisterNotificationResponseBuilder::Serialize(
const std::shared_ptr<::bluetooth::Packet>& pkt) {
ReserveSpace(pkt, size());
PacketBuilder::PushHeader(pkt);
VendorPacketBuilder::PushHeader(pkt, size() - VendorPacket::kMinSize());
AddPayloadOctets1(pkt, static_cast(event_));
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;
}
case Event::VOLUME_CHANGED:
// TODO (apanicke): Add Volume Changed builder for when we are controller.
LOG(FATAL) << "Volume Changed Notification Not Implemented";
break;
}
return true;
}
Event RegisterNotificationRequest::GetEventRegistered() const {
auto value = *(begin() + VendorPacket::kMinSize());
return static_cast(value);
}
uint32_t RegisterNotificationRequest::GetInterval() const {
auto it = begin() + VendorPacket::kMinSize() + static_cast(1);
return it.extractBE();
}
bool RegisterNotificationRequest::IsValid() const {
return (size() == kMinSize());
}
std::string RegisterNotificationRequest::ToString() const {
std::stringstream ss;
ss << "RegisterNotificationPacket: " << 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 = " << GetEventRegistered() << std::endl;
ss << " └ Interval = " << loghex(GetInterval()) << std::endl;
ss << std::endl;
return ss.str();
}
std::unique_ptr
RegisterNotificationRequestBuilder::MakeBuilder(Event event,
uint32_t interval) {
std::unique_ptr 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(event_));
AddPayloadOctets4(pkt, base::ByteSwap(interval_));
return true;
}
} // namespace avrcp
} // namespace bluetooth