blob: bd86e8898ced084de802866bdf854b2e64f29a44 [file] [log] [blame]
/*
* Copyright 2021 HIMSA II K/S - www.himsa.com.
* Represented by EHIMA - www.ehima.com
*
* 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 "client_parser.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "le_audio_types.h"
namespace le_audio {
namespace client_parser {
namespace pacs {
TEST(LeAudioClientParserTest, testParsePacInvalidLength) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t invalid_num_records[] = {0x01};
ASSERT_FALSE(
ParsePac(pac_recs, sizeof(invalid_num_records), invalid_num_records));
const uint8_t no_caps_len[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x02,
0x03,
0x04,
0x05,
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(no_caps_len), no_caps_len));
const uint8_t no_metalen[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x02,
0x03,
0x04,
0x05,
// Codec Spec. Caps. Len
0x00,
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(no_metalen), no_metalen));
}
TEST(LeAudioClientParserTest, testParsePacEmpty) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {0x00};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
}
TEST(LeAudioClientParserTest, testParsePacEmptyCapsEmptyMeta) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x00,
// Metadata Length
0x00,
};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
ASSERT_EQ(pac_recs.size(), 1u);
ASSERT_EQ(pac_recs[0].codec_id.coding_format, 0x01u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_company_id, 0x0203u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_codec_id, 0x0405u);
}
TEST(LeAudioClientParserTest, testParsePacInvalidCapsLen) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t bad_capslem[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x05,
// Codec Spec. Caps.
0x02, // [0].length,
0x02, // [0].type,
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x00,
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(bad_capslem), bad_capslem));
std::vector<struct types::acs_ac_record> pac_recs2;
const uint8_t bad_capslen2[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x20,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x00,
};
ASSERT_FALSE(ParsePac(pac_recs2, sizeof(bad_capslen2), bad_capslen2));
}
TEST(LeAudioClientParserTest, testParsePacInvalidCapsLtvLen) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t bad_ltv_len[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x06, // [1].bad_length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x00,
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(bad_ltv_len), bad_ltv_len));
const uint8_t bad_ltv_len2[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x04, // [1].bad_length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x00,
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(bad_ltv_len2), bad_ltv_len2));
}
TEST(LeAudioClientParserTest, testParsePacNullLtv) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x0A,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
0x01, // [2].length <-- a capability without a value
0x04, // [2].type
0x00, // [3]length <-- this seems possible although useless
// Metadata Length
0x00,
};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
ASSERT_EQ(pac_recs.size(), 1u);
ASSERT_EQ(pac_recs[0].codec_id.coding_format, 0x01u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_company_id, 0x0203u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_codec_id, 0x0405u);
auto codec_spec_caps = pac_recs[0].codec_spec_caps.Values();
ASSERT_EQ(codec_spec_caps.size(), 3u);
ASSERT_EQ(codec_spec_caps.count(0x02u), 1u);
ASSERT_EQ(codec_spec_caps[0x02u].size(), 1u);
ASSERT_EQ(codec_spec_caps[0x02u][0], 0x03u);
ASSERT_EQ(codec_spec_caps.count(0x03u), 1u);
ASSERT_EQ(codec_spec_caps[0x03u].size(), 2u);
ASSERT_EQ(codec_spec_caps[0x03u][0], 0x04u);
ASSERT_EQ(codec_spec_caps[0x03u][1], 0x05u);
ASSERT_EQ(codec_spec_caps.count(0x04u), 1u);
ASSERT_EQ(codec_spec_caps[0x04u].size(), 0u);
}
TEST(LeAudioClientParserTest, testParsePacEmptyMeta) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x01,
// Codec_ID
0x01,
0x03,
0x02,
0x05,
0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x00,
};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
ASSERT_EQ(pac_recs.size(), 1u);
ASSERT_EQ(pac_recs[0].codec_id.coding_format, 0x01u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_company_id, 0x0203u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_codec_id, 0x0405u);
auto codec_spec_caps = pac_recs[0].codec_spec_caps.Values();
ASSERT_EQ(codec_spec_caps.size(), 2u);
ASSERT_EQ(codec_spec_caps.count(0x02u), 1u);
ASSERT_EQ(codec_spec_caps[0x02u].size(), 1u);
ASSERT_EQ(codec_spec_caps[0x02u][0], 0x03u);
ASSERT_EQ(codec_spec_caps.count(0x03u), 1u);
ASSERT_EQ(codec_spec_caps[0x03u].size(), 2u);
ASSERT_EQ(codec_spec_caps[0x03u][0], 0x04u);
ASSERT_EQ(codec_spec_caps[0x03u][1], 0x05u);
}
TEST(LeAudioClientParserTest, testParsePacInvalidMetaLength) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x01,
// Codec_ID
0x01, 0x03, 0x02, 0x05, 0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x05,
// Metadata
0x03, // [0].length
0x02, // [0].type
0x01, // [0].value[0]
0x00, // [0].value[1]
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(value), value));
}
TEST(LeAudioClientParserTest, testParsePacValidMeta) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x01,
// Codec_ID
0x01, 0x03, 0x02, 0x05, 0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x04,
// Metadata
0x03, // [0].length
0x02, // [0].type
0x01, // [0].value[0]
0x00, // [0].value[1]
};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
ASSERT_EQ(pac_recs.size(), 1u);
ASSERT_EQ(pac_recs[0].codec_id.coding_format, 0x01u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_company_id, 0x0203u);
ASSERT_EQ(pac_recs[0].codec_id.vendor_codec_id, 0x0405u);
auto codec_spec_caps = pac_recs[0].codec_spec_caps.Values();
ASSERT_EQ(codec_spec_caps.size(), 2u);
ASSERT_EQ(codec_spec_caps.count(0x02u), 1u);
ASSERT_EQ(codec_spec_caps[0x02u].size(), 1u);
ASSERT_EQ(codec_spec_caps[0x02u][0], 0x03u);
ASSERT_EQ(codec_spec_caps.count(0x03u), 1u);
ASSERT_EQ(codec_spec_caps[0x03u].size(), 2u);
ASSERT_EQ(codec_spec_caps[0x03u][0], 0x04u);
ASSERT_EQ(codec_spec_caps[0x03u][1], 0x05u);
ASSERT_EQ(pac_recs[0].metadata.size(), 4u);
ASSERT_EQ(pac_recs[0].metadata[0], 0x03u);
ASSERT_EQ(pac_recs[0].metadata[1], 0x02u);
ASSERT_EQ(pac_recs[0].metadata[2], 0x01u);
ASSERT_EQ(pac_recs[0].metadata[3], 0x00u);
}
TEST(LeAudioClientParserTest, testParsePacInvalidNumRecords) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x02,
// Codec_ID
0x01, 0x03, 0x02, 0x05, 0x04,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
0x03, // [1].length
0x03, // [1].type
0x04, // [1].value[0]
0x05, // [1].value[1]
// Metadata Length
0x04,
// Metadata
0x03, // [0].length
0x02, // [0].type
0x01, // [0].value[0]
0x00, // [0].value[1]
};
ASSERT_FALSE(ParsePac(pac_recs, sizeof(value), value));
}
TEST(LeAudioClientParserTest, testParsePacMultipleRecords) {
std::vector<struct types::acs_ac_record> pac_recs;
const uint8_t value[] = {
// Num records
0x03,
// Codec_ID
0x01, 0x03, 0x02, 0x05, 0x04,
// Codec Spec. Caps. Len
0x00,
// Metadata Length
0x00,
// Codec_ID
0x06, 0x08, 0x07, 0x0A, 0x09,
// Codec Spec. Caps. Len
0x03,
// Codec Spec. Caps.
0x02, // [0].length
0x02, // [0].type
0x03, // [0].value[0]
// Metadata Length
0x04,
// Metadata
0x03, // [0].length
0x02, // [0].type
0x01, // [0].value[0]
0x00, // [0].value[1],
// Codec_ID
0x11, 0x13, 0x12, 0x15, 0x14,
// Codec Spec. Caps. Len
0x07,
// Codec Spec. Caps.
0x02, // [0].length
0x12, // [0].type
0x13, // [0].value[0]
0x03, // [1].length
0x13, // [1].type
0x14, // [1].value[0]
0x15, // [1].value[1]
// Metadata Length
0x04,
// Metadata
0x03, // [0].length
0x12, // [0].type
0x11, // [0].value[0]
0x10, // [0].value[1]
};
ASSERT_TRUE(ParsePac(pac_recs, sizeof(value), value));
ASSERT_EQ(pac_recs.size(), 3u);
// Verify 1st record
auto& record0 = pac_recs[0];
ASSERT_EQ(record0.codec_id.coding_format, 0x01u);
ASSERT_EQ(record0.codec_id.vendor_company_id, 0x0203u);
ASSERT_EQ(record0.codec_id.vendor_codec_id, 0x0405u);
ASSERT_EQ(record0.codec_spec_caps.Size(), 0u);
ASSERT_EQ(record0.metadata.size(), 0u);
// Verify 2nd record
auto& record1 = pac_recs[1];
ASSERT_EQ(record1.codec_id.coding_format, 0x06u);
ASSERT_EQ(record1.codec_id.vendor_company_id, 0x0708u);
ASSERT_EQ(record1.codec_id.vendor_codec_id, 0x090Au);
auto codec_spec_caps1 = record1.codec_spec_caps.Values();
ASSERT_EQ(codec_spec_caps1.size(), 1u);
ASSERT_EQ(codec_spec_caps1.count(0x02u), 1u);
ASSERT_EQ(codec_spec_caps1[0x02u].size(), 1u);
ASSERT_EQ(codec_spec_caps1[0x02u][0], 0x03u);
ASSERT_EQ(record1.metadata.size(), 4u);
ASSERT_EQ(record1.metadata[0], 0x03u);
ASSERT_EQ(record1.metadata[1], 0x02u);
ASSERT_EQ(record1.metadata[2], 0x01u);
ASSERT_EQ(record1.metadata[3], 0x00u);
// Verify 3rd record
auto& record2 = pac_recs[2];
ASSERT_EQ(record2.codec_id.coding_format, 0x11u);
ASSERT_EQ(record2.codec_id.vendor_company_id, 0x1213u);
ASSERT_EQ(record2.codec_id.vendor_codec_id, 0x1415u);
auto codec_spec_caps2 = record2.codec_spec_caps.Values();
ASSERT_EQ(codec_spec_caps2.size(), 2u);
ASSERT_EQ(codec_spec_caps2.count(0x12u), 1u);
ASSERT_EQ(codec_spec_caps2[0x12u].size(), 1u);
ASSERT_EQ(codec_spec_caps2[0x12u][0], 0x13u);
ASSERT_EQ(codec_spec_caps2.count(0x13u), 1u);
ASSERT_EQ(codec_spec_caps2[0x13u].size(), 2u);
ASSERT_EQ(codec_spec_caps2[0x13u][0], 0x14u);
ASSERT_EQ(codec_spec_caps2[0x13u][1], 0x15u);
ASSERT_EQ(record2.metadata.size(), 4u);
ASSERT_EQ(record2.metadata[0], 0x03u);
ASSERT_EQ(record2.metadata[1], 0x12u);
ASSERT_EQ(record2.metadata[2], 0x11u);
ASSERT_EQ(record2.metadata[3], 0x10u);
}
TEST(LeAudioClientParserTest, testParseAudioLocationsInvalidLength) {
types::AudioLocations locations =
codec_spec_conf::kLeAudioLocationMonoUnspecified;
const uint8_t value1[] = {
0x01,
0x02,
0x03,
};
ParseAudioLocations(locations, sizeof(value1), value1);
ASSERT_EQ(locations, 0u);
const uint8_t value2[] = {0x01, 0x02, 0x03, 0x04, 0x05};
ParseAudioLocations(locations, sizeof(value2), value2);
ASSERT_EQ(locations, 0u);
}
TEST(LeAudioClientParserTest, testParseAudioLocations) {
types::AudioLocations locations =
codec_spec_conf::kLeAudioLocationMonoUnspecified;
const uint8_t value1[] = {0x01, 0x02, 0x03, 0x04};
ParseAudioLocations(locations, sizeof(value1), value1);
ASSERT_EQ(locations, 0x04030201u);
}
TEST(LeAudioClientParserTest, testParseAvailableAudioContextsInvalidLength) {
acs_available_audio_contexts avail_contexts;
const uint8_t value1[] = {
// Sink available contexts
0x01, 0x02,
// Missing Source available contexts
};
ParseAvailableAudioContexts(avail_contexts, sizeof(value1), value1);
ASSERT_EQ(avail_contexts.snk_avail_cont, 0u);
ASSERT_EQ(avail_contexts.src_avail_cont, 0u);
}
TEST(LeAudioClientParserTest, testParseAvailableAudioContexts) {
acs_available_audio_contexts avail_contexts;
const uint8_t value1[] = {
// Sink available contexts
0x01,
0x02,
// Source available contexts
0x03,
0x04,
};
ParseAvailableAudioContexts(avail_contexts, sizeof(value1), value1);
ASSERT_EQ(avail_contexts.snk_avail_cont, 0x0201u);
ASSERT_EQ(avail_contexts.src_avail_cont, 0x0403u);
}
TEST(LeAudioClientParserTest, testParseSupportedAudioContextsInvalidLength) {
acs_supported_audio_contexts supp_contexts;
const uint8_t value1[] = {
// Sink supported contexts
0x01, 0x02,
// Missing Source supported contexts
};
ParseSupportedAudioContexts(supp_contexts, sizeof(value1), value1);
ASSERT_EQ(supp_contexts.snk_supp_cont, 0u);
ASSERT_EQ(supp_contexts.src_supp_cont, 0u);
}
TEST(LeAudioClientParserTest, testParseSupportedAudioContexts) {
acs_supported_audio_contexts supp_contexts;
const uint8_t value1[] = {
// Sink supported contexts
0x01,
0x02,
// Source supported contexts
0x03,
0x04,
};
ParseSupportedAudioContexts(supp_contexts, sizeof(value1), value1);
ASSERT_EQ(supp_contexts.snk_supp_cont, 0x0201u);
ASSERT_EQ(supp_contexts.src_supp_cont, 0x0403u);
}
} // namespace pacs
namespace ascs {
TEST(LeAudioClientParserTest, testParseAseStatusHeaderInvalidLength) {
ase_rsp_hdr arh;
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State is missing here
};
ASSERT_FALSE(ParseAseStatusHeader(arh, sizeof(value1), value1));
}
TEST(LeAudioClientParserTest, testParseAseStatusHeader) {
ase_rsp_hdr arh;
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State
0x00, // 'Idle' state
// No additional ASE Params for the 'Idle' state
};
ASSERT_TRUE(ParseAseStatusHeader(arh, sizeof(value1), value1));
ASSERT_EQ(arh.id, 0x01u);
ASSERT_EQ(arh.state, 0x00u);
const uint8_t value2[] = {
// Ase ID
0x02,
// ASE State
0x04, // 'Streaming' state
// Additional ASE Params for the 'Streaming' state
// Metadata Len
0x03,
// Metadata
0x03, // [0].length
0x02, // [0].type
0x01, // [0].value[0]
0x00, // [0].value[1]
};
ASSERT_TRUE(ParseAseStatusHeader(arh, sizeof(value2), value2));
ASSERT_EQ(arh.id, 0x02u);
ASSERT_EQ(arh.state, 0x04u);
// Currently additional state parameters are not handled
}
TEST(LeAudioClientParserTest,
testParseAseStatusCodecConfiguredStateParamsInvalidLength) {
ase_codec_configured_state_params codec_configured_state_params;
const uint8_t value1[] = {
// Ase ID
0x02,
// ASE State
0x01, // 'Codec Configured' state
// Framing
0x01, // Unframed
// Peferred PHY
0x02, // 2M PHY
// Preferred retransimssion Num.
0x04,
// Max transport Latency
0x05, 0x00,
// Pressentation delay min.
0x00, 0x01, 0x02, 0x03,
// Pressentation delay max.
0x00, 0x01, 0x02, 0x03,
// Preferred presentation delay min.
0x01, 0x02, 0x03,
// Preferred presentation delay max.
0x01, 0x02, 0x03,
// Codec ID
0x01, 0x02, 0x03, 0x04, 0x05,
// Missing Codec spec. conf. length
};
ASSERT_FALSE(ParseAseStatusCodecConfiguredStateParams(
codec_configured_state_params, sizeof(value1) - 2, value1 + 2));
}
TEST(LeAudioClientParserTest, testParseAseStatusCodecConfiguredStateParams) {
ase_codec_configured_state_params codec_configured_state_params;
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State
0x01, // 'Codec Configured' state
// Framing
0x01, // Unframed
// Peferred PHY
0x02, // 2M PHY
// Preferred retransimssion Num.
0x04,
// Max transport Latency
0x05,
0x00,
// Pressentation delay min.
0x00,
0x01,
0x02,
// Pressentation delay max.
0x10,
0x11,
0x12,
// Preferred presentation delay min.
0x01,
0x02,
0x03,
// Preferred presentation delay max.
0x09,
0x10,
0x11,
// Codec ID
0x01,
0x02,
0x03,
0x04,
0x05,
// Codec spec. conf. length
0x00,
};
// State additional parameters are right after the ASE ID and state bytes
ASSERT_TRUE(ParseAseStatusCodecConfiguredStateParams(
codec_configured_state_params, sizeof(value1) - 2, value1 + 2));
ASSERT_EQ(codec_configured_state_params.framing, 0x01u);
ASSERT_EQ(codec_configured_state_params.preferred_phy, 0x02u);
ASSERT_EQ(codec_configured_state_params.preferred_retrans_nb, 0x04u);
ASSERT_EQ(codec_configured_state_params.max_transport_latency, 0x0005u);
ASSERT_EQ(codec_configured_state_params.pres_delay_min, 0x020100u);
ASSERT_EQ(codec_configured_state_params.pres_delay_max, 0x121110u);
ASSERT_EQ(codec_configured_state_params.preferred_pres_delay_min, 0x030201u);
ASSERT_EQ(codec_configured_state_params.preferred_pres_delay_max, 0x111009u);
ASSERT_EQ(codec_configured_state_params.codec_id.coding_format, 0x01u);
ASSERT_EQ(codec_configured_state_params.codec_id.vendor_company_id, 0x0302u);
ASSERT_EQ(codec_configured_state_params.codec_id.vendor_codec_id, 0x0504u);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf.size(), 0u);
const uint8_t value2[] = {
// Ase ID
0x02,
// ASE State
0x01, // 'Codec Configured' state
// Framing
0x01, // Unframed
// Peferred PHY
0x02, // 2M PHY
// Preferred retransimssion Num.
0x04,
// Max transport Latency
0x05,
0x00,
// Pressentation delay min.
0x00,
0x01,
0x02,
// Pressentation delay max.
0x10,
0x11,
0x12,
// Preferred presentation delay min.
0x01,
0x02,
0x03,
// Preferred presentation delay max.
0x09,
0x10,
0x11,
// Codec ID
0x01,
0x02,
0x03,
0x04,
0x05,
// Codec spec. conf. length
0x05,
// Codec spec. conf.
0x0A,
0x0B,
0x0C,
0x0D,
0x0E,
};
// State additional parameters are right after the ASE ID and state bytes
ASSERT_TRUE(ParseAseStatusCodecConfiguredStateParams(
codec_configured_state_params, sizeof(value2) - 2, value2 + 2));
ASSERT_EQ(codec_configured_state_params.framing, 0x01u);
ASSERT_EQ(codec_configured_state_params.preferred_phy, 0x02u);
ASSERT_EQ(codec_configured_state_params.preferred_retrans_nb, 0x04u);
ASSERT_EQ(codec_configured_state_params.max_transport_latency, 0x0005u);
ASSERT_EQ(codec_configured_state_params.pres_delay_min, 0x020100u);
ASSERT_EQ(codec_configured_state_params.pres_delay_max, 0x121110u);
ASSERT_EQ(codec_configured_state_params.preferred_pres_delay_min, 0x030201u);
ASSERT_EQ(codec_configured_state_params.preferred_pres_delay_max, 0x111009u);
ASSERT_EQ(codec_configured_state_params.codec_id.coding_format, 0x01u);
ASSERT_EQ(codec_configured_state_params.codec_id.vendor_company_id, 0x0302u);
ASSERT_EQ(codec_configured_state_params.codec_id.vendor_codec_id, 0x0504u);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf.size(), 5u);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf[0], 0x0Au);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf[1], 0x0Bu);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf[2], 0x0Cu);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf[3], 0x0Du);
ASSERT_EQ(codec_configured_state_params.codec_spec_conf[4], 0x0Eu);
}
TEST(LeAudioClientParserTest,
testParseAseStatusQosConfiguredStateParamsInvalidLength) {
struct ase_qos_configured_state_params rsp {
.cig_id = 0, .cis_id = 0
};
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State
0x02, // 'QoS Configured' state
0x03, // CIG_ID
0x04, // CIS_ID
};
ParseAseStatusQosConfiguredStateParams(rsp, sizeof(value1) - 2, value1 + 2);
ASSERT_EQ(rsp.cig_id, 0);
ASSERT_EQ(rsp.cis_id, 0);
const uint8_t value2[] = {
// Ase ID
0x01,
// ASE State
0x02, // 'QoS Configured' state
// CIG_ID
0x03,
// CIS_ID
0x04,
// SDU Interval
0x05, 0x06, 0x07,
// Framing
0x01,
// PHY
0x02,
// Max SDU
0x08, 0x09,
// Retransmission Num.
0x0A,
// Max Transport Latency
0x0B, 0x0C,
// Presentation Delay
0x0D, 0x0E,
// Missing Byte
};
ParseAseStatusQosConfiguredStateParams(rsp, sizeof(value2) - 2, value2 + 2);
ASSERT_EQ(rsp.cig_id, 0);
ASSERT_EQ(rsp.cis_id, 0);
}
TEST(LeAudioClientParserTest, testParseAseStatusQosConfiguredStateParams) {
struct ase_qos_configured_state_params rsp;
const uint8_t value[] = {
// Ase ID
0x01,
// ASE State - 'QoS Configured'
0x02,
// CIG_ID
0x03,
// CIS_ID
0x04,
// SDU Interval
0x05,
0x06,
0x07,
// Framing
0x01,
// PHY
0x02,
// Max SDU
0x18,
0x19,
// Retransmission Num.
0x1A,
// Max Transport Latency
0x1B,
0x1C,
// Presentation Delay
0x1D,
0x1E,
0x1F,
};
ParseAseStatusQosConfiguredStateParams(rsp, sizeof(value) - 2, value + 2);
ASSERT_EQ(rsp.cig_id, 0x03u);
ASSERT_EQ(rsp.cis_id, 0x04u);
ASSERT_EQ(rsp.sdu_interval, 0x070605u);
ASSERT_EQ(rsp.framing, 0x01u);
ASSERT_EQ(rsp.phy, 0x02u);
ASSERT_EQ(rsp.max_sdu, 0x1918u);
ASSERT_EQ(rsp.retrans_nb, 0x1Au);
ASSERT_EQ(rsp.max_transport_latency, 0x1C1Bu);
ASSERT_EQ(rsp.pres_delay, 0x1F1E1Du);
}
TEST(LeAudioClientParserTest,
testParseAseStatusTransientStateParamsInvalidLength) {
ase_transient_state_params params;
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State
0x03, // 'Enabling' state
// missing Metadata length
// missing Metadata
};
ParseAseStatusTransientStateParams(params, sizeof(value1) - 2, value1 + 2);
}
TEST(LeAudioClientParserTest, testParseAseStatusTransientStateParams) {
ase_transient_state_params params;
const uint8_t value1[] = {
// Ase ID
0x01,
// ASE State
0x03, // 'Enabling' state
// Metadata length
0x00,
};
ParseAseStatusTransientStateParams(params, sizeof(value1) - 2, value1 + 2);
ASSERT_EQ(params.metadata.size(), 0u);
const uint8_t value2[] = {
// Ase ID
0x01,
// ASE State
0x03, // 'Enabling' state
// CIG_ID
0x03,
// CIS_ID
0x04,
// Metadata length
0x03,
// Metadata
0x02, // [0].length
0x01, // [0].type
0x00, // [0].value[0]
};
ParseAseStatusTransientStateParams(params, sizeof(value2) - 2, value2 + 2);
ASSERT_EQ(params.metadata.size(), 3u);
ASSERT_EQ(params.metadata[0], 0x02u);
ASSERT_EQ(params.metadata[1], 0x01u);
ASSERT_EQ(params.metadata[2], 0x00u);
}
TEST(LeAudioClientParserTest, testParseAseCtpNotificationInvalidLength) {
ctp_ntf ntf;
const uint8_t value1[] = {
// Opcode
0x01,
// Number of ASEs
0x02,
// ASE ID
0x01,
// Response Code
0x01,
// Reason
0x01,
// ASE ID
0x02,
// Response Code
0x02,
// Missing Reason
};
ParseAseCtpNotification(ntf, sizeof(value1), value1);
// In case of invalid payload at least we get the opcode
ASSERT_EQ(ntf.op, 0x01u);
ASSERT_EQ(ntf.entries.size(), 0u);
const uint8_t value2[] = {
// Opcode
0x01,
// Missing Number of ASEs
// Missing ASE ID
// Missing Response Code
// Missing Reason
// Missing ASE ID
// Missing Response Code
// Missing Reason
};
ntf.entries.clear();
ParseAseCtpNotification(ntf, sizeof(value2), value2);
// In case of invalid payload at least we get the opcode
ASSERT_EQ(ntf.op, 0x01u);
ASSERT_EQ(ntf.entries.size(), 0u);
const uint8_t value3[] = {
// Opcode
0x01,
// Number of ASEs
0x03,
// ASE ID
0x01,
// Response Code
0x01,
// Reason
0x01,
// ASE ID
0x02,
// Response Code
0x02,
// Reason
0x03,
// Missing the entire ASE entry
};
ntf.entries.clear();
ParseAseCtpNotification(ntf, sizeof(value3), value3);
// In case of invalid payload at least we get the opcode
ASSERT_EQ(ntf.op, 0x01u);
ASSERT_EQ(ntf.entries.size(), 0u);
}
TEST(LeAudioClientParserTest, testParseAseCtpNotification) {
ctp_ntf ntf;
const uint8_t value1[] = {
// Opcode
0x01,
// Number of ASEs
0x02,
// ASE ID
0x01,
// Response Code
0x01,
// Reason
0x01,
// ASE ID
0x03,
// Response Code
0x02,
// Reason
0x03,
};
ParseAseCtpNotification(ntf, sizeof(value1), value1);
ASSERT_EQ(ntf.op, 0x01u);
ASSERT_EQ(ntf.entries.size(), 2u);
ASSERT_EQ(ntf.entries[0].ase_id, 0x01u);
ASSERT_EQ(ntf.entries[0].response_code, 0x01u);
ASSERT_EQ(ntf.entries[0].reason, 0x01);
ASSERT_EQ(ntf.entries[1].ase_id, 0x03u);
ASSERT_EQ(ntf.entries[1].response_code, 0x02u);
ASSERT_EQ(ntf.entries[1].reason, 0x03);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigEmpty) {
std::vector<struct ctp_codec_conf> confs;
std::vector<uint8_t> value;
PrepareAseCtpCodecConfig(confs, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigSingle) {
std::vector<struct ctp_codec_conf> confs;
std::vector<uint8_t> value;
types::LeAudioCodecId codec_id{.coding_format = 0x06,
.vendor_company_id = 0x0203,
.vendor_codec_id = 0x0405};
types::LeAudioLc3Config codec_conf{.sampling_frequency = 0x10,
.frame_duration = 0x03,
.audio_channel_allocation = 0x04050607,
.octets_per_codec_frame = 0x0203};
confs.push_back(ctp_codec_conf{
.ase_id = 0x05,
.target_latency = 0x03,
.target_phy = 0x02,
.codec_id = codec_id,
.codec_config = codec_conf,
});
PrepareAseCtpCodecConfig(confs, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x01); // Config Codec Opcode
ASSERT_EQ(value[i++], 0x01); // Number of ASEs
ASSERT_EQ(value[i++], 0x05); // ASE[0] ASE ID
ASSERT_EQ(value[i++], 0x03); // ASE[0] Target Latency
ASSERT_EQ(value[i++], 0x02); // ASE[0] Target Phy
ASSERT_EQ(value[i++], 0x06); // ASE[0].CodecID Coding Format
ASSERT_EQ(value[i++], 0x03); // ASE[0].CodecID Company ID LSB
ASSERT_EQ(value[i++], 0x02); // ASE[0].CodecID Company ID MSB
ASSERT_EQ(value[i++], 0x05); // ASE[0].CodecID Codec ID LSB
ASSERT_EQ(value[i++], 0x04); // ASE[0].CodecID Codec ID MSB
// ASE[0].Codec Spec. Conf. Length - LC3 specific
ASSERT_EQ(value[i++], 8 + 8); // * 4*2 bytes for 4 LTV types and lengths + 8
// bytes for the values
ASSERT_EQ(value[i++], 0x02); // Sampling Freq. Length
ASSERT_EQ(value[i++], 0x01); // Sampling Freq. Type
ASSERT_EQ(value[i++], 0x10); // Sampling Freq. Value
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Length
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Type
ASSERT_EQ(value[i++], 0x03); // Frame Duration. Value
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Length
ASSERT_EQ(value[i++], 0x03); // Audio Channel Allocations Type
ASSERT_EQ(value[i++], 0x07); // Audio Channel Allocations Value[0]
ASSERT_EQ(value[i++], 0x06); // Audio Channel Allocations Value[1]
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Value[2]
ASSERT_EQ(value[i++], 0x04); // Audio Channel Allocations Value[3]
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Length
ASSERT_EQ(value[i++], 0x04); // Octets Per Frame Type
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Value[0]
ASSERT_EQ(value[i++], 0x02); // Octets Per Frame Value[1]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpCodecConfigMultiple) {
std::vector<struct ctp_codec_conf> confs;
std::vector<uint8_t> value;
types::LeAudioCodecId codec_id{.coding_format = 0x06,
.vendor_company_id = 0x0203,
.vendor_codec_id = 0x0405};
types::LeAudioLc3Config codec_conf{.sampling_frequency = 0x10,
.frame_duration = 0x03,
.audio_channel_allocation = 0x04050607,
.octets_per_codec_frame = 0x0203};
confs.push_back(ctp_codec_conf{
.ase_id = 0x05,
.target_latency = 0x03,
.target_phy = 0x02,
.codec_id = codec_id,
.codec_config = codec_conf,
});
PrepareAseCtpCodecConfig(confs, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x01); // Config Codec Opcode
ASSERT_EQ(value[i++], 0x01); // Number of ASEs
ASSERT_EQ(value[i++], 0x05); // ASE[0] ASE ID
ASSERT_EQ(value[i++], 0x03); // ASE[0] Target Latency
ASSERT_EQ(value[i++], 0x02); // ASE[0] Target Phy
ASSERT_EQ(value[i++], 0x06); // ASE[0].CodecID Coding Format
ASSERT_EQ(value[i++], 0x03); // ASE[0].CodecID Company ID LSB
ASSERT_EQ(value[i++], 0x02); // ASE[0].CodecID Company ID MSB
ASSERT_EQ(value[i++], 0x05); // ASE[0].CodecID Codec ID LSB
ASSERT_EQ(value[i++], 0x04); // ASE[0].CodecID Codec ID MSB
// ASE[0].Codec Spec. Conf. Length - LC3 specific
ASSERT_EQ(value[i++], 8 + 8); // * 4*2 bytes for 4 LTV types and lengths + 8
// bytes for the values
ASSERT_EQ(value[i++], 0x02); // Sampling Freq. Length
ASSERT_EQ(value[i++], 0x01); // Sampling Freq. Type
ASSERT_EQ(value[i++], 0x10); // Sampling Freq. Value
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Length
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Type
ASSERT_EQ(value[i++], 0x03); // Frame Duration. Value
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Length
ASSERT_EQ(value[i++], 0x03); // Audio Channel Allocations Type
ASSERT_EQ(value[i++], 0x07); // Audio Channel Allocations Value[0]
ASSERT_EQ(value[i++], 0x06); // Audio Channel Allocations Value[1]
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Value[2]
ASSERT_EQ(value[i++], 0x04); // Audio Channel Allocations Value[3]
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Length
ASSERT_EQ(value[i++], 0x04); // Octets Per Frame Type
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Value[0]
ASSERT_EQ(value[i++], 0x02); // Octets Per Frame Value[1]
ASSERT_EQ(value.size(), i);
types::LeAudioCodecId codec_id2{.coding_format = 0x16,
.vendor_company_id = 0x1213,
.vendor_codec_id = 0x1415};
types::LeAudioLc3Config codec_conf2{.sampling_frequency = 0x11,
.frame_duration = 0x13,
.audio_channel_allocation = 0x14151617,
.octets_per_codec_frame = 0x1213};
confs.push_back(ctp_codec_conf{
.ase_id = 0x15,
.target_latency = 0x13,
.target_phy = 0x01,
.codec_id = codec_id2,
.codec_config = codec_conf2,
});
PrepareAseCtpCodecConfig(confs, value);
i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x01); // Config Codec Opcode
ASSERT_EQ(value[i++], 0x02); // Number of ASEs
ASSERT_EQ(value[i++], 0x05); // ASE[0] ASE ID
ASSERT_EQ(value[i++], 0x03); // ASE[0] Target Latency
ASSERT_EQ(value[i++], 0x02); // ASE[0] Target Phy
ASSERT_EQ(value[i++], 0x06); // ASE[0].CodecID Coding Format
ASSERT_EQ(value[i++], 0x03); // ASE[0].CodecID Company ID LSB
ASSERT_EQ(value[i++], 0x02); // ASE[0].CodecID Company ID MSB
ASSERT_EQ(value[i++], 0x05); // ASE[0].CodecID Codec ID LSB
ASSERT_EQ(value[i++], 0x04); // ASE[0].CodecID Codec ID MSB
// ASE[0].Codec Spec. Conf. Length - LC3 specific
ASSERT_EQ(value[i++], 8 + 8); // * 4*2 bytes for 4 LTV types and lengths + 8
// bytes for the values
ASSERT_EQ(value[i++], 0x02); // Sampling Freq. Length
ASSERT_EQ(value[i++], 0x01); // Sampling Freq. Type
ASSERT_EQ(value[i++], 0x10); // Sampling Freq. Value
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Length
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Type
ASSERT_EQ(value[i++], 0x03); // Frame Duration. Value
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Length
ASSERT_EQ(value[i++], 0x03); // Audio Channel Allocations Type
ASSERT_EQ(value[i++], 0x07); // Audio Channel Allocations Value[0]
ASSERT_EQ(value[i++], 0x06); // Audio Channel Allocations Value[1]
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Value[2]
ASSERT_EQ(value[i++], 0x04); // Audio Channel Allocations Value[3]
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Length
ASSERT_EQ(value[i++], 0x04); // Octets Per Frame Type
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Value[0]
ASSERT_EQ(value[i++], 0x02); // Octets Per Frame Value[1]
ASSERT_EQ(value[i++], 0x15); // ASE[1] ASE ID
ASSERT_EQ(value[i++], 0x13); // ASE[1] Target Latency
ASSERT_EQ(value[i++], 0x01); // ASE[1] Target Phy
ASSERT_EQ(value[i++], 0x16); // ASE[1].CodecID Coding Format
ASSERT_EQ(value[i++], 0x13); // ASE[1].CodecID Company ID LSB
ASSERT_EQ(value[i++], 0x12); // ASE[1].CodecID Company ID MSB
ASSERT_EQ(value[i++], 0x15); // ASE[1].CodecID Codec ID LSB
ASSERT_EQ(value[i++], 0x14); // ASE[1].CodecID Codec ID MSB
// ASE[1].Codec Spec. Conf. Length - LC3 specific
ASSERT_EQ(value[i++], 8 + 8); // * 4*2 bytes for 4 LTV types and lengths + 8
// bytes for the values
ASSERT_EQ(value[i++], 0x02); // Sampling Freq. Length
ASSERT_EQ(value[i++], 0x01); // Sampling Freq. Type
ASSERT_EQ(value[i++], 0x11); // Sampling Freq. Value
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Length
ASSERT_EQ(value[i++], 0x02); // Frame Duration. Type
ASSERT_EQ(value[i++], 0x13); // Frame Duration. Value
ASSERT_EQ(value[i++], 0x05); // Audio Channel Allocations Length
ASSERT_EQ(value[i++], 0x03); // Audio Channel Allocations Type
ASSERT_EQ(value[i++], 0x17); // Audio Channel Allocations Value[0]
ASSERT_EQ(value[i++], 0x16); // Audio Channel Allocations Value[1]
ASSERT_EQ(value[i++], 0x15); // Audio Channel Allocations Value[2]
ASSERT_EQ(value[i++], 0x14); // Audio Channel Allocations Value[3]
ASSERT_EQ(value[i++], 0x03); // Octets Per Frame Length
ASSERT_EQ(value[i++], 0x04); // Octets Per Frame Type
ASSERT_EQ(value[i++], 0x13); // Octets Per Frame Value[0]
ASSERT_EQ(value[i++], 0x12); // Octets Per Frame Value[1]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpConfigQosEmpty) {
std::vector<struct ctp_qos_conf> confs;
std::vector<uint8_t> value;
PrepareAseCtpConfigQos(confs, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpConfigQosSingle) {
std::vector<struct ctp_qos_conf> confs;
std::vector<uint8_t> value;
const ctp_qos_conf conf{.ase_id = 0x01,
.cig = 0x11,
.cis = 0x12,
.sdu_interval = 0x00131415,
.framing = 0x01,
.phy = 0x01,
.max_sdu = 0x0203,
.retrans_nb = 0x04,
.max_transport_latency = 0x0302,
.pres_delay = 0x00121314};
confs.push_back(conf);
PrepareAseCtpConfigQos(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x02u); // Config QOS Opcode
ASSERT_EQ(value[i++], 0x01u); // Number of ASE
ASSERT_EQ(value[i++], 0x01u); // ASE ID
ASSERT_EQ(value[i++], 0x11u); // CIG ID
ASSERT_EQ(value[i++], 0x12u); // CIS ID
ASSERT_EQ(value[i++], 0x15u); // SDU Interval [0]
ASSERT_EQ(value[i++], 0x14u); // SDU Interval [1]
ASSERT_EQ(value[i++], 0x13u); // SDU Interval [2]
ASSERT_EQ(value[i++], 0x01u); // Framing
ASSERT_EQ(value[i++], 0x01u); // Phy
ASSERT_EQ(value[i++], 0x03u); // Max SDU LSB
ASSERT_EQ(value[i++], 0x02u); // Max SDU MSB
ASSERT_EQ(value[i++], 0x04u); // Retransmission
ASSERT_EQ(value[i++], 0x02u); // Max. Trans. Latency LSB
ASSERT_EQ(value[i++], 0x03u); // Max. Trans. Latency MSB
ASSERT_EQ(value[i++], 0x14u); // Pres. Delay[0]
ASSERT_EQ(value[i++], 0x13u); // Pres. Delay[1]
ASSERT_EQ(value[i++], 0x12u); // Pres. Delay[2]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpConfigQosMultiple) {
std::vector<struct ctp_qos_conf> confs;
std::vector<uint8_t> value;
const ctp_qos_conf conf{.ase_id = 0x01,
.cig = 0x11,
.cis = 0x12,
.sdu_interval = 0x131415,
.framing = 0x01,
.phy = 0x01,
.max_sdu = 0x0203,
.retrans_nb = 0x04,
.max_transport_latency = 0x0302,
.pres_delay = 0x121314};
confs.push_back(conf);
const ctp_qos_conf conf2{.ase_id = 0x11,
.cig = 0x21,
.cis = 0x22,
.sdu_interval = 0x232425,
.framing = 0x02,
.phy = 0x02,
.max_sdu = 0x2223,
.retrans_nb = 0x24,
.max_transport_latency = 0x2322,
.pres_delay = 0x222324};
confs.push_back(conf2);
PrepareAseCtpConfigQos(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x02u); // Config QOS Opcode
ASSERT_EQ(value[i++], 0x02u); // Number of ASE
// 1st ASE Config
ASSERT_EQ(value[i++], 0x01u); // ASE ID
ASSERT_EQ(value[i++], 0x11u); // CIG ID
ASSERT_EQ(value[i++], 0x12u); // CIS ID
ASSERT_EQ(value[i++], 0x15u); // SDU Interval [0]
ASSERT_EQ(value[i++], 0x14u); // SDU Interval [1]
ASSERT_EQ(value[i++], 0x13u); // SDU Interval [2]
ASSERT_EQ(value[i++], 0x01u); // Framing
ASSERT_EQ(value[i++], 0x01u); // Phy
ASSERT_EQ(value[i++], 0x03u); // Max SDU LSB
ASSERT_EQ(value[i++], 0x02u); // Max SDU MSB
ASSERT_EQ(value[i++], 0x04u); // Retransmission
ASSERT_EQ(value[i++], 0x02u); // Max. Trans. Latency LSB
ASSERT_EQ(value[i++], 0x03u); // Max. Trans. Latency MSB
ASSERT_EQ(value[i++], 0x14u); // Pres. Delay[0]
ASSERT_EQ(value[i++], 0x13u); // Pres. Delay[1]
ASSERT_EQ(value[i++], 0x12u); // Pres. Delay[2]
// 2nd ASE Config
ASSERT_EQ(value[i++], 0x11u); // ASE ID
ASSERT_EQ(value[i++], 0x21u); // CIG ID
ASSERT_EQ(value[i++], 0x22u); // CIS ID
ASSERT_EQ(value[i++], 0x25u); // SDU Interval [0]
ASSERT_EQ(value[i++], 0x24u); // SDU Interval [1]
ASSERT_EQ(value[i++], 0x23u); // SDU Interval [2]
ASSERT_EQ(value[i++], 0x02u); // Framing
ASSERT_EQ(value[i++], 0x02u); // Phy
ASSERT_EQ(value[i++], 0x23u); // Max SDU LSB
ASSERT_EQ(value[i++], 0x22u); // Max SDU MSB
ASSERT_EQ(value[i++], 0x24u); // Retransmission
ASSERT_EQ(value[i++], 0x22u); // Max. Trans. Latency LSB
ASSERT_EQ(value[i++], 0x23u); // Max. Trans. Latency MSB
ASSERT_EQ(value[i++], 0x24u); // Pres. Delay[0]
ASSERT_EQ(value[i++], 0x23u); // Pres. Delay[1]
ASSERT_EQ(value[i++], 0x22u); // Pres. Delay[2]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpEnableEmpty) {
std::vector<struct ctp_enable> confs;
std::vector<uint8_t> value;
PrepareAseCtpEnable(confs, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpEnableSingle) {
std::vector<struct ctp_enable> confs;
std::vector<uint8_t> value;
ctp_enable conf{.ase_id = 0x11, .metadata = {0x02, 0x22, 0x21}};
confs.push_back(conf);
PrepareAseCtpEnable(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x03u); // Enable Opcode
ASSERT_EQ(value[i++], 0x01u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x03u); // Metadata Len
ASSERT_EQ(value[i++], 0x02u); // Metadata[0]
ASSERT_EQ(value[i++], 0x22u); // Metadata[1]
ASSERT_EQ(value[i++], 0x21u); // Metadata[2]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpEnableMultiple) {
std::vector<struct ctp_enable> confs;
std::vector<uint8_t> value;
ctp_enable conf{.ase_id = 0x11, .metadata = {0x02, 0x22, 0x21}};
confs.push_back(conf);
ctp_enable conf2{.ase_id = 0x21, .metadata = {0x03, 0x35, 0x36, 0x37}};
confs.push_back(conf2);
PrepareAseCtpEnable(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x03u); // Enable Opcode
ASSERT_EQ(value[i++], 0x02u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x03u); // ASE[0] Metadata Len
ASSERT_EQ(value[i++], 0x02u); // ASE[0] Metadata[0]
ASSERT_EQ(value[i++], 0x22u); // ASE[0] Metadata[1]
ASSERT_EQ(value[i++], 0x21u); // ASE[0] Metadata[2]
ASSERT_EQ(value[i++], 0x21u); // ASE[1] ID
ASSERT_EQ(value[i++], 0x04u); // ASE[1] Metadata Len
ASSERT_EQ(value[i++], 0x03u); // ASE[1] Metadata[0]
ASSERT_EQ(value[i++], 0x35u); // ASE[1] Metadata[1]
ASSERT_EQ(value[i++], 0x36u); // ASE[1] Metadata[2]
ASSERT_EQ(value[i++], 0x37u); // ASE[1] Metadata[3]
ASSERT_EQ(value.size(), i);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpAudioReceiverStartReadyEmpty) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
PrepareAseCtpAudioReceiverStartReady(ase_ids, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpAudioReceiverStartReadySingle) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
PrepareAseCtpAudioReceiverStartReady(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x04u); // Receiver Start Ready Opcode
ASSERT_EQ(value[i++], 1u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest,
testPrepareAseCtpAudioReceiverStartReadyMultiple) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
ase_ids.push_back(0x36);
PrepareAseCtpAudioReceiverStartReady(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x04u); // Receiver Start Ready Opcode
ASSERT_EQ(value[i++], 2u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x36u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpDisableEmpty) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
PrepareAseCtpDisable(ase_ids, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpDisableSingle) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
PrepareAseCtpDisable(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x05u); // Disable Opcode
ASSERT_EQ(value[i++], 1u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpDisableMultiple) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
ase_ids.push_back(0x36);
PrepareAseCtpDisable(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x05u); // Disable Opcode
ASSERT_EQ(value[i++], 2u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x36u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpAudioReceiverStopReadyEmpty) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
PrepareAseCtpAudioReceiverStopReady(ase_ids, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpAudioReceiverStopReadySingle) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
PrepareAseCtpAudioReceiverStopReady(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x06u); // Reveicer Stop Ready Opcode
ASSERT_EQ(value[i++], 1u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpAudioReceiverStopReadyMultiple) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
ase_ids.push_back(0x36);
PrepareAseCtpAudioReceiverStopReady(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x06u); // Reveicer Stop Ready Opcode
ASSERT_EQ(value[i++], 2u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x36u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpUpdateMetadataEmpty) {
std::vector<struct ctp_update_metadata> confs;
std::vector<uint8_t> value;
PrepareAseCtpUpdateMetadata(confs, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpUpdateMetadataSingle) {
std::vector<struct ctp_update_metadata> confs;
std::vector<uint8_t> value;
ctp_update_metadata conf{.ase_id = 0x11, .metadata = {0x02, 0x22, 0x21}};
confs.push_back(conf);
PrepareAseCtpUpdateMetadata(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x07u); // Update Metadata Opcode
ASSERT_EQ(value[i++], 0x01u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x03u); // Metadata Len
ASSERT_EQ(value[i++], 0x02u); // Metadata[0]
ASSERT_EQ(value[i++], 0x22u); // Metadata[1]
ASSERT_EQ(value[i++], 0x21u); // Metadata[2]
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpUpdateMetadataMultiple) {
std::vector<struct ctp_update_metadata> confs;
std::vector<uint8_t> value;
ctp_update_metadata conf{.ase_id = 0x11, .metadata = {0x02, 0x22, 0x21}};
confs.push_back(conf);
ctp_update_metadata conf2{.ase_id = 0x21,
.metadata = {0x03, 0x35, 0x36, 0x37}};
confs.push_back(conf2);
PrepareAseCtpUpdateMetadata(confs, value);
ASSERT_NE(value.size(), 0u);
uint8_t i = 0;
ASSERT_EQ(value[i++], 0x07u); // Update Metadata Opcode
ASSERT_EQ(value[i++], 0x02u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x03u); // ASE[0] Metadata Len
ASSERT_EQ(value[i++], 0x02u); // ASE[0] Metadata[0]
ASSERT_EQ(value[i++], 0x22u); // ASE[0] Metadata[1]
ASSERT_EQ(value[i++], 0x21u); // ASE[0] Metadata[2]
ASSERT_EQ(value[i++], 0x21u); // ASE[1] ID
ASSERT_EQ(value[i++], 0x04u); // ASE[1] Metadata Len
ASSERT_EQ(value[i++], 0x03u); // ASE[1] Metadata[0]
ASSERT_EQ(value[i++], 0x35u); // ASE[1] Metadata[1]
ASSERT_EQ(value[i++], 0x36u); // ASE[1] Metadata[2]
ASSERT_EQ(value[i++], 0x37u); // ASE[1] Metadata[2]
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpReleaseEmpty) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
PrepareAseCtpRelease(ase_ids, value);
ASSERT_EQ(value.size(), 0u);
}
TEST(LeAudioClientParserTest, testPrepareAseCtpReleaseSingle) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
PrepareAseCtpRelease(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x08u); // Release Opcode
ASSERT_EQ(value[i++], 1u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
TEST(LeAudioClientParserTest, testPrepareAseCtpReleaseMultiple) {
std::vector<uint8_t> ase_ids;
std::vector<uint8_t> value;
ase_ids.push_back(0x11);
ase_ids.push_back(0x36);
PrepareAseCtpRelease(ase_ids, value);
uint8_t i = 0;
ASSERT_NE(value.size(), 0u);
ASSERT_EQ(value[i++], 0x08u); // Release Opcode
ASSERT_EQ(value[i++], 2u); // Number of ASEs
ASSERT_EQ(value[i++], 0x11u); // ASE[0] ID
ASSERT_EQ(value[i++], 0x36u); // ASE[0] ID
ASSERT_EQ(i, value.size());
}
} // namespace ascs
} // namespace client_parser
} // namespace le_audio