mirror of
https://github.com/danog/termux-api.git
synced 2024-11-30 04:19:20 +01:00
AudioAPI: updates for AudioTrack methods
There are several changes in the commit: 1. Use instance methods to get sample rate and buffer size info on Android N or above only instead of Android M, since both AudioAttributes.FLAG_LOW_LATENCY (256) and the implicitly used AudioFormat.SAMPLE_RATE_UNSPECIFIED (0) are available only since API 24 (N). 2. Use setPerformanceMode() on Android O, as FLAG_LOW_LATENCY is deprecated since API 26 (O). 3. Create AudioTrack instance of both the fast (LOW_LATENCY) and deep buffer (POWER_SAVING) mixer path. The two paths can be using different subdevices on different rate and buffer size (or same subdevice on same rate but different buffer size). For example on my phone: AUDIOTRACK_SAMPLE_RATE: 192000 AUDIOTRACK_BUFFER_SIZE_IN_FRAMES: 23046 AUDIOTRACK_SAMPLE_RATE_LOW_LATENCY: 48000 AUDIOTRACK_BUFFER_SIZE_IN_FRAMES_LOW_LATENCY: 192 4. Get info on sample rate with the getNativeOutputSampleRate() static method (static in Java's sense; the value is still sink- based) on builds older than N only. The rate appears to be of the fast (LOW_LATENCY) mixer path if it is available. 5. A note on the static method getMinBufferSize(). The reason it is not used even for older devices is, it returns buffer size info of the deep buffer (POWER_SAVING) mixer path, while NOSR is the rate of the fast (LOW_LATENCY) mixer path, so the value we can get with it is not always sensical.
This commit is contained in:
parent
299d55789b
commit
34c6841a05
@ -3,7 +3,6 @@ package com.termux.api;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.Build;
|
||||
@ -22,25 +21,53 @@ public class AudioAPI {
|
||||
final int maxvolume_level = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||||
final boolean bluetootha2dp = am.isBluetoothA2dpOn();
|
||||
final boolean wiredhs = am.isWiredHeadsetOn();
|
||||
final int nativeoutput = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
|
||||
int _bs = 0;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
AudioTrack at = new AudioTrack(
|
||||
new AudioAttributes.Builder()
|
||||
.setFlags(256) // FLAG_LOW_LATENCY
|
||||
.build(),
|
||||
new AudioFormat.Builder()
|
||||
.build(),
|
||||
4, // bytes; i.e. one 16bit 2ch frame
|
||||
AudioTrack.MODE_STREAM,
|
||||
AudioManager.AUDIO_SESSION_ID_GENERATE
|
||||
);
|
||||
_bs = at.getBufferSizeInFrames();
|
||||
//final int bc = at.getBufferCapacityInFrames(); only available api 24 and up and apparently
|
||||
// always returns same value as the initial getbuffersizeinframes.
|
||||
at.release();
|
||||
|
||||
int _sr, _bs, _sr_ll, _bs_ll, _nosr;
|
||||
_sr = _bs = _sr_ll = _bs_ll = _nosr = 0;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
int[] modes = {AudioTrack.PERFORMANCE_MODE_POWER_SAVING,
|
||||
AudioTrack.PERFORMANCE_MODE_LOW_LATENCY};
|
||||
for (int mode: modes) {
|
||||
AudioTrack at = new AudioTrack.Builder()
|
||||
.setBufferSizeInBytes(4) // one 16bit 2ch frame
|
||||
.setPerformanceMode(mode)
|
||||
.build();
|
||||
if (mode == AudioTrack.PERFORMANCE_MODE_POWER_SAVING) {
|
||||
_sr = at.getSampleRate();
|
||||
_bs = at.getBufferSizeInFrames();
|
||||
} else if (mode == AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) {
|
||||
_sr_ll = at.getSampleRate();
|
||||
_bs_ll = at.getBufferSizeInFrames();
|
||||
}
|
||||
at.release();
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
int[] flags = {0,AudioAttributes.FLAG_LOW_LATENCY};
|
||||
for (int flag: flags) {
|
||||
AudioAttributes aa = new AudioAttributes.Builder()
|
||||
.setFlags(flag)
|
||||
.build();
|
||||
AudioTrack at = new AudioTrack.Builder()
|
||||
.setAudioAttributes(aa)
|
||||
.setBufferSizeInBytes(4) // one 16bit 2ch frame
|
||||
.build();
|
||||
if (flag == 0) {
|
||||
_sr = at.getSampleRate();
|
||||
_bs = at.getBufferSizeInFrames();
|
||||
} else if (flag == AudioAttributes.FLAG_LOW_LATENCY) {
|
||||
_sr_ll = at.getSampleRate();
|
||||
_bs_ll = at.getBufferSizeInFrames();
|
||||
}
|
||||
at.release();
|
||||
}
|
||||
} else {
|
||||
_nosr = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
final int sr = _sr;
|
||||
final int bs = _bs;
|
||||
final int sr_ll = _sr_ll;
|
||||
final int bs_ll = _bs_ll;
|
||||
final int nosr = _nosr;
|
||||
|
||||
ResultReturner.returnData(apiReceiver, intent, new ResultReturner.ResultJsonWriter() {
|
||||
public void writeJson(JsonWriter out) throws Exception {
|
||||
@ -52,9 +79,15 @@ public class AudioAPI {
|
||||
out.name("STREAM_MUSIC_MAXVOLUME").value(maxvolume_level);
|
||||
out.name("BLUETOOTH_A2DP_IS_ON").value(bluetootha2dp);
|
||||
out.name("WIREDHEADSET_IS_CONNECTED").value(wiredhs);
|
||||
out.name("CURRENT_NATIVE_OUTPUT_SAMPLERATE").value(nativeoutput);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
out.name("AUDIOTRACK_NATIVE_OUTPUT_SAMPLE_RATE").value(nosr);
|
||||
}
|
||||
out.endObject();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user