Loading android/app/src/com/android/bluetooth/bass_client/BaseData.java +74 −11 Original line number Diff line number Diff line Loading @@ -141,26 +141,36 @@ class BaseData { levelOne.print(); log("levelOne subgroups" + levelOne.numSubGroups); for (int i = 0; i < (int) levelOne.numSubGroups; i++) { if (offset >= serviceData.length) { Log.e(TAG, "Error: parsing Level 2"); return null; } Pair<BaseInformation, Integer> pair1 = parseLevelTwo(serviceData, i, offset); BaseInformation node2 = pair1.first; if (node2 == null) { if (pair1 == null) { Log.e(TAG, "Error: parsing Level 2"); return null; } BaseInformation node2 = pair1.first; numOfBISIndices += node2.numSubGroups; levelTwo.add(node2); node2.print(); offset = pair1.second; for (int k = 0; k < node2.numSubGroups; k++) { if (offset >= serviceData.length) { Log.e(TAG, "Error: parsing Level 3"); return null; } Pair<BaseInformation, Integer> pair2 = parseLevelThree(serviceData, offset); BaseInformation node3 = pair2.first; offset = pair2.second; if (node3 == null) { if (pair2 == null) { Log.e(TAG, "Error: parsing Level 3"); return null; } BaseInformation node3 = pair2.first; levelThree.add(node3); node3.print(); offset = pair2.second; } } consolidateBaseofLevelTwo(levelTwo, levelThree); Loading @@ -173,17 +183,52 @@ class BaseData { BaseInformation node = new BaseInformation(); node.level = METADATA_LEVEL2; node.subGroupId = groupIndex; int bufferLengthLeft = (serviceData.length - offset); // Min. length expected is: codecID (5) + numBis (1) + codecSpecCfgLen (1) + metadataLen (1) final int minNodeBufferLen = METADATA_CODEC_LENGTH + 3; if (bufferLengthLeft < minNodeBufferLen) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } node.numSubGroups = serviceData[offset++]; // NumBis System.arraycopy(serviceData, offset, node.codecId, 0, METADATA_CODEC_LENGTH); offset += METADATA_CODEC_LENGTH; node.codecConfigLength = serviceData[offset++] & 0xff; if (node.codecConfigLength != 0) { // Declared codec specific data length int declaredLength = serviceData[offset++] & 0xff; bufferLengthLeft = (serviceData.length - offset); if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid codec config length or codec config truncated."); return null; } if (declaredLength != 0) { node.codecConfigLength = declaredLength; node.codecConfigInfo = new byte[node.codecConfigLength]; System.arraycopy(serviceData, offset, node.codecConfigInfo, 0, node.codecConfigLength); offset += node.codecConfigLength; } node.metaDataLength = serviceData[offset++] & 0xff; if (node.metaDataLength != 0) { // Verify the buffer size left bufferLengthLeft = (serviceData.length - offset); if (bufferLengthLeft < 1) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } // Declared metadata length declaredLength = serviceData[offset++] & 0xff; --bufferLengthLeft; if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid metadata length or metadata truncated."); return null; } if (declaredLength != 0) { node.metaDataLength = declaredLength; node.metaData = new byte[node.metaDataLength]; System.arraycopy(serviceData, offset, node.metaData, 0, node.metaDataLength); offset += node.metaDataLength; Loading @@ -195,9 +240,27 @@ class BaseData { log("Parsing Level 3"); BaseInformation node = new BaseInformation(); node.level = METADATA_LEVEL3; int bufferLengthLeft = (serviceData.length - offset); // Min. length expected is: bisIdx (1) + codecSpecCfgLen (1) final int minNodeBufferLen = 2; if (bufferLengthLeft < minNodeBufferLen) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } node.index = serviceData[offset++]; node.codecConfigLength = serviceData[offset++] & 0xff; if (node.codecConfigLength != 0) { // Verify the buffer size left int declaredLength = serviceData[offset++] & 0xff; bufferLengthLeft = (serviceData.length - offset); if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid metadata length or metadata truncated."); return null; } if (declaredLength != 0) { node.codecConfigLength = declaredLength; node.codecConfigInfo = new byte[node.codecConfigLength]; System.arraycopy(serviceData, offset, node.codecConfigInfo, 0, node.codecConfigLength); offset += node.codecConfigLength; Loading android/app/tests/unit/src/com/android/bluetooth/bass_client/BaseDataTest.java +277 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,283 @@ public class BaseDataTest { assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseDataLvl2TruncatedConfig() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Lc3 (byte) 0x03, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataLvl2TruncatedMetadata() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // UNKNOWN_CODEC (byte) 0x02, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo (byte) 0x04, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataLvl3TruncatedConfig() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // UNKNOWN_CODEC (byte) 0x02, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x04, // codecConfigLength (byte) 0x02, (byte) 'B', (byte) 'C' // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataInvalidLtv() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // LC3 (byte) 0x02, // codecConfigLength (byte) 0x04, (byte) 'A', // codecConfigInfo (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x03, // codecConfigLength (byte) 0x03, (byte) 'B', (byte) 'C' // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId).isEqualTo(new byte[] {0x06, 0x00, 0x00, 0x00, 0x00}); assertThat(level.codecConfigLength).isEqualTo(2); assertThat(level.metaDataLength).isEqualTo(3); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); // Got the whole config, without interpreting it as LTV assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseVendorCodecBaseData() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0xFF, // VENDOR_CODEC (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD, (byte) 0x04, // codecConfigLength (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, // opaque vendor data (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x03, // codecConfigLength (byte) 0x03, (byte) 0x02, (byte) 0x01 // opaque vendor data }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId) .isEqualTo( new byte[] { (byte) 0xFF, (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD }); assertThat(level.codecConfigLength).isEqualTo(4); assertThat(level.metaDataLength).isEqualTo(3); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseVendorCodecBaseDataMinimal() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0xFF, // VENDOR_CODEC (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD, (byte) 0x00, // codecConfigLength (byte) 0x00, // metaDataLength // LEVEL 3 (byte) 0x04, // index (byte) 0x00, // codecConfigLength }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId) .isEqualTo( new byte[] { (byte) 0xFF, (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD }); assertThat(level.codecConfigLength).isEqualTo(0); assertThat(level.metaDataLength).isEqualTo(0); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); assertThat(level.codecConfigLength).isEqualTo(0); } @Test public void parseBaseVendorCodecBaseDataInvalid() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x00, // numBIS invalid value (byte) 0xFE, // UNKNOWN CODEC (byte) 0x00, // codecConfigLength (byte) 0x00, // metaDataLength }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseData_longMetaData() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); Loading Loading
android/app/src/com/android/bluetooth/bass_client/BaseData.java +74 −11 Original line number Diff line number Diff line Loading @@ -141,26 +141,36 @@ class BaseData { levelOne.print(); log("levelOne subgroups" + levelOne.numSubGroups); for (int i = 0; i < (int) levelOne.numSubGroups; i++) { if (offset >= serviceData.length) { Log.e(TAG, "Error: parsing Level 2"); return null; } Pair<BaseInformation, Integer> pair1 = parseLevelTwo(serviceData, i, offset); BaseInformation node2 = pair1.first; if (node2 == null) { if (pair1 == null) { Log.e(TAG, "Error: parsing Level 2"); return null; } BaseInformation node2 = pair1.first; numOfBISIndices += node2.numSubGroups; levelTwo.add(node2); node2.print(); offset = pair1.second; for (int k = 0; k < node2.numSubGroups; k++) { if (offset >= serviceData.length) { Log.e(TAG, "Error: parsing Level 3"); return null; } Pair<BaseInformation, Integer> pair2 = parseLevelThree(serviceData, offset); BaseInformation node3 = pair2.first; offset = pair2.second; if (node3 == null) { if (pair2 == null) { Log.e(TAG, "Error: parsing Level 3"); return null; } BaseInformation node3 = pair2.first; levelThree.add(node3); node3.print(); offset = pair2.second; } } consolidateBaseofLevelTwo(levelTwo, levelThree); Loading @@ -173,17 +183,52 @@ class BaseData { BaseInformation node = new BaseInformation(); node.level = METADATA_LEVEL2; node.subGroupId = groupIndex; int bufferLengthLeft = (serviceData.length - offset); // Min. length expected is: codecID (5) + numBis (1) + codecSpecCfgLen (1) + metadataLen (1) final int minNodeBufferLen = METADATA_CODEC_LENGTH + 3; if (bufferLengthLeft < minNodeBufferLen) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } node.numSubGroups = serviceData[offset++]; // NumBis System.arraycopy(serviceData, offset, node.codecId, 0, METADATA_CODEC_LENGTH); offset += METADATA_CODEC_LENGTH; node.codecConfigLength = serviceData[offset++] & 0xff; if (node.codecConfigLength != 0) { // Declared codec specific data length int declaredLength = serviceData[offset++] & 0xff; bufferLengthLeft = (serviceData.length - offset); if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid codec config length or codec config truncated."); return null; } if (declaredLength != 0) { node.codecConfigLength = declaredLength; node.codecConfigInfo = new byte[node.codecConfigLength]; System.arraycopy(serviceData, offset, node.codecConfigInfo, 0, node.codecConfigLength); offset += node.codecConfigLength; } node.metaDataLength = serviceData[offset++] & 0xff; if (node.metaDataLength != 0) { // Verify the buffer size left bufferLengthLeft = (serviceData.length - offset); if (bufferLengthLeft < 1) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } // Declared metadata length declaredLength = serviceData[offset++] & 0xff; --bufferLengthLeft; if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid metadata length or metadata truncated."); return null; } if (declaredLength != 0) { node.metaDataLength = declaredLength; node.metaData = new byte[node.metaDataLength]; System.arraycopy(serviceData, offset, node.metaData, 0, node.metaDataLength); offset += node.metaDataLength; Loading @@ -195,9 +240,27 @@ class BaseData { log("Parsing Level 3"); BaseInformation node = new BaseInformation(); node.level = METADATA_LEVEL3; int bufferLengthLeft = (serviceData.length - offset); // Min. length expected is: bisIdx (1) + codecSpecCfgLen (1) final int minNodeBufferLen = 2; if (bufferLengthLeft < minNodeBufferLen) { Log.e(TAG, "Error: Invalid Lvl2 buffer length."); return null; } node.index = serviceData[offset++]; node.codecConfigLength = serviceData[offset++] & 0xff; if (node.codecConfigLength != 0) { // Verify the buffer size left int declaredLength = serviceData[offset++] & 0xff; bufferLengthLeft = (serviceData.length - offset); if (declaredLength < 0 || declaredLength > bufferLengthLeft) { Log.e(TAG, "Error: Invalid metadata length or metadata truncated."); return null; } if (declaredLength != 0) { node.codecConfigLength = declaredLength; node.codecConfigInfo = new byte[node.codecConfigLength]; System.arraycopy(serviceData, offset, node.codecConfigInfo, 0, node.codecConfigLength); offset += node.codecConfigLength; Loading
android/app/tests/unit/src/com/android/bluetooth/bass_client/BaseDataTest.java +277 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,283 @@ public class BaseDataTest { assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseDataLvl2TruncatedConfig() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Lc3 (byte) 0x03, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataLvl2TruncatedMetadata() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // UNKNOWN_CODEC (byte) 0x02, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo (byte) 0x04, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataLvl3TruncatedConfig() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // UNKNOWN_CODEC (byte) 0x02, // codecConfigLength (byte) 0x01, (byte) 'A', // codecConfigInfo (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x04, // codecConfigLength (byte) 0x02, (byte) 'B', (byte) 'C' // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseDataInvalidLtv() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // LC3 (byte) 0x02, // codecConfigLength (byte) 0x04, (byte) 'A', // codecConfigInfo (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x03, // codecConfigLength (byte) 0x03, (byte) 'B', (byte) 'C' // codecConfigInfo }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId).isEqualTo(new byte[] {0x06, 0x00, 0x00, 0x00, 0x00}); assertThat(level.codecConfigLength).isEqualTo(2); assertThat(level.metaDataLength).isEqualTo(3); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); // Got the whole config, without interpreting it as LTV assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseVendorCodecBaseData() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0xFF, // VENDOR_CODEC (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD, (byte) 0x04, // codecConfigLength (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, // opaque vendor data (byte) 0x03, // metaDataLength (byte) 0x06, (byte) 0x07, (byte) 0x08, // metaData // LEVEL 3 (byte) 0x04, // index (byte) 0x03, // codecConfigLength (byte) 0x03, (byte) 0x02, (byte) 0x01 // opaque vendor data }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId) .isEqualTo( new byte[] { (byte) 0xFF, (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD }); assertThat(level.codecConfigLength).isEqualTo(4); assertThat(level.metaDataLength).isEqualTo(3); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); assertThat(level.codecConfigLength).isEqualTo(3); } @Test public void parseBaseVendorCodecBaseDataMinimal() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x01, // numBIS (byte) 0xFF, // VENDOR_CODEC (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD, (byte) 0x00, // codecConfigLength (byte) 0x00, // metaDataLength // LEVEL 3 (byte) 0x04, // index (byte) 0x00, // codecConfigLength }; BaseData data = BaseData.parseBaseData(serviceData); BaseData.BaseInformation level = data.getLevelOne(); assertThat(level.presentationDelay).isEqualTo(new byte[] {0x01, 0x02, 0x03}); assertThat(level.numSubGroups).isEqualTo(1); assertThat(data.getLevelTwo().size()).isEqualTo(1); level = data.getLevelTwo().get(0); assertThat(level.numSubGroups).isEqualTo(1); assertThat(level.codecId) .isEqualTo( new byte[] { (byte) 0xFF, (byte) 0x0A, (byte) 0xAB, (byte) 0xBC, (byte) 0xCD }); assertThat(level.codecConfigLength).isEqualTo(0); assertThat(level.metaDataLength).isEqualTo(0); assertThat(data.getLevelThree().size()).isEqualTo(1); level = data.getLevelThree().get(0); assertThat(level.index).isEqualTo(4); assertThat(level.codecConfigLength).isEqualTo(0); } @Test public void parseBaseVendorCodecBaseDataInvalid() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); byte[] serviceData = new byte[] { // LEVEL 1 (byte) 0x01, (byte) 0x02, (byte) 0x03, // presentationDelay (byte) 0x01, // numSubGroups // LEVEL 2 (byte) 0x00, // numBIS invalid value (byte) 0xFE, // UNKNOWN CODEC (byte) 0x00, // codecConfigLength (byte) 0x00, // metaDataLength }; BaseData data = BaseData.parseBaseData(serviceData); assertThat(data).isEqualTo(null); } @Test public void parseBaseData_longMetaData() { assertThrows(IllegalArgumentException.class, () -> BaseData.parseBaseData(null)); Loading