Merge "Update logic for determining if an USB device is a headset or not."

This commit is contained in:
TreeHugger Robot
2022-06-22 18:31:50 +00:00
committed by Android (Google) Code Review
9 changed files with 134 additions and 29 deletions

View File

@@ -22,7 +22,7 @@ import com.android.server.usb.descriptors.report.ReportCanvas;
* An audio class-specific Input Terminal interface.
* see audio10.pdf section 4.3.2.1
*/
public final class Usb10ACInputTerminal extends UsbACTerminal {
public final class Usb10ACInputTerminal extends UsbACTerminal implements UsbAudioChannelCluster {
private static final String TAG = "Usb10ACInputTerminal";
private byte mNrChannels; // 7:1 1 Channel (0x01)
@@ -36,14 +36,17 @@ public final class Usb10ACInputTerminal extends UsbACTerminal {
super(length, type, subtype, subclass);
}
public byte getNrChannels() {
@Override
public byte getChannelCount() {
return mNrChannels;
}
@Override
public int getChannelConfig() {
return mChannelConfig;
}
@Override
public byte getChannelNames() {
return mChannelNames;
}
@@ -69,9 +72,7 @@ public final class Usb10ACInputTerminal extends UsbACTerminal {
super.report(canvas);
canvas.openList();
canvas.writeListItem("Associated Terminal: "
+ ReportCanvas.getHexString(getAssocTerminal()));
canvas.writeListItem("" + getNrChannels() + " Chans. Config: "
canvas.writeListItem("" + getChannelCount() + " Chans. Config: "
+ ReportCanvas.getHexString(getChannelConfig()));
canvas.closeList();
}

View File

@@ -22,7 +22,7 @@ import com.android.server.usb.descriptors.report.ReportCanvas;
* An audio class-specific Mixer Interface.
* see audio10.pdf section 4.3.2.3
*/
public final class Usb10ACMixerUnit extends UsbACMixerUnit {
public final class Usb10ACMixerUnit extends UsbACMixerUnit implements UsbAudioChannelCluster {
private static final String TAG = "Usb10ACMixerUnit";
private int mChannelConfig; // Spatial location of output channels
@@ -34,11 +34,18 @@ public final class Usb10ACMixerUnit extends UsbACMixerUnit {
super(length, type, subtype, subClass);
}
@Override
public byte getChannelCount() {
return mNumOutputs;
}
@Override
public int getChannelConfig() {
return mChannelConfig;
}
public byte getChanNameID() {
@Override
public byte getChannelNames() {
return mChanNameID;
}

View File

@@ -22,7 +22,7 @@ import com.android.server.usb.descriptors.report.ReportCanvas;
* An audio class-specific Input Terminal interface.
* see Audio20.pdf section 3.13.2 Input Terminal
*/
public final class Usb20ACInputTerminal extends UsbACTerminal {
public final class Usb20ACInputTerminal extends UsbACTerminal implements UsbAudioChannelCluster {
private static final String TAG = "Usb20ACInputTerminal";
// See Audio20.pdf - Table 4-9
@@ -47,14 +47,21 @@ public final class Usb20ACInputTerminal extends UsbACTerminal {
return mClkSourceID;
}
public byte getNumChannels() {
@Override
public byte getChannelCount() {
return mNumChannels;
}
public int getChanConfig() {
@Override
public int getChannelConfig() {
return mChanConfig;
}
@Override
public byte getChannelNames() {
return mChanNames;
}
public int getControls() {
return mControls;
}
@@ -79,8 +86,8 @@ public final class Usb20ACInputTerminal extends UsbACTerminal {
canvas.openList();
canvas.writeListItem("Clock Source: " + getClkSourceID());
canvas.writeListItem("" + getNumChannels() + " Channels. Config: "
+ ReportCanvas.getHexString(getChanConfig()));
canvas.writeListItem("" + getChannelCount() + " Channels. Config: "
+ ReportCanvas.getHexString(getChannelConfig()));
canvas.closeList();
}
}

View File

@@ -20,7 +20,7 @@ package com.android.server.usb.descriptors;
* An audio class-specific Mixer Unit interface.
* see Audio20.pdf section 4.7.2.6 Mixer Unit Descriptor
*/
public final class Usb20ACMixerUnit extends UsbACMixerUnit {
public final class Usb20ACMixerUnit extends UsbACMixerUnit implements UsbAudioChannelCluster {
private static final String TAG = "Usb20ACMixerUnit";
private int mChanConfig; // 6+p:4 Describes the spatial location of the
@@ -37,6 +37,21 @@ public final class Usb20ACMixerUnit extends UsbACMixerUnit {
super(length, type, subtype, subClass);
}
@Override
public byte getChannelCount() {
return mNumOutputs;
}
@Override
public int getChannelConfig() {
return mChanConfig;
}
@Override
public byte getChannelNames() {
return mChanNames;
}
@Override
public int parseRawDescriptors(ByteStream stream) {
super.parseRawDescriptors(stream);

View File

@@ -71,6 +71,7 @@ public final class Usb20ACOutputTerminal extends UsbACTerminal {
super.report(canvas);
canvas.openList();
canvas.writeListItem("Source ID:" + getSourceID());
canvas.writeListItem("Clock Source ID: " + getClkSourceID());
canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
canvas.writeListItem("Terminal Name ID: " + getTerminalID());

View File

@@ -21,7 +21,7 @@ import com.android.server.usb.descriptors.report.ReportCanvas;
* Audio20.pdf - 4.9.2 Class-Specific AS Interface Descriptor
* 16 bytes
*/
public final class Usb20ASGeneral extends UsbACInterface {
public final class Usb20ASGeneral extends UsbACInterface implements UsbAudioChannelCluster {
private static final String TAG = "Usb20ASGeneral";
// Audio20.pdf - Table 4-27
@@ -61,14 +61,17 @@ public final class Usb20ASGeneral extends UsbACInterface {
return mFormats;
}
public byte getNumChannels() {
@Override
public byte getChannelCount() {
return mNumChannels;
}
@Override
public int getChannelConfig() {
return mChannelConfig;
}
@Override
public byte getChannelNames() {
return mChannelNames;
}
@@ -96,7 +99,7 @@ public final class Usb20ASGeneral extends UsbACInterface {
canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
canvas.writeListItem("Format Type: " + ReportCanvas.getHexString(getFormatType()));
canvas.writeListItem("Formats: " + ReportCanvas.getHexString(getFormats()));
canvas.writeListItem("Num Channels: " + getNumChannels());
canvas.writeListItem("Channel Count: " + getChannelCount());
canvas.writeListItem("Channel Config: " + ReportCanvas.getHexString(getChannelConfig()));
canvas.writeListItem("Channel Names String ID: " + getChannelNames());
canvas.closeList();

View File

@@ -66,6 +66,8 @@ public abstract class UsbACTerminal extends UsbACInterface {
canvas.writeListItem("Type: " + ReportCanvas.getHexString(terminalType) + ": "
+ UsbStrings.getTerminalName(terminalType));
canvas.writeListItem("ID: " + ReportCanvas.getHexString(getTerminalID()));
canvas.writeListItem("Associated terminal: "
+ ReportCanvas.getHexString(getAssocTerminal()));
canvas.closeList();
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 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.server.usb.descriptors;
/**
* @hide
* Group of logical audio channels that carry tightly related synchronous audio information.
* See Audio10.pdf section 3.7.2.3 Audio Channel Cluster format and Audio20.pdf section 3.13.1
* audio channel cluster.
*/
public interface UsbAudioChannelCluster {
/**
* @return logical channels in the cluster.
*/
byte getChannelCount();
/**
* @return a bit field that indicates which spatial locations are present in the cluster.
*/
int getChannelConfig();
/**
* @return index to a string descriptor that describes the spatial location of the first
* non-predefined logical channel in the cluster.
*/
byte getChannelNames();
}

View File

@@ -832,31 +832,47 @@ public final class UsbDescriptorParser {
return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
}
// TODO: Up/Downmix process descriptor is not yet parsed, which may affect the result here.
private int getMaximumChannelCount() {
int maxChannelCount = 0;
for (UsbDescriptor descriptor : mDescriptors) {
if (descriptor instanceof UsbAudioChannelCluster) {
maxChannelCount = Math.max(maxChannelCount,
((UsbAudioChannelCluster) descriptor).getChannelCount());
}
}
return maxChannelCount;
}
/**
* @hide
*/
public float getOutputHeadsetProbability() {
public float getOutputHeadsetLikelihood() {
if (hasMIDIInterface()) {
return 0.0f;
}
float probability = 0.0f;
float likelihood = 0.0f;
ArrayList<UsbDescriptor> acDescriptors;
// Look for a "speaker"
boolean hasSpeaker = false;
boolean hasAssociatedInputTerminal = false;
boolean hasHeadphoneOrHeadset = false;
acDescriptors =
getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
UsbACInterface.AUDIO_AUDIOCONTROL);
for (UsbDescriptor descriptor : acDescriptors) {
if (descriptor instanceof UsbACTerminal) {
UsbACTerminal outDescr = (UsbACTerminal) descriptor;
if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
|| outDescr.getTerminalType()
== UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
|| outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER) {
hasSpeaker = true;
break;
if (outDescr.getAssocTerminal() != 0x0) {
hasAssociatedInputTerminal = true;
}
} else if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
|| outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET) {
hasHeadphoneOrHeadset = true;
}
} else {
Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
@@ -864,15 +880,27 @@ public final class UsbDescriptorParser {
}
}
if (hasSpeaker) {
probability += 0.75f;
if (hasHeadphoneOrHeadset) {
likelihood += 0.75f;
} else if (hasSpeaker) {
// The device only reports output terminal as speaker. Try to figure out if the device
// is a headset or not by checking if it has associated input terminal and if multiple
// channels are supported or not.
likelihood += 0.5f;
if (hasAssociatedInputTerminal) {
likelihood += 0.25f;
}
if (getMaximumChannelCount() > 2) {
// When multiple channels are supported, it is less likely to be a headset.
likelihood -= 0.25f;
}
}
if (hasSpeaker && hasHIDInterface()) {
probability += 0.25f;
if ((hasHeadphoneOrHeadset || hasSpeaker) && hasHIDInterface()) {
likelihood += 0.25f;
}
return probability;
return likelihood;
}
/**
@@ -882,7 +910,7 @@ public final class UsbDescriptorParser {
* to count on the peripheral being a headset.
*/
public boolean isOutputHeadset() {
return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
return getOutputHeadsetLikelihood() >= OUT_HEADSET_TRIGGER;
}
/**