[androiddebugbridge] Fix volume channel for android 11/12 (#13828)
* [androiddebugbridge] Fix volume channel for android 11/12 * [androiddebugbridge] Try get max volume level from device properties * [androiddebugbridge] Fixes reported code analysis * [androiddebugbridge] Fix comparison Signed-off-by: Miguel Álvarez <miguelwork92@gmail.com>
This commit is contained in:
parent
d777aa46c9
commit
3e068ed431
@ -50,6 +50,8 @@ You could customize the discovery process through the binding options.
|
|||||||
| refreshTime | int | Seconds between device status refreshes (default: 30) |
|
| refreshTime | int | Seconds between device status refreshes (default: 30) |
|
||||||
| timeout | int | Command timeout in seconds (default: 5) |
|
| timeout | int | Command timeout in seconds (default: 5) |
|
||||||
| recordDuration | int | Record input duration in seconds |
|
| recordDuration | int | Record input duration in seconds |
|
||||||
|
| deviceMaxVolume | int | Assumed max volume for devices with android versions that do not expose this value. |
|
||||||
|
| volumeSettingKey | String | Settings key for android versions where volume is gather using settings command (>=android 11). |
|
||||||
| mediaStateJSONConfig | String | Expects a JSON array. Allow to configure the media state detection method per app. Described in the following section |
|
| mediaStateJSONConfig | String | Expects a JSON array. Allow to configure the media state detection method per app. Described in the following section |
|
||||||
|
|
||||||
## Media State Detection
|
## Media State Detection
|
||||||
|
|||||||
@ -42,6 +42,14 @@ public class AndroidDebugBridgeConfiguration {
|
|||||||
* Record input duration in seconds.
|
* Record input duration in seconds.
|
||||||
*/
|
*/
|
||||||
public int recordDuration = 5;
|
public int recordDuration = 5;
|
||||||
|
/**
|
||||||
|
* Assumed max volume for devices with android versions that do not expose this value (>=android 11).
|
||||||
|
*/
|
||||||
|
public int deviceMaxVolume = 25;
|
||||||
|
/**
|
||||||
|
* Settings key for android versions where volume is gather using settings command (>=android 11).
|
||||||
|
*/
|
||||||
|
public String volumeSettingKey = "volume_music_hdmi";
|
||||||
/**
|
/**
|
||||||
* Configure media state detection behavior by package
|
* Configure media state detection behavior by package
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -97,22 +97,34 @@ public class AndroidDebugBridgeDevice {
|
|||||||
private int port = 5555;
|
private int port = 5555;
|
||||||
private int timeoutSec = 5;
|
private int timeoutSec = 5;
|
||||||
private int recordDuration;
|
private int recordDuration;
|
||||||
|
private @Nullable Integer maxVolumeLevel = null;
|
||||||
private @Nullable Socket socket;
|
private @Nullable Socket socket;
|
||||||
private @Nullable AdbConnection connection;
|
private @Nullable AdbConnection connection;
|
||||||
private @Nullable Future<String> commandFuture;
|
private @Nullable Future<String> commandFuture;
|
||||||
private int majorVersionNumber = 0;
|
private int majorVersionNumber = 0;
|
||||||
private int minorVersionNumber = 0;
|
private int minorVersionNumber = 0;
|
||||||
private int patchVersionNumber = 0;
|
private int patchVersionNumber = 0;
|
||||||
|
/**
|
||||||
|
* Assumed max volume for android versions that do not expose this value.
|
||||||
|
*/
|
||||||
|
private int deviceMaxVolume = 25;
|
||||||
|
private String volumeSettingKey = "volume_music_hdmi";
|
||||||
|
|
||||||
public AndroidDebugBridgeDevice(ScheduledExecutorService scheduler) {
|
public AndroidDebugBridgeDevice(ScheduledExecutorService scheduler) {
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configure(String ip, int port, int timeout, int recordDuration) {
|
public void configure(AndroidDebugBridgeConfiguration config) {
|
||||||
|
configureConnection(config.ip, config.port, config.timeout);
|
||||||
|
this.recordDuration = config.recordDuration;
|
||||||
|
this.volumeSettingKey = config.volumeSettingKey;
|
||||||
|
this.deviceMaxVolume = config.deviceMaxVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configureConnection(String ip, int port, int timeout) {
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.timeoutSec = timeout;
|
this.timeoutSec = timeout;
|
||||||
this.recordDuration = recordDuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendKeyEvent(String eventCode)
|
public void sendKeyEvent(String eventCode)
|
||||||
@ -291,7 +303,16 @@ public class AndroidDebugBridgeDevice {
|
|||||||
|
|
||||||
private void setVolume(int stream, int volume)
|
private void setVolume(int stream, int volume)
|
||||||
throws AndroidDebugBridgeDeviceException, InterruptedException, TimeoutException, ExecutionException {
|
throws AndroidDebugBridgeDeviceException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--set", String.valueOf(volume));
|
if (isAtLeastVersion(12)) {
|
||||||
|
runAdbShell("service", "call", "audio", "11", "i32", String.valueOf(stream), "i32", String.valueOf(volume),
|
||||||
|
"i32", "1");
|
||||||
|
} else if (isAtLeastVersion(11)) {
|
||||||
|
runAdbShell("service", "call", "audio", "10", "i32", String.valueOf(stream), "i32", String.valueOf(volume),
|
||||||
|
"i32", "1");
|
||||||
|
} else {
|
||||||
|
runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--set",
|
||||||
|
String.valueOf(volume));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getModel() throws AndroidDebugBridgeDeviceException, InterruptedException,
|
public String getModel() throws AndroidDebugBridgeDeviceException, InterruptedException,
|
||||||
@ -353,17 +374,32 @@ public class AndroidDebugBridgeDevice {
|
|||||||
|
|
||||||
private VolumeInfo getVolume(int stream) throws AndroidDebugBridgeDeviceException, InterruptedException,
|
private VolumeInfo getVolume(int stream) throws AndroidDebugBridgeDeviceException, InterruptedException,
|
||||||
AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException {
|
AndroidDebugBridgeDeviceReadException, TimeoutException, ExecutionException {
|
||||||
String volumeResp = runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--get", "|",
|
if (isAtLeastVersion(11)) {
|
||||||
"grep", "volume");
|
String volumeResp = runAdbShell("settings", "get", "system", volumeSettingKey);
|
||||||
Matcher matcher = VOLUME_PATTERN.matcher(volumeResp);
|
var maxVolumeLevel = this.maxVolumeLevel;
|
||||||
if (!matcher.find()) {
|
if (maxVolumeLevel == null) {
|
||||||
throw new AndroidDebugBridgeDeviceReadException("Unable to get volume info");
|
try {
|
||||||
|
maxVolumeLevel = Integer.parseInt(getDeviceProp("ro.config.media_vol_steps"));
|
||||||
|
this.maxVolumeLevel = maxVolumeLevel;
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
logger.debug("Max volume level not available, using 'deviceMaxVolume' config");
|
||||||
|
maxVolumeLevel = deviceMaxVolume;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new VolumeInfo(Integer.parseInt(volumeResp.replace("\n", "")), 0, maxVolumeLevel);
|
||||||
|
} else {
|
||||||
|
String volumeResp = runAdbShell("media", "volume", "--show", "--stream", String.valueOf(stream), "--get",
|
||||||
|
"|", "grep", "volume");
|
||||||
|
Matcher matcher = VOLUME_PATTERN.matcher(volumeResp);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
throw new AndroidDebugBridgeDeviceReadException("Unable to get volume info");
|
||||||
|
}
|
||||||
|
var volumeInfo = new VolumeInfo(Integer.parseInt(matcher.group("current")),
|
||||||
|
Integer.parseInt(matcher.group("min")), Integer.parseInt(matcher.group("max")));
|
||||||
|
logger.debug("Device {}:{} VolumeInfo: current {}, min {}, max {}", this.ip, this.port, volumeInfo.current,
|
||||||
|
volumeInfo.min, volumeInfo.max);
|
||||||
|
return volumeInfo;
|
||||||
}
|
}
|
||||||
var volumeInfo = new VolumeInfo(Integer.parseInt(matcher.group("current")),
|
|
||||||
Integer.parseInt(matcher.group("min")), Integer.parseInt(matcher.group("max")));
|
|
||||||
logger.debug("Device {}:{} VolumeInfo: current {}, min {}, max {}", this.ip, this.port, volumeInfo.current,
|
|
||||||
volumeInfo.min, volumeInfo.max);
|
|
||||||
return volumeInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String recordInputEvents()
|
public String recordInputEvents()
|
||||||
|
|||||||
@ -320,8 +320,7 @@ public class AndroidDebugBridgeHandler extends BaseThingHandler {
|
|||||||
if (mediaStateJSONConfig != null && !mediaStateJSONConfig.isEmpty()) {
|
if (mediaStateJSONConfig != null && !mediaStateJSONConfig.isEmpty()) {
|
||||||
loadMediaStateConfig(mediaStateJSONConfig);
|
loadMediaStateConfig(mediaStateJSONConfig);
|
||||||
}
|
}
|
||||||
adbConnection.configure(currentConfig.ip, currentConfig.port, currentConfig.timeout,
|
adbConnection.configure(currentConfig);
|
||||||
currentConfig.recordDuration);
|
|
||||||
var androidVersion = thing.getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION);
|
var androidVersion = thing.getProperties().get(Thing.PROPERTY_FIRMWARE_VERSION);
|
||||||
if (androidVersion != null) {
|
if (androidVersion != null) {
|
||||||
// configure android implementation to use
|
// configure android implementation to use
|
||||||
|
|||||||
@ -135,7 +135,7 @@ public class AndroidDebugBridgeDiscoveryService extends AbstractDiscoveryService
|
|||||||
throws InterruptedException, AndroidDebugBridgeDeviceException, AndroidDebugBridgeDeviceReadException,
|
throws InterruptedException, AndroidDebugBridgeDeviceException, AndroidDebugBridgeDeviceReadException,
|
||||||
TimeoutException, ExecutionException {
|
TimeoutException, ExecutionException {
|
||||||
var device = new AndroidDebugBridgeDevice(scheduler);
|
var device = new AndroidDebugBridgeDevice(scheduler);
|
||||||
device.configure(ip, port, 10, 0);
|
device.configureConnection(ip, port, 10);
|
||||||
try {
|
try {
|
||||||
device.connect();
|
device.connect();
|
||||||
logger.debug("connected adb at {}:{}", ip, port);
|
logger.debug("connected adb at {}:{}", ip, port);
|
||||||
|
|||||||
@ -34,8 +34,6 @@ import org.osgi.service.component.ComponentContext;
|
|||||||
import org.osgi.service.component.annotations.Activate;
|
import org.osgi.service.component.annotations.Activate;
|
||||||
import org.osgi.service.component.annotations.Component;
|
import org.osgi.service.component.annotations.Component;
|
||||||
import org.osgi.service.component.annotations.Modified;
|
import org.osgi.service.component.annotations.Modified;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link AndroidTVMDNSDiscoveryParticipant} is responsible for discovering new and removed Android TV devices. It
|
* The {@link AndroidTVMDNSDiscoveryParticipant} is responsible for discovering new and removed Android TV devices. It
|
||||||
@ -50,7 +48,6 @@ public class AndroidTVMDNSDiscoveryParticipant implements MDNSDiscoveryParticipa
|
|||||||
|
|
||||||
private static final String SERVICE_TYPE = "_androidtvremote2._tcp.local.";
|
private static final String SERVICE_TYPE = "_androidtvremote2._tcp.local.";
|
||||||
private static final String MDNS_PROPERTY_MAC_ADDRESS = "bt";
|
private static final String MDNS_PROPERTY_MAC_ADDRESS = "bt";
|
||||||
private final Logger logger = LoggerFactory.getLogger(AndroidTVMDNSDiscoveryParticipant.class);
|
|
||||||
|
|
||||||
private boolean isAutoDiscoveryEnabled = true;
|
private boolean isAutoDiscoveryEnabled = true;
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,8 @@ thing-type.androiddebugbridge.android.description = Android Device Thing for And
|
|||||||
|
|
||||||
# thing types config
|
# thing types config
|
||||||
|
|
||||||
|
thing-type.config.androiddebugbridge.android.deviceMaxVolume.label = Device Max Volume
|
||||||
|
thing-type.config.androiddebugbridge.android.deviceMaxVolume.description = Assumed max volume for devices with android versions that do not expose this value (>=android 11).
|
||||||
thing-type.config.androiddebugbridge.android.ip.label = IP Address
|
thing-type.config.androiddebugbridge.android.ip.label = IP Address
|
||||||
thing-type.config.androiddebugbridge.android.ip.description = Device ip address.
|
thing-type.config.androiddebugbridge.android.ip.description = Device ip address.
|
||||||
thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.label = Media State Config
|
thing-type.config.androiddebugbridge.android.mediaStateJSONConfig.label = Media State Config
|
||||||
@ -33,6 +35,16 @@ thing-type.config.androiddebugbridge.android.refreshTime.label = Refresh Time
|
|||||||
thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes.
|
thing-type.config.androiddebugbridge.android.refreshTime.description = Seconds between device status refreshes.
|
||||||
thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout
|
thing-type.config.androiddebugbridge.android.timeout.label = Command Timeout
|
||||||
thing-type.config.androiddebugbridge.android.timeout.description = Command timeout seconds.
|
thing-type.config.androiddebugbridge.android.timeout.description = Command timeout seconds.
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.label = Volume Setting Key
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.description = Settings key for android versions where the volume level is gathered using the 'settings' cli (>=android 11).
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_bluetooth_sco = volume bluetooth sco
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music = volume music
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_bt_a2dp = volume music bt a2dp
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_hdmi = volume music hdmi
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_headphone = volume music headphone
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_headset = volume music headset
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_music_usb_headset = volume music usb headset
|
||||||
|
thing-type.config.androiddebugbridge.android.volumeSettingKey.option.volume_system = volume system
|
||||||
|
|
||||||
# channel types
|
# channel types
|
||||||
|
|
||||||
|
|||||||
@ -58,6 +58,29 @@
|
|||||||
<description>JSON config that allows to modify the media state detection strategy for each app. Refer to the binding
|
<description>JSON config that allows to modify the media state detection strategy for each app. Refer to the binding
|
||||||
documentation.</description>
|
documentation.</description>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="volumeSettingKey" type="text">
|
||||||
|
<label>Volume Setting Key</label>
|
||||||
|
<description>Settings key for android versions where the volume level is gathered using the 'settings' cli
|
||||||
|
(>=android 11).</description>
|
||||||
|
<default>volume_music_hdmi</default>
|
||||||
|
<options>
|
||||||
|
<option value="volume_bluetooth_sco">volume bluetooth sco</option>
|
||||||
|
<option value="volume_music">volume music</option>
|
||||||
|
<option value="volume_music_bt_a2dp">volume music bt a2dp</option>
|
||||||
|
<option value="volume_music_hdmi">volume music hdmi</option>
|
||||||
|
<option value="volume_music_headphone">volume music headphone</option>
|
||||||
|
<option value="volume_music_headset">volume music headset</option>
|
||||||
|
<option value="volume_music_usb_headset">volume music usb headset</option>
|
||||||
|
<option value="volume_system">volume system</option>
|
||||||
|
</options>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="deviceMaxVolume" type="integer" min="1" max="100">
|
||||||
|
<label>Device Max Volume</label>
|
||||||
|
<description>Assumed max volume for devices with android versions that do not expose this value (>=android 11).</description>
|
||||||
|
<default>25</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</thing-type>
|
</thing-type>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user