Android audio device selection (#6824)
Make it possible to select a specific audio device for Androidmain
parent
b461d9e183
commit
abf5cc5203
|
@ -29,6 +29,7 @@ public class SDL {
|
||||||
|
|
||||||
// This function stores the current activity (SDL or not)
|
// This function stores the current activity (SDL or not)
|
||||||
public static void setContext(Context context) {
|
public static void setContext(Context context) {
|
||||||
|
SDLAudioManager.setContext(context);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,7 +393,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
mHIDDeviceManager = HIDDeviceManager.acquire(this);
|
mHIDDeviceManager = HIDDeviceManager.acquire(this);
|
||||||
|
|
||||||
// Set up the surface
|
// Set up the surface
|
||||||
mSurface = createSDLSurface(getApplication());
|
mSurface = createSDLSurface(this);
|
||||||
|
|
||||||
mLayout = new RelativeLayout(this);
|
mLayout = new RelativeLayout(this);
|
||||||
mLayout.addView(mSurface);
|
mLayout.addView(mSurface);
|
||||||
|
@ -588,6 +588,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
mHIDDeviceManager = null;
|
mHIDDeviceManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDLAudioManager.release(this);
|
||||||
|
|
||||||
if (SDLActivity.mBrokenLibraries) {
|
if (SDLActivity.mBrokenLibraries) {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package org.libsdl.app;
|
package org.libsdl.app;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.AudioDeviceCallback;
|
||||||
|
import android.media.AudioDeviceInfo;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.AudioRecord;
|
import android.media.AudioRecord;
|
||||||
|
@ -8,34 +11,59 @@ import android.media.MediaRecorder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class SDLAudioManager
|
import java.util.Arrays;
|
||||||
{
|
|
||||||
|
public class SDLAudioManager {
|
||||||
protected static final String TAG = "SDLAudio";
|
protected static final String TAG = "SDLAudio";
|
||||||
|
|
||||||
protected static AudioTrack mAudioTrack;
|
protected static AudioTrack mAudioTrack;
|
||||||
protected static AudioRecord mAudioRecord;
|
protected static AudioRecord mAudioRecord;
|
||||||
|
protected static Context mContext;
|
||||||
|
|
||||||
|
private static final AudioDeviceCallback mAudioDeviceCallback = new AudioDeviceCallback() {
|
||||||
|
@Override
|
||||||
|
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
|
||||||
|
Arrays.stream(addedDevices).forEach(deviceInfo -> addAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
|
||||||
|
Arrays.stream(removedDevices).forEach(deviceInfo -> removeAudioDevice(deviceInfo.isSink(), deviceInfo.getId()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
mAudioTrack = null;
|
mAudioTrack = null;
|
||||||
mAudioRecord = null;
|
mAudioRecord = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setContext(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
if (context != null) {
|
||||||
|
registerAudioDeviceCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void release(Context context) {
|
||||||
|
unregisterAudioDeviceCallback(context);
|
||||||
|
}
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
|
|
||||||
protected static String getAudioFormatString(int audioFormat) {
|
protected static String getAudioFormatString(int audioFormat) {
|
||||||
switch (audioFormat) {
|
switch (audioFormat) {
|
||||||
case AudioFormat.ENCODING_PCM_8BIT:
|
case AudioFormat.ENCODING_PCM_8BIT:
|
||||||
return "8-bit";
|
return "8-bit";
|
||||||
case AudioFormat.ENCODING_PCM_16BIT:
|
case AudioFormat.ENCODING_PCM_16BIT:
|
||||||
return "16-bit";
|
return "16-bit";
|
||||||
case AudioFormat.ENCODING_PCM_FLOAT:
|
case AudioFormat.ENCODING_PCM_FLOAT:
|
||||||
return "float";
|
return "float";
|
||||||
default:
|
default:
|
||||||
return Integer.toString(audioFormat);
|
return Integer.toString(audioFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||||
int channelConfig;
|
int channelConfig;
|
||||||
int sampleSize;
|
int sampleSize;
|
||||||
int frameSize;
|
int frameSize;
|
||||||
|
@ -201,6 +229,10 @@ public class SDLAudioManager
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceId != 0) {
|
||||||
|
mAudioRecord.setPreferredDevice(getOutputAudioDeviceInfo(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
mAudioRecord.startRecording();
|
mAudioRecord.startRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +256,10 @@ public class SDLAudioManager
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceId != 0) {
|
||||||
|
mAudioTrack.setPreferredDevice(getInputAudioDeviceInfo(deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
mAudioTrack.play();
|
mAudioTrack.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,11 +274,53 @@ public class SDLAudioManager
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static AudioDeviceInfo getInputAudioDeviceInfo(int deviceId) {
|
||||||
|
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
|
||||||
|
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AudioDeviceInfo getOutputAudioDeviceInfo(int deviceId) {
|
||||||
|
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
|
||||||
|
.filter(deviceInfo -> deviceInfo.getId() == deviceId)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerAudioDeviceCallback() {
|
||||||
|
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unregisterAudioDeviceCallback(Context context) {
|
||||||
|
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL using JNI.
|
* This method is called by SDL using JNI.
|
||||||
*/
|
*/
|
||||||
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
public static int[] getAudioOutputDevices() {
|
||||||
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
|
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by SDL using JNI.
|
||||||
|
*/
|
||||||
|
public static int[] getAudioInputDevices() {
|
||||||
|
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
return Arrays.stream(audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).mapToInt(AudioDeviceInfo::getId).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called by SDL using JNI.
|
||||||
|
*/
|
||||||
|
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||||
|
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -326,8 +404,8 @@ public class SDLAudioManager
|
||||||
/**
|
/**
|
||||||
* This method is called by SDL using JNI.
|
* This method is called by SDL using JNI.
|
||||||
*/
|
*/
|
||||||
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
|
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames, int deviceId) {
|
||||||
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
|
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames, deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is called by SDL using JNI. */
|
/** This method is called by SDL using JNI. */
|
||||||
|
@ -391,4 +469,9 @@ public class SDLAudioManager
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native int nativeSetupJNI();
|
public static native int nativeSetupJNI();
|
||||||
|
|
||||||
|
public static native void removeAudioDevice(boolean isCapture, int deviceId);
|
||||||
|
|
||||||
|
public static native void addAudioDevice(boolean isCapture, int deviceId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,7 +577,7 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface(SDL_Surface *surface,
|
||||||
* it might be easier to call but it doesn't have access to palette
|
* it might be easier to call but it doesn't have access to palette
|
||||||
* information for the destination surface, in case that would be important.
|
* information for the destination surface, in case that would be important.
|
||||||
*
|
*
|
||||||
* \param surface the existing SDL_Surface structure to convert
|
* \param src the existing SDL_Surface structure to convert
|
||||||
* \param pixel_format the SDL_PixelFormatEnum that the new surface is
|
* \param pixel_format the SDL_PixelFormatEnum that the new surface is
|
||||||
* optimized for
|
* optimized for
|
||||||
* \returns the new SDL_Surface structure that is created or NULL if it fails;
|
* \returns the new SDL_Surface structure that is created or NULL if it fails;
|
||||||
|
|
|
@ -68,6 +68,45 @@ void aaudio_errorCallback(AAudioStream *stream, void *userData, aaudio_result_t
|
||||||
|
|
||||||
#define LIB_AAUDIO_SO "libaaudio.so"
|
#define LIB_AAUDIO_SO "libaaudio.so"
|
||||||
|
|
||||||
|
static void aaudio_DetectDevices(void)
|
||||||
|
{
|
||||||
|
int *inputs;
|
||||||
|
inputs = SDL_malloc(sizeof(int) * 100);
|
||||||
|
SDL_zerop(inputs);
|
||||||
|
int inputs_length = 0;
|
||||||
|
|
||||||
|
Android_JNI_GetAudioInputDevices(inputs, &inputs_length);
|
||||||
|
|
||||||
|
for (int i = 0; i < inputs_length; ++i) {
|
||||||
|
int device_id = inputs[i];
|
||||||
|
int n = (int) (log10(device_id) + 1);
|
||||||
|
char device_name[n];
|
||||||
|
SDL_itoa(device_id, device_name, 10);
|
||||||
|
SDL_Log("Adding input device with name %s", device_name);
|
||||||
|
SDL_AddAudioDevice(SDL_FALSE, SDL_strdup(device_name), NULL, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(inputs);
|
||||||
|
|
||||||
|
int *outputs;
|
||||||
|
outputs = SDL_malloc(sizeof(int) * 100);
|
||||||
|
SDL_zerop(outputs);
|
||||||
|
int outputs_length = 0;
|
||||||
|
|
||||||
|
Android_JNI_GetAudioOutputDevices(outputs, &outputs_length);
|
||||||
|
|
||||||
|
for (int i = 0; i < outputs_length; ++i) {
|
||||||
|
int device_id = outputs[i];
|
||||||
|
int n = (int) (log10(device_id) + 1);
|
||||||
|
char device_name[n];
|
||||||
|
SDL_itoa(device_id, device_name, 10);
|
||||||
|
SDL_Log("Adding output device with name %s", device_name);
|
||||||
|
SDL_AddAudioDevice(SDL_TRUE, SDL_strdup(device_name), NULL, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(outputs);
|
||||||
|
}
|
||||||
|
|
||||||
static int aaudio_OpenDevice(_THIS, const char *devname)
|
static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private;
|
struct SDL_PrivateAudioData *private;
|
||||||
|
@ -99,6 +138,11 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, this->spec.freq);
|
ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, this->spec.freq);
|
||||||
ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, this->spec.channels);
|
ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, this->spec.channels);
|
||||||
|
if(devname != NULL) {
|
||||||
|
int aaudio_device_id = SDL_atoi(devname);
|
||||||
|
LOGI("Opening device id %d", aaudio_device_id);
|
||||||
|
ctx.AAudioStreamBuilder_setDeviceId(ctx.builder, aaudio_device_id);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||||
ctx.AAudioStreamBuilder_setDirection(ctx.builder, direction);
|
ctx.AAudioStreamBuilder_setDirection(ctx.builder, direction);
|
||||||
|
@ -298,17 +342,19 @@ static SDL_bool aaudio_Init(SDL_AudioDriverImpl *impl)
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl->DetectDevices = aaudio_DetectDevices;
|
||||||
impl->Deinitialize = aaudio_Deinitialize;
|
impl->Deinitialize = aaudio_Deinitialize;
|
||||||
impl->OpenDevice = aaudio_OpenDevice;
|
impl->OpenDevice = aaudio_OpenDevice;
|
||||||
impl->CloseDevice = aaudio_CloseDevice;
|
impl->CloseDevice = aaudio_CloseDevice;
|
||||||
impl->PlayDevice = aaudio_PlayDevice;
|
impl->PlayDevice = aaudio_PlayDevice;
|
||||||
impl->GetDeviceBuf = aaudio_GetDeviceBuf;
|
impl->GetDeviceBuf = aaudio_GetDeviceBuf;
|
||||||
impl->CaptureFromDevice = aaudio_CaptureFromDevice;
|
impl->CaptureFromDevice = aaudio_CaptureFromDevice;
|
||||||
|
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
|
||||||
|
|
||||||
/* and the capabilities */
|
/* and the capabilities */
|
||||||
impl->HasCaptureSupport = SDL_TRUE;
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
impl->OnlyHasDefaultOutputDevice = SDL_FALSE;
|
||||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
impl->OnlyHasDefaultCaptureDevice = SDL_FALSE;
|
||||||
|
|
||||||
/* this audio target is available. */
|
/* this audio target is available. */
|
||||||
LOGI("SDL aaudio_Init OK");
|
LOGI("SDL aaudio_Init OK");
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
SDL_PROC(const char *, AAudio_convertResultToText, (aaudio_result_t returnCode))
|
SDL_PROC(const char *, AAudio_convertResultToText, (aaudio_result_t returnCode))
|
||||||
SDL_PROC(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
|
SDL_PROC(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
|
||||||
SDL_PROC(aaudio_result_t, AAudio_createStreamBuilder, (AAudioStreamBuilder * *builder))
|
SDL_PROC(aaudio_result_t, AAudio_createStreamBuilder, (AAudioStreamBuilder * *builder))
|
||||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDeviceId, (AAudioStreamBuilder * builder, int32_t deviceId))
|
SDL_PROC(void, AAudioStreamBuilder_setDeviceId, (AAudioStreamBuilder * builder, int32_t deviceId))
|
||||||
SDL_PROC(void, AAudioStreamBuilder_setSampleRate, (AAudioStreamBuilder * builder, int32_t sampleRate))
|
SDL_PROC(void, AAudioStreamBuilder_setSampleRate, (AAudioStreamBuilder * builder, int32_t sampleRate))
|
||||||
SDL_PROC(void, AAudioStreamBuilder_setChannelCount, (AAudioStreamBuilder * builder, int32_t channelCount))
|
SDL_PROC(void, AAudioStreamBuilder_setChannelCount, (AAudioStreamBuilder * builder, int32_t channelCount))
|
||||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuilder * builder, int32_t samplesPerFrame))
|
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuilder * builder, int32_t samplesPerFrame))
|
||||||
|
|
|
@ -34,6 +34,44 @@
|
||||||
static SDL_AudioDevice *audioDevice = NULL;
|
static SDL_AudioDevice *audioDevice = NULL;
|
||||||
static SDL_AudioDevice *captureDevice = NULL;
|
static SDL_AudioDevice *captureDevice = NULL;
|
||||||
|
|
||||||
|
static void ANDROIDAUDIO_DetectDevices(void) {
|
||||||
|
int *inputs;
|
||||||
|
inputs = SDL_malloc(sizeof(int) * 100);
|
||||||
|
SDL_zerop(inputs);
|
||||||
|
int inputs_length = 0;
|
||||||
|
|
||||||
|
Android_JNI_GetAudioInputDevices(inputs, &inputs_length);
|
||||||
|
|
||||||
|
for (int i = 0; i < inputs_length; ++i) {
|
||||||
|
int device_id = inputs[i];
|
||||||
|
int n = (int) (log10(device_id) + 1);
|
||||||
|
char device_name[n];
|
||||||
|
SDL_itoa(device_id, device_name, 10);
|
||||||
|
SDL_Log("Adding input device with name %s", device_name);
|
||||||
|
SDL_AddAudioDevice(SDL_FALSE, SDL_strdup(device_name), NULL, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(inputs);
|
||||||
|
|
||||||
|
int *outputs;
|
||||||
|
outputs = SDL_malloc(sizeof(int) * 100);
|
||||||
|
SDL_zerop(outputs);
|
||||||
|
int outputs_length = 0;
|
||||||
|
|
||||||
|
Android_JNI_GetAudioOutputDevices(outputs, &outputs_length);
|
||||||
|
|
||||||
|
for (int i = 0; i < outputs_length; ++i) {
|
||||||
|
int device_id = outputs[i];
|
||||||
|
int n = (int) (log10(device_id) + 1);
|
||||||
|
char device_name[n];
|
||||||
|
SDL_itoa(device_id, device_name, 10);
|
||||||
|
SDL_Log("Adding output device with name %s", device_name);
|
||||||
|
SDL_AddAudioDevice(SDL_TRUE, SDL_strdup(device_name), NULL, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_free(outputs);
|
||||||
|
}
|
||||||
|
|
||||||
static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
|
@ -62,12 +100,18 @@ static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int audio_device_id = 0;
|
||||||
|
|
||||||
|
if(devname != NULL) {
|
||||||
|
audio_device_id = SDL_atoi(devname);
|
||||||
|
}
|
||||||
|
|
||||||
if (!test_format) {
|
if (!test_format) {
|
||||||
/* Didn't find a compatible format :( */
|
/* Didn't find a compatible format :( */
|
||||||
return SDL_SetError("%s: Unsupported audio format", "android");
|
return SDL_SetError("%s: Unsupported audio format", "android");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) {
|
if (Android_JNI_OpenAudioDevice(iscapture, audio_device_id, &this->spec) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,17 +159,19 @@ static void ANDROIDAUDIO_CloseDevice(_THIS)
|
||||||
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||||
{
|
{
|
||||||
/* Set the function pointers */
|
/* Set the function pointers */
|
||||||
|
impl->DetectDevices = ANDROIDAUDIO_DetectDevices;
|
||||||
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
|
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
|
||||||
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
|
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
|
||||||
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
|
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
|
||||||
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
|
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
|
||||||
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
|
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
|
||||||
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
|
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
|
||||||
|
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
|
||||||
|
|
||||||
/* and the capabilities */
|
/* and the capabilities */
|
||||||
impl->HasCaptureSupport = SDL_TRUE;
|
impl->HasCaptureSupport = SDL_TRUE;
|
||||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
impl->OnlyHasDefaultOutputDevice = SDL_FALSE;
|
||||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
impl->OnlyHasDefaultCaptureDevice = SDL_FALSE;
|
||||||
|
|
||||||
return SDL_TRUE; /* this audio target is available. */
|
return SDL_TRUE; /* this audio target is available. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,8 +213,18 @@ static JNINativeMethod SDLInputConnection_tab[] = {
|
||||||
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
|
JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
|
||||||
JNIEnv *env, jclass jcls);
|
JNIEnv *env, jclass jcls);
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||||
|
jint device_id);
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||||
|
jint device_id);
|
||||||
|
|
||||||
static JNINativeMethod SDLAudioManager_tab[] = {
|
static JNINativeMethod SDLAudioManager_tab[] = {
|
||||||
{ "nativeSetupJNI", "()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }
|
{ "nativeSetupJNI", "()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) },
|
||||||
|
{ "addAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(addAudioDevice) },
|
||||||
|
{ "removeAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice) }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Java class SDLControllerManager */
|
/* Java class SDLControllerManager */
|
||||||
|
@ -322,6 +332,8 @@ static jmethodID midSupportsRelativeMouse;
|
||||||
static jclass mAudioManagerClass;
|
static jclass mAudioManagerClass;
|
||||||
|
|
||||||
/* method signatures */
|
/* method signatures */
|
||||||
|
static jmethodID midGetAudioOutputDevices;
|
||||||
|
static jmethodID midGetAudioInputDevices;
|
||||||
static jmethodID midAudioOpen;
|
static jmethodID midAudioOpen;
|
||||||
static jmethodID midAudioWriteByteBuffer;
|
static jmethodID midAudioWriteByteBuffer;
|
||||||
static jmethodID midAudioWriteShortBuffer;
|
static jmethodID midAudioWriteShortBuffer;
|
||||||
|
@ -647,8 +659,14 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
|
||||||
|
|
||||||
mAudioManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
|
mAudioManagerClass = (jclass)((*env)->NewGlobalRef(env, cls));
|
||||||
|
|
||||||
|
midGetAudioOutputDevices = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
|
"getAudioOutputDevices",
|
||||||
|
"()[I");
|
||||||
|
midGetAudioInputDevices = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
|
"getAudioInputDevices",
|
||||||
|
"()[I");
|
||||||
midAudioOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midAudioOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"audioOpen", "(IIII)[I");
|
"audioOpen", "(IIIII)[I");
|
||||||
midAudioWriteByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midAudioWriteByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"audioWriteByteBuffer", "([B)V");
|
"audioWriteByteBuffer", "([B)V");
|
||||||
midAudioWriteShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midAudioWriteShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
|
@ -658,7 +676,7 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
|
||||||
midAudioClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midAudioClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"audioClose", "()V");
|
"audioClose", "()V");
|
||||||
midCaptureOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midCaptureOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"captureOpen", "(IIII)[I");
|
"captureOpen", "(IIIII)[I");
|
||||||
midCaptureReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midCaptureReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"captureReadByteBuffer", "([BZ)I");
|
"captureReadByteBuffer", "([BZ)I");
|
||||||
midCaptureReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midCaptureReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
|
@ -670,9 +688,13 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
|
||||||
midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||||
"audioSetThreadPriority", "(ZI)V");
|
"audioSetThreadPriority", "(ZI)V");
|
||||||
|
|
||||||
if (!midAudioOpen || !midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer || !midAudioClose ||
|
if (!midGetAudioOutputDevices || !midGetAudioInputDevices || !midAudioOpen ||
|
||||||
!midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer || !midCaptureReadFloatBuffer || !midCaptureClose || !midAudioSetThreadPriority) {
|
!midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer ||
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
|
!midAudioClose ||
|
||||||
|
!midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer ||
|
||||||
|
!midCaptureReadFloatBuffer || !midCaptureClose || !midAudioSetThreadPriority) {
|
||||||
|
__android_log_print(ANDROID_LOG_WARN, "SDL",
|
||||||
|
"Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
|
||||||
}
|
}
|
||||||
|
|
||||||
checkJNIReady();
|
checkJNIReady();
|
||||||
|
@ -903,6 +925,26 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)(
|
||||||
SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE);
|
SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle);
|
||||||
|
extern void SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle);
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||||
|
jint device_id) {
|
||||||
|
int n = (int) (log10(device_id) + 1);
|
||||||
|
char device_name[n];
|
||||||
|
SDL_itoa(device_id, device_name, 10);
|
||||||
|
SDL_Log("Adding device with name %s, capture %d", device_name, is_capture);
|
||||||
|
SDL_AddAudioDevice(is_capture, SDL_strdup(device_name), NULL, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||||
|
jint device_id) {
|
||||||
|
SDL_Log("Removing device with handle %d, capture %d", device_id + 1, is_capture);
|
||||||
|
SDL_RemoveAudioDevice(is_capture, (void *) ((size_t) device_id + 1));
|
||||||
|
}
|
||||||
|
|
||||||
/* Paddown */
|
/* Paddown */
|
||||||
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
|
JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
|
||||||
JNIEnv *env, jclass jcls,
|
JNIEnv *env, jclass jcls,
|
||||||
|
@ -1421,7 +1463,29 @@ static void *audioBufferPinned = NULL;
|
||||||
static int captureBufferFormat = 0;
|
static int captureBufferFormat = 0;
|
||||||
static jobject captureBuffer = NULL;
|
static jobject captureBuffer = NULL;
|
||||||
|
|
||||||
int Android_JNI_OpenAudioDevice(int iscapture, SDL_AudioSpec *spec)
|
void Android_JNI_GetAudioOutputDevices(int *devices, int *length) {
|
||||||
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
jintArray result;
|
||||||
|
|
||||||
|
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midGetAudioOutputDevices);
|
||||||
|
|
||||||
|
*length = (*env)->GetArrayLength(env, result);
|
||||||
|
|
||||||
|
(*env)->GetIntArrayRegion(env, result, 0, *length, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Android_JNI_GetAudioInputDevices(int * devices, int *length) {
|
||||||
|
JNIEnv *env = Android_JNI_GetEnv();
|
||||||
|
jintArray result;
|
||||||
|
|
||||||
|
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midGetAudioInputDevices);
|
||||||
|
|
||||||
|
*length = (*env)->GetArrayLength(env, result);
|
||||||
|
|
||||||
|
(*env)->GetIntArrayRegion(env, result, 0, *length, devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spec)
|
||||||
{
|
{
|
||||||
int audioformat;
|
int audioformat;
|
||||||
jobject jbufobj = NULL;
|
jobject jbufobj = NULL;
|
||||||
|
@ -1447,10 +1511,10 @@ int Android_JNI_OpenAudioDevice(int iscapture, SDL_AudioSpec *spec)
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
|
||||||
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midCaptureOpen, spec->freq, audioformat, spec->channels, spec->samples);
|
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midCaptureOpen, spec->freq, audioformat, spec->channels, spec->samples, device_id);
|
||||||
} else {
|
} else {
|
||||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
|
||||||
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, spec->samples);
|
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, spec->samples, device_id);
|
||||||
}
|
}
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
/* Error during audio initialization, error printed from Java */
|
/* Error during audio initialization, error printed from Java */
|
||||||
|
|
|
@ -47,7 +47,9 @@ extern SDL_DisplayOrientation Android_JNI_GetDisplayOrientation(void);
|
||||||
extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
|
extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
|
||||||
|
|
||||||
/* Audio support */
|
/* Audio support */
|
||||||
extern int Android_JNI_OpenAudioDevice(int iscapture, SDL_AudioSpec *spec);
|
extern void Android_JNI_GetAudioOutputDevices(int* devices, int *length);
|
||||||
|
extern void Android_JNI_GetAudioInputDevices(int* devices, int *length);
|
||||||
|
extern int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spec);
|
||||||
extern void *Android_JNI_GetAudioBuffer(void);
|
extern void *Android_JNI_GetAudioBuffer(void);
|
||||||
extern void Android_JNI_WriteAudioBuffer(void);
|
extern void Android_JNI_WriteAudioBuffer(void);
|
||||||
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
|
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
|
||||||
|
|
Loading…
Reference in New Issue