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 <algorithm> 18 #include <iostream> 19 20 #include <base/bind.h> 21 #include <base/logging.h> 22 #include <base/threading/thread.h> 23 #include <gmock/gmock.h> 24 #include <gtest/gtest.h> 25 26 #include "avrcp_packet.h" 27 #include "avrcp_test_helper.h" 28 #include "device.h" 29 #include "stack_config.h" 30 #include "tests/avrcp/avrcp_test_packets.h" 31 #include "tests/packet_test_helper.h" 32 33 namespace bluetooth { 34 namespace avrcp { 35 36 // TODO (apanicke): All the tests below are just basic positive unit tests. 37 // Add more tests to increase code coverage. 38 39 using AvrcpResponse = std::unique_ptr<::bluetooth::PacketBuilder>; 40 using TestAvrcpPacket = TestPacketType<Packet>; 41 using TestBrowsePacket = TestPacketType<BrowsePacket>; 42 43 using ::testing::_; 44 using ::testing::MockFunction; 45 using ::testing::Mock; 46 using ::testing::NiceMock; 47 using ::testing::Return; 48 49 bool get_pts_avrcp_test(void) { return false; } 50 51 const stack_config_t interface = { 52 nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr, 53 nullptr}; 54 55 // TODO (apanicke): All the tests below are just basic positive unit tests. 56 // Add more tests to increase code coverage. 57 class AvrcpDeviceTest : public ::testing::Test { 58 public: 59 virtual void SetUp() override { 60 // NOTE: We use a wrapper lambda for the MockFunction in order to 61 // add a const qualifier to the response. Otherwise the MockFunction 62 // type doesn't match the callback type and a compiler error occurs. 63 base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = base::Bind( 64 [](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, 65 uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, 66 &response_cb); 67 68 // TODO (apanicke): Test setting avrc13 to false once we have full 69 // functionality. 70 test_device = new Device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF); 71 } 72 73 virtual void TearDown() override { 74 delete test_device; 75 Mock::VerifyAndClear(&response_cb); 76 } 77 78 void SendMessage(uint8_t label, std::shared_ptr<Packet> message) { 79 test_device->MessageReceived(label, message); 80 } 81 82 void SendBrowseMessage(uint8_t label, std::shared_ptr<BrowsePacket> message) { 83 test_device->BrowseMessageReceived(label, message); 84 } 85 86 MockFunction<void(uint8_t, bool, const AvrcpResponse&)> response_cb; 87 Device* test_device; 88 }; 89 90 TEST_F(AvrcpDeviceTest, addressTest) { 91 base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = 92 base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, 93 uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, 94 &response_cb); 95 96 Device device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF); 97 ASSERT_EQ(device.GetAddress(), RawAddress::kAny); 98 } 99 100 TEST_F(AvrcpDeviceTest, trackChangedTest) { 101 MockMediaInterface interface; 102 NiceMock<MockA2dpInterface> a2dp_interface; 103 104 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 105 106 SongInfo info = {"test_id", 107 {// The attribute map 108 AttributeEntry(Attribute::TITLE, "Test Song"), 109 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 110 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 111 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 112 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 113 AttributeEntry(Attribute::GENRE, "Test Genre"), 114 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 115 std::vector<SongInfo> list = {info}; 116 117 EXPECT_CALL(interface, GetNowPlayingList(_)) 118 .Times(2) 119 .WillRepeatedly(InvokeCb<0>("test_id", list)); 120 121 // Test the interim response for track changed 122 auto interim_response = 123 RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(true, 0x01); 124 EXPECT_CALL(response_cb, 125 Call(1, false, matchPacket(std::move(interim_response)))) 126 .Times(1); 127 128 auto request = 129 RegisterNotificationRequestBuilder::MakeBuilder(Event::TRACK_CHANGED, 0); 130 auto pkt = TestAvrcpPacket::Make(); 131 request->Serialize(pkt); 132 SendMessage(1, pkt); 133 134 // Test the changed response for track changed 135 auto changed_response = 136 RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(false, 0x01); 137 EXPECT_CALL(response_cb, 138 Call(1, false, matchPacket(std::move(changed_response)))) 139 .Times(1); 140 141 test_device->HandleTrackUpdate(); 142 } 143 144 TEST_F(AvrcpDeviceTest, playStatusTest) { 145 MockMediaInterface interface; 146 NiceMock<MockA2dpInterface> a2dp_interface; 147 148 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 149 150 PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING}; 151 PlayStatus status2 = {0x1234, 0x5678, PlayState::STOPPED}; 152 153 EXPECT_CALL(interface, GetPlayStatus(_)) 154 .Times(2) 155 .WillOnce(InvokeCb<0>(status1)) 156 .WillOnce(InvokeCb<0>(status2)); 157 158 // Pretend the device is active 159 EXPECT_CALL(a2dp_interface, active_peer()) 160 .WillRepeatedly(Return(test_device->GetAddress())); 161 162 // Test the interim response for play status changed 163 auto interim_response = 164 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( 165 true, PlayState::PLAYING); 166 EXPECT_CALL(response_cb, 167 Call(1, false, matchPacket(std::move(interim_response)))) 168 .Times(1); 169 170 auto request = RegisterNotificationRequestBuilder::MakeBuilder( 171 Event::PLAYBACK_STATUS_CHANGED, 0); 172 auto pkt = TestAvrcpPacket::Make(); 173 request->Serialize(pkt); 174 SendMessage(1, pkt); 175 176 // Test the changed response for play status changed 177 auto changed_response = 178 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( 179 false, PlayState::STOPPED); 180 EXPECT_CALL(response_cb, 181 Call(1, false, matchPacket(std::move(changed_response)))) 182 .Times(1); 183 test_device->HandlePlayStatusUpdate(); 184 } 185 186 TEST_F(AvrcpDeviceTest, playPositionTest) { 187 MockMediaInterface interface; 188 NiceMock<MockA2dpInterface> a2dp_interface; 189 190 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 191 192 PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING}; 193 PlayStatus status2 = {0x5678, 0x9ABC, PlayState::STOPPED}; 194 195 EXPECT_CALL(interface, GetPlayStatus(_)) 196 .Times(2) 197 .WillOnce(InvokeCb<0>(status1)) 198 .WillOnce(InvokeCb<0>(status2)); 199 200 // Pretend the device is active 201 EXPECT_CALL(a2dp_interface, active_peer()) 202 .WillRepeatedly(Return(test_device->GetAddress())); 203 204 // Test the interim response for play status changed 205 auto interim_response = 206 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( 207 true, PlayState::PLAYING); 208 EXPECT_CALL(response_cb, 209 Call(1, false, matchPacket(std::move(interim_response)))) 210 .Times(1); 211 212 auto request = RegisterNotificationRequestBuilder::MakeBuilder( 213 Event::PLAYBACK_STATUS_CHANGED, 0); 214 auto pkt = TestAvrcpPacket::Make(); 215 request->Serialize(pkt); 216 SendMessage(1, pkt); 217 218 // Test the changed response for play status changed 219 auto changed_response = 220 RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( 221 false, PlayState::STOPPED); 222 EXPECT_CALL(response_cb, 223 Call(1, false, matchPacket(std::move(changed_response)))) 224 .Times(1); 225 test_device->HandlePlayStatusUpdate(); 226 } 227 228 TEST_F(AvrcpDeviceTest, nowPlayingTest) { 229 MockMediaInterface interface; 230 NiceMock<MockA2dpInterface> a2dp_interface; 231 232 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 233 234 SongInfo info = {"test_id", 235 {// The attribute map 236 AttributeEntry(Attribute::TITLE, "Test Song"), 237 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 238 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 239 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 240 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 241 AttributeEntry(Attribute::GENRE, "Test Genre"), 242 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 243 std::vector<SongInfo> list = {info}; 244 EXPECT_CALL(interface, GetNowPlayingList(_)) 245 .Times(2) 246 .WillRepeatedly(InvokeCb<0>("test_id", list)); 247 248 // Test the interim response for now playing list changed 249 auto interim_response = 250 RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(true); 251 EXPECT_CALL(response_cb, 252 Call(1, false, matchPacket(std::move(interim_response)))) 253 .Times(1); 254 255 auto request = RegisterNotificationRequestBuilder::MakeBuilder( 256 Event::NOW_PLAYING_CONTENT_CHANGED, 0); 257 auto pkt = TestAvrcpPacket::Make(); 258 request->Serialize(pkt); 259 SendMessage(1, pkt); 260 261 // Test the changed response for now playing list changed 262 auto changed_response = 263 RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(false); 264 EXPECT_CALL(response_cb, 265 Call(1, false, matchPacket(std::move(changed_response)))) 266 .Times(1); 267 test_device->HandleNowPlayingUpdate(); 268 } 269 270 TEST_F(AvrcpDeviceTest, getPlayStatusTest) { 271 MockMediaInterface interface; 272 NiceMock<MockA2dpInterface> a2dp_interface; 273 274 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 275 276 PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; 277 278 EXPECT_CALL(interface, GetPlayStatus(_)) 279 .Times(1) 280 .WillOnce(InvokeCb<0>(status)); 281 282 // Pretend the device is active 283 EXPECT_CALL(a2dp_interface, active_peer()) 284 .WillRepeatedly(Return(test_device->GetAddress())); 285 286 auto expected_response = GetPlayStatusResponseBuilder::MakeBuilder( 287 0x5678, 0x1234, PlayState::PLAYING); 288 EXPECT_CALL(response_cb, 289 Call(1, false, matchPacket(std::move(expected_response)))) 290 .Times(1); 291 292 auto request = TestAvrcpPacket::Make(get_play_status_request); 293 SendMessage(1, request); 294 } 295 296 TEST_F(AvrcpDeviceTest, getElementAttributesTest) { 297 MockMediaInterface interface; 298 NiceMock<MockA2dpInterface> a2dp_interface; 299 300 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 301 302 SongInfo info = {"test_id", 303 {// The attribute map 304 AttributeEntry(Attribute::TITLE, "Test Song"), 305 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 306 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 307 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 308 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 309 AttributeEntry(Attribute::GENRE, "Test Genre"), 310 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 311 312 EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info)); 313 314 auto compare_to_partial = 315 GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); 316 compare_to_partial->AddAttributeEntry(Attribute::TITLE, "Test Song"); 317 EXPECT_CALL(response_cb, 318 Call(2, false, matchPacket(std::move(compare_to_partial)))) 319 .Times(1); 320 SendMessage(2, TestAvrcpPacket::Make(get_element_attributes_request_partial)); 321 322 auto compare_to_full = 323 GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); 324 compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); 325 compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); 326 compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); 327 compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); 328 compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); 329 compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); 330 compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); 331 EXPECT_CALL(response_cb, 332 Call(3, false, matchPacket(std::move(compare_to_full)))) 333 .Times(1); 334 SendMessage(3, TestAvrcpPacket::Make(get_element_attributes_request_full)); 335 } 336 337 TEST_F(AvrcpDeviceTest, getElementAttributesMtuTest) { 338 auto truncated_packet = 339 GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); 340 truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234"); 341 342 MockMediaInterface interface; 343 NiceMock<MockA2dpInterface> a2dp_interface; 344 345 base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = 346 base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, 347 uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, 348 &response_cb); 349 Device device(RawAddress::kAny, true, cb, truncated_packet->size(), 0xFFFF); 350 351 device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); 352 353 SongInfo info = {"test_id", 354 {AttributeEntry(Attribute::TITLE, "1234truncated")}}; 355 EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info)); 356 357 EXPECT_CALL(response_cb, 358 Call(1, false, matchPacket(std::move(truncated_packet)))) 359 .Times(1); 360 361 device.MessageReceived( 362 1, TestAvrcpPacket::Make(get_element_attributes_request_full)); 363 } 364 365 TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsMediaPlayersTest) { 366 MockMediaInterface interface; 367 NiceMock<MockA2dpInterface> a2dp_interface; 368 369 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 370 371 std::vector<MediaPlayerInfo> player_list = { 372 {0, "player1", true}, {1, "player2", true}, {2, "player3", true}, 373 }; 374 375 EXPECT_CALL(interface, GetMediaPlayerList(_)) 376 .Times(1) 377 .WillOnce(InvokeCb<0>(0, player_list)); 378 379 auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( 380 Status::NO_ERROR, 0, player_list.size()); 381 EXPECT_CALL(response_cb, 382 Call(1, true, matchPacket(std::move(expected_response)))) 383 .Times(1); 384 385 SendBrowseMessage(1, TestBrowsePacket::Make( 386 get_total_number_of_items_request_media_players)); 387 } 388 389 TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsVFSTest) { 390 MockMediaInterface interface; 391 NiceMock<MockA2dpInterface> a2dp_interface; 392 393 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 394 395 std::vector<ListItem> vfs_list = { 396 {ListItem::FOLDER, {"id1", true, "folder1"}, SongInfo()}, 397 {ListItem::FOLDER, {"id2", true, "folder2"}, SongInfo()}, 398 }; 399 400 EXPECT_CALL(interface, GetFolderItems(_, "", _)) 401 .Times(1) 402 .WillOnce(InvokeCb<2>(vfs_list)); 403 404 auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( 405 Status::NO_ERROR, 0, vfs_list.size()); 406 EXPECT_CALL(response_cb, 407 Call(1, true, matchPacket(std::move(expected_response)))) 408 .Times(1); 409 410 SendBrowseMessage( 411 1, TestBrowsePacket::Make(get_total_number_of_items_request_vfs)); 412 } 413 414 TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsNowPlayingTest) { 415 MockMediaInterface interface; 416 NiceMock<MockA2dpInterface> a2dp_interface; 417 418 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 419 420 std::vector<SongInfo> now_playing_list = { 421 {"test_id1", {}}, {"test_id2", {}}, {"test_id3", {}}, 422 {"test_id4", {}}, {"test_id5", {}}, 423 }; 424 425 EXPECT_CALL(interface, GetNowPlayingList(_)) 426 .WillRepeatedly(InvokeCb<0>("test_id1", now_playing_list)); 427 428 auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( 429 Status::NO_ERROR, 0, now_playing_list.size()); 430 EXPECT_CALL(response_cb, 431 Call(1, true, matchPacket(std::move(expected_response)))) 432 .Times(1); 433 434 SendBrowseMessage( 435 1, TestBrowsePacket::Make(get_total_number_of_items_request_now_playing)); 436 } 437 438 TEST_F(AvrcpDeviceTest, getMediaPlayerListTest) { 439 MockMediaInterface interface; 440 NiceMock<MockA2dpInterface> a2dp_interface; 441 442 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 443 444 MediaPlayerInfo info = {0, "Test Player", true}; 445 std::vector<MediaPlayerInfo> list = {info}; 446 447 EXPECT_CALL(interface, GetMediaPlayerList(_)) 448 .Times(1) 449 .WillOnce(InvokeCb<0>(0, list)); 450 451 auto expected_response = GetFolderItemsResponseBuilder::MakePlayerListBuilder( 452 Status::NO_ERROR, 0x0000, 0xFFFF); 453 expected_response->AddMediaPlayer(MediaPlayerItem(0, "Test Player", true)); 454 EXPECT_CALL(response_cb, 455 Call(1, true, matchPacket(std::move(expected_response)))) 456 .Times(1); 457 458 auto request = TestBrowsePacket::Make(get_folder_items_request); 459 SendBrowseMessage(1, request); 460 } 461 462 TEST_F(AvrcpDeviceTest, getNowPlayingListTest) { 463 MockMediaInterface interface; 464 NiceMock<MockA2dpInterface> a2dp_interface; 465 466 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 467 468 SongInfo info = {"test_id", 469 {// The attribute map 470 AttributeEntry(Attribute::TITLE, "Test Song"), 471 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 472 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 473 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 474 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 475 AttributeEntry(Attribute::GENRE, "Test Genre"), 476 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 477 std::vector<SongInfo> list = {info}; 478 479 EXPECT_CALL(interface, GetNowPlayingList(_)) 480 .WillRepeatedly(InvokeCb<0>("test_id", list)); 481 482 auto expected_response = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder( 483 Status::NO_ERROR, 0x0000, 0xFFFF); 484 expected_response->AddSong(MediaElementItem(1, "Test Song", info.attributes)); 485 EXPECT_CALL(response_cb, 486 Call(1, true, matchPacket(std::move(expected_response)))) 487 .Times(1); 488 489 auto request = TestBrowsePacket::Make(get_folder_items_request_now_playing); 490 SendBrowseMessage(1, request); 491 } 492 493 TEST_F(AvrcpDeviceTest, getVFSFolderTest) { 494 MockMediaInterface interface; 495 NiceMock<MockA2dpInterface> a2dp_interface; 496 497 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 498 499 FolderInfo info = {"test_id", true, "Test Folder"}; 500 ListItem item = {ListItem::FOLDER, info, SongInfo()}; 501 std::vector<ListItem> list = {item}; 502 503 EXPECT_CALL(interface, GetFolderItems(_, "", _)) 504 .Times(1) 505 .WillOnce(InvokeCb<2>(list)); 506 507 auto expected_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( 508 Status::NO_ERROR, 0x0000, 0xFFFF); 509 expected_response->AddFolder(FolderItem(1, 0, true, "Test Folder")); 510 EXPECT_CALL(response_cb, 511 Call(1, true, matchPacket(std::move(expected_response)))) 512 .Times(1); 513 514 auto request = TestBrowsePacket::Make(get_folder_items_request_vfs); 515 SendBrowseMessage(1, request); 516 } 517 518 TEST_F(AvrcpDeviceTest, getFolderItemsMtuTest) { 519 auto truncated_packet = GetFolderItemsResponseBuilder::MakeVFSBuilder( 520 Status::NO_ERROR, 0x0000, 0xFFFF); 521 truncated_packet->AddFolder(FolderItem(1, 0, true, "Test Folder0")); 522 truncated_packet->AddFolder(FolderItem(2, 0, true, "Test Folder1")); 523 524 MockMediaInterface interface; 525 NiceMock<MockA2dpInterface> a2dp_interface; 526 base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = 527 base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, 528 uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, 529 &response_cb); 530 Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size()); 531 device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); 532 533 FolderInfo info0 = {"test_id0", true, "Test Folder0"}; 534 FolderInfo info1 = {"test_id1", true, "Test Folder1"}; 535 FolderInfo info2 = {"test_id1", true, "Truncated folder"}; 536 ListItem item0 = {ListItem::FOLDER, info0, SongInfo()}; 537 ListItem item1 = {ListItem::FOLDER, info1, SongInfo()}; 538 ListItem item2 = {ListItem::FOLDER, info1, SongInfo()}; 539 std::vector<ListItem> list0 = {item0, item1, item2}; 540 EXPECT_CALL(interface, GetFolderItems(_, "", _)) 541 .WillRepeatedly(InvokeCb<2>(list0)); 542 543 EXPECT_CALL(response_cb, 544 Call(1, true, matchPacket(std::move(truncated_packet)))) 545 .Times(1); 546 device.BrowseMessageReceived( 547 1, TestBrowsePacket::Make(get_folder_items_request_vfs)); 548 } 549 550 TEST_F(AvrcpDeviceTest, changePathTest) { 551 MockMediaInterface interface; 552 NiceMock<MockA2dpInterface> a2dp_interface; 553 554 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 555 556 FolderInfo info0 = {"test_id0", true, "Test Folder0"}; 557 FolderInfo info1 = {"test_id1", true, "Test Folder1"}; 558 ListItem item0 = {ListItem::FOLDER, info0, SongInfo()}; 559 ListItem item1 = {ListItem::FOLDER, info1, SongInfo()}; 560 std::vector<ListItem> list0 = {item0, item1}; 561 EXPECT_CALL(interface, GetFolderItems(_, "", _)) 562 .Times(1) 563 .WillRepeatedly(InvokeCb<2>(list0)); 564 565 FolderInfo info2 = {"test_id2", true, "Test Folder2"}; 566 FolderInfo info3 = {"test_id3", true, "Test Folder3"}; 567 FolderInfo info4 = {"test_id4", true, "Test Folder4"}; 568 ListItem item2 = {ListItem::FOLDER, info2, SongInfo()}; 569 ListItem item3 = {ListItem::FOLDER, info3, SongInfo()}; 570 ListItem item4 = {ListItem::FOLDER, info4, SongInfo()}; 571 std::vector<ListItem> list1 = {item2, item3, item4}; 572 EXPECT_CALL(interface, GetFolderItems(_, "test_id1", _)) 573 .Times(3) 574 .WillRepeatedly(InvokeCb<2>(list1)); 575 576 std::vector<ListItem> list2 = {}; 577 EXPECT_CALL(interface, GetFolderItems(_, "test_id3", _)) 578 .Times(1) 579 .WillOnce(InvokeCb<2>(list2)); 580 581 // Populate the VFS ID map 582 auto folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( 583 Status::NO_ERROR, 0x0000, 0xFFFF); 584 folder_items_response->AddFolder(FolderItem(1, 0, true, "Test Folder0")); 585 folder_items_response->AddFolder(FolderItem(2, 0, true, "Test Folder1")); 586 EXPECT_CALL(response_cb, 587 Call(1, true, matchPacket(std::move(folder_items_response)))) 588 .Times(1); 589 590 auto folder_request_builder = 591 GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {}); 592 auto request = TestBrowsePacket::Make(); 593 folder_request_builder->Serialize(request); 594 SendBrowseMessage(1, request); 595 596 // Change path down into Test Folder1 597 auto change_path_response = 598 ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size()); 599 EXPECT_CALL(response_cb, 600 Call(2, true, matchPacket(std::move(change_path_response)))); 601 auto path_request_builder = 602 ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2); 603 request = TestBrowsePacket::Make(); 604 path_request_builder->Serialize(request); 605 SendBrowseMessage(2, request); 606 607 // Populate the new VFS ID 608 folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( 609 Status::NO_ERROR, 0x0000, 0xFFFF); 610 folder_items_response->AddFolder(FolderItem(3, 0, true, "Test Folder2")); 611 folder_items_response->AddFolder(FolderItem(4, 0, true, "Test Folder3")); 612 folder_items_response->AddFolder(FolderItem(5, 0, true, "Test Folder4")); 613 EXPECT_CALL(response_cb, 614 Call(3, true, matchPacket(std::move(folder_items_response)))) 615 .Times(1); 616 folder_request_builder = 617 GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {}); 618 request = TestBrowsePacket::Make(); 619 folder_request_builder->Serialize(request); 620 SendBrowseMessage(3, request); 621 622 // Change path down into Test Folder3 623 change_path_response = 624 ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list2.size()); 625 EXPECT_CALL(response_cb, 626 Call(4, true, matchPacket(std::move(change_path_response)))); 627 path_request_builder = 628 ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 4); 629 request = TestBrowsePacket::Make(); 630 path_request_builder->Serialize(request); 631 SendBrowseMessage(4, request); 632 633 // Change path up back into Test Folder1 634 change_path_response = 635 ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size()); 636 EXPECT_CALL(response_cb, 637 Call(5, true, matchPacket(std::move(change_path_response)))); 638 path_request_builder = 639 ChangePathRequestBuilder::MakeBuilder(0, Direction::UP, 0); 640 request = TestBrowsePacket::Make(); 641 path_request_builder->Serialize(request); 642 SendBrowseMessage(5, request); 643 } 644 645 TEST_F(AvrcpDeviceTest, getItemAttributesNowPlayingTest) { 646 MockMediaInterface interface; 647 NiceMock<MockA2dpInterface> a2dp_interface; 648 649 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 650 651 SongInfo info = {"test_id", 652 {// The attribute map 653 AttributeEntry(Attribute::TITLE, "Test Song"), 654 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 655 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 656 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 657 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 658 AttributeEntry(Attribute::GENRE, "Test Genre"), 659 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 660 std::vector<SongInfo> list = {info}; 661 662 EXPECT_CALL(interface, GetNowPlayingList(_)) 663 .WillRepeatedly(InvokeCb<0>("test_id", list)); 664 665 auto compare_to_full = 666 GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF); 667 compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); 668 compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); 669 compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); 670 compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); 671 compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); 672 compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); 673 compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); 674 EXPECT_CALL(response_cb, 675 Call(1, true, matchPacket(std::move(compare_to_full)))) 676 .Times(1); 677 678 auto request = 679 TestBrowsePacket::Make(get_item_attributes_request_all_attributes); 680 SendBrowseMessage(1, request); 681 } 682 683 TEST_F(AvrcpDeviceTest, geItemAttributesMtuTest) { 684 auto truncated_packet = 685 GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF); 686 truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234"); 687 688 MockMediaInterface interface; 689 NiceMock<MockA2dpInterface> a2dp_interface; 690 base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = 691 base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, 692 uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, 693 &response_cb); 694 Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size()); 695 device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); 696 697 SongInfo info = {"test_id", 698 {AttributeEntry(Attribute::TITLE, "1234truncated")}}; 699 std::vector<SongInfo> list = {info}; 700 EXPECT_CALL(interface, GetNowPlayingList(_)) 701 .WillRepeatedly(InvokeCb<0>("test_id", list)); 702 703 EXPECT_CALL(response_cb, 704 Call(1, true, matchPacket(std::move(truncated_packet)))) 705 .Times(1); 706 device.BrowseMessageReceived( 707 1, TestBrowsePacket::Make(get_item_attributes_request_all_attributes)); 708 } 709 710 TEST_F(AvrcpDeviceTest, setAddressedPlayerTest) { 711 MockMediaInterface interface; 712 NiceMock<MockA2dpInterface> a2dp_interface; 713 714 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 715 716 auto set_addr_player_rsp = RejectBuilder::MakeBuilder( 717 CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID); 718 719 EXPECT_CALL(response_cb, 720 Call(1, false, matchPacket(std::move(set_addr_player_rsp)))) 721 .Times(1); 722 723 auto request = TestAvrcpPacket::Make(set_addressed_player_request); 724 SendMessage(1, request); 725 } 726 727 TEST_F(AvrcpDeviceTest, volumeChangedTest) { 728 MockMediaInterface interface; 729 NiceMock<MockA2dpInterface> a2dp_interface; 730 MockVolumeInterface vol_interface; 731 732 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 733 734 // Pretend the device is active 735 EXPECT_CALL(a2dp_interface, active_peer()) 736 .WillRepeatedly(Return(test_device->GetAddress())); 737 738 auto reg_notif = 739 RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); 740 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) 741 .Times(1); 742 test_device->RegisterVolumeChanged(); 743 744 EXPECT_CALL(vol_interface, DeviceConnected(test_device->GetAddress(), _)) 745 .Times(1) 746 .WillOnce(InvokeCb<1>(0x30)); 747 auto set_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x30); 748 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_vol)))) 749 .Times(1); 750 751 auto response = TestAvrcpPacket::Make(interim_volume_changed_notification); 752 SendMessage(1, response); 753 754 EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(1); 755 auto reg_notif2 = 756 RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); 757 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif2)))) 758 .Times(1); 759 response = TestAvrcpPacket::Make(changed_volume_changed_notification); 760 SendMessage(1, response); 761 response = TestAvrcpPacket::Make(interim_volume_changed_notification); 762 SendMessage(1, response); 763 } 764 765 TEST_F(AvrcpDeviceTest, volumeChangedNonActiveTest) { 766 MockMediaInterface interface; 767 NiceMock<MockA2dpInterface> a2dp_interface; 768 MockVolumeInterface vol_interface; 769 770 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 771 772 // Pretend the device isn't active 773 EXPECT_CALL(a2dp_interface, active_peer()) 774 .WillRepeatedly(Return(RawAddress::kEmpty)); 775 776 auto reg_notif = 777 RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); 778 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) 779 .Times(1); 780 test_device->RegisterVolumeChanged(); 781 782 EXPECT_CALL(vol_interface, DeviceConnected(test_device->GetAddress(), _)) 783 .Times(1) 784 .WillOnce(InvokeCb<1>(0x30)); 785 auto set_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x30); 786 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_vol)))) 787 .Times(1); 788 789 auto response = TestAvrcpPacket::Make(interim_volume_changed_notification); 790 SendMessage(1, response); 791 792 // Ensure that SetVolume is never called 793 EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(0); 794 795 auto reg_notif2 = 796 RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); 797 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif2)))) 798 .Times(1); 799 response = TestAvrcpPacket::Make(changed_volume_changed_notification); 800 SendMessage(1, response); 801 response = TestAvrcpPacket::Make(interim_volume_changed_notification); 802 SendMessage(1, response); 803 } 804 805 TEST_F(AvrcpDeviceTest, volumeRejectedTest) { 806 MockMediaInterface interface; 807 NiceMock<MockA2dpInterface> a2dp_interface; 808 MockVolumeInterface vol_interface; 809 810 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 811 812 auto reg_notif = 813 RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); 814 EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) 815 .Times(1); 816 test_device->RegisterVolumeChanged(); 817 818 auto response = TestAvrcpPacket::Make(rejected_volume_changed_notification); 819 SendMessage(1, response); 820 821 EXPECT_CALL(response_cb, Call(_, _, _)).Times(0); 822 } 823 824 TEST_F(AvrcpDeviceTest, playPushedActiveDeviceTest) { 825 MockMediaInterface interface; 826 NiceMock<MockA2dpInterface> a2dp_interface; 827 MockVolumeInterface vol_interface; 828 829 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 830 831 // Pretend the device is active 832 EXPECT_CALL(a2dp_interface, active_peer()) 833 .WillRepeatedly(Return(test_device->GetAddress())); 834 835 auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44); 836 auto play_pushed_response = 837 PassThroughPacketBuilder::MakeBuilder(true, true, 0x44); 838 EXPECT_CALL(response_cb, 839 Call(_, false, matchPacket(std::move(play_pushed_response)))) 840 .Times(1); 841 842 PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; 843 EXPECT_CALL(interface, GetPlayStatus(_)) 844 .Times(1) 845 .WillOnce(InvokeCb<0>(status)); 846 847 EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(1); 848 849 auto play_pushed_pkt = TestAvrcpPacket::Make(); 850 play_pushed->Serialize(play_pushed_pkt); 851 852 SendMessage(1, play_pushed_pkt); 853 } 854 855 TEST_F(AvrcpDeviceTest, playPushedInactiveDeviceTest) { 856 MockMediaInterface interface; 857 NiceMock<MockA2dpInterface> a2dp_interface; 858 MockVolumeInterface vol_interface; 859 860 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 861 862 // Pretend the device is not active 863 EXPECT_CALL(a2dp_interface, active_peer()) 864 .WillRepeatedly(Return(RawAddress::kEmpty)); 865 866 auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44); 867 auto play_pushed_response = 868 PassThroughPacketBuilder::MakeBuilder(true, true, 0x44); 869 EXPECT_CALL(response_cb, 870 Call(_, false, matchPacket(std::move(play_pushed_response)))) 871 .Times(1); 872 873 // Expect that the device will try to set itself as active 874 EXPECT_CALL(interface, SetActiveDevice(test_device->GetAddress())).Times(1); 875 876 // No play command should be sent since the music is already playing 877 PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; 878 EXPECT_CALL(interface, GetPlayStatus(_)) 879 .Times(1) 880 .WillOnce(InvokeCb<0>(status)); 881 EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(0); 882 883 auto play_pushed_pkt = TestAvrcpPacket::Make(); 884 play_pushed->Serialize(play_pushed_pkt); 885 886 SendMessage(1, play_pushed_pkt); 887 } 888 889 TEST_F(AvrcpDeviceTest, mediaKeyActiveDeviceTest) { 890 MockMediaInterface interface; 891 NiceMock<MockA2dpInterface> a2dp_interface; 892 MockVolumeInterface vol_interface; 893 894 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 895 896 // Pretend the device is active 897 EXPECT_CALL(a2dp_interface, active_peer()) 898 .WillRepeatedly(Return(test_device->GetAddress())); 899 900 auto play_released = 901 PassThroughPacketBuilder::MakeBuilder(false, false, 0x44); 902 auto play_released_response = 903 PassThroughPacketBuilder::MakeBuilder(true, false, 0x44); 904 EXPECT_CALL(response_cb, 905 Call(_, false, matchPacket(std::move(play_released_response)))) 906 .Times(1); 907 908 EXPECT_CALL(interface, GetPlayStatus(_)).Times(0); 909 910 EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(1); 911 912 auto play_released_pkt = TestAvrcpPacket::Make(); 913 play_released->Serialize(play_released_pkt); 914 915 SendMessage(1, play_released_pkt); 916 } 917 918 TEST_F(AvrcpDeviceTest, mediaKeyInactiveDeviceTest) { 919 MockMediaInterface interface; 920 NiceMock<MockA2dpInterface> a2dp_interface; 921 MockVolumeInterface vol_interface; 922 923 test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); 924 925 // Pretend the device is not active 926 EXPECT_CALL(a2dp_interface, active_peer()) 927 .WillRepeatedly(Return(RawAddress::kEmpty)); 928 929 auto play_released = 930 PassThroughPacketBuilder::MakeBuilder(false, false, 0x44); 931 auto play_released_response = 932 PassThroughPacketBuilder::MakeBuilder(true, false, 0x44); 933 EXPECT_CALL(response_cb, 934 Call(_, false, matchPacket(std::move(play_released_response)))) 935 .Times(1); 936 937 EXPECT_CALL(interface, GetPlayStatus(_)).Times(0); 938 939 // Expect that the key event wont be sent to the media interface 940 EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(0); 941 942 auto play_released_pkt = TestAvrcpPacket::Make(); 943 play_released->Serialize(play_released_pkt); 944 945 SendMessage(1, play_released_pkt); 946 } 947 948 TEST_F(AvrcpDeviceTest, getCapabilitiesTest) { 949 MockMediaInterface interface; 950 NiceMock<MockA2dpInterface> a2dp_interface; 951 952 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 953 954 // GetCapabilities with CapabilityID COMPANY_ID 955 auto request_company_id_response = 956 GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958); 957 request_company_id_response->AddCompanyId(0x002345); 958 EXPECT_CALL( 959 response_cb, 960 Call(1, false, matchPacket(std::move(request_company_id_response)))) 961 .Times(1); 962 963 auto request_company_id = 964 TestAvrcpPacket::Make(get_capabilities_request_company_id); 965 SendMessage(1, request_company_id); 966 967 // GetCapabilities with CapabilityID EVENTS_SUPPORTED 968 auto request_events_supported_response = 969 GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder( 970 Event::PLAYBACK_STATUS_CHANGED); 971 request_events_supported_response->AddEvent(Event::TRACK_CHANGED); 972 request_events_supported_response->AddEvent(Event::PLAYBACK_POS_CHANGED); 973 974 EXPECT_CALL( 975 response_cb, 976 Call(2, false, matchPacket(std::move(request_events_supported_response)))) 977 .Times(1); 978 979 auto request_events_supported = 980 TestAvrcpPacket::Make(get_capabilities_request); 981 SendMessage(2, request_events_supported); 982 983 // GetCapabilities with CapabilityID UNKNOWN 984 auto request_unknown_response = RejectBuilder::MakeBuilder( 985 CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER); 986 987 EXPECT_CALL(response_cb, 988 Call(3, false, matchPacket(std::move(request_unknown_response)))) 989 .Times(1); 990 991 auto request_unknown = 992 TestAvrcpPacket::Make(get_capabilities_request_unknown); 993 SendMessage(3, request_unknown); 994 } 995 996 TEST_F(AvrcpDeviceTest, getInvalidItemAttributesTest) { 997 MockMediaInterface interface; 998 NiceMock<MockA2dpInterface> a2dp_interface; 999 1000 test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); 1001 1002 SongInfo info = {"test_id", 1003 {// The attribute map 1004 AttributeEntry(Attribute::TITLE, "Test Song"), 1005 AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), 1006 AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), 1007 AttributeEntry(Attribute::TRACK_NUMBER, "1"), 1008 AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), 1009 AttributeEntry(Attribute::GENRE, "Test Genre"), 1010 AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; 1011 std::vector<SongInfo> list = {info}; 1012 1013 EXPECT_CALL(interface, GetNowPlayingList(_)) 1014 .WillRepeatedly(InvokeCb<0>("test_id", list)); 1015 1016 auto compare_to_full = GetItemAttributesResponseBuilder::MakeBuilder( 1017 Status::UIDS_CHANGED, 0xFFFF); 1018 compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); 1019 compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); 1020 compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); 1021 compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); 1022 compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); 1023 compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); 1024 compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); 1025 EXPECT_CALL(response_cb, 1026 Call(1, true, matchPacket(std::move(compare_to_full)))) 1027 .Times(1); 1028 1029 auto request = TestBrowsePacket::Make( 1030 get_item_attributes_request_all_attributes_invalid); 1031 SendBrowseMessage(1, request); 1032 } 1033 1034 } // namespace avrcp 1035 } // namespace bluetooth 1036 1037 const stack_config_t* stack_config_get_interface(void) { 1038 return &bluetooth::avrcp::interface; 1039 } 1040