blob: b004afa669eaa0093fd9d0df640306a21acb7f86 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package com.android.bluetooth.bc;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Iterator;
import android.os.Message;
import android.util.Log;
import java.util.UUID;
import java.util.Collection;
import android.os.UserHandle;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Scanner;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.lang.String;
import java.lang.StringBuffer;
import java.lang.Integer;
import java.nio.ByteBuffer;
import java.lang.Byte;
import java.util.stream.IntStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import android.bluetooth.BleBroadcastSourceInfo;
import android.bluetooth.BleBroadcastSourceChannel;
///*_BMS
import com.android.bluetooth.broadcast.BroadcastService.BisInfo;
import com.android.bluetooth.broadcast.BroadcastService.MetadataLtv;
//_BMS*/
/**
* Helper class to parase the Broadcast Announcement BASE data
*/
final class BaseData {
private static final String TAG = "Bassclient-BaseData";
BaseInformation levelOne = new BaseInformation();
ArrayList<BaseInformation> levelTwo = new ArrayList<BaseInformation>();
ArrayList<BaseInformation> levelThree = new ArrayList<BaseInformation>();
int mNumBISIndicies;
public static byte UNKNOWN_CODEC = (byte)0xFE;
public class BaseInformation {
public byte[] presentationDelay = new byte[3]; //valid only if level=1
public byte[] codecId = new byte[5]; //valid only if level=1
public byte codecConfigLength;
public byte[] codecConfigInfo;
public byte metaDataLength;
public byte[] metaData;
public byte numSubGroups;
public byte[] bisIndicies; //valid only if level = 2
public byte index; //valid only if level=3 and level=2 (as subgroup Id)
public int subGroupId;
public int level;//differentiate different levels of BASE data
public LinkedHashSet<String> keyCodecCfgDiff;
public LinkedHashSet<String> keyMetadataDiff;
public String diffText;
public String description;
public byte[] consolidatedCodecId;
public Set<String> consolidatedMetadata;
public Set<String> consolidatedCodecInfo;
public HashMap<Integer, String> consolidatedUniqueCodecInfo;
public HashMap<Integer, String> consolidatedUniqueMetadata;
BaseInformation() {
presentationDelay = new byte[3];
codecId = new byte[5];
codecConfigLength = 0;
codecConfigInfo = null;
metaDataLength = 0;
metaData = null;
numSubGroups = 0;
bisIndicies = null;
index = (byte)0xFF;
level = 0;
keyCodecCfgDiff = new LinkedHashSet<String>();
keyMetadataDiff = new LinkedHashSet<String>();
consolidatedMetadata = new LinkedHashSet<String>();
consolidatedCodecInfo = new LinkedHashSet<String>();
consolidatedCodecId = new byte[5];
consolidatedUniqueMetadata = new HashMap<Integer, String>();
consolidatedUniqueCodecInfo = new HashMap<Integer, String>();
diffText = new String("");
description = new String("");
log("BaseInformation is Initialized");
}
boolean isCodecIdUnknown() {
return (codecId != null && codecId[4] == (byte)BaseData.UNKNOWN_CODEC);
}
void printConsolidated() {
log("**BEGIN: BIS consolidated Information**");
log("BIS index:" + index);
log("CodecId:" + Arrays.toString(consolidatedCodecId));
/*if (consolidatedCodecInfo != null) {
Iterator<String> itr = consolidatedCodecInfo.iterator();
for (int k=0; itr.hasNext(); k++) {
log("consolidatedCodecInfo:[" + k + "]:" + Arrays.toString(itr.next().getBytes()));
}
}
if (consolidatedMetadata != null) {
Iterator<String> itr = consolidatedMetadata.iterator();
for (int k=0; itr.hasNext(); k++) {
log("consolidatedMetadata:[" + k + "]:" + Arrays.toString(itr.next().getBytes()));
}
}*/
if (consolidatedUniqueCodecInfo != null) {
for (Map.Entry<Integer,String> entry : consolidatedUniqueCodecInfo.entrySet()) {
log("consolidatedUniqueCodecInfo:[" + entry.getKey() + "]:" + Arrays.toString(entry.getValue().getBytes()));
}
}
if (consolidatedUniqueMetadata != null) {
for (Map.Entry<Integer,String> entry : consolidatedUniqueMetadata.entrySet()) {
log("consolidatedUniqueMetadata:[" + entry.getKey() + "]:" + Arrays.toString(entry.getValue().getBytes()));
}
}
log("**END: BIS consolidated Information****");
}
void print() {
log("**BEGIN: Base Information**");
log("**Level: " + level + "***");
if (level == 1) {
log("presentationDelay: " + Arrays.toString(presentationDelay));
}
if (level == 2) {
log("codecId: " + Arrays.toString(codecId));
}
if (level == 2 || level == 3) {
log("codecConfigLength: " + codecConfigLength);
log("subGroupId: " + subGroupId);
}
if (codecConfigLength != (byte)0) {
log("codecConfigInfo: " + Arrays.toString(codecConfigInfo));
}
if (level == 2) {
log("metaDataLength: " + metaDataLength);
if (metaDataLength != (byte)0) {
log("metaData: " + Arrays.toString(metaData));
}
if (level == 1 || level == 2)
log("numSubGroups: " + numSubGroups);
}
if (level == 2) {
log("Level2: Key Metadata differentiators");
if (keyMetadataDiff != null) {
Iterator<String> itr = keyMetadataDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
log("keyMetadataDiff:[" + k + "]:" + Arrays.toString(itr.next().getBytes()));
}
}
log("END: Level2: Key Metadata differentiators");
log("Level2: Key CodecConfig differentiators");
if (keyCodecCfgDiff != null) {
Iterator<String> itr = keyCodecCfgDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
log("LEVEL2: keyCodecCfgDiff:[" + k + "]:" + Arrays.toString(itr.next().getBytes()));
}
}
log("END: Level2: Key CodecConfig differentiators");
//log("bisIndicies: " + Arrays.toString(bisIndicies));
log("LEVEL2: diffText: " + diffText);
}
if (level == 3) {
log("Level3: Key CodecConfig differentiators");
if (keyCodecCfgDiff != null) {
Iterator<String> itr = keyCodecCfgDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
log("LEVEL3: keyCodecCfgDiff:[" + k + "]:" + Arrays.toString(itr.next().getBytes()));
}
}
log("END: Level3: Key CodecConfig differentiators");
log("index: " + index);
log("LEVEL3: diffText: " + diffText);
}
log("**END: Base Information****");
}
};
///*_BMS
BaseData(int numSubGroups, List<BisInfo> colocatedBisInfo, Map<Integer, MetadataLtv> metaInfo) {
if (metaInfo == null || colocatedBisInfo == null) {
Log.e(TAG, "BaseData Contruction with Invalid parameters");
throw new IllegalArgumentException("Basedata: Parameters can't be null");
}
levelOne = new BaseInformation();
levelTwo = new ArrayList<BaseInformation>();
levelThree = new ArrayList<BaseInformation>();
levelOne.level = 1;
levelOne.numSubGroups = (byte)numSubGroups;
//create the level Two and update the Metadata Info
for (int i=0; i<numSubGroups; i++) {
BaseInformation a = new BaseInformation();
a.level = 2;
//get Metadata Ltv
byte[] metadataLtv = null;
if (metaInfo != null) {
Log.d(TAG, "metaInfo: " + metaInfo);
MetadataLtv obj = metaInfo.get(i);
if (obj != null) {
metadataLtv = obj.getByteArray();
Log.d(TAG, "metadataLtv: " + metadataLtv);
} else {
Log.d(TAG, "metadataLtv[" +i+"] is not available");
}
}
if (metadataLtv != null) {
a.metaData = new byte[(int)metadataLtv.length];
System.arraycopy(metadataLtv, 0, a.metaData, 0, (int)metadataLtv.length);
}
levelTwo.add(a);
}
if (colocatedBisInfo != null) {
mNumBISIndicies = colocatedBisInfo.size();
for (int i = 0; i < colocatedBisInfo.size(); i++) {
BisInfo bisInfo = colocatedBisInfo.get(i);
BaseInformation b = new BaseInformation();
b.level = 3;
b.subGroupId = bisInfo.mSubGroupId;
b.index = (byte)bisInfo.BisIndex;
b.consolidatedCodecId = bisInfo.mCodecId;
//get Metadata Ltv
byte[] metadataLtv = bisInfo.BisMetadata.getByteArray();
if (metadataLtv != null) {
int k = 0;
while (k<metadataLtv.length) {
byte length = metadataLtv[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(metadataLtv, k, ltv, 1, length);
//put in type, ltv hashmap
String s = new String(ltv);
b.consolidatedUniqueMetadata.put((int)ltv[1], s);
log("add Metadata:::");
k = k+length;
}
}
//get CodecConfig ltv
byte[] codecConfigLtv = bisInfo.BisCodecConfig.getByteArray();
if (codecConfigLtv != null) {
int k = 0;
while (k<codecConfigLtv.length) {
byte length = codecConfigLtv[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(codecConfigLtv, k, ltv, 1, length);
//put in type, ltv hashmap
String s = new String(ltv);
b.consolidatedUniqueCodecInfo.put((int)ltv[1], s);
log("add CodecConfig entry:::");
k = k+length;
}
}
//update description with "Chennel: X"
b.description = "Channel: " + String.valueOf(b.index);
levelThree.add(b);
}
}
}
//_BMS*/
BaseData(byte[] serviceData) {
if (serviceData == null) {
Log.e(TAG, "Invalid service data for BaseData construction");
throw new IllegalArgumentException("Basedata: serviceData is null");
}
levelOne = new BaseInformation();
levelTwo = new ArrayList<BaseInformation>();
levelThree = new ArrayList<BaseInformation>();
mNumBISIndicies = 0;
log("members initialized");
log("BASE input" + Arrays.toString(serviceData));
//Parse Level 1 base
levelOne.level = 1;
int level1Idx = 0;
System.arraycopy(serviceData, level1Idx, levelOne.presentationDelay,0, 3);
level1Idx = level1Idx + 3;
levelOne.numSubGroups = serviceData[level1Idx++];
levelOne.print();
log("levelOne subgroups" + levelOne.numSubGroups);
int level2Idx = level1Idx;
for (int i =0; i<(int)levelOne.numSubGroups; i++) {
log("parsing subgroup" + i);
BaseInformation b = new BaseInformation();
b.level = 2;
b.subGroupId = i;
b.numSubGroups = serviceData[level2Idx++];
if (serviceData[level2Idx] == (byte)UNKNOWN_CODEC) {
//Place It in the last byte of codecID
System.arraycopy(serviceData, level2Idx, b.codecId, 4, 1);
level2Idx = level2Idx + 1;
log("codecId is FE");
} else {
System.arraycopy(serviceData, level2Idx, b.codecId, 0, 5);
level2Idx = level2Idx + 5;
}
b.codecConfigLength = serviceData[level2Idx++];
if (b.codecConfigLength != 0) {
b.codecConfigInfo = new byte[(int)b.codecConfigLength];
System.arraycopy(serviceData, level2Idx, b.codecConfigInfo, 0, (int)b.codecConfigLength);
level2Idx = level2Idx + (int)b.codecConfigLength;
}
b.metaDataLength = serviceData[level2Idx++];
if (b.metaDataLength != 0) {
b.metaData = new byte[(int)b.metaDataLength];
System.arraycopy(serviceData, level2Idx, b.metaData, 0, (int)b.metaDataLength);
level2Idx = level2Idx + (int)b.metaDataLength;
}
mNumBISIndicies = mNumBISIndicies + b.numSubGroups;
levelTwo.add(b);
b.print();
}
//Parse Level 3 Base
int level3Index = level2Idx;
for (int k=0; k<mNumBISIndicies; k++) {
BaseInformation c = new BaseInformation();
c.level = 3;
c.index = serviceData[level3Index++];
c.codecConfigLength = serviceData[level3Index++];
if (c.codecConfigLength != 0) {
c.codecConfigInfo = new byte[(int)c.codecConfigLength];
System.arraycopy(serviceData, level3Index, c.codecConfigInfo, 0, (int)c.codecConfigLength);
level3Index = level3Index + (int)c.codecConfigLength;
}
levelThree.add(c);
}
consolidateBaseofLevelTwo();
//Detailed BASE parsing below
//log("calling updateUniquenessForLevelTwo");
//updateUniquenessForLevelTwo(levelOne.numSubGroups);
//updateDiffTextforNodes();
}
void consolidateBaseofLevelTwo() {
int startIdx = 0;
int children = 0;
for (int i=0; i<levelTwo.size(); i++) {
startIdx = startIdx+ children;
children = children + levelTwo.get(i).numSubGroups;
consolidateBaseofLevelThree(i, startIdx, levelTwo.get(i).numSubGroups);
}
//Eliminate Duplicates at Level 3
for (int i=0; i<levelThree.size(); i++) {
Map<Integer, String> uniqueMds = new HashMap<Integer, String> ();
Map<Integer, String> uniqueCcis = new HashMap<Integer, String> ();
Set<String> Csfs = levelThree.get(i).consolidatedCodecInfo;
if (Csfs.size() > 0) {
Iterator<String> itr = Csfs.iterator();
for (int j=0; itr.hasNext(); j++) {
byte[] ltvEntries = itr.next().getBytes();
int k = 0;
byte length = ltvEntries[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(ltvEntries, k, ltv, 1, length);
//
int type = (int)ltv[1];
String s = uniqueCcis.get(type);
String ltvS = new String(ltv);
if (s == null) {
uniqueCcis.put(type, ltvS);
} else {
//if same type exists
//replace
uniqueCcis.replace(type, ltvS);
}
}
}
Set<String> Mds = levelThree.get(i).consolidatedMetadata;
if (Mds.size() > 0) {
Iterator<String> itr = Mds.iterator();
for (int j=0; itr.hasNext(); j++) {
byte[] ltvEntries = itr.next().getBytes();
int k = 0;
byte length = ltvEntries[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(ltvEntries, k, ltv, 1, length);
/*CHECK: This can be straight PUT, there wont be dups in Metadata with new BASE*/
int type = (int)ltv[1];
String s = uniqueCcis.get(type);
String ltvS = new String(ltv);
if (s == null) {
uniqueMds.put(type, ltvS);
} else {
//if same type exists
//replace
uniqueMds.replace(type, ltvS);
}
}
}
levelThree.get(i).consolidatedUniqueMetadata = new HashMap<Integer, String>(uniqueMds);
levelThree.get(i).consolidatedUniqueCodecInfo = new HashMap<Integer, String>(uniqueCcis);
}
}
void consolidateBaseofLevelThree(int parentSubgroup, int startIdx, int numNodes) {
for (int i=startIdx; i<startIdx+numNodes||i<levelThree.size(); i++) {
levelThree.get(i).subGroupId = levelTwo.get(parentSubgroup).subGroupId;
log("Copy Codec Id from Level2 Parent" + parentSubgroup);
System.arraycopy(levelTwo.get(parentSubgroup).consolidatedCodecId,
0 ,levelThree.get(i).consolidatedCodecId, 0, 5);
//Metadata clone from Parent
levelThree.get(i).consolidatedMetadata = new LinkedHashSet<String>(levelTwo.get(parentSubgroup).consolidatedMetadata);
//log("Parent Cons Info>>");
//levelTwo.get(parentSubgroup).printConsolidated();
//CCI clone from Parent
levelThree.get(i).consolidatedCodecInfo = new LinkedHashSet<String>(levelTwo.get(parentSubgroup).consolidatedCodecInfo);
//log("before " + i);
//levelThree.get(i).printConsolidated();
//Append Level 2 Codec Config
if (levelThree.get(i).codecConfigLength != 0) {
log("append level 3 cci to level 3 cons:" + i);
String s = new String(levelThree.get(i).codecConfigInfo);
levelThree.get(i).consolidatedCodecInfo.add(s);
}
//log("after " + i);
//levelThree.get(i).printConsolidated();
//log("Parent Cons Info>>");
//levelTwo.get(parentSubgroup).printConsolidated();
}
}
public int getNumberOfIndicies() {
return mNumBISIndicies;
}
public byte getNumberOfSubgroupsofBIG() {
byte ret = 0;
if (levelOne != null) {
ret = levelOne.numSubGroups;
}
return ret;
}
public ArrayList<BaseInformation> getBISIndexInfos() {
return levelThree;
}
List<BleBroadcastSourceChannel> getBroadcastChannels() {
List<BleBroadcastSourceChannel> bChannels = new ArrayList<BleBroadcastSourceChannel>();
for (int k=0; k<mNumBISIndicies; k++) {
int index = levelThree.get(k).index;
String desc = levelThree.get(k).description;
//String desc = String.valueOf(index);
BleBroadcastSourceChannel bc = new BleBroadcastSourceChannel(index, desc, false,
levelThree.get(k).subGroupId, levelThree.get(k).metaData);
bChannels.add(bc);
}
return bChannels;
}
List<BleBroadcastSourceChannel> pickAllBroadcastChannels() {
List<BleBroadcastSourceChannel> bChannels = new ArrayList<BleBroadcastSourceChannel>();
for (int k=0; k<mNumBISIndicies; k++) {
int index = levelThree.get(k).index;
//String desc = levelThree.get(k).description;
//String desc = String.valueOf(index);
BleBroadcastSourceChannel bc = new BleBroadcastSourceChannel(index, String.valueOf(index), true,
levelThree.get(k).subGroupId, levelThree.get(k).metaData);
bChannels.add(bc);
}
return bChannels;
}
byte[] getMetadata(int subGroup) {
if (levelTwo != null) {
return levelTwo.get(subGroup).metaData;
}
return null;
}
String getMetadataString(byte[] metadataBytes) {
final int _LANGUAGE = 0;
//Different language
final int _ENGLISH = 1;
final int _SPANISH = 2;
final int _DESCRIPTION = 1;
String ret = new String();
switch(metadataBytes[1]) {
case _LANGUAGE:
switch (metadataBytes[2]) {
case _ENGLISH:
ret = "ENGLISH"; break;
case _SPANISH:
ret = "SPANISH"; break;
default:
ret = "UNKNOWN"; break;
}
break;
case _DESCRIPTION:
ret = "UNKNOWN";
break;
default:
ret = "UNKNOWN";
}
log("getMetadataString: " + ret);
return ret;
}
String getCodecParamString(byte[] csiBytes) {
final int LOCATION = 4;
final int LEFT = 0x01000000;
final int RIGHT =0x02000000;
String ret = new String();
//sample rate
final int SAMPLE_RATE = 1;
//frame duration
final int FRAME_DURATION = 2;
//Octets per frame
final int OCTETS_PER_FRAME = 8;
switch(csiBytes[1]) {
case LOCATION:
byte[] location = new byte[4];
System.arraycopy(csiBytes, 2, location, 0, 4);
ByteBuffer wrapped = ByteBuffer.wrap(location);
int audioLocation = wrapped.getInt();
log("audioLocation: " + audioLocation);
switch (audioLocation) {
case LEFT: ret = "LEFT"; break;
case RIGHT: ret = "RIGHT"; break;
case LEFT|RIGHT: ret = "LR"; break;
}
break;
case SAMPLE_RATE:
switch(csiBytes[2]) {
case 1:
ret = "8K"; break;
case 2:
ret = "16K"; break;
case 3:
ret = "24K"; break;
case 4:
ret = "32K"; break;
case 5:
ret = "44.1K"; break;
case 6:
ret = "48K"; break;
}
break;
case FRAME_DURATION:
switch(csiBytes[2]) {
case 1:
ret = "FD_1"; break;
}
break;
case OCTETS_PER_FRAME:
switch(csiBytes[2]) {
case 28:
ret = "OPF_28"; break;
case 64:
ret = "OPF_64"; break;
}
break;
default:
ret = "UNKNOWN";
}
log("getCodecParamString: " + ret);
return ret;
}
void updateDiffTextforNodes() {
for (int i=0; i<levelTwo.size(); i++) {
if (levelTwo.get(i).keyMetadataDiff != null) {
Iterator<String> itr = levelTwo.get(i).keyMetadataDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
levelTwo.get(i).diffText = levelTwo.get(i).diffText.concat(getMetadataString(itr.next().getBytes()));
levelTwo.get(i).diffText = levelTwo.get(i).diffText.concat("_");
}
}
if (levelTwo.get(i).keyCodecCfgDiff != null) {
Iterator<String> itr = levelTwo.get(i).keyCodecCfgDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
levelTwo.get(i).diffText = levelTwo.get(i).diffText.concat(getCodecParamString(itr.next().getBytes()));
levelTwo.get(i).diffText = levelTwo.get(i).diffText.concat("_");
}
}
}
for (int i=0; i<levelThree.size(); i++) {
if (levelThree.get(i).keyCodecCfgDiff != null) {
Iterator<String> itr = levelThree.get(i).keyCodecCfgDiff.iterator();
for (int k=0; itr.hasNext(); k++) {
levelThree.get(i).diffText = levelThree.get(i).diffText.concat(getCodecParamString(itr.next().getBytes()));
levelThree.get(i).diffText = levelThree.get(i).diffText.concat("_");
}
}
}
//Concat and update the Description
int startIdx = 0;
int children = 0;
for (int i=0; i<levelTwo.size(); i++) {
startIdx = startIdx+ children;
children = children + levelTwo.get(i).numSubGroups;
for (int j=startIdx; j<startIdx+levelTwo.get(i).numSubGroups||j<levelThree.size(); j++) {
levelThree.get(j).description = levelTwo.get(i).diffText + levelThree.get(j).diffText;
}
}
}
void updateUniquenessForLevelTwo(int numNodes) {
log("updateUniquenessForLevelTwo: ENTER");
Set<String> uniqueCodecIds = new LinkedHashSet<String>();
Set<String> uniqueCsfs = new LinkedHashSet<String>();
Set<String> uniqueMetadatas = new LinkedHashSet<String>();
log("updateUniquenessForLevelTwo");
int startIdx = 0;
int children = 0;
for (int i=0; i<levelTwo.size(); i++) {
//levelTwo.get(i).print();
if (!levelTwo.get(i).isCodecIdUnknown()) {
log("add codecId of subg: " + i);
String s = new String(levelTwo.get(i).codecId);
uniqueCodecIds.add(s);
}
if (levelTwo.get(i).codecConfigLength != 0) {
log("add codecConfig of subg: " + i);
String s = new String(levelTwo.get(i).codecConfigInfo);
uniqueCsfs.add(s);
}
if (levelTwo.get(i).metaDataLength != 0) {
String s = new String(levelTwo.get(i).metaData);
log("add metadata of subg: " + i);
uniqueMetadatas.add(s);
}
startIdx = startIdx+ children;
children = children + levelTwo.get(i).numSubGroups;
updateUniquenessForLevelThree(i, startIdx, levelTwo.get(i).numSubGroups);
}
Set<String> uniqueCodecParams = new LinkedHashSet<String>();
Set<String> uniqueMetadataParams = new LinkedHashSet<String>();
if (uniqueCodecIds.size() > 0) log("LevelTwo: UniqueCodecIds");
if (uniqueCsfs.size() > 0) {
log("LevelTwo: uniqueCsfs");
//uniqueCodecParams =
Iterator<String> itr = uniqueCsfs.iterator();
for (int i=0; itr.hasNext(); i++) {
byte[] ltvEntries = itr.next().getBytes();
int k = 0;
byte length = ltvEntries[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(ltvEntries, k, ltv, 1, length);
//This should ensure Duplicate entries at this level
String s = new String(ltvEntries);
uniqueCodecParams.add(s);
}
}
if (uniqueMetadatas.size() > 0) {
log("LevelTwo: uniqueMetadatas");
//uniqueMetadataParams = new LinkedHashSet<String>();
Iterator<String> itr = uniqueMetadatas.iterator();
for (int i=0; itr.hasNext(); i++) {
byte[] ltvEntries = itr.next().getBytes();
int k = 0;
byte length = ltvEntries[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(ltvEntries, k, ltv, 1, length);
//This should ensure Duplicate entries at this level
String s = new String(ltvEntries);
uniqueMetadataParams.add(s);
}
}
//run though the nodes and update KEY differentiating factors
if (uniqueCodecParams != null) {
Iterator<String> itr = uniqueCodecParams.iterator();
int i = 0;
for (int k=0; itr.hasNext(); k++) {
levelTwo.get(i).keyCodecCfgDiff.add(itr.next());
i = (i+1)%(numNodes);
}
}
//run though the nodes and update KEY differentiating factors
if (uniqueMetadataParams != null) {
Iterator<String> itr = uniqueMetadataParams.iterator();
int i = 0;
for (int k=0; itr.hasNext(); k++) {
levelTwo.get(i).keyMetadataDiff.add(itr.next());
i = (i+1)%(numNodes);
}
}
/*log("Level2: Uniqueness among subgroups");
if (uniqueCodecParams != null) {
Iterator<String> itr = uniqueCodecParams.iterator();
for (int k=0; itr.hasNext(); k++) {
log("UniqueCodecParams:[" + k + "]" + Arrays.toString(itr.next().getBytes()));
}
}
if (uniqueMetadataParams != null) {
Iterator<String> itr = uniqueMetadataParams.iterator();
for (int k=0; itr.hasNext(); k++) {
log("uniqueMetadataParams:["+ k + "]" + Arrays.toString(itr.next().getBytes()));
}
}
log("END: Level2: Uniqueness among subgroups");
*/
}
void updateUniquenessForLevelThree(int parentSubgroup, int startIdx, int numNodes) {
//Set<String> uniqueCodecIds = new LinkedHashSet<String>();
Set<String> uniqueCsfs = new LinkedHashSet<String>();
//Set<String> uniqueMetadatas = new LinkedHashSet<String>();
log("updateUniquenessForLevelThree: startIdx" + startIdx + "numNodes" + numNodes);
for (int i=startIdx; i<startIdx+numNodes||i<levelThree.size(); i++) {
if (levelThree.get(i).codecConfigLength != 0) {
String s = new String(levelThree.get(i).codecConfigInfo);
uniqueCsfs.add(s);
log("LEVEL3: add unique CSFs:");
}
}
Set<String> uniqueCodecParams = new LinkedHashSet<String>();
if (uniqueCsfs.size() > 0) {
log("LevelThree: uniqueCsfs");
//uniqueCodecParams =
Iterator<String> itr = uniqueCsfs.iterator();
for (int i=0; itr.hasNext(); i++) {
byte[] ltvEntries = itr.next().getBytes();
int k = 0;
byte length = ltvEntries[k++];
byte[] ltv = new byte[length+1];
ltv[0] = length;
System.arraycopy(ltvEntries, k, ltv, 1, length);
//This should ensure Duplicate entries at this level
String s = new String(ltvEntries);
uniqueCodecParams.add(s);
}
}
//run though the nodes and update KEY differentiating factors
if (uniqueCodecParams != null) {
Iterator<String> itr = uniqueCodecParams.iterator();
int i = startIdx;
for (int k=0; itr.hasNext(); k++) {
levelThree.get(i).keyCodecCfgDiff.add(itr.next());
i = (i+1)%(startIdx+numNodes);
}
}
/*
log("Level3: Uniqueness among children of " + parentSubgroup + "th Subgroup");
if (uniqueCodecParams != null) {
Iterator<String> itr = uniqueCodecParams.iterator();
for (int k=0; itr.hasNext(); k++) {
log("UniqueCodecParams:[" + k + "]" + Arrays.toString(itr.next().getBytes()));
}
}
log("END: Level3: Uniqueness among children of " + parentSubgroup + "th Subgroup");
*/
}
void print() {
levelOne.print();
log("----- Level TWO BASE ----");
for (int i=0; i<levelTwo.size(); i++) {
levelTwo.get(i).print();
}
log("----- Level THREE BASE ----");
for (int i=0; i<levelThree.size(); i++) {
levelThree.get(i).print();
}
}
void printConsolidated() {
log("----- printConsolidated ----");
for (int i=0; i<levelThree.size(); i++) {
levelThree.get(i).printConsolidated();
}
}
static void log(String msg) {
if (BassClientStateMachine.BASS_DBG) {
Log.d(TAG, msg);
}
}
}