From b15a10ae2d9e8a0fdd82a61dc6f927fea49f65f5 Mon Sep 17 00:00:00 2001 From: Benjamin Loison Date: Sat, 7 Mar 2026 00:34:07 +0100 Subject: [PATCH] AudioAPI: add media key injection --- .../com/termux/api/TermuxApiReceiver.java | 1 + .../java/com/termux/api/apis/AudioAPI.java | 127 ++++++++++-------- 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/termux/api/TermuxApiReceiver.java b/app/src/main/java/com/termux/api/TermuxApiReceiver.java index b752864b..e4d056a7 100644 --- a/app/src/main/java/com/termux/api/TermuxApiReceiver.java +++ b/app/src/main/java/com/termux/api/TermuxApiReceiver.java @@ -85,6 +85,7 @@ private void doWork(Context context, Intent intent) { switch (apiMethod) { case "AudioInfo": + case "Audio": AudioAPI.onReceive(this, context, intent); break; case "BatteryStatus": diff --git a/app/src/main/java/com/termux/api/apis/AudioAPI.java b/app/src/main/java/com/termux/api/apis/AudioAPI.java index d69800b6..70095b48 100644 --- a/app/src/main/java/com/termux/api/apis/AudioAPI.java +++ b/app/src/main/java/com/termux/api/apis/AudioAPI.java @@ -12,6 +12,8 @@ import com.termux.api.util.ResultReturner; import com.termux.shared.logger.Logger; +import android.view.KeyEvent; + public class AudioAPI { private static final String LOG_TAG = "AudioAPI"; @@ -20,69 +22,76 @@ public static void onReceive(TermuxApiReceiver apiReceiver, final Context contex Logger.logDebug(LOG_TAG, "onReceive"); AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - final String SampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - final String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); - final boolean bluetootha2dp = am.isBluetoothA2dpOn(); - final boolean wiredhs = am.isWiredHeadsetOn(); - final int sr, bs, sr_ll, bs_ll, sr_ps, bs_ps; - AudioTrack at; - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .build(); - sr = at.getSampleRate(); - bs = at.getBufferSizeInFrames(); - at.release(); + ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { + public void writeJson(JsonWriter out) throws Exception { + if (!intent.hasExtra("media-key")) { + final String SampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + final String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER); + final boolean bluetootha2dp = am.isBluetoothA2dpOn(); + final boolean wiredhs = am.isWiredHeadsetOn(); + + final int sr, bs, sr_ll, bs_ll, sr_ps, bs_ps; + AudioTrack at; + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .build(); + sr = at.getSampleRate(); + bs = at.getBufferSizeInFrames(); + at.release(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) - .build(); - } else { - AudioAttributes aa = new AudioAttributes.Builder() - .setFlags(AudioAttributes.FLAG_LOW_LATENCY) - .build(); - at = new AudioTrack.Builder() - .setAudioAttributes(aa) - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .build(); - } - sr_ll = at.getSampleRate(); - bs_ll = at.getBufferSizeInFrames(); - at.release(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) + .build(); + } else { + AudioAttributes aa = new AudioAttributes.Builder() + .setFlags(AudioAttributes.FLAG_LOW_LATENCY) + .build(); + at = new AudioTrack.Builder() + .setAudioAttributes(aa) + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .build(); + } + sr_ll = at.getSampleRate(); + bs_ll = at.getBufferSizeInFrames(); + at.release(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - at = new AudioTrack.Builder() - .setBufferSizeInBytes(4) // one 16bit 2ch frame - .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_POWER_SAVING) - .build(); - sr_ps = at.getSampleRate(); - bs_ps = at.getBufferSizeInFrames(); - at.release(); - } else { - sr_ps = sr; - bs_ps = bs; - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + at = new AudioTrack.Builder() + .setBufferSizeInBytes(4) // one 16bit 2ch frame + .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_POWER_SAVING) + .build(); + sr_ps = at.getSampleRate(); + bs_ps = at.getBufferSizeInFrames(); + at.release(); + } else { + sr_ps = sr; + bs_ps = bs; + } - ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() { - public void writeJson(JsonWriter out) throws Exception { - out.beginObject(); - out.name("PROPERTY_OUTPUT_SAMPLE_RATE").value(SampleRate); - out.name("PROPERTY_OUTPUT_FRAMES_PER_BUFFER").value(framesPerBuffer); - out.name("AUDIOTRACK_SAMPLE_RATE").value(sr); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES").value(bs); - if (sr_ll != sr || bs_ll != bs) { // all or nothing - out.name("AUDIOTRACK_SAMPLE_RATE_LOW_LATENCY").value(sr_ll); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_LOW_LATENCY").value(bs_ll); - } - if (sr_ps != sr || bs_ps != bs) { // all or nothing - out.name("AUDIOTRACK_SAMPLE_RATE_POWER_SAVING").value(sr_ps); - out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_POWER_SAVING").value(bs_ps); - } - out.name("BLUETOOTH_A2DP_IS_ON").value(bluetootha2dp); - out.name("WIREDHEADSET_IS_CONNECTED").value(wiredhs); - out.endObject(); + out.beginObject(); + out.name("PROPERTY_OUTPUT_SAMPLE_RATE").value(SampleRate); + out.name("PROPERTY_OUTPUT_FRAMES_PER_BUFFER").value(framesPerBuffer); + out.name("AUDIOTRACK_SAMPLE_RATE").value(sr); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES").value(bs); + if (sr_ll != sr || bs_ll != bs) { // all or nothing + out.name("AUDIOTRACK_SAMPLE_RATE_LOW_LATENCY").value(sr_ll); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_LOW_LATENCY").value(bs_ll); + } + if (sr_ps != sr || bs_ps != bs) { // all or nothing + out.name("AUDIOTRACK_SAMPLE_RATE_POWER_SAVING").value(sr_ps); + out.name("AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_POWER_SAVING").value(bs_ps); + } + out.name("BLUETOOTH_A2DP_IS_ON").value(bluetootha2dp); + out.name("WIREDHEADSET_IS_CONNECTED").value(wiredhs); + out.endObject(); + } else { + int keyCode = (int)KeyEvent.class.getDeclaredField("KEYCODE_MEDIA_" + intent.getStringExtra("media-key").toUpperCase()).get(null); + am.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); + am.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode)); + } } }); }