audio: Refer to audio devices to "playback" and "recording".
Fixes #9619.
This commit is contained in:
@@ -226,7 +226,7 @@ static SDL_bool AudioDeviceCanUseSimpleCopy(SDL_AudioDevice *device)
|
||||
// should hold device->lock before calling.
|
||||
static void UpdateAudioStreamFormatsPhysical(SDL_AudioDevice *device)
|
||||
{
|
||||
if (!device->iscapture) { // for capture devices, we only want to move to float32 for postmix, which we'll handle elsewhere.
|
||||
if (!device->recording) { // for recording devices, we only want to move to float32 for postmix, which we'll handle elsewhere.
|
||||
const SDL_bool simple_copy = AudioDeviceCanUseSimpleCopy(device);
|
||||
SDL_AudioSpec spec;
|
||||
|
||||
@@ -273,14 +273,14 @@ static Uint8 *ZombieGetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->work_buffer;
|
||||
}
|
||||
|
||||
static int ZombieCaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int ZombieRecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
// return a full buffer of silence every time.
|
||||
SDL_memset(buffer, device->silence_value, buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void ZombieFlushCapture(SDL_AudioDevice *device)
|
||||
static void ZombieFlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
// no-op, this is all imaginary.
|
||||
}
|
||||
@@ -303,19 +303,19 @@ static void ZombieFlushCapture(SDL_AudioDevice *device)
|
||||
static void ClosePhysicalAudioDevice(SDL_AudioDevice *device);
|
||||
|
||||
|
||||
SDL_COMPILE_TIME_ASSERT(check_lowest_audio_default_value, SDL_AUDIO_DEVICE_DEFAULT_CAPTURE < SDL_AUDIO_DEVICE_DEFAULT_OUTPUT);
|
||||
SDL_COMPILE_TIME_ASSERT(check_lowest_audio_default_value, SDL_AUDIO_DEVICE_DEFAULT_RECORDING < SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK);
|
||||
|
||||
static SDL_AtomicInt last_device_instance_id; // increments on each device add to provide unique instance IDs
|
||||
static SDL_AudioDeviceID AssignAudioDeviceInstanceId(SDL_bool iscapture, SDL_bool islogical)
|
||||
static SDL_AudioDeviceID AssignAudioDeviceInstanceId(SDL_bool recording, SDL_bool islogical)
|
||||
{
|
||||
/* Assign an instance id! Start at 2, in case there are things from the SDL2 era that still think 1 is a special value.
|
||||
Also, make sure we don't assign SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, etc. */
|
||||
Also, make sure we don't assign SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, etc. */
|
||||
|
||||
// The bottom two bits of the instance id tells you if it's an output device (1<<0), and if it's a physical device (1<<1).
|
||||
const SDL_AudioDeviceID flags = (iscapture ? 0 : (1<<0)) | (islogical ? 0 : (1<<1));
|
||||
// The bottom two bits of the instance id tells you if it's an playback device (1<<0), and if it's a physical device (1<<1).
|
||||
const SDL_AudioDeviceID flags = (recording ? 0 : (1<<0)) | (islogical ? 0 : (1<<1));
|
||||
|
||||
const SDL_AudioDeviceID instance_id = (((SDL_AudioDeviceID) (SDL_AtomicIncRef(&last_device_instance_id) + 1)) << 2) | flags;
|
||||
SDL_assert( (instance_id >= 2) && (instance_id < SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) );
|
||||
SDL_assert( (instance_id >= 2) && (instance_id < SDL_AUDIO_DEVICE_DEFAULT_RECORDING) );
|
||||
return instance_id;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
|
||||
|
||||
static SDL_AudioDevice *ObtainPhysicalAudioDeviceDefaultAllowed(SDL_AudioDeviceID devid) // !!! FIXME: SDL_ACQUIRE
|
||||
{
|
||||
const SDL_bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) || (devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE));
|
||||
const SDL_bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) || (devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING));
|
||||
if (!wants_default) {
|
||||
return ObtainPhysicalAudioDevice(devid);
|
||||
}
|
||||
@@ -427,10 +427,10 @@ static SDL_AudioDevice *ObtainPhysicalAudioDeviceDefaultAllowed(SDL_AudioDeviceI
|
||||
|
||||
while (SDL_TRUE) {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) {
|
||||
devid = current_audio.default_output_device_id;
|
||||
} else if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) {
|
||||
devid = current_audio.default_capture_device_id;
|
||||
if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) {
|
||||
devid = current_audio.default_playback_device_id;
|
||||
} else if (orig_devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING) {
|
||||
devid = current_audio.default_recording_device_id;
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
@@ -447,9 +447,9 @@ static SDL_AudioDevice *ObtainPhysicalAudioDeviceDefaultAllowed(SDL_AudioDeviceI
|
||||
// make sure the default didn't change while we were waiting for the lock...
|
||||
SDL_bool got_it = SDL_FALSE;
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) && (devid == current_audio.default_output_device_id)) {
|
||||
if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) && (devid == current_audio.default_playback_device_id)) {
|
||||
got_it = SDL_TRUE;
|
||||
} else if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) && (devid == current_audio.default_capture_device_id)) {
|
||||
} else if ((orig_devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING) && (devid == current_audio.default_recording_device_id)) {
|
||||
got_it = SDL_TRUE;
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -534,7 +534,7 @@ void UnrefPhysicalAudioDevice(SDL_AudioDevice *device)
|
||||
// take it out of the device list.
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
if (SDL_RemoveFromHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id)) {
|
||||
SDL_AtomicAdd(device->iscapture ? ¤t_audio.capture_device_count : ¤t_audio.output_device_count, -1);
|
||||
SDL_AtomicAdd(device->recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count, -1);
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
DestroyPhysicalAudioDevice(device); // ...and nuke it.
|
||||
@@ -546,7 +546,7 @@ void RefPhysicalAudioDevice(SDL_AudioDevice *device)
|
||||
SDL_AtomicIncRef(&device->refcount);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool iscapture, const SDL_AudioSpec *spec, void *handle, SDL_AtomicInt *device_count)
|
||||
static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool recording, const SDL_AudioSpec *spec, void *handle, SDL_AtomicInt *device_count)
|
||||
{
|
||||
SDL_assert(name != NULL);
|
||||
|
||||
@@ -585,14 +585,14 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool isc
|
||||
|
||||
SDL_AtomicSet(&device->shutdown, 0);
|
||||
SDL_AtomicSet(&device->zombie, 0);
|
||||
device->iscapture = iscapture;
|
||||
device->recording = recording;
|
||||
SDL_copyp(&device->spec, spec);
|
||||
SDL_copyp(&device->default_spec, spec);
|
||||
device->sample_frames = GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format);
|
||||
device->handle = handle;
|
||||
|
||||
device->instance_id = AssignAudioDeviceInstanceId(iscapture, /*islogical=*/SDL_FALSE);
|
||||
device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/SDL_FALSE);
|
||||
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
|
||||
@@ -610,26 +610,26 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool isc
|
||||
return device;
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *CreateAudioCaptureDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
|
||||
static SDL_AudioDevice *CreateAudioRecordingDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
|
||||
{
|
||||
SDL_assert(current_audio.impl.HasCaptureSupport);
|
||||
return CreatePhysicalAudioDevice(name, SDL_TRUE, spec, handle, ¤t_audio.capture_device_count);
|
||||
SDL_assert(current_audio.impl.HasRecordingSupport);
|
||||
return CreatePhysicalAudioDevice(name, SDL_TRUE, spec, handle, ¤t_audio.recording_device_count);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *CreateAudioOutputDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
|
||||
static SDL_AudioDevice *CreateAudioPlaybackDevice(const char *name, const SDL_AudioSpec *spec, void *handle)
|
||||
{
|
||||
return CreatePhysicalAudioDevice(name, SDL_FALSE, spec, handle, ¤t_audio.output_device_count);
|
||||
return CreatePhysicalAudioDevice(name, SDL_FALSE, spec, handle, ¤t_audio.playback_device_count);
|
||||
}
|
||||
|
||||
// The audio backends call this when a new device is plugged in.
|
||||
SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, const SDL_AudioSpec *inspec, void *handle)
|
||||
SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool recording, const char *name, const SDL_AudioSpec *inspec, void *handle)
|
||||
{
|
||||
// device handles MUST be unique! If the target reuses the same handle for hardware with both input and output interfaces, wrap it in a pointer you SDL_malloc'd!
|
||||
// device handles MUST be unique! If the target reuses the same handle for hardware with both recording and playback interfaces, wrap it in a pointer you SDL_malloc'd!
|
||||
SDL_assert(SDL_FindPhysicalAudioDeviceByHandle(handle) == NULL);
|
||||
|
||||
const SDL_AudioFormat default_format = iscapture ? DEFAULT_AUDIO_CAPTURE_FORMAT : DEFAULT_AUDIO_OUTPUT_FORMAT;
|
||||
const int default_channels = iscapture ? DEFAULT_AUDIO_CAPTURE_CHANNELS : DEFAULT_AUDIO_OUTPUT_CHANNELS;
|
||||
const int default_freq = iscapture ? DEFAULT_AUDIO_CAPTURE_FREQUENCY : DEFAULT_AUDIO_OUTPUT_FREQUENCY;
|
||||
const SDL_AudioFormat default_format = recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int default_channels = recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int default_freq = recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
if (!inspec) {
|
||||
@@ -642,7 +642,7 @@ SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name,
|
||||
spec.freq = (inspec->freq != 0) ? inspec->freq : default_freq;
|
||||
}
|
||||
|
||||
SDL_AudioDevice *device = iscapture ? CreateAudioCaptureDevice(name, &spec, handle) : CreateAudioOutputDevice(name, &spec, handle);
|
||||
SDL_AudioDevice *device = recording ? CreateAudioRecordingDevice(name, &spec, handle) : CreateAudioPlaybackDevice(name, &spec, handle);
|
||||
|
||||
// Add a device add event to the pending list, to be pushed when the event queue is pumped (away from any of our internal threads).
|
||||
if (device) {
|
||||
@@ -682,7 +682,7 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
const SDL_AudioDeviceID devid = device->instance_id;
|
||||
const SDL_bool is_default_device = ((devid == current_audio.default_output_device_id) || (devid == current_audio.default_capture_device_id));
|
||||
const SDL_bool is_default_device = ((devid == current_audio.default_playback_device_id) || (devid == current_audio.default_recording_device_id));
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
const SDL_bool first_disconnect = SDL_AtomicCompareAndSwap(&device->zombie, 0, 1);
|
||||
@@ -694,9 +694,9 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
device->WaitDevice = ZombieWaitDevice;
|
||||
device->GetDeviceBuf = ZombieGetDeviceBuf;
|
||||
device->PlayDevice = ZombiePlayDevice;
|
||||
device->WaitCaptureDevice = ZombieWaitDevice;
|
||||
device->CaptureFromDevice = ZombieCaptureFromDevice;
|
||||
device->FlushCapture = ZombieFlushCapture;
|
||||
device->WaitRecordingDevice = ZombieWaitDevice;
|
||||
device->RecordDevice = ZombieRecordDevice;
|
||||
device->FlushRecording = ZombieFlushRecording;
|
||||
|
||||
// on default devices, dump any logical devices that explicitly opened this device. Things that opened the system default can stay.
|
||||
// on non-default devices, dump everything.
|
||||
@@ -746,8 +746,8 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
|
||||
static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static int SDL_AudioWaitDevice_Default(SDL_AudioDevice *device) { return 0; /* no-op. */ }
|
||||
static int SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size) { return 0; /* no-op. */ }
|
||||
static int SDL_AudioWaitCaptureDevice_Default(SDL_AudioDevice *device) { return 0; /* no-op. */ }
|
||||
static void SDL_AudioFlushCapture_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static int SDL_AudioWaitRecordingDevice_Default(SDL_AudioDevice *device) { return 0; /* no-op. */ }
|
||||
static void SDL_AudioFlushRecording_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
|
||||
static void SDL_AudioDeinitializeStart_Default(void) { /* no-op. */ }
|
||||
static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ }
|
||||
@@ -755,18 +755,18 @@ static void SDL_AudioFreeDeviceHandle_Default(SDL_AudioDevice *device) { /* no-o
|
||||
|
||||
static void SDL_AudioThreadInit_Default(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
SDL_SetThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
|
||||
static void SDL_AudioDetectDevices_Default(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void SDL_AudioDetectDevices_Default(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
// you have to write your own implementation if these assertions fail.
|
||||
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
|
||||
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
|
||||
SDL_assert(current_audio.impl.OnlyHasDefaultPlaybackDevice);
|
||||
SDL_assert(current_audio.impl.OnlyHasDefaultRecordingDevice || !current_audio.impl.HasRecordingSupport);
|
||||
|
||||
*default_output = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)((size_t)0x1));
|
||||
if (current_audio.impl.HasCaptureSupport) {
|
||||
*default_capture = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)((size_t)0x2));
|
||||
*default_playback = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_PLAYBACK_DEVNAME, NULL, (void *)((size_t)0x1));
|
||||
if (current_audio.impl.HasRecordingSupport) {
|
||||
*default_recording = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_RECORDING_DEVNAME, NULL, (void *)((size_t)0x2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,7 +776,7 @@ static Uint8 *SDL_AudioGetDeviceBuf_Default(SDL_AudioDevice *device, int *buffer
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int SDL_AudioCaptureFromDevice_Default(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int SDL_AudioRecordDevice_Default(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
@@ -797,9 +797,9 @@ static void CompleteAudioEntryPoints(void)
|
||||
FILL_STUB(WaitDevice);
|
||||
FILL_STUB(PlayDevice);
|
||||
FILL_STUB(GetDeviceBuf);
|
||||
FILL_STUB(WaitCaptureDevice);
|
||||
FILL_STUB(CaptureFromDevice);
|
||||
FILL_STUB(FlushCapture);
|
||||
FILL_STUB(WaitRecordingDevice);
|
||||
FILL_STUB(RecordDevice);
|
||||
FILL_STUB(FlushRecording);
|
||||
FILL_STUB(CloseDevice);
|
||||
FILL_STUB(FreeDeviceHandle);
|
||||
FILL_STUB(DeinitializeStart);
|
||||
@@ -807,9 +807,9 @@ static void CompleteAudioEntryPoints(void)
|
||||
#undef FILL_STUB
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const SDL_bool iscapture)
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const SDL_bool recording)
|
||||
{
|
||||
SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_OUTPUT; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
SDL_AudioDevice *retval = NULL;
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
@@ -820,11 +820,11 @@ static SDL_AudioDevice *GetFirstAddedAudioDevice(const SDL_bool iscapture)
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for output devices and unset for capture.
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_bool devid_iscapture = !(devid & (1 << 0));
|
||||
const SDL_bool devid_recording = !(devid & (1 << 0));
|
||||
const SDL_bool isphysical = (devid & (1 << 1));
|
||||
if (isphysical && (devid_iscapture == iscapture) && (devid < highest)) {
|
||||
if (isphysical && (devid_recording == recording) && (devid < highest)) {
|
||||
highest = devid;
|
||||
retval = (SDL_AudioDevice *) value;
|
||||
}
|
||||
@@ -837,7 +837,7 @@ static SDL_AudioDevice *GetFirstAddedAudioDevice(const SDL_bool iscapture)
|
||||
static Uint32 HashAudioDeviceID(const void *key, void *data)
|
||||
{
|
||||
// shift right 2, to dump the first two bits, since these are flags
|
||||
// (capture vs playback, logical vs physical) and the rest are unique incrementing integers.
|
||||
// (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
|
||||
return ((Uint32) ((uintptr_t) key)) >> 2;
|
||||
}
|
||||
|
||||
@@ -964,27 +964,27 @@ int SDL_InitAudio(const char *driver_name)
|
||||
CompleteAudioEntryPoints();
|
||||
|
||||
// Make sure we have a list of devices available at startup...
|
||||
SDL_AudioDevice *default_output = NULL;
|
||||
SDL_AudioDevice *default_capture = NULL;
|
||||
current_audio.impl.DetectDevices(&default_output, &default_capture);
|
||||
SDL_AudioDevice *default_playback = NULL;
|
||||
SDL_AudioDevice *default_recording = NULL;
|
||||
current_audio.impl.DetectDevices(&default_playback, &default_recording);
|
||||
|
||||
// If no default was _ever_ specified, just take the first device we see, if any.
|
||||
if (!default_output) {
|
||||
default_output = GetFirstAddedAudioDevice(/*iscapture=*/SDL_FALSE);
|
||||
if (!default_playback) {
|
||||
default_playback = GetFirstAddedAudioDevice(/*recording=*/SDL_FALSE);
|
||||
}
|
||||
|
||||
if (!default_capture) {
|
||||
default_capture = GetFirstAddedAudioDevice(/*iscapture=*/SDL_TRUE);
|
||||
if (!default_recording) {
|
||||
default_recording = GetFirstAddedAudioDevice(/*recording=*/SDL_TRUE);
|
||||
}
|
||||
|
||||
if (default_output) {
|
||||
current_audio.default_output_device_id = default_output->instance_id;
|
||||
RefPhysicalAudioDevice(default_output); // extra ref on default devices.
|
||||
if (default_playback) {
|
||||
current_audio.default_playback_device_id = default_playback->instance_id;
|
||||
RefPhysicalAudioDevice(default_playback); // extra ref on default devices.
|
||||
}
|
||||
|
||||
if (default_capture) {
|
||||
current_audio.default_capture_device_id = default_capture->instance_id;
|
||||
RefPhysicalAudioDevice(default_capture); // extra ref on default devices.
|
||||
if (default_recording) {
|
||||
current_audio.default_recording_device_id = default_recording->instance_id;
|
||||
RefPhysicalAudioDevice(default_recording); // extra ref on default devices.
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1009,8 +1009,8 @@ void SDL_QuitAudio(void)
|
||||
current_audio.device_hash = NULL;
|
||||
SDL_PendingAudioDeviceEvent *pending_events = current_audio.pending_events.next;
|
||||
current_audio.pending_events.next = NULL;
|
||||
SDL_AtomicSet(¤t_audio.output_device_count, 0);
|
||||
SDL_AtomicSet(¤t_audio.capture_device_count, 0);
|
||||
SDL_AtomicSet(¤t_audio.playback_device_count, 0);
|
||||
SDL_AtomicSet(¤t_audio.recording_device_count, 0);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
SDL_PendingAudioDeviceEvent *pending_next = NULL;
|
||||
@@ -1053,17 +1053,17 @@ static void MixFloat32Audio(float *dst, const float *src, const int buffer_size)
|
||||
}
|
||||
|
||||
|
||||
// Output device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
|
||||
// Playback device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
|
||||
|
||||
void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device)
|
||||
void SDL_PlaybackAudioThreadSetup(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(!device->iscapture);
|
||||
SDL_assert(!device->recording);
|
||||
current_audio.impl.ThreadInit(device);
|
||||
}
|
||||
|
||||
SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device)
|
||||
SDL_bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(!device->iscapture);
|
||||
SDL_assert(!device->recording);
|
||||
|
||||
SDL_LockMutex(device->lock);
|
||||
|
||||
@@ -1171,9 +1171,9 @@ SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device)
|
||||
return SDL_TRUE; // always go on if not shutting down, even if device failed.
|
||||
}
|
||||
|
||||
void SDL_OutputAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
void SDL_PlaybackAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(!device->iscapture);
|
||||
SDL_assert(!device->recording);
|
||||
const int frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
// Wait for the audio to drain if device didn't die.
|
||||
if (!SDL_AtomicGet(&device->zombie)) {
|
||||
@@ -1183,36 +1183,36 @@ void SDL_OutputAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
SDL_AudioThreadFinalize(device);
|
||||
}
|
||||
|
||||
static int SDLCALL OutputAudioThread(void *devicep) // thread entry point
|
||||
static int SDLCALL PlaybackAudioThread(void *devicep) // thread entry point
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
|
||||
SDL_assert(device != NULL);
|
||||
SDL_assert(!device->iscapture);
|
||||
SDL_OutputAudioThreadSetup(device);
|
||||
SDL_assert(!device->recording);
|
||||
SDL_PlaybackAudioThreadSetup(device);
|
||||
|
||||
do {
|
||||
if (device->WaitDevice(device) < 0) {
|
||||
SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
|
||||
}
|
||||
} while (SDL_OutputAudioThreadIterate(device));
|
||||
} while (SDL_PlaybackAudioThreadIterate(device));
|
||||
|
||||
SDL_OutputAudioThreadShutdown(device);
|
||||
SDL_PlaybackAudioThreadShutdown(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Capture device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
|
||||
// Recording device thread. This is split into chunks, so backends that need to control this directly can use the pieces they need without duplicating effort.
|
||||
|
||||
void SDL_CaptureAudioThreadSetup(SDL_AudioDevice *device)
|
||||
void SDL_RecordingAudioThreadSetup(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(device->iscapture);
|
||||
SDL_assert(device->recording);
|
||||
current_audio.impl.ThreadInit(device);
|
||||
}
|
||||
|
||||
SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device)
|
||||
SDL_bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(device->iscapture);
|
||||
SDL_assert(device->recording);
|
||||
|
||||
SDL_LockMutex(device->lock);
|
||||
|
||||
@@ -1224,10 +1224,10 @@ SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device)
|
||||
SDL_bool failed = SDL_FALSE;
|
||||
|
||||
if (!device->logical_devices) {
|
||||
device->FlushCapture(device); // nothing wants data, dump anything pending.
|
||||
device->FlushRecording(device); // nothing wants data, dump anything pending.
|
||||
} else {
|
||||
// this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitCaptureDevice!
|
||||
int br = device->CaptureFromDevice(device, device->work_buffer, device->buffer_size);
|
||||
// this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitRecordingDevice!
|
||||
int br = device->RecordDevice(device, device->work_buffer, device->buffer_size);
|
||||
if (br < 0) { // uhoh, device failed for some reason!
|
||||
failed = SDL_TRUE;
|
||||
} else if (br > 0) { // queue the new data to each bound stream.
|
||||
@@ -1238,7 +1238,7 @@ SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device)
|
||||
|
||||
void *output_buffer = device->work_buffer;
|
||||
|
||||
// I don't know why someone would want a postmix on a capture device, but we offer it for API consistency.
|
||||
// I don't know why someone would want a postmix on a recording device, but we offer it for API consistency.
|
||||
if (logdev->postmix) {
|
||||
// move to float format.
|
||||
SDL_AudioSpec outspec;
|
||||
@@ -1281,33 +1281,33 @@ SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device)
|
||||
return SDL_TRUE; // always go on if not shutting down, even if device failed.
|
||||
}
|
||||
|
||||
void SDL_CaptureAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
void SDL_RecordingAudioThreadShutdown(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_assert(device->iscapture);
|
||||
device->FlushCapture(device);
|
||||
SDL_assert(device->recording);
|
||||
device->FlushRecording(device);
|
||||
current_audio.impl.ThreadDeinit(device);
|
||||
SDL_AudioThreadFinalize(device);
|
||||
}
|
||||
|
||||
static int SDLCALL CaptureAudioThread(void *devicep) // thread entry point
|
||||
static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)devicep;
|
||||
SDL_assert(device != NULL);
|
||||
SDL_assert(device->iscapture);
|
||||
SDL_CaptureAudioThreadSetup(device);
|
||||
SDL_assert(device->recording);
|
||||
SDL_RecordingAudioThreadSetup(device);
|
||||
|
||||
do {
|
||||
if (device->WaitCaptureDevice(device) < 0) {
|
||||
if (device->WaitRecordingDevice(device) < 0) {
|
||||
SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
|
||||
}
|
||||
} while (SDL_CaptureAudioThreadIterate(device));
|
||||
} while (SDL_RecordingAudioThreadIterate(device));
|
||||
|
||||
SDL_CaptureAudioThreadShutdown(device);
|
||||
SDL_RecordingAudioThreadShutdown(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static SDL_AudioDeviceID *GetAudioDevices(int *count, SDL_bool iscapture)
|
||||
static SDL_AudioDeviceID *GetAudioDevices(int *count, SDL_bool recording)
|
||||
{
|
||||
SDL_AudioDeviceID *retval = NULL;
|
||||
int num_devices = 0;
|
||||
@@ -1315,7 +1315,7 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, SDL_bool iscapture)
|
||||
if (SDL_GetCurrentAudioDriver()) {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
{
|
||||
num_devices = SDL_AtomicGet(iscapture ? ¤t_audio.capture_device_count : ¤t_audio.output_device_count);
|
||||
num_devices = SDL_AtomicGet(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count);
|
||||
retval = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
|
||||
if (retval) {
|
||||
int devs_seen = 0;
|
||||
@@ -1324,11 +1324,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, SDL_bool iscapture)
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #0 of devid is set for output devices and unset for capture.
|
||||
// bit #0 of devid is set for playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_bool devid_iscapture = !(devid & (1<<0));
|
||||
const SDL_bool devid_recording = !(devid & (1<<0));
|
||||
const SDL_bool isphysical = (devid & (1<<1));
|
||||
if (isphysical && (devid_iscapture == iscapture)) {
|
||||
if (isphysical && (devid_recording == recording)) {
|
||||
SDL_assert(devs_seen < num_devices);
|
||||
retval[devs_seen++] = devid;
|
||||
}
|
||||
@@ -1353,12 +1353,12 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, SDL_bool iscapture)
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_AudioDeviceID *SDL_GetAudioOutputDevices(int *count)
|
||||
SDL_AudioDeviceID *SDL_GetAudioPlaybackDevices(int *count)
|
||||
{
|
||||
return GetAudioDevices(count, SDL_FALSE);
|
||||
}
|
||||
|
||||
SDL_AudioDeviceID *SDL_GetAudioCaptureDevices(int *count)
|
||||
SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count)
|
||||
{
|
||||
return GetAudioDevices(count, SDL_TRUE);
|
||||
}
|
||||
@@ -1527,10 +1527,10 @@ static SDL_AudioFormat ParseAudioFormatString(const char *string)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PrepareAudioFormat(SDL_bool iscapture, SDL_AudioSpec *spec)
|
||||
static void PrepareAudioFormat(SDL_bool recording, SDL_AudioSpec *spec)
|
||||
{
|
||||
if (spec->freq == 0) {
|
||||
spec->freq = iscapture ? DEFAULT_AUDIO_CAPTURE_FREQUENCY : DEFAULT_AUDIO_OUTPUT_FREQUENCY;
|
||||
spec->freq = recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
const char *env = SDL_getenv("SDL_AUDIO_FREQUENCY"); // !!! FIXME: should be a hint?
|
||||
if (env) {
|
||||
@@ -1542,7 +1542,7 @@ static void PrepareAudioFormat(SDL_bool iscapture, SDL_AudioSpec *spec)
|
||||
}
|
||||
|
||||
if (spec->channels == 0) {
|
||||
spec->channels = iscapture ? DEFAULT_AUDIO_CAPTURE_CHANNELS : DEFAULT_AUDIO_OUTPUT_CHANNELS;;
|
||||
spec->channels = recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;;
|
||||
const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
|
||||
if (env) {
|
||||
const int val = SDL_atoi(env);
|
||||
@@ -1554,7 +1554,7 @@ static void PrepareAudioFormat(SDL_bool iscapture, SDL_AudioSpec *spec)
|
||||
|
||||
if (spec->format == 0) {
|
||||
const SDL_AudioFormat val = ParseAudioFormatString(SDL_getenv("SDL_AUDIO_FORMAT"));
|
||||
spec->format = (val != 0) ? val : (iscapture ? DEFAULT_AUDIO_CAPTURE_FORMAT : DEFAULT_AUDIO_OUTPUT_FORMAT);
|
||||
spec->format = (val != 0) ? val : (recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1568,7 +1568,7 @@ void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device)
|
||||
|
||||
char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen)
|
||||
{
|
||||
(void)SDL_snprintf(buf, buflen, "SDLAudio%c%d", (device->iscapture) ? 'C' : 'P', (int) device->instance_id);
|
||||
(void)SDL_snprintf(buf, buflen, "SDLAudio%c%d", (device->recording) ? 'C' : 'P', (int) device->instance_id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1591,13 +1591,13 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
device->WaitDevice = current_audio.impl.WaitDevice;
|
||||
device->PlayDevice = current_audio.impl.PlayDevice;
|
||||
device->GetDeviceBuf = current_audio.impl.GetDeviceBuf;
|
||||
device->WaitCaptureDevice = current_audio.impl.WaitCaptureDevice;
|
||||
device->CaptureFromDevice = current_audio.impl.CaptureFromDevice;
|
||||
device->FlushCapture = current_audio.impl.FlushCapture;
|
||||
device->WaitRecordingDevice = current_audio.impl.WaitRecordingDevice;
|
||||
device->RecordDevice = current_audio.impl.RecordDevice;
|
||||
device->FlushRecording = current_audio.impl.FlushRecording;
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_spec);
|
||||
PrepareAudioFormat(device->iscapture, &spec);
|
||||
PrepareAudioFormat(device->recording, &spec);
|
||||
|
||||
/* We allow the device format to change if it's better than the current settings (by various definitions of "better"). This prevents
|
||||
something low quality, like an old game using S8/8000Hz audio, from ruining a music thing playing at CD quality that tries to open later.
|
||||
@@ -1636,7 +1636,7 @@ static int OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
if (!current_audio.impl.ProvidesOwnCallbackThread) {
|
||||
char threadname[64];
|
||||
SDL_GetAudioThreadName(device, threadname, sizeof (threadname));
|
||||
device->thread = SDL_CreateThread(device->iscapture ? CaptureAudioThread : OutputAudioThread, threadname, device);
|
||||
device->thread = SDL_CreateThread(device->recording ? RecordingAudioThread : PlaybackAudioThread, threadname, device);
|
||||
|
||||
if (!device->thread) {
|
||||
ClosePhysicalAudioDevice(device);
|
||||
@@ -1654,7 +1654,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) || (devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE));
|
||||
SDL_bool wants_default = ((devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) || (devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING));
|
||||
|
||||
// this will let you use a logical device to make a new logical device on the parent physical device. Could be useful?
|
||||
SDL_AudioDevice *device = NULL;
|
||||
@@ -1682,7 +1682,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
} else {
|
||||
RefPhysicalAudioDevice(device); // unref'd on successful SDL_CloseAudioDevice
|
||||
SDL_AtomicSet(&logdev->paused, 0);
|
||||
retval = logdev->instance_id = AssignAudioDeviceInstanceId(device->iscapture, /*islogical=*/SDL_TRUE);
|
||||
retval = logdev->instance_id = AssignAudioDeviceInstanceId(device->recording, /*islogical=*/SDL_TRUE);
|
||||
logdev->physical_device = device;
|
||||
logdev->opened_as_default = wants_default;
|
||||
logdev->next = device->logical_devices;
|
||||
@@ -1758,7 +1758,7 @@ int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallbac
|
||||
logdev->postmix = callback;
|
||||
logdev->postmix_userdata = userdata;
|
||||
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
||||
// set the proper end of the stream to the device's format.
|
||||
// SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
|
||||
@@ -1836,7 +1836,7 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
||||
|
||||
if (retval == 0) {
|
||||
// Now that everything is verified, chain everything together.
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
for (int i = 0; i < num_streams; i++) {
|
||||
SDL_AudioStream *stream = streams[i];
|
||||
if (stream) { // shouldn't be NULL, but just in case...
|
||||
@@ -1848,7 +1848,7 @@ int SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream **streams, int
|
||||
}
|
||||
logdev->bound_streams = stream;
|
||||
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
SDL_copyp(&stream->src_spec, &device->spec);
|
||||
if (logdev->postmix) {
|
||||
stream->src_spec.format = SDL_AUDIO_F32;
|
||||
@@ -1982,7 +1982,7 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au
|
||||
SDL_AtomicSet(&logdev->paused, 1); // start the device paused, to match SDL2.
|
||||
|
||||
SDL_assert(device != NULL);
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
|
||||
// if the app didn't request a format _at all_, just make a stream that does no conversion; they can query for it later.
|
||||
SDL_AudioSpec tmpspec;
|
||||
@@ -1991,7 +1991,7 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au
|
||||
spec = &tmpspec;
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
stream = SDL_CreateAudioStream(&device->spec, spec);
|
||||
} else {
|
||||
stream = SDL_CreateAudioStream(spec, &device->spec);
|
||||
@@ -2011,7 +2011,7 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au
|
||||
|
||||
if (callback) {
|
||||
int rc;
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
rc = SDL_SetAudioStreamPutCallback(stream, callback, userdata);
|
||||
} else {
|
||||
rc = SDL_SetAudioStreamGetCallback(stream, callback, userdata);
|
||||
@@ -2086,17 +2086,17 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
return; // uhoh.
|
||||
}
|
||||
|
||||
const SDL_bool iscapture = new_default_device->iscapture;
|
||||
const SDL_bool recording = new_default_device->recording;
|
||||
|
||||
// change the official default over right away, so new opens will go to the new device.
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
const SDL_AudioDeviceID current_devid = iscapture ? current_audio.default_capture_device_id : current_audio.default_output_device_id;
|
||||
const SDL_AudioDeviceID current_devid = recording ? current_audio.default_recording_device_id : current_audio.default_playback_device_id;
|
||||
const SDL_bool is_already_default = (new_default_device->instance_id == current_devid);
|
||||
if (!is_already_default) {
|
||||
if (iscapture) {
|
||||
current_audio.default_capture_device_id = new_default_device->instance_id;
|
||||
if (recording) {
|
||||
current_audio.default_recording_device_id = new_default_device->instance_id;
|
||||
} else {
|
||||
current_audio.default_output_device_id = new_default_device->instance_id;
|
||||
current_audio.default_playback_device_id = new_default_device->instance_id;
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -2122,7 +2122,7 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
if (current_default_device) {
|
||||
// migrate any logical devices that were opened as a default to the new physical device...
|
||||
|
||||
SDL_assert(current_default_device->iscapture == iscapture);
|
||||
SDL_assert(current_default_device->recording == recording);
|
||||
|
||||
// See if we have to open the new physical device, and if so, find the best audiospec for it.
|
||||
SDL_AudioSpec spec;
|
||||
@@ -2133,7 +2133,7 @@ void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
|
||||
if (logdev->opened_as_default) {
|
||||
needs_migration = SDL_TRUE;
|
||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
||||
const SDL_AudioSpec *streamspec = iscapture ? &stream->dst_spec : &stream->src_spec;
|
||||
const SDL_AudioSpec *streamspec = recording ? &stream->dst_spec : &stream->src_spec;
|
||||
if (SDL_AUDIO_BITSIZE(streamspec->format) > SDL_AUDIO_BITSIZE(spec.format)) {
|
||||
spec.format = streamspec->format;
|
||||
}
|
||||
@@ -2350,7 +2350,7 @@ void SDL_UpdateAudio(void)
|
||||
SDL_zero(event);
|
||||
event.type = i->type;
|
||||
event.adevice.which = (Uint32) i->devid;
|
||||
event.adevice.iscapture = (i->devid & (1<<0)) ? 0 : 1; // bit #0 of devid is set for output devices and unset for capture.
|
||||
event.adevice.recording = (i->devid & (1<<0)) ? 0 : 1; // bit #0 of devid is set for playback devices and unset for recording.
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
SDL_free(i);
|
||||
|
||||
@@ -472,7 +472,7 @@ int SDL_SetAudioStreamFormat(SDL_AudioStream *stream, const SDL_AudioSpec *src_s
|
||||
|
||||
// quietly refuse to change the format of the end currently bound to a device.
|
||||
if (stream->bound_device) {
|
||||
if (stream->bound_device->physical_device->iscapture) {
|
||||
if (stream->bound_device->physical_device->recording) {
|
||||
src_spec = NULL;
|
||||
} else {
|
||||
dst_spec = NULL;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define SDL_PATH_DEV_AUDIO "/dev/audio"
|
||||
#endif
|
||||
|
||||
static void test_device(const SDL_bool iscapture, const char *fname, int flags, SDL_bool (*test)(int fd))
|
||||
static void test_device(const SDL_bool recording, const char *fname, int flags, SDL_bool (*test)(int fd))
|
||||
{
|
||||
struct stat sb;
|
||||
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
|
||||
@@ -63,7 +63,7 @@ static void test_device(const SDL_bool iscapture, const char *fname, int flags,
|
||||
* information, making this information inaccessible at
|
||||
* enumeration time
|
||||
*/
|
||||
SDL_AddAudioDevice(iscapture, fname, NULL, (void *)(uintptr_t)dummyhandle);
|
||||
SDL_AddAudioDevice(recording, fname, NULL, (void *)(uintptr_t)dummyhandle);
|
||||
}
|
||||
} else {
|
||||
close(audio_fd);
|
||||
@@ -76,9 +76,9 @@ static SDL_bool test_stub(int fd)
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool iscapture, const SDL_bool classic, SDL_bool (*test)(int))
|
||||
static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool recording, const SDL_bool classic, SDL_bool (*test)(int))
|
||||
{
|
||||
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
|
||||
const int flags = recording ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
|
||||
const char *audiodev;
|
||||
char audiopath[1024];
|
||||
|
||||
@@ -105,7 +105,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool iscapture, const SD
|
||||
}
|
||||
}
|
||||
}
|
||||
test_device(iscapture, audiodev, flags, test);
|
||||
test_device(recording, audiodev, flags, test);
|
||||
|
||||
if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
|
||||
int instance = 0;
|
||||
@@ -113,7 +113,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool iscapture, const SD
|
||||
(void)SDL_snprintf(audiopath, SDL_arraysize(audiopath),
|
||||
"%s%d", audiodev, instance);
|
||||
instance++;
|
||||
test_device(iscapture, audiopath, flags, test);
|
||||
test_device(recording, audiopath, flags, test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,17 +36,17 @@
|
||||
#endif
|
||||
|
||||
// !!! FIXME: These are wordy and unlocalized...
|
||||
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
|
||||
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
|
||||
#define DEFAULT_PLAYBACK_DEVNAME "System audio playback device"
|
||||
#define DEFAULT_RECORDING_DEVNAME "System audio recording device"
|
||||
|
||||
// these are used when no better specifics are known. We default to CD audio quality.
|
||||
#define DEFAULT_AUDIO_OUTPUT_FORMAT SDL_AUDIO_S16
|
||||
#define DEFAULT_AUDIO_OUTPUT_CHANNELS 2
|
||||
#define DEFAULT_AUDIO_OUTPUT_FREQUENCY 44100
|
||||
#define DEFAULT_AUDIO_PLAYBACK_FORMAT SDL_AUDIO_S16
|
||||
#define DEFAULT_AUDIO_PLAYBACK_CHANNELS 2
|
||||
#define DEFAULT_AUDIO_PLAYBACK_FREQUENCY 44100
|
||||
|
||||
#define DEFAULT_AUDIO_CAPTURE_FORMAT SDL_AUDIO_S16
|
||||
#define DEFAULT_AUDIO_CAPTURE_CHANNELS 1
|
||||
#define DEFAULT_AUDIO_CAPTURE_FREQUENCY 44100
|
||||
#define DEFAULT_AUDIO_RECORDING_FORMAT SDL_AUDIO_S16
|
||||
#define DEFAULT_AUDIO_RECORDING_CHANNELS 1
|
||||
#define DEFAULT_AUDIO_RECORDING_FREQUENCY 44100
|
||||
|
||||
#define AUDIO_SPECS_EQUAL(x, y) (((x).format == (y).format) && ((x).channels == (y).channels) && ((x).freq == (y).freq))
|
||||
|
||||
@@ -69,7 +69,7 @@ extern void SDL_SetupAudioResampler(void);
|
||||
/* Backends should call this as devices are added to the system (such as
|
||||
a USB headset being plugged in), and should also be called for
|
||||
for every device found during DetectDevices(). */
|
||||
extern SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, const SDL_AudioSpec *spec, void *handle);
|
||||
extern SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool recording, const char *name, const SDL_AudioSpec *spec, void *handle);
|
||||
|
||||
/* Backends should call this if an opened audio device is lost.
|
||||
This can happen due to i/o errors, or a device being unplugged, etc. */
|
||||
@@ -101,12 +101,12 @@ extern void RefPhysicalAudioDevice(SDL_AudioDevice *device);
|
||||
extern void UnrefPhysicalAudioDevice(SDL_AudioDevice *device);
|
||||
|
||||
// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread.
|
||||
extern void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device);
|
||||
extern SDL_bool SDL_OutputAudioThreadIterate(SDL_AudioDevice *device);
|
||||
extern void SDL_OutputAudioThreadShutdown(SDL_AudioDevice *device);
|
||||
extern void SDL_CaptureAudioThreadSetup(SDL_AudioDevice *device);
|
||||
extern SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device);
|
||||
extern void SDL_CaptureAudioThreadShutdown(SDL_AudioDevice *device);
|
||||
extern void SDL_PlaybackAudioThreadSetup(SDL_AudioDevice *device);
|
||||
extern SDL_bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device);
|
||||
extern void SDL_PlaybackAudioThreadShutdown(SDL_AudioDevice *device);
|
||||
extern void SDL_RecordingAudioThreadSetup(SDL_AudioDevice *device);
|
||||
extern SDL_bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device);
|
||||
extern void SDL_RecordingAudioThreadShutdown(SDL_AudioDevice *device);
|
||||
extern void SDL_AudioThreadFinalize(SDL_AudioDevice *device);
|
||||
|
||||
extern void ConvertAudioToFloat(float *dst, const void *src, int num_samples, SDL_AudioFormat src_fmt);
|
||||
@@ -123,16 +123,16 @@ extern void OnAudioStreamDestroy(SDL_AudioStream *stream);
|
||||
|
||||
typedef struct SDL_AudioDriverImpl
|
||||
{
|
||||
void (*DetectDevices)(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||
void (*DetectDevices)(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
||||
int (*OpenDevice)(SDL_AudioDevice *device);
|
||||
void (*ThreadInit)(SDL_AudioDevice *device); // Called by audio thread at start
|
||||
void (*ThreadDeinit)(SDL_AudioDevice *device); // Called by audio thread at end
|
||||
int (*WaitDevice)(SDL_AudioDevice *device);
|
||||
int (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); // buffer and buflen are always from GetDeviceBuf, passed here for convenience.
|
||||
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
|
||||
int (*WaitCaptureDevice)(SDL_AudioDevice *device);
|
||||
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
|
||||
void (*FlushCapture)(SDL_AudioDevice *device);
|
||||
int (*WaitRecordingDevice)(SDL_AudioDevice *device);
|
||||
int (*RecordDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
|
||||
void (*FlushRecording)(SDL_AudioDevice *device);
|
||||
void (*CloseDevice)(SDL_AudioDevice *device);
|
||||
void (*FreeDeviceHandle)(SDL_AudioDevice *device); // SDL is done with this device; free the handle from SDL_AddAudioDevice()
|
||||
void (*DeinitializeStart)(void); // SDL calls this, then starts destroying objects, then calls Deinitialize. This is a good place to stop hotplug detection.
|
||||
@@ -140,9 +140,9 @@ typedef struct SDL_AudioDriverImpl
|
||||
|
||||
// Some flags to push duplicate code into the core and reduce #ifdefs.
|
||||
SDL_bool ProvidesOwnCallbackThread; // !!! FIXME: rename this, it's not a callback thread anymore.
|
||||
SDL_bool HasCaptureSupport;
|
||||
SDL_bool OnlyHasDefaultOutputDevice;
|
||||
SDL_bool OnlyHasDefaultCaptureDevice; // !!! FIXME: is there ever a time where you'd have a default output and not a default capture (or vice versa)?
|
||||
SDL_bool HasRecordingSupport;
|
||||
SDL_bool OnlyHasDefaultPlaybackDevice;
|
||||
SDL_bool OnlyHasDefaultRecordingDevice; // !!! FIXME: is there ever a time where you'd have a default playback and not a default recording (or vice versa)?
|
||||
} SDL_AudioDriverImpl;
|
||||
|
||||
|
||||
@@ -159,16 +159,16 @@ typedef struct SDL_AudioDriver
|
||||
const char *desc; // The description of this audio driver
|
||||
SDL_AudioDriverImpl impl; // the backend's interface
|
||||
SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash`
|
||||
SDL_HashTable *device_hash; // the collection of currently-available audio devices (capture, playback, logical and physical!)
|
||||
SDL_HashTable *device_hash; // the collection of currently-available audio devices (recording, playback, logical and physical!)
|
||||
SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams.
|
||||
SDL_AudioDeviceID default_output_device_id;
|
||||
SDL_AudioDeviceID default_capture_device_id;
|
||||
SDL_AudioDeviceID default_playback_device_id;
|
||||
SDL_AudioDeviceID default_recording_device_id;
|
||||
SDL_PendingAudioDeviceEvent pending_events;
|
||||
SDL_PendingAudioDeviceEvent *pending_events_tail;
|
||||
|
||||
// !!! FIXME: most (all?) of these don't have to be atomic.
|
||||
SDL_AtomicInt output_device_count;
|
||||
SDL_AtomicInt capture_device_count;
|
||||
SDL_AtomicInt playback_device_count;
|
||||
SDL_AtomicInt recording_device_count;
|
||||
SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
|
||||
} SDL_AudioDriver;
|
||||
|
||||
@@ -257,9 +257,9 @@ struct SDL_AudioDevice
|
||||
int (*WaitDevice)(SDL_AudioDevice *device);
|
||||
int (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen);
|
||||
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
|
||||
int (*WaitCaptureDevice)(SDL_AudioDevice *device);
|
||||
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
|
||||
void (*FlushCapture)(SDL_AudioDevice *device);
|
||||
int (*WaitRecordingDevice)(SDL_AudioDevice *device);
|
||||
int (*RecordDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
|
||||
void (*FlushRecording)(SDL_AudioDevice *device);
|
||||
|
||||
// human-readable name of the device. ("SoundBlaster Pro 16")
|
||||
char *name;
|
||||
@@ -289,8 +289,8 @@ struct SDL_AudioDevice
|
||||
// non-zero if this was a disconnected device and we're waiting for it to be decommissioned.
|
||||
SDL_AtomicInt zombie;
|
||||
|
||||
// SDL_TRUE if this is a capture device instead of an output device
|
||||
SDL_bool iscapture;
|
||||
// SDL_TRUE if this is a recording device instead of an playback device
|
||||
SDL_bool recording;
|
||||
|
||||
// SDL_TRUE if audio thread can skip silence/mix/convert stages and just do a basic memcpy.
|
||||
SDL_bool simple_copy;
|
||||
|
||||
@@ -96,7 +96,7 @@ static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, v
|
||||
size_t callback_bytes = numFrames * framesize;
|
||||
size_t old_buffer_index = hidden->callback_bytes / device->buffer_size;
|
||||
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
const Uint8 *input = (const Uint8 *)audioData;
|
||||
size_t available_bytes = hidden->mixbuf_bytes - (hidden->callback_bytes - hidden->processed_bytes);
|
||||
size_t size = SDL_min(available_bytes, callback_bytes);
|
||||
@@ -228,7 +228,7 @@ static int AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int b
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int AAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *hidden = device->hidden;
|
||||
|
||||
@@ -272,7 +272,7 @@ static void AAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
static int BuildAAudioStream(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *hidden = device->hidden;
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
aaudio_result_t res;
|
||||
|
||||
SDL_AtomicSet(&hidden->error_callback_triggered, 0);
|
||||
@@ -307,7 +307,7 @@ static int BuildAAudioStream(SDL_AudioDevice *device)
|
||||
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
|
||||
#endif
|
||||
|
||||
const aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
ctx.AAudioStreamBuilder_setErrorCallback(builder, AAUDIO_errorCallback, device);
|
||||
ctx.AAudioStreamBuilder_setDataCallback(builder, AAUDIO_dataCallback, device);
|
||||
@@ -360,9 +360,9 @@ static int BuildAAudioStream(SDL_AudioDevice *device)
|
||||
hidden->processed_bytes = 0;
|
||||
hidden->callback_bytes = 0;
|
||||
|
||||
hidden->semaphore = SDL_CreateSemaphore(iscapture ? 0 : hidden->num_buffers);
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
|
||||
if (!hidden->semaphore) {
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s iscapture:%d", SDL_GetError(), iscapture);
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ static int BuildAAudioStream(SDL_AudioDevice *device)
|
||||
|
||||
res = ctx.AAudioStream_requestStart(hidden->stream);
|
||||
if (res != AAUDIO_OK) {
|
||||
LOGI("SDL Failed AAudioStream_requestStart %d iscapture:%d", res, iscapture);
|
||||
LOGI("SDL Failed AAudioStream_requestStart %d recording:%d", res, recording);
|
||||
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
LOGI(__func__);
|
||||
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
// !!! FIXME: make this non-blocking!
|
||||
SDL_AtomicInt permission_response;
|
||||
SDL_AtomicSet(&permission_response, 0);
|
||||
@@ -428,8 +428,8 @@ static SDL_bool PauseOneDevice(SDL_AudioDevice *device, void *userdata)
|
||||
if (hidden->stream) {
|
||||
aaudio_result_t res;
|
||||
|
||||
if (device->iscapture) {
|
||||
// Pause() isn't implemented for 'capture', use Stop()
|
||||
if (device->recording) {
|
||||
// Pause() isn't implemented for recording, use Stop()
|
||||
res = ctx.AAudioStream_requestStop(hidden->stream);
|
||||
} else {
|
||||
res = ctx.AAudioStream_requestPause(hidden->stream);
|
||||
@@ -530,16 +530,16 @@ static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->WaitDevice = AAUDIO_WaitDevice;
|
||||
impl->PlayDevice = AAUDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = AAUDIO_GetDeviceBuf;
|
||||
impl->WaitCaptureDevice = AAUDIO_WaitDevice;
|
||||
impl->CaptureFromDevice = AAUDIO_CaptureFromDevice;
|
||||
impl->WaitRecordingDevice = AAUDIO_WaitDevice;
|
||||
impl->RecordDevice = AAUDIO_RecordDevice;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
|
||||
impl->DetectDevices = Android_StartAudioHotplug;
|
||||
#else
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
#endif
|
||||
|
||||
LOGI("SDL AAUDIO_Init OK");
|
||||
|
||||
@@ -206,17 +206,17 @@ static int LoadALSALibrary(void)
|
||||
typedef struct ALSA_Device
|
||||
{
|
||||
char *name;
|
||||
SDL_bool iscapture;
|
||||
SDL_bool recording;
|
||||
struct ALSA_Device *next;
|
||||
} ALSA_Device;
|
||||
|
||||
static const ALSA_Device default_output_handle = {
|
||||
static const ALSA_Device default_playback_handle = {
|
||||
"default",
|
||||
SDL_FALSE,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const ALSA_Device default_capture_handle = {
|
||||
static const ALSA_Device default_recording_handle = {
|
||||
"default",
|
||||
SDL_TRUE,
|
||||
NULL
|
||||
@@ -427,7 +427,7 @@ static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static int ALSA_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int ALSA_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
SDL_assert((buflen % frame_size) == 0);
|
||||
@@ -451,12 +451,12 @@ static int ALSA_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buf
|
||||
device->hidden->swizzle_func(device, buffer, total_frames - rc);
|
||||
}
|
||||
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: captured %d bytes", rc * frame_size);
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: recorded %d bytes", rc * frame_size);
|
||||
|
||||
return rc * frame_size;
|
||||
}
|
||||
|
||||
static void ALSA_FlushCapture(SDL_AudioDevice *device)
|
||||
static void ALSA_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
ALSA_snd_pcm_reset(device->hidden->pcm_handle);
|
||||
}
|
||||
@@ -531,7 +531,7 @@ static int ALSA_set_buffer_size(SDL_AudioDevice *device, snd_pcm_hw_params_t *pa
|
||||
|
||||
static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
int status = 0;
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
@@ -545,7 +545,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
snd_pcm_t *pcm_handle = NULL;
|
||||
status = ALSA_snd_pcm_open(&pcm_handle,
|
||||
get_audio_device(device->handle, device->spec.channels),
|
||||
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||
recording ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||
SND_PCM_NONBLOCK);
|
||||
|
||||
if (status < 0) {
|
||||
@@ -680,7 +680,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
// Allocate mixing buffer
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
|
||||
if (!device->hidden->mixbuf) {
|
||||
return -1;
|
||||
@@ -689,7 +689,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
#if !SDL_ALSA_NON_BLOCKING
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -699,7 +699,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
return 0; // We're ready to rock and roll. :-)
|
||||
}
|
||||
|
||||
static void add_device(const SDL_bool iscapture, const char *name, void *hint, ALSA_Device **pSeen)
|
||||
static void add_device(const SDL_bool recording, const char *name, void *hint, ALSA_Device **pSeen)
|
||||
{
|
||||
ALSA_Device *dev = SDL_malloc(sizeof(ALSA_Device));
|
||||
char *desc;
|
||||
@@ -733,7 +733,7 @@ static void add_device(const SDL_bool iscapture, const char *name, void *hint, A
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: adding %s device '%s' (%s)", iscapture ? "capture" : "output", name, desc);
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: adding %s device '%s' (%s)", recording ? "recording" : "playback", name, desc);
|
||||
|
||||
dev->name = SDL_strdup(name);
|
||||
if (!dev->name) {
|
||||
@@ -748,19 +748,19 @@ static void add_device(const SDL_bool iscapture, const char *name, void *hint, A
|
||||
// Note that spec is NULL, because we are required to open the device before
|
||||
// acquiring the mix format, making this information inaccessible at
|
||||
// enumeration time
|
||||
SDL_AddAudioDevice(iscapture, desc, NULL, dev);
|
||||
SDL_AddAudioDevice(recording, desc, NULL, dev);
|
||||
if (hint) {
|
||||
free(desc); // This should NOT be SDL_free()
|
||||
}
|
||||
|
||||
dev->iscapture = iscapture;
|
||||
dev->recording = recording;
|
||||
dev->next = *pSeen;
|
||||
*pSeen = dev;
|
||||
}
|
||||
|
||||
static ALSA_Device *hotplug_devices = NULL;
|
||||
|
||||
static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_default_capture)
|
||||
static void ALSA_HotplugIteration(SDL_bool *has_default_playback, SDL_bool *has_default_recording)
|
||||
{
|
||||
void **hints = NULL;
|
||||
ALSA_Device *unseen = NULL;
|
||||
@@ -834,10 +834,10 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
|
||||
}
|
||||
|
||||
if (is_default) {
|
||||
if (has_default_output && isoutput) {
|
||||
*has_default_output = SDL_TRUE;
|
||||
} else if (has_default_capture && isinput) {
|
||||
*has_default_capture = SDL_TRUE;
|
||||
if (has_default_playback && isoutput) {
|
||||
*has_default_playback = SDL_TRUE;
|
||||
} else if (has_default_recording && isinput) {
|
||||
*has_default_recording = SDL_TRUE;
|
||||
}
|
||||
free(name); // This should NOT be SDL_free()
|
||||
continue;
|
||||
@@ -847,7 +847,7 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
|
||||
ALSA_Device *next;
|
||||
for (ALSA_Device *dev = unseen; dev; dev = next) {
|
||||
next = dev->next;
|
||||
if ((SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture))) {
|
||||
if ((SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->recording) || ((isoutput) && !dev->recording))) {
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
@@ -885,7 +885,7 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
|
||||
// report anything still in unseen as removed.
|
||||
ALSA_Device *next = NULL;
|
||||
for (ALSA_Device *dev = unseen; dev; dev = next) {
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: removing %s device '%s'", dev->iscapture ? "capture" : "output", dev->name);
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: removing %s device '%s'", dev->recording ? "recording" : "playback", dev->name);
|
||||
next = dev->next;
|
||||
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle(dev));
|
||||
SDL_free(dev->name);
|
||||
@@ -916,17 +916,17 @@ static int SDLCALL ALSA_HotplugThread(void *arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ALSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void ALSA_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
// ALSA doesn't have a concept of a changeable default device, afaik, so we expose a generic default
|
||||
// device here. It's the best we can do at this level.
|
||||
SDL_bool has_default_output = SDL_FALSE, has_default_capture = SDL_FALSE;
|
||||
ALSA_HotplugIteration(&has_default_output, &has_default_capture); // run once now before a thread continues to check.
|
||||
if (has_default_output) {
|
||||
*default_output = SDL_AddAudioDevice(/*iscapture=*/SDL_FALSE, "ALSA default output device", NULL, (void*)&default_output_handle);
|
||||
SDL_bool has_default_playback = SDL_FALSE, has_default_recording = SDL_FALSE;
|
||||
ALSA_HotplugIteration(&has_default_playback, &has_default_recording); // run once now before a thread continues to check.
|
||||
if (has_default_playback) {
|
||||
*default_playback = SDL_AddAudioDevice(/*recording=*/SDL_FALSE, "ALSA default playback device", NULL, (void*)&default_playback_handle);
|
||||
}
|
||||
if (has_default_capture) {
|
||||
*default_capture = SDL_AddAudioDevice(/*iscapture=*/SDL_TRUE, "ALSA default capture device", NULL, (void*)&default_capture_handle);
|
||||
if (has_default_recording) {
|
||||
*default_recording = SDL_AddAudioDevice(/*recording=*/SDL_TRUE, "ALSA default recording device", NULL, (void*)&default_recording_handle);
|
||||
}
|
||||
|
||||
#if SDL_ALSA_HOTPLUG_THREAD
|
||||
@@ -951,7 +951,7 @@ static void ALSA_DeinitializeStart(void)
|
||||
|
||||
// Shutting down! Clean up any data we've gathered.
|
||||
for (dev = hotplug_devices; dev; dev = next) {
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: at shutdown, removing %s device '%s'", dev->iscapture ? "capture" : "output", dev->name);
|
||||
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: at shutdown, removing %s device '%s'", dev->recording ? "recording" : "playback", dev->name);
|
||||
next = dev->next;
|
||||
SDL_free(dev->name);
|
||||
SDL_free(dev);
|
||||
@@ -978,11 +978,11 @@ static SDL_bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->CloseDevice = ALSA_CloseDevice;
|
||||
impl->DeinitializeStart = ALSA_DeinitializeStart;
|
||||
impl->Deinitialize = ALSA_Deinitialize;
|
||||
impl->WaitCaptureDevice = ALSA_WaitDevice;
|
||||
impl->CaptureFromDevice = ALSA_CaptureFromDevice;
|
||||
impl->FlushCapture = ALSA_FlushCapture;
|
||||
impl->WaitRecordingDevice = ALSA_WaitDevice;
|
||||
impl->RecordDevice = ALSA_RecordDevice;
|
||||
impl->FlushRecording = ALSA_FlushRecording;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ struct SDL_PrivateAudioData
|
||||
int resume; // Resume device if it was paused automatically
|
||||
};
|
||||
|
||||
static SDL_AudioDevice *audioDevice = NULL;
|
||||
static SDL_AudioDevice *captureDevice = NULL;
|
||||
static SDL_AudioDevice *playbackDevice = NULL;
|
||||
static SDL_AudioDevice *recordingDevice = NULL;
|
||||
|
||||
static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
@@ -46,18 +46,18 @@ static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
|
||||
if (iscapture) {
|
||||
if (captureDevice) {
|
||||
return SDL_SetError("An audio capture device is already opened");
|
||||
if (recording) {
|
||||
if (recordingDevice) {
|
||||
return SDL_SetError("An audio recording device is already opened");
|
||||
}
|
||||
captureDevice = device;
|
||||
recordingDevice = device;
|
||||
} else {
|
||||
if (audioDevice) {
|
||||
if (playbackDevice) {
|
||||
return SDL_SetError("An audio playback device is already opened");
|
||||
}
|
||||
audioDevice = device;
|
||||
playbackDevice = device;
|
||||
}
|
||||
|
||||
SDL_AudioFormat test_format;
|
||||
@@ -97,14 +97,14 @@ static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_siz
|
||||
return Android_JNI_GetAudioBuffer();
|
||||
}
|
||||
|
||||
static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int ANDROIDAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
|
||||
return Android_JNI_RecordAudioBuffer(buffer, buflen);
|
||||
}
|
||||
|
||||
static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void ANDROIDAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
Android_JNI_FlushCapturedAudio();
|
||||
Android_JNI_FlushRecordedAudio();
|
||||
}
|
||||
|
||||
static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
@@ -113,13 +113,13 @@ static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
so it's safe to terminate the Java side buffer and AudioTrack
|
||||
*/
|
||||
if (device->hidden) {
|
||||
Android_JNI_CloseAudioDevice(device->iscapture);
|
||||
if (device->iscapture) {
|
||||
SDL_assert(captureDevice == device);
|
||||
captureDevice = NULL;
|
||||
Android_JNI_CloseAudioDevice(device->recording);
|
||||
if (device->recording) {
|
||||
SDL_assert(recordingDevice == device);
|
||||
recordingDevice = NULL;
|
||||
} else {
|
||||
SDL_assert(audioDevice == device);
|
||||
audioDevice = NULL;
|
||||
SDL_assert(playbackDevice == device);
|
||||
playbackDevice = NULL;
|
||||
}
|
||||
SDL_free(device->hidden);
|
||||
device->hidden = NULL;
|
||||
@@ -131,15 +131,15 @@ void ANDROIDAUDIO_PauseDevices(void)
|
||||
{
|
||||
// TODO: Handle multiple devices?
|
||||
struct SDL_PrivateAudioData *hidden;
|
||||
if (audioDevice && audioDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
|
||||
SDL_LockMutex(audioDevice->lock);
|
||||
if (playbackDevice && playbackDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)playbackDevice->hidden;
|
||||
SDL_LockMutex(playbackDevice->lock);
|
||||
hidden->resume = SDL_TRUE;
|
||||
}
|
||||
|
||||
if (captureDevice && captureDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
|
||||
SDL_LockMutex(captureDevice->lock);
|
||||
if (recordingDevice && recordingDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)recordingDevice->hidden;
|
||||
SDL_LockMutex(recordingDevice->lock);
|
||||
hidden->resume = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -149,26 +149,26 @@ void ANDROIDAUDIO_ResumeDevices(void)
|
||||
{
|
||||
// TODO: Handle multiple devices?
|
||||
struct SDL_PrivateAudioData *hidden;
|
||||
if (audioDevice && audioDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
|
||||
if (playbackDevice && playbackDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)playbackDevice->hidden;
|
||||
if (hidden->resume) {
|
||||
hidden->resume = SDL_FALSE;
|
||||
SDL_UnlockMutex(audioDevice->lock);
|
||||
SDL_UnlockMutex(playbackDevice->lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (captureDevice && captureDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
|
||||
if (recordingDevice && recordingDevice->hidden) {
|
||||
hidden = (struct SDL_PrivateAudioData *)recordingDevice->hidden;
|
||||
if (hidden->resume) {
|
||||
hidden->resume = SDL_FALSE;
|
||||
SDL_UnlockMutex(captureDevice->lock);
|
||||
SDL_UnlockMutex(recordingDevice->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
// !!! FIXME: if on Android API < 24, DetectDevices and Deinitialize should be NULL and OnlyHasDefaultOutputDevice and OnlyHasDefaultCaptureDevice should be SDL_TRUE, since audio device enum and hotplug appears to require Android 7.0+.
|
||||
// !!! FIXME: if on Android API < 24, DetectDevices and Deinitialize should be NULL and OnlyHasDefaultPlaybackDevice and OnlyHasDefaultRecordingDevice should be SDL_TRUE, since audio device enum and hotplug appears to require Android 7.0+.
|
||||
impl->ThreadInit = Android_AudioThreadInit;
|
||||
impl->DetectDevices = Android_StartAudioHotplug;
|
||||
impl->DeinitializeStart = Android_StopAudioHotplug;
|
||||
@@ -176,10 +176,10 @@ static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
|
||||
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
|
||||
impl->RecordDevice = ANDROIDAUDIO_RecordDevice;
|
||||
impl->FlushRecording = ANDROIDAUDIO_FlushRecording;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -48,19 +48,19 @@
|
||||
typedef struct SDLCoreAudioHandle
|
||||
{
|
||||
AudioDeviceID devid;
|
||||
SDL_bool iscapture;
|
||||
SDL_bool recording;
|
||||
} SDLCoreAudioHandle;
|
||||
|
||||
static SDL_bool TestCoreAudioDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
|
||||
{
|
||||
const SDLCoreAudioHandle *a = (const SDLCoreAudioHandle *) device->handle;
|
||||
const SDLCoreAudioHandle *b = (const SDLCoreAudioHandle *) handle;
|
||||
return (a->devid == b->devid) && (!!a->iscapture == !!b->iscapture);
|
||||
return (a->devid == b->devid) && (!!a->recording == !!b->recording);
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *FindCoreAudioDeviceByHandle(const AudioDeviceID devid, const SDL_bool iscapture)
|
||||
static SDL_AudioDevice *FindCoreAudioDeviceByHandle(const AudioDeviceID devid, const SDL_bool recording)
|
||||
{
|
||||
SDLCoreAudioHandle handle = { devid, iscapture };
|
||||
SDLCoreAudioHandle handle = { devid, recording };
|
||||
return SDL_FindPhysicalAudioDeviceByCallback(TestCoreAudioDeviceHandleCallback, &handle);
|
||||
}
|
||||
|
||||
@@ -70,13 +70,13 @@ static const AudioObjectPropertyAddress devlist_address = {
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
static const AudioObjectPropertyAddress default_output_device_address = {
|
||||
static const AudioObjectPropertyAddress default_playback_device_address = {
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
static const AudioObjectPropertyAddress default_input_device_address = {
|
||||
static const AudioObjectPropertyAddress default_recording_device_address = {
|
||||
kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMain
|
||||
@@ -146,20 +146,20 @@ static void RefreshPhysicalDevices(void)
|
||||
}
|
||||
|
||||
// any non-zero items remaining in `devs` are new devices to be added.
|
||||
for (int iscapture = 0; iscapture < 2; iscapture++) {
|
||||
for (int recording = 0; recording < 2; recording++) {
|
||||
const AudioObjectPropertyAddress addr = {
|
||||
kAudioDevicePropertyStreamConfiguration,
|
||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
recording ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
const AudioObjectPropertyAddress nameaddr = {
|
||||
kAudioObjectPropertyName,
|
||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
recording ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
const AudioObjectPropertyAddress freqaddr = {
|
||||
kAudioDevicePropertyNominalSampleRate,
|
||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
recording ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
@@ -224,15 +224,13 @@ static void RefreshPhysicalDevices(void)
|
||||
name[len] = '\0';
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
SDL_Log("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
|
||||
((iscapture) ? "capture" : "output"),
|
||||
(int)i, name, (int)dev);
|
||||
SDL_Log("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n", ((recording) ? "recording" : "playback"), (int)i, name, (int)dev);
|
||||
#endif
|
||||
SDLCoreAudioHandle *newhandle = (SDLCoreAudioHandle *) SDL_calloc(1, sizeof (*newhandle));
|
||||
if (newhandle) {
|
||||
newhandle->devid = dev;
|
||||
newhandle->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(newhandle->iscapture, name, &spec, newhandle);
|
||||
newhandle->recording = recording ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(newhandle->recording, name, &spec, newhandle);
|
||||
if (device) {
|
||||
AudioObjectAddPropertyListener(dev, &alive_address, DeviceAliveNotification, device);
|
||||
} else {
|
||||
@@ -254,35 +252,35 @@ static OSStatus DeviceListChangedNotification(AudioObjectID systemObj, UInt32 nu
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static OSStatus DefaultAudioDeviceChangedNotification(const SDL_bool iscapture, AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
||||
static OSStatus DefaultAudioDeviceChangedNotification(const SDL_bool recording, AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
||||
{
|
||||
AudioDeviceID devid;
|
||||
UInt32 size = sizeof(devid);
|
||||
if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
|
||||
SDL_DefaultAudioDeviceChanged(FindCoreAudioDeviceByHandle(devid, iscapture));
|
||||
SDL_DefaultAudioDeviceChanged(FindCoreAudioDeviceByHandle(devid, recording));
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static OSStatus DefaultOutputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
static OSStatus DefaultPlaybackDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
{
|
||||
#if DEBUG_COREAUDIO
|
||||
SDL_Log("COREAUDIO: default output device changed!");
|
||||
SDL_Log("COREAUDIO: default playback device changed!");
|
||||
#endif
|
||||
SDL_assert(inNumberAddresses == 1);
|
||||
return DefaultAudioDeviceChangedNotification(SDL_FALSE, inObjectID, inAddresses);
|
||||
}
|
||||
|
||||
static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
static OSStatus DefaultRecordingDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
{
|
||||
#if DEBUG_COREAUDIO
|
||||
SDL_Log("COREAUDIO: default input device changed!");
|
||||
SDL_Log("COREAUDIO: default recording device changed!");
|
||||
#endif
|
||||
SDL_assert(inNumberAddresses == 1);
|
||||
return DefaultAudioDeviceChangedNotification(SDL_TRUE, inObjectID, inAddresses);
|
||||
}
|
||||
|
||||
static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
RefreshPhysicalDevices();
|
||||
|
||||
@@ -293,22 +291,22 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
|
||||
AudioDeviceID devid;
|
||||
|
||||
size = sizeof(AudioDeviceID);
|
||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_output_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_playback_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||
SDL_AudioDevice *device = FindCoreAudioDeviceByHandle(devid, SDL_FALSE);
|
||||
if (device) {
|
||||
*default_output = device;
|
||||
*default_playback = device;
|
||||
}
|
||||
}
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_output_device_address, DefaultOutputDeviceChangedNotification, NULL);
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_playback_device_address, DefaultPlaybackDeviceChangedNotification, NULL);
|
||||
|
||||
size = sizeof(AudioDeviceID);
|
||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_input_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_recording_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||
SDL_AudioDevice *device = FindCoreAudioDeviceByHandle(devid, SDL_TRUE);
|
||||
if (device) {
|
||||
*default_capture = device;
|
||||
*default_recording = device;
|
||||
}
|
||||
}
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_input_device_address, DefaultInputDeviceChangedNotification, NULL);
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_recording_device_address, DefaultRecordingDeviceChangedNotification, NULL);
|
||||
}
|
||||
|
||||
#else // iOS-specific section follows.
|
||||
@@ -387,18 +385,18 @@ static void InterruptionEnd(SDL_AudioDevice *device)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int output;
|
||||
int capture;
|
||||
int playback;
|
||||
int recording;
|
||||
} CountOpenAudioDevicesData;
|
||||
|
||||
static SDL_bool CountOpenAudioDevices(SDL_AudioDevice *device, void *userdata)
|
||||
{
|
||||
CountOpenAudioDevicesData *data = (CountOpenAudioDevicesData *) userdata;
|
||||
if (device->hidden != NULL) { // assume it's open if hidden != NULL
|
||||
if (device->iscapture) {
|
||||
data->capture++;
|
||||
if (device->recording) {
|
||||
data->recording++;
|
||||
} else {
|
||||
data->output++;
|
||||
data->playback++;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE; // keep enumerating until all devices have been checked.
|
||||
@@ -437,9 +435,9 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
|
||||
category = AVAudioSessionCategoryPlayAndRecord;
|
||||
}
|
||||
}
|
||||
} else if (data.output && data.capture) {
|
||||
} else if (data.playback && data.recording) {
|
||||
category = AVAudioSessionCategoryPlayAndRecord;
|
||||
} else if (data.capture) {
|
||||
} else if (data.recording) {
|
||||
category = AVAudioSessionCategoryRecord;
|
||||
}
|
||||
|
||||
@@ -492,7 +490,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
|
||||
}
|
||||
}
|
||||
|
||||
if ((data.output || data.capture) && !session_active) {
|
||||
if ((data.playback || data.recording) && !session_active) {
|
||||
if (![session setActive:YES error:&err]) {
|
||||
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
|
||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
@@ -505,7 +503,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
|
||||
}
|
||||
session_active = SDL_TRUE;
|
||||
ResumeAudioDevices();
|
||||
} else if (!data.output && !data.capture && session_active) {
|
||||
} else if (!data.playback && !data.recording && session_active) {
|
||||
PauseAudioDevices();
|
||||
[session setActive:NO error:nil];
|
||||
session_active = SDL_FALSE;
|
||||
@@ -553,7 +551,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
|
||||
static int COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
|
||||
SDL_assert(current_buffer != NULL); // should have been called from OutputBufferReadyCallback
|
||||
SDL_assert(current_buffer != NULL); // should have been called from PlaybackBufferReadyCallback
|
||||
SDL_assert(buffer == (Uint8 *) current_buffer->mAudioData);
|
||||
current_buffer->mAudioDataByteSize = current_buffer->mAudioDataBytesCapacity;
|
||||
device->hidden->current_buffer = NULL;
|
||||
@@ -564,19 +562,19 @@ static int COREAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
|
||||
static Uint8 *COREAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
{
|
||||
AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
|
||||
SDL_assert(current_buffer != NULL); // should have been called from OutputBufferReadyCallback
|
||||
SDL_assert(current_buffer != NULL); // should have been called from PlaybackBufferReadyCallback
|
||||
SDL_assert(current_buffer->mAudioData != NULL);
|
||||
*buffer_size = (int) current_buffer->mAudioDataBytesCapacity;
|
||||
return (Uint8 *) current_buffer->mAudioData;
|
||||
}
|
||||
|
||||
static void OutputBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
static void PlaybackBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)inUserData;
|
||||
SDL_assert(inBuffer != NULL); // ...right?
|
||||
SDL_assert(device->hidden->current_buffer == NULL); // shouldn't have anything pending
|
||||
device->hidden->current_buffer = inBuffer;
|
||||
const SDL_bool okay = SDL_OutputAudioThreadIterate(device);
|
||||
const SDL_bool okay = SDL_PlaybackAudioThreadIterate(device);
|
||||
SDL_assert((device->hidden->current_buffer == NULL) || !okay); // PlayDevice should have enqueued and cleaned it out, unless we failed or shutdown.
|
||||
|
||||
// buffer is unexpectedly here? We're probably dying, but try to requeue this buffer with silence.
|
||||
@@ -588,10 +586,10 @@ static void OutputBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, Audi
|
||||
}
|
||||
}
|
||||
|
||||
static int COREAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int COREAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
|
||||
SDL_assert(current_buffer != NULL); // should have been called from InputBufferReadyCallback
|
||||
SDL_assert(current_buffer != NULL); // should have been called from RecordingBufferReadyCallback
|
||||
SDL_assert(current_buffer->mAudioData != NULL);
|
||||
SDL_assert(buflen >= (int) current_buffer->mAudioDataByteSize); // `cpy` makes sure this won't overflow a buffer, but we _will_ drop samples if this assertion fails!
|
||||
const int cpy = SDL_min(buflen, (int) current_buffer->mAudioDataByteSize);
|
||||
@@ -601,7 +599,7 @@ static int COREAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, in
|
||||
return cpy;
|
||||
}
|
||||
|
||||
static void COREAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void COREAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
AudioQueueBufferRef current_buffer = device->hidden->current_buffer;
|
||||
if (current_buffer != NULL) { // also gets called at shutdown, when no buffer is available.
|
||||
@@ -611,7 +609,7 @@ static void COREAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static void InputBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||
static void RecordingBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription *inPacketDescs)
|
||||
{
|
||||
@@ -620,12 +618,12 @@ static void InputBufferReadyCallback(void *inUserData, AudioQueueRef inAQ, Audio
|
||||
SDL_assert(inBuffer != NULL); // ...right?
|
||||
SDL_assert(device->hidden->current_buffer == NULL); // shouldn't have anything pending
|
||||
device->hidden->current_buffer = inBuffer;
|
||||
SDL_CaptureAudioThreadIterate(device);
|
||||
SDL_RecordingAudioThreadIterate(device);
|
||||
|
||||
// buffer is unexpectedly here? We're probably dying, but try to requeue this buffer anyhow.
|
||||
if (device->hidden->current_buffer != NULL) {
|
||||
SDL_assert(SDL_AtomicGet(&device->shutdown) != 0);
|
||||
COREAUDIO_FlushCapture(device); // just flush it manually, which will requeue it.
|
||||
COREAUDIO_FlushRecording(device); // just flush it manually, which will requeue it.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,7 +678,7 @@ static int PrepareDevice(SDL_AudioDevice *device)
|
||||
UInt32 alive = 0;
|
||||
size = sizeof(alive);
|
||||
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
|
||||
addr.mScope = device->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
|
||||
addr.mScope = device->recording ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
|
||||
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
|
||||
CHECK_RESULT("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
|
||||
if (!alive) {
|
||||
@@ -705,7 +703,7 @@ static int AssignDeviceToAudioQueue(SDL_AudioDevice *device)
|
||||
{
|
||||
const AudioObjectPropertyAddress prop = {
|
||||
kAudioDevicePropertyDeviceUID,
|
||||
device->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
device->recording ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMain
|
||||
};
|
||||
|
||||
@@ -726,16 +724,16 @@ static int AssignDeviceToAudioQueue(SDL_AudioDevice *device)
|
||||
static int PrepareAudioQueue(SDL_AudioDevice *device)
|
||||
{
|
||||
const AudioStreamBasicDescription *strdesc = &device->hidden->strdesc;
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
OSStatus result;
|
||||
|
||||
SDL_assert(CFRunLoopGetCurrent() != NULL);
|
||||
|
||||
if (iscapture) {
|
||||
result = AudioQueueNewInput(strdesc, InputBufferReadyCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
if (recording) {
|
||||
result = AudioQueueNewInput(strdesc, RecordingBufferReadyCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
CHECK_RESULT("AudioQueueNewInput");
|
||||
} else {
|
||||
result = AudioQueueNewOutput(strdesc, OutputBufferReadyCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
result = AudioQueueNewOutput(strdesc, PlaybackBufferReadyCallback, device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &device->hidden->audioQueue);
|
||||
CHECK_RESULT("AudioQueueNewOutput");
|
||||
}
|
||||
|
||||
@@ -827,10 +825,10 @@ static int AudioQueueThreadEntry(void *arg)
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *)arg;
|
||||
|
||||
if (device->iscapture) {
|
||||
SDL_CaptureAudioThreadSetup(device);
|
||||
if (device->recording) {
|
||||
SDL_RecordingAudioThreadSetup(device);
|
||||
} else {
|
||||
SDL_OutputAudioThreadSetup(device);
|
||||
SDL_PlaybackAudioThreadSetup(device);
|
||||
}
|
||||
|
||||
if (PrepareAudioQueue(device) < 0) {
|
||||
@@ -842,18 +840,18 @@ static int AudioQueueThreadEntry(void *arg)
|
||||
// init was successful, alert parent thread and start running...
|
||||
SDL_PostSemaphore(device->hidden->ready_semaphore);
|
||||
|
||||
// This would be WaitDevice/WaitCaptureDevice in the normal SDL audio thread, but we get *BufferReadyCallback calls here to know when to iterate.
|
||||
// This would be WaitDevice/WaitRecordingDevice in the normal SDL audio thread, but we get *BufferReadyCallback calls here to know when to iterate.
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
||||
}
|
||||
|
||||
if (device->iscapture) {
|
||||
SDL_CaptureAudioThreadShutdown(device);
|
||||
if (device->recording) {
|
||||
SDL_RecordingAudioThreadShutdown(device);
|
||||
} else {
|
||||
// Drain off any pending playback.
|
||||
const CFTimeInterval secs = (((CFTimeInterval)device->sample_frames) / ((CFTimeInterval)device->spec.freq)) * 2.0;
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||
SDL_OutputAudioThreadShutdown(device);
|
||||
SDL_PlaybackAudioThreadShutdown(device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -878,7 +876,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
[session setPreferredSampleRate:device->spec.freq error:nil];
|
||||
device->spec.freq = (int)session.sampleRate;
|
||||
#ifdef SDL_PLATFORM_TVOS
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
[session setPreferredInputNumberOfChannels:device->spec.channels error:nil];
|
||||
device->spec.channels = (int)session.preferredInputNumberOfChannels;
|
||||
} else {
|
||||
@@ -974,8 +972,8 @@ static void COREAUDIO_DeinitializeStart(void)
|
||||
{
|
||||
#ifdef MACOSX_COREAUDIO
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, DeviceListChangedNotification, NULL);
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_output_device_address, DefaultOutputDeviceChangedNotification, NULL);
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_input_device_address, DefaultInputDeviceChangedNotification, NULL);
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_playback_device_address, DefaultPlaybackDeviceChangedNotification, NULL);
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_recording_device_address, DefaultRecordingDeviceChangedNotification, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -984,8 +982,8 @@ static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->OpenDevice = COREAUDIO_OpenDevice;
|
||||
impl->PlayDevice = COREAUDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = COREAUDIO_GetDeviceBuf;
|
||||
impl->CaptureFromDevice = COREAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = COREAUDIO_FlushCapture;
|
||||
impl->RecordDevice = COREAUDIO_RecordDevice;
|
||||
impl->FlushRecording = COREAUDIO_FlushRecording;
|
||||
impl->CloseDevice = COREAUDIO_CloseDevice;
|
||||
impl->DeinitializeStart = COREAUDIO_DeinitializeStart;
|
||||
|
||||
@@ -993,12 +991,12 @@ static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->DetectDevices = COREAUDIO_DetectDevices;
|
||||
impl->FreeDeviceHandle = COREAUDIO_FreeDeviceHandle;
|
||||
#else
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
#endif
|
||||
|
||||
impl->ProvidesOwnCallbackThread = SDL_TRUE;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ static void DSOUND_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
// FindAllDevs is presumably only used on WinXP; Vista and later can use IMMDevice for better results.
|
||||
typedef struct FindAllDevsData
|
||||
{
|
||||
SDL_bool iscapture;
|
||||
SDL_bool recording;
|
||||
SDL_AudioDevice **default_device;
|
||||
LPCGUID default_device_guid;
|
||||
} FindAllDevsData;
|
||||
@@ -189,7 +189,7 @@ static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVO
|
||||
* device before getting the channel mask and output format, making
|
||||
* this information inaccessible at enumeration time
|
||||
*/
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(data->iscapture, str, NULL, cpyguid);
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(data->recording, str, NULL, cpyguid);
|
||||
if (device && data->default_device && data->default_device_guid) {
|
||||
if (SDL_memcmp(cpyguid, data->default_device_guid, sizeof (GUID)) == 0) {
|
||||
*data->default_device = device;
|
||||
@@ -202,11 +202,11 @@ static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVO
|
||||
return TRUE; // keep enumerating.
|
||||
}
|
||||
|
||||
static void DSOUND_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
#ifdef HAVE_MMDEVICEAPI_H
|
||||
if (SupportsIMMDevice) {
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_output, default_capture);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -216,13 +216,13 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevi
|
||||
FindAllDevsData data;
|
||||
GUID guid;
|
||||
|
||||
data.iscapture = SDL_TRUE;
|
||||
data.default_device = default_capture;
|
||||
data.recording = SDL_TRUE;
|
||||
data.default_device = default_recording;
|
||||
data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultCapture, &guid) == DS_OK) ? &guid : NULL;
|
||||
pDirectSoundCaptureEnumerateW(FindAllDevs, &data);
|
||||
|
||||
data.iscapture = SDL_FALSE;
|
||||
data.default_device = default_output;
|
||||
data.recording = SDL_FALSE;
|
||||
data.default_device = default_playback;
|
||||
data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultPlayback, &guid) == DS_OK) ? &guid : NULL;
|
||||
pDirectSoundEnumerateW(FindAllDevs, &data);
|
||||
}
|
||||
@@ -333,7 +333,7 @@ static Uint8 *DSOUND_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->locked_buf;
|
||||
}
|
||||
|
||||
static int DSOUND_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
static int DSOUND_WaitRecordingDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
@@ -349,7 +349,7 @@ static int DSOUND_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DSOUND_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int DSOUND_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
DWORD ptr1len, ptr2len;
|
||||
@@ -376,7 +376,7 @@ static int DSOUND_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int b
|
||||
return (int) ptr1len;
|
||||
}
|
||||
|
||||
static void DSOUND_FlushCapture(SDL_AudioDevice *device)
|
||||
static void DSOUND_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
DWORD junk, cursor;
|
||||
@@ -409,7 +409,7 @@ static void DSOUND_CloseDevice(SDL_AudioDevice *device)
|
||||
|
||||
/* This function tries to create a secondary audio buffer, and returns the
|
||||
number of audio chunks available in the created buffer. This is for
|
||||
playback devices, not capture.
|
||||
playback devices, not recording.
|
||||
*/
|
||||
static int CreateSecondary(SDL_AudioDevice *device, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||
{
|
||||
@@ -450,7 +450,7 @@ static int CreateSecondary(SDL_AudioDevice *device, const DWORD bufsize, WAVEFOR
|
||||
|
||||
/* This function tries to create a capture buffer, and returns the
|
||||
number of audio chunks available in the created buffer. This is for
|
||||
capture devices, not playback.
|
||||
recording devices, not playback.
|
||||
*/
|
||||
static int CreateCaptureBuffer(SDL_AudioDevice *device, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||
{
|
||||
@@ -513,7 +513,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL_assert(guid != NULL);
|
||||
|
||||
HRESULT result;
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
result = pDirectSoundCaptureCreate8(guid, &device->hidden->capture, NULL);
|
||||
if (result != DS_OK) {
|
||||
return SetDSerror("DirectSoundCaptureCreate8", result);
|
||||
@@ -603,7 +603,7 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
|
||||
wfmt.Format.nBlockAlign = wfmt.Format.nChannels * (wfmt.Format.wBitsPerSample / 8);
|
||||
wfmt.Format.nAvgBytesPerSec = wfmt.Format.nSamplesPerSec * wfmt.Format.nBlockAlign;
|
||||
|
||||
const int rc = device->iscapture ? CreateCaptureBuffer(device, bufsize, (WAVEFORMATEX *)&wfmt) : CreateSecondary(device, bufsize, (WAVEFORMATEX *)&wfmt);
|
||||
const int rc = device->recording ? CreateCaptureBuffer(device, bufsize, (WAVEFORMATEX *)&wfmt) : CreateSecondary(device, bufsize, (WAVEFORMATEX *)&wfmt);
|
||||
if (rc == 0) {
|
||||
device->hidden->num_buffers = numchunks;
|
||||
break;
|
||||
@@ -660,15 +660,15 @@ static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = DSOUND_PlayDevice;
|
||||
impl->WaitDevice = DSOUND_WaitDevice;
|
||||
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
|
||||
impl->WaitCaptureDevice = DSOUND_WaitCaptureDevice;
|
||||
impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
|
||||
impl->FlushCapture = DSOUND_FlushCapture;
|
||||
impl->WaitRecordingDevice = DSOUND_WaitRecordingDevice;
|
||||
impl->RecordDevice = DSOUND_RecordDevice;
|
||||
impl->FlushRecording = DSOUND_FlushRecording;
|
||||
impl->CloseDevice = DSOUND_CloseDevice;
|
||||
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
|
||||
impl->DeinitializeStart = DSOUND_DeinitializeStart;
|
||||
impl->Deinitialize = DSOUND_Deinitialize;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ static Uint8 *DISKAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int DISKAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
const int origbuflen = buflen;
|
||||
@@ -79,7 +79,7 @@ static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, in
|
||||
return origbuflen;
|
||||
}
|
||||
|
||||
static void DISKAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void DISKAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
// no op...we don't advance the file pointer or anything.
|
||||
}
|
||||
@@ -96,19 +96,19 @@ static void DISKAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_filename(const SDL_bool iscapture)
|
||||
static const char *get_filename(const SDL_bool recording)
|
||||
{
|
||||
const char *devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
|
||||
const char *devname = SDL_getenv(recording ? DISKENVR_INFILE : DISKENVR_OUTFILE);
|
||||
if (!devname) {
|
||||
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
|
||||
devname = recording ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
|
||||
}
|
||||
return devname;
|
||||
}
|
||||
|
||||
static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_bool iscapture = device->iscapture;
|
||||
const char *fname = get_filename(iscapture);
|
||||
SDL_bool recording = device->recording;
|
||||
const char *fname = get_filename(recording);
|
||||
const char *envr = SDL_getenv(DISKENVR_IODELAY);
|
||||
|
||||
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
|
||||
@@ -123,13 +123,13 @@ static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// Open the "audio device"
|
||||
device->hidden->io = SDL_IOFromFile(fname, iscapture ? "rb" : "wb");
|
||||
device->hidden->io = SDL_IOFromFile(fname, recording ? "rb" : "wb");
|
||||
if (!device->hidden->io) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate mixing buffer
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
|
||||
if (!device->hidden->mixbuf) {
|
||||
return -1;
|
||||
@@ -138,30 +138,30 @@ static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, "You are using the SDL disk i/o audio driver!");
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, " %s file [%s].\n", iscapture ? "Reading from" : "Writing to", fname);
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO, " %s file [%s].\n", recording ? "Reading from" : "Writing to", fname);
|
||||
|
||||
return 0; // We're ready to rock and roll. :-)
|
||||
}
|
||||
|
||||
static void DISKAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void DISKAUDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
*default_output = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
|
||||
*default_capture = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
|
||||
*default_playback = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_PLAYBACK_DEVNAME, NULL, (void *)0x1);
|
||||
*default_recording = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_RECORDING_DEVNAME, NULL, (void *)0x2);
|
||||
}
|
||||
|
||||
static SDL_bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
impl->OpenDevice = DISKAUDIO_OpenDevice;
|
||||
impl->WaitDevice = DISKAUDIO_WaitDevice;
|
||||
impl->WaitCaptureDevice = DISKAUDIO_WaitDevice;
|
||||
impl->WaitRecordingDevice = DISKAUDIO_WaitDevice;
|
||||
impl->PlayDevice = DISKAUDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
|
||||
impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = DISKAUDIO_FlushCapture;
|
||||
impl->RecordDevice = DISKAUDIO_RecordDevice;
|
||||
impl->FlushRecording = DISKAUDIO_FlushRecording;
|
||||
impl->CloseDevice = DISKAUDIO_CloseDevice;
|
||||
impl->DetectDevices = DISKAUDIO_DetectDevices;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_dspaudio.h"
|
||||
|
||||
static void DSP_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void DSP_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
SDL_EnumUnixAudioDevices(SDL_FALSE, NULL);
|
||||
}
|
||||
@@ -74,7 +74,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// Open the audio device; we hardcode the device path in `device->name` for lack of better info, so use that.
|
||||
const int flags = ((device->iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
const int flags = ((device->recording) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
device->hidden->audio_fd = open(device->name, flags | O_CLOEXEC, 0);
|
||||
if (device->hidden->audio_fd < 0) {
|
||||
return SDL_SetError("Couldn't open %s: %s", device->name, strerror(errno));
|
||||
@@ -188,7 +188,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
|
||||
#endif
|
||||
|
||||
// Allocate mixing buffer
|
||||
if (!device->iscapture) {
|
||||
if (!device->recording) {
|
||||
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
|
||||
if (!device->hidden->mixbuf) {
|
||||
return -1;
|
||||
@@ -201,7 +201,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
static int DSP_WaitDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const unsigned long ioctlreq = device->iscapture ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE;
|
||||
const unsigned long ioctlreq = device->recording ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE;
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
@@ -242,12 +242,12 @@ static Uint8 *DSP_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static int DSP_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int DSP_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
return (int)read(device->hidden->audio_fd, buffer, buflen);
|
||||
}
|
||||
|
||||
static void DSP_FlushCapture(SDL_AudioDevice *device)
|
||||
static void DSP_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
audio_buf_info info;
|
||||
@@ -287,11 +287,11 @@ static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = DSP_PlayDevice;
|
||||
impl->GetDeviceBuf = DSP_GetDeviceBuf;
|
||||
impl->CloseDevice = DSP_CloseDevice;
|
||||
impl->WaitCaptureDevice = DSP_WaitDevice;
|
||||
impl->CaptureFromDevice = DSP_CaptureFromDevice;
|
||||
impl->FlushCapture = DSP_FlushCapture;
|
||||
impl->WaitRecordingDevice = DSP_WaitDevice;
|
||||
impl->RecordDevice = DSP_RecordDevice;
|
||||
impl->FlushRecording = DSP_FlushRecording;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!device->iscapture) {
|
||||
if (!device->recording) {
|
||||
device->hidden->mixbuf = (Uint8 *) SDL_malloc(device->buffer_size);
|
||||
if (!device->hidden->mixbuf) {
|
||||
return -1;
|
||||
@@ -69,7 +69,7 @@ static Uint8 *DUMMYAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static int DUMMYAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int DUMMYAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
// always return a full buffer of silence.
|
||||
SDL_memset(buffer, device->silence_value, buflen);
|
||||
@@ -82,12 +82,12 @@ static SDL_bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->CloseDevice = DUMMYAUDIO_CloseDevice;
|
||||
impl->WaitDevice = DUMMYAUDIO_WaitDevice;
|
||||
impl->GetDeviceBuf = DUMMYAUDIO_GetDeviceBuf;
|
||||
impl->WaitCaptureDevice = DUMMYAUDIO_WaitDevice;
|
||||
impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
|
||||
impl->WaitRecordingDevice = DUMMYAUDIO_WaitDevice;
|
||||
impl->RecordDevice = DUMMYAUDIO_RecordDevice;
|
||||
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ static int EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buff
|
||||
const int framelen = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
var numChannels = SDL3.audio.currentOutputBuffer['numberOfChannels'];
|
||||
var numChannels = SDL3.audio_playback.currentPlaybackBuffer['numberOfChannels'];
|
||||
for (var c = 0; c < numChannels; ++c) {
|
||||
var channelData = SDL3.audio.currentOutputBuffer['getChannelData'](c);
|
||||
var channelData = SDL3.audio_playback.currentPlaybackBuffer['getChannelData'](c);
|
||||
if (channelData.length != $1) {
|
||||
throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
throw 'Web Audio playback buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
}
|
||||
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
@@ -57,20 +57,20 @@ static int EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buff
|
||||
}
|
||||
|
||||
|
||||
static void EMSCRIPTENAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void EMSCRIPTENAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
// Do nothing, the new data will just be dropped.
|
||||
}
|
||||
|
||||
static int EMSCRIPTENAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int EMSCRIPTENAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
var numChannels = SDL3.capture.currentCaptureBuffer.numberOfChannels;
|
||||
var numChannels = SDL3.audio_recording.currentRecordingBuffer.numberOfChannels;
|
||||
for (var c = 0; c < numChannels; ++c) {
|
||||
var channelData = SDL3.capture.currentCaptureBuffer.getChannelData(c);
|
||||
var channelData = SDL3.audio_recording.currentRecordingBuffer.getChannelData(c);
|
||||
if (channelData.length != $1) {
|
||||
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
throw 'Web Audio recording buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
}
|
||||
|
||||
if (numChannels == 1) { // fastpath this a little for the common (mono) case.
|
||||
@@ -97,37 +97,37 @@ static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
if ($0) {
|
||||
if (SDL3.capture.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.capture.silenceTimer);
|
||||
if (SDL3.audio_recording.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio_recording.silenceTimer);
|
||||
}
|
||||
if (SDL3.capture.stream !== undefined) {
|
||||
var tracks = SDL3.capture.stream.getAudioTracks();
|
||||
if (SDL3.audio_recording.stream !== undefined) {
|
||||
var tracks = SDL3.audio_recording.stream.getAudioTracks();
|
||||
for (var i = 0; i < tracks.length; i++) {
|
||||
SDL3.capture.stream.removeTrack(tracks[i]);
|
||||
SDL3.audio_recording.stream.removeTrack(tracks[i]);
|
||||
}
|
||||
}
|
||||
if (SDL3.capture.scriptProcessorNode !== undefined) {
|
||||
SDL3.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
|
||||
SDL3.capture.scriptProcessorNode.disconnect();
|
||||
if (SDL3.audio_recording.scriptProcessorNode !== undefined) {
|
||||
SDL3.audio_recording.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
|
||||
SDL3.audio_recording.scriptProcessorNode.disconnect();
|
||||
}
|
||||
if (SDL3.capture.mediaStreamNode !== undefined) {
|
||||
SDL3.capture.mediaStreamNode.disconnect();
|
||||
if (SDL3.audio_recording.mediaStreamNode !== undefined) {
|
||||
SDL3.audio_recording.mediaStreamNode.disconnect();
|
||||
}
|
||||
SDL3.capture = undefined;
|
||||
SDL3.audio_recording = undefined;
|
||||
} else {
|
||||
if (SDL3.audio.scriptProcessorNode != undefined) {
|
||||
SDL3.audio.scriptProcessorNode.disconnect();
|
||||
if (SDL3.audio_playback.scriptProcessorNode != undefined) {
|
||||
SDL3.audio_playback.scriptProcessorNode.disconnect();
|
||||
}
|
||||
if (SDL3.audio.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio.silenceTimer);
|
||||
if (SDL3.audio_playback.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio_playback.silenceTimer);
|
||||
}
|
||||
SDL3.audio = undefined;
|
||||
SDL3.audio_playback = undefined;
|
||||
}
|
||||
if ((SDL3.audioContext !== undefined) && (SDL3.audio === undefined) && (SDL3.capture === undefined)) {
|
||||
if ((SDL3.audioContext !== undefined) && (SDL3.audio_playback === undefined) && (SDL3.audio_recording === undefined)) {
|
||||
SDL3.audioContext.close();
|
||||
SDL3.audioContext = undefined;
|
||||
}
|
||||
}, device->iscapture);
|
||||
}, device->recording);
|
||||
|
||||
SDL_free(device->hidden->mixbuf);
|
||||
SDL_free(device->hidden);
|
||||
@@ -149,9 +149,9 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
var SDL3 = Module['SDL3'];
|
||||
if (!$0) {
|
||||
SDL3.audio = {};
|
||||
SDL3.audio_playback = {};
|
||||
} else {
|
||||
SDL3.capture = {};
|
||||
SDL3.audio_recording = {};
|
||||
}
|
||||
|
||||
if (!SDL3.audioContext) {
|
||||
@@ -167,7 +167,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
return SDL3.audioContext === undefined ? -1 : 0;
|
||||
}, device->iscapture);
|
||||
}, device->recording);
|
||||
|
||||
if (result < 0) {
|
||||
return SDL_SetError("Web Audio API is not available!");
|
||||
@@ -186,7 +186,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
if (!device->iscapture) {
|
||||
if (!device->recording) {
|
||||
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
|
||||
if (!device->hidden->mixbuf) {
|
||||
return -1;
|
||||
@@ -194,18 +194,18 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
|
||||
}
|
||||
|
||||
if (device->iscapture) {
|
||||
/* The idea is to take the capture media stream, hook it up to an
|
||||
if (device->recording) {
|
||||
/* The idea is to take the recording media stream, hook it up to an
|
||||
audio graph where we can pass it through a ScriptProcessorNode
|
||||
to access the raw PCM samples and push them to the SDL app's
|
||||
callback. From there, we "process" the audio data into silence
|
||||
and forget about it.
|
||||
|
||||
This should, strictly speaking, use MediaRecorder for capture, but
|
||||
This should, strictly speaking, use MediaRecorder for recording, but
|
||||
this API is cleaner to use and better supported, and fires a
|
||||
callback whenever there's enough data to fire down into the app.
|
||||
The downside is that we are spending CPU time silencing a buffer
|
||||
that the audiocontext uselessly mixes into any output. On the
|
||||
that the audiocontext uselessly mixes into any playback. On the
|
||||
upside, both of those things are not only run in native code in
|
||||
the browser, they're probably SIMD code, too. MediaRecorder
|
||||
feels like it's a pretty inefficient tapdance in similar ways,
|
||||
@@ -214,67 +214,67 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
var have_microphone = function(stream) {
|
||||
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
|
||||
if (SDL3.capture.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.capture.silenceTimer);
|
||||
SDL3.capture.silenceTimer = undefined;
|
||||
SDL3.capture.silenceBuffer = undefined
|
||||
//console.log('SDL audio recording: we have a microphone! Replacing silence callback.');
|
||||
if (SDL3.audio_recording.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio_recording.silenceTimer);
|
||||
SDL3.audio_recording.silenceTimer = undefined;
|
||||
SDL3.audio_recording.silenceBuffer = undefined
|
||||
}
|
||||
SDL3.capture.mediaStreamNode = SDL3.audioContext.createMediaStreamSource(stream);
|
||||
SDL3.capture.scriptProcessorNode = SDL3.audioContext.createScriptProcessor($1, $0, 1);
|
||||
SDL3.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {
|
||||
if ((SDL3 === undefined) || (SDL3.capture === undefined)) { return; }
|
||||
SDL3.audio_recording.mediaStreamNode = SDL3.audioContext.createMediaStreamSource(stream);
|
||||
SDL3.audio_recording.scriptProcessorNode = SDL3.audioContext.createScriptProcessor($1, $0, 1);
|
||||
SDL3.audio_recording.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {
|
||||
if ((SDL3 === undefined) || (SDL3.audio_recording === undefined)) { return; }
|
||||
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
|
||||
SDL3.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
|
||||
SDL3.audio_recording.currentRecordingBuffer = audioProcessingEvent.inputBuffer;
|
||||
dynCall('vi', $2, [$3]);
|
||||
};
|
||||
SDL3.capture.mediaStreamNode.connect(SDL3.capture.scriptProcessorNode);
|
||||
SDL3.capture.scriptProcessorNode.connect(SDL3.audioContext.destination);
|
||||
SDL3.capture.stream = stream;
|
||||
SDL3.audio_recording.mediaStreamNode.connect(SDL3.audio_recording.scriptProcessorNode);
|
||||
SDL3.audio_recording.scriptProcessorNode.connect(SDL3.audioContext.destination);
|
||||
SDL3.audio_recording.stream = stream;
|
||||
};
|
||||
|
||||
var no_microphone = function(error) {
|
||||
//console.log('SDL audio capture: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.');
|
||||
//console.log('SDL audio recording: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.');
|
||||
};
|
||||
|
||||
// we write silence to the audio callback until the microphone is available (user approves use, etc).
|
||||
SDL3.capture.silenceBuffer = SDL3.audioContext.createBuffer($0, $1, SDL3.audioContext.sampleRate);
|
||||
SDL3.capture.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
SDL3.audio_recording.silenceBuffer = SDL3.audioContext.createBuffer($0, $1, SDL3.audioContext.sampleRate);
|
||||
SDL3.audio_recording.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
var silence_callback = function() {
|
||||
SDL3.capture.currentCaptureBuffer = SDL3.capture.silenceBuffer;
|
||||
SDL3.audio_recording.currentRecordingBuffer = SDL3.audio_recording.silenceBuffer;
|
||||
dynCall('vi', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.capture.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
SDL3.audio_recording.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
|
||||
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
|
||||
} else if (navigator.webkitGetUserMedia !== undefined) {
|
||||
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
||||
}
|
||||
}, device->spec.channels, device->sample_frames, SDL_CaptureAudioThreadIterate, device);
|
||||
}, device->spec.channels, device->sample_frames, SDL_RecordingAudioThreadIterate, device);
|
||||
} else {
|
||||
// setup a ScriptProcessorNode
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var SDL3 = Module['SDL3'];
|
||||
SDL3.audio.scriptProcessorNode = SDL3.audioContext['createScriptProcessor']($1, 0, $0);
|
||||
SDL3.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
|
||||
if ((SDL3 === undefined) || (SDL3.audio === undefined)) { return; }
|
||||
SDL3.audio_playback.scriptProcessorNode = SDL3.audioContext['createScriptProcessor']($1, 0, $0);
|
||||
SDL3.audio_playback.scriptProcessorNode['onaudioprocess'] = function (e) {
|
||||
if ((SDL3 === undefined) || (SDL3.audio_playback === undefined)) { return; }
|
||||
// if we're actually running the node, we don't need the fake callback anymore, so kill it.
|
||||
if (SDL3.audio.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio.silenceTimer);
|
||||
SDL3.audio.silenceTimer = undefined;
|
||||
SDL3.audio.silenceBuffer = undefined;
|
||||
if (SDL3.audio_playback.silenceTimer !== undefined) {
|
||||
clearInterval(SDL3.audio_playback.silenceTimer);
|
||||
SDL3.audio_playback.silenceTimer = undefined;
|
||||
SDL3.audio_playback.silenceBuffer = undefined;
|
||||
}
|
||||
SDL3.audio.currentOutputBuffer = e['outputBuffer'];
|
||||
SDL3.audio_playback.currentPlaybackBuffer = e['outputBuffer'];
|
||||
dynCall('vi', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||
SDL3.audio_playback.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||
|
||||
if (SDL3.audioContext.state === 'suspended') { // uhoh, autoplay is blocked.
|
||||
SDL3.audio.silenceBuffer = SDL3.audioContext.createBuffer($0, $1, SDL3.audioContext.sampleRate);
|
||||
SDL3.audio.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
SDL3.audio_playback.silenceBuffer = SDL3.audioContext.createBuffer($0, $1, SDL3.audioContext.sampleRate);
|
||||
SDL3.audio_playback.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
var silence_callback = function() {
|
||||
if ((typeof navigator.userActivation) !== 'undefined') { // Almost everything modern except Firefox (as of August 2023)
|
||||
if (navigator.userActivation.hasBeenActive) {
|
||||
@@ -284,14 +284,14 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
// the buffer that gets filled here just gets ignored, so the app can make progress
|
||||
// and/or avoid flooding audio queues until we can actually play audio.
|
||||
SDL3.audio.currentOutputBuffer = SDL3.audio.silenceBuffer;
|
||||
SDL3.audio_playback.currentPlaybackBuffer = SDL3.audio_playback.silenceBuffer;
|
||||
dynCall('vi', $2, [$3]);
|
||||
SDL3.audio.currentOutputBuffer = undefined;
|
||||
SDL3.audio_playback.currentPlaybackBuffer = undefined;
|
||||
};
|
||||
|
||||
SDL3.audio.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
SDL3.audio_playback.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
}
|
||||
}, device->spec.channels, device->sample_frames, SDL_OutputAudioThreadIterate, device);
|
||||
}, device->spec.channels, device->sample_frames, SDL_PlaybackAudioThreadIterate, device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -299,16 +299,16 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
SDL_bool available, capture_available;
|
||||
SDL_bool available, recording_available;
|
||||
|
||||
impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
|
||||
impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
|
||||
impl->GetDeviceBuf = EMSCRIPTENAUDIO_GetDeviceBuf;
|
||||
impl->PlayDevice = EMSCRIPTENAUDIO_PlayDevice;
|
||||
impl->FlushCapture = EMSCRIPTENAUDIO_FlushCapture;
|
||||
impl->CaptureFromDevice = EMSCRIPTENAUDIO_CaptureFromDevice;
|
||||
impl->FlushRecording = EMSCRIPTENAUDIO_FlushRecording;
|
||||
impl->RecordDevice = EMSCRIPTENAUDIO_RecordDevice;
|
||||
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
|
||||
// technically, this is just runs in idle time in the main thread, but it's close enough to a "thread" for our purposes.
|
||||
impl->ProvidesOwnCallbackThread = SDL_TRUE;
|
||||
@@ -327,7 +327,7 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
SDL_SetError("No audio context available");
|
||||
}
|
||||
|
||||
capture_available = available && MAIN_THREAD_EM_ASM_INT({
|
||||
recording_available = available && MAIN_THREAD_EM_ASM_INT({
|
||||
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
|
||||
return true;
|
||||
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
|
||||
@@ -336,8 +336,8 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
return false;
|
||||
});
|
||||
|
||||
impl->HasCaptureSupport = capture_available;
|
||||
impl->OnlyHasDefaultCaptureDevice = capture_available;
|
||||
impl->HasRecordingSupport = recording_available;
|
||||
impl->OnlyHasDefaultRecordingDevice = recording_available;
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ static void FillSound(void *data, void *stream, size_t len, const media_raw_audi
|
||||
SDL_assert(device->hidden->current_buffer_len == 0);
|
||||
device->hidden->current_buffer = (Uint8 *) stream;
|
||||
device->hidden->current_buffer_len = (int) len;
|
||||
SDL_OutputAudioThreadIterate(device);
|
||||
SDL_PlaybackAudioThreadIterate(device);
|
||||
}
|
||||
|
||||
static void HAIKUAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
@@ -207,7 +207,7 @@ static SDL_bool HAIKUAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->CloseDevice = HAIKUAUDIO_CloseDevice;
|
||||
impl->Deinitialize = HAIKUAUDIO_Deinitialize;
|
||||
impl->ProvidesOwnCallbackThread = SDL_TRUE;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ static int jackBufferSizeCallback(jack_nframes_t nframes, void *arg)
|
||||
static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
|
||||
SDL_OutputAudioThreadIterate((SDL_AudioDevice *)arg);
|
||||
SDL_PlaybackAudioThreadIterate((SDL_AudioDevice *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -201,14 +201,14 @@ static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
return (Uint8 *)device->hidden->iobuffer;
|
||||
}
|
||||
|
||||
static int jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
|
||||
static int jackProcessRecordingCallback(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
|
||||
SDL_CaptureAudioThreadIterate((SDL_AudioDevice *)arg);
|
||||
SDL_RecordingAudioThreadIterate((SDL_AudioDevice *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int JACK_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
|
||||
static int JACK_RecordDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
|
||||
{
|
||||
float *buffer = (float *) vbuffer;
|
||||
jack_port_t **ports = device->hidden->sdlports;
|
||||
@@ -230,7 +230,7 @@ static int JACK_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer, int bu
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void JACK_FlushCapture(SDL_AudioDevice *device)
|
||||
static void JACK_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
// do nothing, the data will just be replaced next callback.
|
||||
}
|
||||
@@ -277,15 +277,15 @@ static const char *GetJackAppName(void)
|
||||
|
||||
static int JACK_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
/* Note that JACK uses "output" for capture devices (they output audio
|
||||
/* Note that JACK uses "output" for recording devices (they output audio
|
||||
data to us) and "input" for playback (we input audio data to them).
|
||||
Likewise, SDL's playback port will be "output" (we write data out)
|
||||
and capture will be "input" (we read data in). */
|
||||
SDL_bool iscapture = device->iscapture;
|
||||
const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
|
||||
const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
|
||||
const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
|
||||
const char *sdlportstr = iscapture ? "input" : "output";
|
||||
and recording will be "input" (we read data in). */
|
||||
const SDL_bool recording = device->recording;
|
||||
const unsigned long sysportflags = recording ? JackPortIsOutput : JackPortIsInput;
|
||||
const unsigned long sdlportflags = recording ? JackPortIsInput : JackPortIsOutput;
|
||||
const JackProcessCallback callback = recording ? jackProcessRecordingCallback : jackProcessPlaybackCallback;
|
||||
const char *sdlportstr = recording ? "input" : "output";
|
||||
const char **devports = NULL;
|
||||
int *audio_ports;
|
||||
jack_client_t *client = NULL;
|
||||
@@ -339,7 +339,7 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
if (!device->iscapture) {
|
||||
if (!recording) {
|
||||
device->hidden->iobuffer = (float *)SDL_calloc(1, device->buffer_size);
|
||||
if (!device->hidden->iobuffer) {
|
||||
SDL_free(audio_ports);
|
||||
@@ -385,8 +385,8 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
|
||||
// once activated, we can connect all the ports.
|
||||
for (i = 0; i < channels; i++) {
|
||||
const char *sdlport = JACK_jack_port_name(device->hidden->sdlports[i]);
|
||||
const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
|
||||
const char *dstport = iscapture ? sdlport : devports[audio_ports[i]];
|
||||
const char *srcport = recording ? devports[audio_ports[i]] : sdlport;
|
||||
const char *dstport = recording ? sdlport : devports[audio_ports[i]];
|
||||
if (JACK_jack_connect(client, srcport, dstport) != 0) {
|
||||
SDL_free(audio_ports);
|
||||
return SDL_SetError("Couldn't connect JACK ports: %s => %s", srcport, dstport);
|
||||
@@ -427,11 +427,11 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = JACK_PlayDevice;
|
||||
impl->CloseDevice = JACK_CloseDevice;
|
||||
impl->Deinitialize = JACK_Deinitialize;
|
||||
impl->CaptureFromDevice = JACK_CaptureFromDevice;
|
||||
impl->FlushCapture = JACK_FlushCapture;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->RecordDevice = JACK_RecordDevice;
|
||||
impl->FlushRecording = JACK_FlushRecording;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
impl->ProvidesOwnCallbackThread = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
@@ -269,10 +269,10 @@ static SDL_bool N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->GetDeviceBuf = N3DSAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = N3DSAUDIO_CloseDevice;
|
||||
impl->ThreadInit = N3DSAUDIO_ThreadInit;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
|
||||
// Should be possible, but micInit would fail
|
||||
impl->HasCaptureSupport = SDL_FALSE;
|
||||
impl->HasRecordingSupport = SDL_FALSE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
//#define DEBUG_AUDIO
|
||||
|
||||
static void NETBSDAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void NETBSDAUDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
SDL_EnumUnixAudioDevices(SDL_FALSE, NULL);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
|
||||
return;
|
||||
}
|
||||
|
||||
prinfo = device->iscapture ? &info.record : &info.play;
|
||||
prinfo = device->recording ? &info.record : &info.play;
|
||||
|
||||
fprintf(stderr, "\n"
|
||||
"[%s info]\n"
|
||||
@@ -73,7 +73,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
|
||||
"waiting : %s\n"
|
||||
"active : %s\n"
|
||||
"",
|
||||
device->iscapture ? "record" : "play",
|
||||
device->recording ? "record" : "play",
|
||||
prinfo->buffer_size,
|
||||
prinfo->sample_rate,
|
||||
prinfo->channels,
|
||||
@@ -116,7 +116,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
|
||||
|
||||
static int NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
audio_info_t info;
|
||||
const int rc = ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info);
|
||||
@@ -128,10 +128,10 @@ static int NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
fprintf(stderr, "netbsdaudio WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
const size_t remain = (size_t)((iscapture ? info.record.seek : info.play.seek) * SDL_AUDIO_BYTESIZE(device->spec.format));
|
||||
if (!iscapture && (remain >= device->buffer_size)) {
|
||||
const size_t remain = (size_t)((recording ? info.record.seek : info.play.seek) * SDL_AUDIO_BYTESIZE(device->spec.format));
|
||||
if (!recording && (remain >= device->buffer_size)) {
|
||||
SDL_Delay(10);
|
||||
} else if (iscapture && (remain < device->buffer_size)) {
|
||||
} else if (recording && (remain < device->buffer_size)) {
|
||||
SDL_Delay(10);
|
||||
} else {
|
||||
break; // ready to go!
|
||||
@@ -160,7 +160,7 @@ static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size
|
||||
return device->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
|
||||
static int NETBSDAUDIO_RecordDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
|
||||
{
|
||||
Uint8 *buffer = (Uint8 *)vbuffer;
|
||||
const int br = read(device->hidden->audio_fd, buffer, buflen);
|
||||
@@ -171,12 +171,12 @@ static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer,
|
||||
}
|
||||
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Captured %d bytes of audio data\n", br);
|
||||
fprintf(stderr, "Recorded %d bytes of audio data\n", br);
|
||||
#endif
|
||||
return br;
|
||||
}
|
||||
|
||||
static void NETBSDAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void NETBSDAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
audio_info_t info;
|
||||
@@ -208,10 +208,10 @@ static void NETBSDAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
|
||||
static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
int encoding = AUDIO_ENCODING_NONE;
|
||||
audio_info_t info, hwinfo;
|
||||
struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play;
|
||||
struct audio_prinfo *prinfo = recording ? &info.record : &info.play;
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
|
||||
@@ -220,7 +220,7 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// Open the audio device; we hardcode the device path in `device->name` for lack of better info, so use that.
|
||||
const int flags = ((device->iscapture) ? O_RDONLY : O_WRONLY);
|
||||
const int flags = ((device->recording) ? O_RDONLY : O_WRONLY);
|
||||
device->hidden->audio_fd = open(device->name, flags | O_CLOEXEC);
|
||||
if (device->hidden->audio_fd < 0) {
|
||||
return SDL_SetError("Couldn't open %s: %s", device->name, strerror(errno));
|
||||
@@ -231,7 +231,7 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
#ifdef AUDIO_GETFORMAT // Introduced in NetBSD 9.0
|
||||
if (ioctl(device->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
|
||||
// Use the device's native sample rate so the kernel doesn't have to resample.
|
||||
device->spec.freq = iscapture ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
|
||||
device->spec.freq = recording ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -289,7 +289,7 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
// Allocate mixing buffer
|
||||
device->hidden->mixlen = device->buffer_size;
|
||||
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->hidden->mixlen);
|
||||
@@ -312,11 +312,11 @@ static SDL_bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = NETBSDAUDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = NETBSDAUDIO_CloseDevice;
|
||||
impl->WaitCaptureDevice = NETBSDAUDIO_WaitDevice;
|
||||
impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
|
||||
impl->WaitRecordingDevice = NETBSDAUDIO_WaitDevice;
|
||||
impl->RecordDevice = NETBSDAUDIO_RecordDevice;
|
||||
impl->FlushRecording = NETBSDAUDIO_FlushRecording;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -107,10 +107,10 @@ static const char *sldevaudioplayerstr = "SLES Audio Player";
|
||||
|
||||
#define SLES_DEV_AUDIO_RECORDER sldevaudiorecorderstr
|
||||
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
|
||||
static void OPENSLES_DetectDevices( int iscapture )
|
||||
static void OPENSLES_DetectDevices( int recording )
|
||||
{
|
||||
LOGI( "openSLES_DetectDevices()" );
|
||||
if ( iscapture )
|
||||
if ( recording )
|
||||
addfn( SLES_DEV_AUDIO_RECORDER );
|
||||
else
|
||||
addfn( SLES_DEV_AUDIO_PLAYER );
|
||||
@@ -622,12 +622,12 @@ static int OPENSLES_OpenDevice(SDL_AudioDevice *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (device->iscapture) {
|
||||
LOGI("OPENSLES_OpenDevice() for capture");
|
||||
if (device->recording) {
|
||||
LOGI("OPENSLES_OpenDevice() for recording");
|
||||
return OPENSLES_CreatePCMRecorder(device);
|
||||
} else {
|
||||
int ret;
|
||||
LOGI("OPENSLES_OpenDevice() for playing");
|
||||
LOGI("OPENSLES_OpenDevice() for playback");
|
||||
ret = OPENSLES_CreatePCMPlayer(device);
|
||||
if (ret < 0) {
|
||||
// Another attempt to open the device with a lower frequency
|
||||
@@ -699,7 +699,7 @@ static Uint8 *OPENSLES_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
|
||||
return audiodata->pmixbuff[audiodata->next_buffer];
|
||||
}
|
||||
|
||||
static int OPENSLES_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int OPENSLES_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = device->hidden;
|
||||
|
||||
@@ -726,8 +726,8 @@ static void OPENSLES_CloseDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
// struct SDL_PrivateAudioData *audiodata = device->hidden;
|
||||
if (device->hidden) {
|
||||
if (device->iscapture) {
|
||||
LOGI("OPENSLES_CloseDevice() for capture");
|
||||
if (device->recording) {
|
||||
LOGI("OPENSLES_CloseDevice() for recording");
|
||||
OPENSLES_DestroyPCMRecorder(device);
|
||||
} else {
|
||||
LOGI("OPENSLES_CloseDevice() for playing");
|
||||
@@ -756,15 +756,15 @@ static SDL_bool OPENSLES_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->WaitDevice = OPENSLES_WaitDevice;
|
||||
impl->PlayDevice = OPENSLES_PlayDevice;
|
||||
impl->GetDeviceBuf = OPENSLES_GetDeviceBuf;
|
||||
impl->WaitCaptureDevice = OPENSLES_WaitDevice;
|
||||
impl->CaptureFromDevice = OPENSLES_CaptureFromDevice;
|
||||
impl->WaitRecordingDevice = OPENSLES_WaitDevice;
|
||||
impl->RecordDevice = OPENSLES_RecordDevice;
|
||||
impl->CloseDevice = OPENSLES_CloseDevice;
|
||||
impl->Deinitialize = OPENSLES_DestroyEngine;
|
||||
|
||||
// and the capabilities
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
|
||||
LOGI("OPENSLES_Init() - success");
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ struct io_node
|
||||
struct spa_list link;
|
||||
|
||||
Uint32 id;
|
||||
SDL_bool is_capture;
|
||||
SDL_bool recording;
|
||||
SDL_AudioSpec spec;
|
||||
|
||||
const char *name; // Friendly name
|
||||
@@ -356,7 +356,7 @@ static SDL_bool io_list_check_add(struct io_node *node)
|
||||
spa_list_append(&hotplug_io_list, &node->link);
|
||||
|
||||
if (hotplug_events_enabled) {
|
||||
SDL_AddAudioDevice(node->is_capture, node->name, &node->spec, PW_ID_TO_HANDLE(node->id));
|
||||
SDL_AddAudioDevice(node->recording, node->name, &node->spec, PW_ID_TO_HANDLE(node->id));
|
||||
}
|
||||
|
||||
dup_found:
|
||||
@@ -706,15 +706,15 @@ static void registry_event_global_callback(void *object, uint32_t id, uint32_t p
|
||||
const char *node_desc;
|
||||
const char *node_path;
|
||||
struct io_node *io;
|
||||
SDL_bool is_capture;
|
||||
SDL_bool recording;
|
||||
int desc_buffer_len;
|
||||
int path_buffer_len;
|
||||
|
||||
// Just want sink and capture
|
||||
// Just want sink and source
|
||||
if (!SDL_strcasecmp(media_class, "Audio/Sink")) {
|
||||
is_capture = SDL_FALSE;
|
||||
recording = SDL_FALSE;
|
||||
} else if (!SDL_strcasecmp(media_class, "Audio/Source")) {
|
||||
is_capture = SDL_TRUE;
|
||||
recording = SDL_TRUE;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -740,7 +740,7 @@ static void registry_event_global_callback(void *object, uint32_t id, uint32_t p
|
||||
|
||||
// Begin setting the node properties
|
||||
io->id = id;
|
||||
io->is_capture = is_capture;
|
||||
io->recording = recording;
|
||||
io->spec.format = SDL_AUDIO_F32; // Pipewire uses floats internally, other formats require conversion.
|
||||
io->name = io->buf;
|
||||
io->path = io->buf + desc_buffer_len;
|
||||
@@ -858,7 +858,7 @@ static void hotplug_loop_destroy(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
struct io_node *io;
|
||||
|
||||
@@ -870,14 +870,14 @@ static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDe
|
||||
}
|
||||
|
||||
spa_list_for_each (io, &hotplug_io_list, link) {
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(io->recording, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
|
||||
if (pipewire_default_sink_id && SDL_strcmp(io->path, pipewire_default_sink_id) == 0) {
|
||||
if (!io->is_capture) {
|
||||
*default_output = device;
|
||||
if (!io->recording) {
|
||||
*default_playback = device;
|
||||
}
|
||||
} else if (pipewire_default_source_id && SDL_strcmp(io->path, pipewire_default_source_id) == 0) {
|
||||
if (io->is_capture) {
|
||||
*default_capture = device;
|
||||
if (io->recording) {
|
||||
*default_recording = device;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -969,7 +969,7 @@ static void initialize_spa_info(const SDL_AudioSpec *spec, struct spa_audio_info
|
||||
|
||||
static Uint8 *PIPEWIRE_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
{
|
||||
// See if a buffer is available. If this returns NULL, SDL_OutputAudioThreadIterate will return SDL_FALSE, but since we own the thread, it won't kill playback.
|
||||
// See if a buffer is available. If this returns NULL, SDL_PlaybackAudioThreadIterate will return SDL_FALSE, but since we own the thread, it won't kill playback.
|
||||
// !!! FIXME: It's not clear to me if this ever returns NULL or if this was just defensive coding.
|
||||
|
||||
struct pw_stream *stream = device->hidden->stream;
|
||||
@@ -1005,10 +1005,10 @@ static int PIPEWIRE_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int
|
||||
|
||||
static void output_callback(void *data)
|
||||
{
|
||||
SDL_OutputAudioThreadIterate((SDL_AudioDevice *)data);
|
||||
SDL_PlaybackAudioThreadIterate((SDL_AudioDevice *)data);
|
||||
}
|
||||
|
||||
static void PIPEWIRE_FlushCapture(SDL_AudioDevice *device)
|
||||
static void PIPEWIRE_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct pw_stream *stream = device->hidden->stream;
|
||||
struct pw_buffer *pw_buf = PIPEWIRE_pw_stream_dequeue_buffer(stream);
|
||||
@@ -1017,7 +1017,7 @@ static void PIPEWIRE_FlushCapture(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static int PIPEWIRE_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int PIPEWIRE_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct pw_stream *stream = device->hidden->stream;
|
||||
struct pw_buffer *pw_buf = PIPEWIRE_pw_stream_dequeue_buffer(stream);
|
||||
@@ -1046,14 +1046,14 @@ static int PIPEWIRE_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int
|
||||
|
||||
static void input_callback(void *data)
|
||||
{
|
||||
SDL_CaptureAudioThreadIterate((SDL_AudioDevice *)data);
|
||||
SDL_RecordingAudioThreadIterate((SDL_AudioDevice *)data);
|
||||
}
|
||||
|
||||
static void stream_add_buffer_callback(void *data, struct pw_buffer *buffer)
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) data;
|
||||
|
||||
if (device->iscapture == SDL_FALSE) {
|
||||
if (device->recording == SDL_FALSE) {
|
||||
/* Clamp the output spec samples and size to the max size of the Pipewire buffer.
|
||||
If they exceed the maximum size of the Pipewire buffer, double buffering will be used. */
|
||||
if (device->buffer_size > buffer->buffer->datas[0].maxsize) {
|
||||
@@ -1110,7 +1110,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
struct pw_properties *props;
|
||||
const char *app_name, *icon_name, *app_id, *stream_name, *stream_role, *error;
|
||||
Uint32 node_id = !device->handle ? PW_ID_ANY : PW_HANDLE_TO_ID(device->handle);
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
int res;
|
||||
|
||||
// Clamp the period size to sane values
|
||||
@@ -1192,7 +1192,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_TYPE, "Audio");
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, iscapture ? "Capture" : "Playback");
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, recording ? "Capture" : "Playback");
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_ROLE, stream_role);
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name);
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_ICON_NAME, icon_name);
|
||||
@@ -1217,13 +1217,13 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
// Create the new stream
|
||||
priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props,
|
||||
iscapture ? &stream_input_events : &stream_output_events, device);
|
||||
recording ? &stream_input_events : &stream_output_events, device);
|
||||
if (!priv->stream) {
|
||||
return SDL_SetError("Pipewire: Failed to create stream (%i)", errno);
|
||||
}
|
||||
|
||||
// The target node is passed via PW_KEY_TARGET_OBJECT; target_id is a legacy parameter and must be PW_ID_ANY.
|
||||
res = PIPEWIRE_pw_stream_connect(priv->stream, iscapture ? PW_DIRECTION_INPUT : PW_DIRECTION_OUTPUT, PW_ID_ANY, STREAM_FLAGS,
|
||||
res = PIPEWIRE_pw_stream_connect(priv->stream, recording ? PW_DIRECTION_INPUT : PW_DIRECTION_OUTPUT, PW_ID_ANY, STREAM_FLAGS,
|
||||
¶ms, 1);
|
||||
if (res != 0) {
|
||||
return SDL_SetError("Pipewire: Failed to connect stream");
|
||||
@@ -1314,11 +1314,11 @@ static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl, SDL_bool check_pre
|
||||
impl->Deinitialize = PIPEWIRE_Deinitialize;
|
||||
impl->PlayDevice = PIPEWIRE_PlayDevice;
|
||||
impl->GetDeviceBuf = PIPEWIRE_GetDeviceBuf;
|
||||
impl->CaptureFromDevice = PIPEWIRE_CaptureFromDevice;
|
||||
impl->FlushCapture = PIPEWIRE_FlushCapture;
|
||||
impl->RecordDevice = PIPEWIRE_RecordDevice;
|
||||
impl->FlushRecording = PIPEWIRE_FlushRecording;
|
||||
impl->CloseDevice = PIPEWIRE_CloseDevice;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
impl->ProvidesOwnCallbackThread = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
@@ -150,7 +150,7 @@ static SDL_bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->CloseDevice = PS2AUDIO_CloseDevice;
|
||||
impl->ThreadInit = PS2AUDIO_ThreadInit;
|
||||
impl->Deinitialize = PS2AUDIO_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
return SDL_TRUE; // this audio target is available.
|
||||
}
|
||||
|
||||
|
||||
@@ -170,9 +170,9 @@ static SDL_bool PSPAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = PSPAUDIO_CloseDevice;
|
||||
impl->ThreadInit = PSPAUDIO_ThreadInit;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
//impl->HasCaptureSupport = SDL_TRUE;
|
||||
//impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
//impl->HasRecordingSupport = SDL_TRUE;
|
||||
//impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -493,14 +493,14 @@ static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
|
||||
static void ReadCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||
{
|
||||
//SDL_Log("PULSEAUDIO READ CALLBACK! nbytes=%u", (unsigned int) nbytes);
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // the capture code queries what it needs, we just need to signal to end any wait
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // the recording code queries what it needs, we just need to signal to end any wait
|
||||
}
|
||||
|
||||
static int PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
static int PULSEAUDIO_WaitRecordingDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
|
||||
if (h->capturebuf) {
|
||||
if (h->recordingbuf) {
|
||||
return 0; // there's still data available to read.
|
||||
}
|
||||
|
||||
@@ -511,7 +511,7 @@ static int PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
|
||||
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
|
||||
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN WAITCAPTUREDEVICE!");
|
||||
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN WAITRECORDINGDEVICE!");
|
||||
retval = -1;
|
||||
break;
|
||||
} else if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) {
|
||||
@@ -523,10 +523,10 @@ static int PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
if (!data) { // If NULL, then the buffer had a hole, ignore that
|
||||
PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment.
|
||||
} else {
|
||||
// store this fragment's data for use with CaptureFromDevice
|
||||
//SDL_Log("PULSEAUDIO: captured %d new bytes", (int) nbytes);
|
||||
h->capturebuf = (const Uint8 *)data;
|
||||
h->capturelen = nbytes;
|
||||
// store this fragment's data for use with RecordDevice
|
||||
//SDL_Log("PULSEAUDIO: recorded %d new bytes", (int) nbytes);
|
||||
h->recordingbuf = (const Uint8 *)data;
|
||||
h->recordinglen = nbytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -537,20 +537,20 @@ static int PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int PULSEAUDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
|
||||
if (h->capturebuf) {
|
||||
const int cpy = SDL_min(buflen, h->capturelen);
|
||||
if (h->recordingbuf) {
|
||||
const int cpy = SDL_min(buflen, h->recordinglen);
|
||||
if (cpy > 0) {
|
||||
//SDL_Log("PULSEAUDIO: fed %d captured bytes", cpy);
|
||||
SDL_memcpy(buffer, h->capturebuf, cpy);
|
||||
h->capturebuf += cpy;
|
||||
h->capturelen -= cpy;
|
||||
//SDL_Log("PULSEAUDIO: fed %d recorded bytes", cpy);
|
||||
SDL_memcpy(buffer, h->recordingbuf, cpy);
|
||||
h->recordingbuf += cpy;
|
||||
h->recordinglen -= cpy;
|
||||
}
|
||||
if (h->capturelen == 0) {
|
||||
h->capturebuf = NULL;
|
||||
if (h->recordinglen == 0) {
|
||||
h->recordingbuf = NULL;
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop); // don't know if you _have_ to lock for this, but just in case.
|
||||
PULSEAUDIO_pa_stream_drop(h->stream); // done with this fragment.
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
@@ -561,7 +561,7 @@ static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, i
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
const void *data = NULL;
|
||||
@@ -569,16 +569,16 @@ static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
if (h->capturebuf) {
|
||||
if (h->recordingbuf) {
|
||||
PULSEAUDIO_pa_stream_drop(h->stream);
|
||||
h->capturebuf = NULL;
|
||||
h->capturelen = 0;
|
||||
h->recordingbuf = NULL;
|
||||
h->recordinglen = 0;
|
||||
}
|
||||
|
||||
while (!SDL_AtomicGet(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0)) {
|
||||
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
|
||||
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
|
||||
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN FLUSHCAPTURE!");
|
||||
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN FLUSHRECORDING!");
|
||||
SDL_AudioDeviceDisconnected(device);
|
||||
break;
|
||||
}
|
||||
@@ -598,7 +598,7 @@ static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
if (device->hidden->stream) {
|
||||
if (device->hidden->capturebuf) {
|
||||
if (device->hidden->recordingbuf) {
|
||||
PULSEAUDIO_pa_stream_drop(device->hidden->stream);
|
||||
}
|
||||
PULSEAUDIO_pa_stream_disconnect(device->hidden->stream);
|
||||
@@ -618,7 +618,7 @@ static void PulseStreamStateChangeCallback(pa_stream *stream, void *userdata)
|
||||
|
||||
static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
struct SDL_PrivateAudioData *h = NULL;
|
||||
SDL_AudioFormat test_format;
|
||||
const SDL_AudioFormat *closefmts;
|
||||
@@ -681,7 +681,7 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
|
||||
// Allocate mixing buffer
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
h->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
|
||||
if (!h->mixbuf) {
|
||||
return -1;
|
||||
@@ -693,7 +693,7 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
paspec.rate = device->spec.freq;
|
||||
|
||||
// Reduced prebuffering compared to the defaults.
|
||||
paattr.fragsize = device->buffer_size; // despite the name, this is only used for capture devices, according to PulseAudio docs!
|
||||
paattr.fragsize = device->buffer_size; // despite the name, this is only used for recording devices, according to PulseAudio docs!
|
||||
paattr.tlength = device->buffer_size;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
@@ -725,7 +725,7 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
flags |= PA_STREAM_DONT_MOVE;
|
||||
|
||||
const char *device_path = ((PulseDeviceHandle *) device->handle)->device_path;
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
PULSEAUDIO_pa_stream_set_read_callback(h->stream, ReadCallback, h);
|
||||
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, device_path, &paattr, flags);
|
||||
} else {
|
||||
@@ -749,7 +749,7 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
if (!actual_bufattr) {
|
||||
retval = SDL_SetError("Could not determine connected PulseAudio stream's buffer attributes");
|
||||
} else {
|
||||
device->buffer_size = (int) iscapture ? actual_bufattr->tlength : actual_bufattr->fragsize;
|
||||
device->buffer_size = (int) recording ? actual_bufattr->tlength : actual_bufattr->fragsize;
|
||||
device->sample_frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
}
|
||||
}
|
||||
@@ -786,7 +786,7 @@ static SDL_AudioFormat PulseFormatToSDLFormat(pa_sample_format_t format)
|
||||
}
|
||||
}
|
||||
|
||||
static void AddPulseAudioDevice(const SDL_bool iscapture, const char *description, const char *name, const uint32_t index, const pa_sample_spec *sample_spec)
|
||||
static void AddPulseAudioDevice(const SDL_bool recording, const char *description, const char *name, const uint32_t index, const pa_sample_spec *sample_spec)
|
||||
{
|
||||
SDL_AudioSpec spec;
|
||||
spec.format = PulseFormatToSDLFormat(sample_spec->format);
|
||||
@@ -800,11 +800,11 @@ static void AddPulseAudioDevice(const SDL_bool iscapture, const char *descriptio
|
||||
} else {
|
||||
handle->device_index = index;
|
||||
}
|
||||
SDL_AddAudioDevice(iscapture, description, &spec, handle);
|
||||
SDL_AddAudioDevice(recording, description, &spec, handle);
|
||||
}
|
||||
}
|
||||
|
||||
// This is called when PulseAudio adds an output ("sink") device.
|
||||
// This is called when PulseAudio adds an playback ("sink") device.
|
||||
static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
||||
{
|
||||
if (i) {
|
||||
@@ -813,7 +813,7 @@ static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last,
|
||||
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
|
||||
}
|
||||
|
||||
// This is called when PulseAudio adds a capture ("source") device.
|
||||
// This is called when PulseAudio adds a recording ("source") device.
|
||||
static void SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
|
||||
{
|
||||
// Maybe skip "monitor" sources. These are just output from other sinks.
|
||||
@@ -958,7 +958,7 @@ static int SDLCALL HotplugThread(void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
SDL_Semaphore *ready_sem = SDL_CreateSemaphore(0);
|
||||
|
||||
@@ -969,11 +969,11 @@ static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_Audio
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
|
||||
if (default_sink_path) {
|
||||
*default_output = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_sink_path);
|
||||
*default_playback = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_sink_path);
|
||||
}
|
||||
|
||||
if (default_source_path) {
|
||||
*default_capture = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_source_path);
|
||||
*default_recording = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_source_path);
|
||||
}
|
||||
|
||||
// ok, we have a sane list, let's set up hotplug notifications now...
|
||||
@@ -1035,12 +1035,12 @@ static SDL_bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->CloseDevice = PULSEAUDIO_CloseDevice;
|
||||
impl->DeinitializeStart = PULSEAUDIO_DeinitializeStart;
|
||||
impl->Deinitialize = PULSEAUDIO_Deinitialize;
|
||||
impl->WaitCaptureDevice = PULSEAUDIO_WaitCaptureDevice;
|
||||
impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = PULSEAUDIO_FlushCapture;
|
||||
impl->WaitRecordingDevice = PULSEAUDIO_WaitRecordingDevice;
|
||||
impl->RecordDevice = PULSEAUDIO_RecordDevice;
|
||||
impl->FlushRecording = PULSEAUDIO_FlushRecording;
|
||||
impl->FreeDeviceHandle = PULSEAUDIO_FreeDeviceHandle;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ struct SDL_PrivateAudioData
|
||||
|
||||
int bytes_requested; // bytes of data the hardware wants _now_.
|
||||
|
||||
const Uint8 *capturebuf;
|
||||
int capturelen;
|
||||
const Uint8 *recordingbuf;
|
||||
int recordinglen;
|
||||
};
|
||||
|
||||
#endif // SDL_pulseaudio_h_
|
||||
|
||||
@@ -93,7 +93,7 @@ static int QSA_WaitDevice(SDL_AudioDevice *device)
|
||||
// For example, Vortex 8820 audio driver stucks on second DAC because
|
||||
// it doesn't exist !
|
||||
const int result = SDL_IOReady(device->hidden->audio_fd,
|
||||
device->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
|
||||
device->recording ? SDL_IOR_READ : SDL_IOR_WRITE,
|
||||
2 * 1000);
|
||||
switch (result) {
|
||||
case -1:
|
||||
@@ -140,14 +140,14 @@ static int QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int bufl
|
||||
} else if ((errno == EINVAL) || (errno == EIO)) {
|
||||
snd_pcm_channel_status_t cstatus;
|
||||
SDL_zero(cstatus);
|
||||
cstatus.channel = device->iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
cstatus.channel = device->recording ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
|
||||
int status = snd_pcm_plugin_status(device->hidden->audio_handle, &cstatus);
|
||||
if (status < 0) {
|
||||
QSA_SetError("snd_pcm_plugin_status", status);
|
||||
return -1;
|
||||
} else if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY)) {
|
||||
status = snd_pcm_plugin_prepare(device->hidden->audio_handle, device->iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
|
||||
status = snd_pcm_plugin_prepare(device->hidden->audio_handle, device->recording ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status < 0) {
|
||||
QSA_SetError("snd_pcm_plugin_prepare", status);
|
||||
return -1;
|
||||
@@ -178,8 +178,8 @@ static void QSA_CloseDevice(SDL_AudioDevice *device)
|
||||
if (device->hidden) {
|
||||
if (device->hidden->audio_handle) {
|
||||
#if _NTO_VERSION < 710
|
||||
// Finish playing available samples or cancel unread samples during capture
|
||||
snd_pcm_plugin_flush(device->hidden->audio_handle, device->iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
|
||||
// Finish playing available samples or cancel unread samples during recording
|
||||
snd_pcm_plugin_flush(device->hidden->audio_handle, device->recording ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
|
||||
#endif
|
||||
snd_pcm_close(device->hidden->audio_handle);
|
||||
}
|
||||
@@ -192,15 +192,15 @@ static void QSA_CloseDevice(SDL_AudioDevice *device)
|
||||
|
||||
static int QSA_OpenDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
if (device->iscapture) {
|
||||
return SDL_SetError("SDL capture support isn't available on QNX atm"); // !!! FIXME: most of this code has support for capture devices, but there's no CaptureFromDevice, etc functions. Fill them in!
|
||||
if (device->recording) {
|
||||
return SDL_SetError("SDL recording support isn't available on QNX atm"); // !!! FIXME: most of this code has support for recording devices, but there's no RecordDevice, etc functions. Fill them in!
|
||||
}
|
||||
|
||||
SDL_assert(device->handle != NULL); // NULL used to mean "system default device" in SDL2; it does not mean that in SDL3.
|
||||
const Uint32 sdlhandle = (Uint32) ((size_t) device->handle);
|
||||
const uint32_t cardno = (uint32_t) (sdlhandle & 0xFFFF);
|
||||
const uint32_t deviceno = (uint32_t) ((sdlhandle >> 16) & 0xFFFF);
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
int status = 0;
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
@@ -214,7 +214,7 @@ static int QSA_OpenDevice(SDL_AudioDevice *device)
|
||||
QSA_InitAudioParams(&cparams);
|
||||
|
||||
// Open requested audio device
|
||||
status = snd_pcm_open(&device->hidden->audio_handle, cardno, deviceno, iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||
status = snd_pcm_open(&device->hidden->audio_handle, cardno, deviceno, recording ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||
if (status < 0) {
|
||||
device->hidden->audio_handle = NULL;
|
||||
return QSA_SetError("snd_pcm_open", status);
|
||||
@@ -263,7 +263,7 @@ static int QSA_OpenDevice(SDL_AudioDevice *device)
|
||||
// Make sure channel is setup right one last time
|
||||
snd_pcm_channel_setup_t csetup;
|
||||
SDL_zero(csetup);
|
||||
csetup.channel = iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
csetup.channel = recording ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
if (snd_pcm_plugin_setup(device->hidden->audio_handle, &csetup) < 0) {
|
||||
return SDL_SetError("QSA: Unable to setup channel");
|
||||
}
|
||||
@@ -312,7 +312,7 @@ static SDL_AudioFormat QnxFormatToSDLFormat(const int32_t qnxfmt)
|
||||
return SDL_AUDIO_S16; // oh well.
|
||||
}
|
||||
|
||||
static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void QSA_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
// Detect amount of available devices
|
||||
// this value can be changed in the runtime
|
||||
@@ -350,13 +350,13 @@ static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
SDL_snprintf(fullname, sizeof (fullname), "%s d%d", name, (int) deviceno);
|
||||
|
||||
// Check if this device id could play anything
|
||||
SDL_bool iscapture = SDL_FALSE;
|
||||
SDL_bool recording = SDL_FALSE;
|
||||
status = snd_pcm_open(&handle, card, deviceno, SND_PCM_OPEN_PLAYBACK);
|
||||
if (status != EOK) { // no? See if it's a capture device instead.
|
||||
#if 0 // !!! FIXME: most of this code has support for capture devices, but there's no CaptureFromDevice, etc functions. Fill them in!
|
||||
if (status != EOK) { // no? See if it's a recording device instead.
|
||||
#if 0 // !!! FIXME: most of this code has support for recording devices, but there's no RecordDevice, etc functions. Fill them in!
|
||||
status = snd_pcm_open(&handle, card, deviceno, SND_PCM_OPEN_CAPTURE);
|
||||
if (status == EOK) {
|
||||
iscapture = SDL_TRUE;
|
||||
recording = SDL_TRUE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -366,7 +366,7 @@ static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
SDL_AudioSpec *pspec = &spec;
|
||||
snd_pcm_channel_setup_t csetup;
|
||||
SDL_zero(csetup);
|
||||
csetup.channel = iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
csetup.channel = recording ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK;
|
||||
|
||||
if (snd_pcm_plugin_setup(device->hidden->audio_handle, &csetup) < 0) {
|
||||
pspec = NULL; // go on without spec info.
|
||||
@@ -382,7 +382,7 @@ static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
SDL_assert(card <= 0xFFFF);
|
||||
SDL_assert(deviceno <= 0xFFFF);
|
||||
const Uint32 sdlhandle = ((Uint32) card) | (((Uint32) deviceno) << 16);
|
||||
SDL_AddAudioDevice(iscapture, fullname, pspec, (void *) ((size_t) sdlhandle));
|
||||
SDL_AddAudioDevice(recording, fullname, pspec, (void *) ((size_t) sdlhandle));
|
||||
}
|
||||
} else {
|
||||
// Check if we got end of devices list
|
||||
@@ -407,7 +407,7 @@ static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
SDL_assert(cardno <= 0xFFFF);
|
||||
SDL_assert(deviceno <= 0xFFFF);
|
||||
const Uint32 sdlhandle = ((Uint32) card) | (((Uint32) deviceno) << 16);
|
||||
*default_output = SDL_FindPhysicalAudioDeviceByHandle((void *) ((size_t) sdlhandle));
|
||||
*default_playback = SDL_FindPhysicalAudioDeviceByHandle((void *) ((size_t) sdlhandle));
|
||||
}
|
||||
|
||||
if (snd_pcm_open_preferred(&handle, &cardno, &deviceno, SND_PCM_OPEN_CAPTURE) == 0) {
|
||||
@@ -416,7 +416,7 @@ static void QSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
SDL_assert(cardno <= 0xFFFF);
|
||||
SDL_assert(deviceno <= 0xFFFF);
|
||||
const Uint32 sdlhandle = ((Uint32) card) | (((Uint32) deviceno) << 16);
|
||||
*default_capture = SDL_FindPhysicalAudioDeviceByHandle((void *) ((size_t) sdlhandle));
|
||||
*default_recording = SDL_FindPhysicalAudioDeviceByHandle((void *) ((size_t) sdlhandle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,8 +436,8 @@ static SDL_bool QSA_Init(SDL_AudioDriverImpl * impl)
|
||||
impl->CloseDevice = QSA_CloseDevice;
|
||||
impl->Deinitialize = QSA_Deinitialize;
|
||||
|
||||
// !!! FIXME: most of this code has support for capture devices, but there's no CaptureFromDevice, etc functions. Fill them in!
|
||||
//impl->HasCaptureSupport = SDL_TRUE;
|
||||
// !!! FIXME: most of this code has support for recording devices, but there's no RecordDevice, etc functions. Fill them in!
|
||||
//impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -149,22 +149,22 @@ static int LoadSNDIOLibrary(void)
|
||||
|
||||
static int SNDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
if (SNDIO_sio_eof(device->hidden->dev)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int nfds = SNDIO_sio_pollfd(device->hidden->dev, device->hidden->pfd, iscapture ? POLLIN : POLLOUT);
|
||||
const int nfds = SNDIO_sio_pollfd(device->hidden->dev, device->hidden->pfd, recording ? POLLIN : POLLOUT);
|
||||
if (nfds <= 0 || poll(device->hidden->pfd, nfds, 10) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int revents = SNDIO_sio_revents(device->hidden->dev, device->hidden->pfd);
|
||||
if (iscapture && (revents & POLLIN)) {
|
||||
if (recording && (revents & POLLIN)) {
|
||||
break;
|
||||
} else if (!iscapture && (revents & POLLOUT)) {
|
||||
} else if (!recording && (revents & POLLOUT)) {
|
||||
break;
|
||||
} else if (revents & POLLHUP) {
|
||||
return -1;
|
||||
@@ -187,9 +187,9 @@ static int SNDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int bu
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SNDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int SNDIO_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
// We set capture devices non-blocking; this can safely return 0 in SDL3, but we'll check for EOF to cause a device disconnect.
|
||||
// We set recording devices non-blocking; this can safely return 0 in SDL3, but we'll check for EOF to cause a device disconnect.
|
||||
const size_t br = SNDIO_sio_read(device->hidden->dev, buffer, buflen);
|
||||
if ((br == 0) && SNDIO_sio_eof(device->hidden->dev)) {
|
||||
return -1;
|
||||
@@ -197,7 +197,7 @@ static int SNDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int bu
|
||||
return (int) br;
|
||||
}
|
||||
|
||||
static void SNDIO_FlushCapture(SDL_AudioDevice *device)
|
||||
static void SNDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
char buf[512];
|
||||
while (!SDL_AtomicGet(&device->shutdown) && (SNDIO_sio_read(device->hidden->dev, buf, sizeof(buf)) > 0)) {
|
||||
@@ -234,9 +234,9 @@ static int SNDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
// !!! FIXME: we really should standardize this on a specific SDL hint.
|
||||
const char *audiodev = SDL_getenv("AUDIODEV");
|
||||
|
||||
// Capture devices must be non-blocking for SNDIO_FlushCapture
|
||||
// Recording devices must be non-blocking for SNDIO_FlushRecording
|
||||
device->hidden->dev = SNDIO_sio_open(audiodev ? audiodev : SIO_DEVANY,
|
||||
device->iscapture ? SIO_REC : SIO_PLAY, device->iscapture);
|
||||
device->recording ? SIO_REC : SIO_PLAY, device->recording);
|
||||
if (!device->hidden->dev) {
|
||||
return SDL_SetError("sio_open() failed");
|
||||
}
|
||||
@@ -324,10 +324,10 @@ static void SNDIO_Deinitialize(void)
|
||||
UnloadSNDIOLibrary();
|
||||
}
|
||||
|
||||
static void SNDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void SNDIO_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
*default_output = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
|
||||
*default_capture = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
|
||||
*default_playback = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_PLAYBACK_DEVNAME, NULL, (void *)0x1);
|
||||
*default_recording = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_RECORDING_DEVNAME, NULL, (void *)0x2);
|
||||
}
|
||||
|
||||
static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
@@ -341,13 +341,13 @@ static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = SNDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = SNDIO_CloseDevice;
|
||||
impl->WaitCaptureDevice = SNDIO_WaitDevice;
|
||||
impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = SNDIO_FlushCapture;
|
||||
impl->WaitRecordingDevice = SNDIO_WaitDevice;
|
||||
impl->RecordDevice = SNDIO_RecordDevice;
|
||||
impl->FlushRecording = SNDIO_FlushRecording;
|
||||
impl->Deinitialize = SNDIO_Deinitialize;
|
||||
impl->DetectDevices = SNDIO_DetectDevices;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63)
|
||||
#define SCE_AUDIO_MAX_VOLUME 0x8000
|
||||
|
||||
static int VITAAUD_OpenCaptureDevice(SDL_AudioDevice *device)
|
||||
static int VITAAUD_OpenRecordingDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
device->spec.freq = 16000;
|
||||
device->spec.channels = 1;
|
||||
@@ -79,8 +79,8 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
return SDL_SetError("Unsupported audio format");
|
||||
}
|
||||
|
||||
if (device->iscapture) {
|
||||
return VITAAUD_OpenCaptureDevice(device);
|
||||
if (device->recording) {
|
||||
return VITAAUD_OpenRecordingDevice(device);
|
||||
}
|
||||
|
||||
// The sample count must be a multiple of 64.
|
||||
@@ -154,7 +154,7 @@ static void VITAAUD_CloseDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
if (device->hidden) {
|
||||
if (device->hidden->port >= 0) {
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
sceAudioInReleasePort(device->hidden->port);
|
||||
} else {
|
||||
sceAudioOutReleasePort(device->hidden->port);
|
||||
@@ -162,7 +162,7 @@ static void VITAAUD_CloseDevice(SDL_AudioDevice *device)
|
||||
device->hidden->port = -1;
|
||||
}
|
||||
|
||||
if (!device->iscapture && device->hidden->rawbuf) {
|
||||
if (!device->recording && device->hidden->rawbuf) {
|
||||
SDL_aligned_free(device->hidden->rawbuf); // this uses SDL_aligned_alloc(), not SDL_malloc()
|
||||
device->hidden->rawbuf = NULL;
|
||||
}
|
||||
@@ -171,7 +171,7 @@ static void VITAAUD_CloseDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static int VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
static int VITAAUD_WaitRecordingDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
// there's only a blocking call to obtain more data, so we'll just sleep as
|
||||
// long as a buffer would run.
|
||||
@@ -182,18 +182,18 @@ static int VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int VITAAUD_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int VITAAUD_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
int ret;
|
||||
SDL_assert(buflen == device->buffer_size);
|
||||
ret = sceAudioInInput(device->hidden->port, buffer);
|
||||
if (ret < 0) {
|
||||
return SDL_SetError("Failed to capture from device: %x", ret);
|
||||
return SDL_SetError("Failed to record from device: %x", ret);
|
||||
}
|
||||
return device->buffer_size;
|
||||
}
|
||||
|
||||
static void VITAAUD_FlushCapture(SDL_AudioDevice *device)
|
||||
static void VITAAUD_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
// just grab the latest and dump it.
|
||||
sceAudioInInput(device->hidden->port, device->work_buffer);
|
||||
@@ -219,13 +219,13 @@ static SDL_bool VITAAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->GetDeviceBuf = VITAAUD_GetDeviceBuf;
|
||||
impl->CloseDevice = VITAAUD_CloseDevice;
|
||||
impl->ThreadInit = VITAAUD_ThreadInit;
|
||||
impl->WaitCaptureDevice = VITAAUD_WaitCaptureDevice;
|
||||
impl->FlushCapture = VITAAUD_FlushCapture;
|
||||
impl->CaptureFromDevice = VITAAUD_CaptureFromDevice;
|
||||
impl->WaitRecordingDevice = VITAAUD_WaitRecordingDevice;
|
||||
impl->FlushRecording = VITAAUD_FlushRecording;
|
||||
impl->RecordDevice = VITAAUD_RecordDevice;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
impl->OnlyHasDefaultPlaybackDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultRecordingDevice = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -253,24 +253,24 @@ static void DeinitManagementThread(void)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_AudioDevice **default_output;
|
||||
SDL_AudioDevice **default_capture;
|
||||
SDL_AudioDevice **default_playback;
|
||||
SDL_AudioDevice **default_recording;
|
||||
} mgmtthrtask_DetectDevicesData;
|
||||
|
||||
static int mgmtthrtask_DetectDevices(void *userdata)
|
||||
{
|
||||
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
|
||||
WASAPI_EnumerateEndpoints(data->default_output, data->default_capture);
|
||||
WASAPI_EnumerateEndpoints(data->default_playback, data->default_recording);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WASAPI_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
static void WASAPI_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
int rc;
|
||||
// this blocks because it needs to finish before the audio subsystem inits
|
||||
mgmtthrtask_DetectDevicesData data;
|
||||
data.default_output = default_output;
|
||||
data.default_capture = default_capture;
|
||||
data.default_playback = default_playback;
|
||||
data.default_recording = default_recording;
|
||||
WASAPI_ProxyToManagementThread(mgmtthrtask_DetectDevices, &data, &rc);
|
||||
}
|
||||
|
||||
@@ -471,9 +471,9 @@ static int WASAPI_WaitDevice(SDL_AudioDevice *device)
|
||||
UINT32 padding = 0;
|
||||
if (!WasapiFailed(device, IAudioClient_GetCurrentPadding(device->hidden->client, &padding))) {
|
||||
//SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
|
||||
if (device->iscapture && (padding > 0)) {
|
||||
if (device->recording && (padding > 0)) {
|
||||
break;
|
||||
} else if (!device->iscapture && (padding <= maxpadding)) {
|
||||
} else if (!device->recording && (padding <= maxpadding)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -487,7 +487,7 @@ static int WASAPI_WaitDevice(SDL_AudioDevice *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WASAPI_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
static int WASAPI_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen)
|
||||
{
|
||||
BYTE *ptr = NULL;
|
||||
UINT32 frames = 0;
|
||||
@@ -524,7 +524,7 @@ static int WASAPI_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int b
|
||||
return -1; // unrecoverable error.
|
||||
}
|
||||
|
||||
static void WASAPI_FlushCapture(SDL_AudioDevice *device)
|
||||
static void WASAPI_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
BYTE *ptr = NULL;
|
||||
UINT32 frames = 0;
|
||||
@@ -706,7 +706,7 @@ static int mgmtthrtask_PrepDevice(void *userdata)
|
||||
|
||||
device->hidden->framesize = SDL_AUDIO_FRAMESIZE(device->spec);
|
||||
|
||||
if (device->iscapture) {
|
||||
if (device->recording) {
|
||||
IAudioCaptureClient *capture = NULL;
|
||||
ret = IAudioClient_GetService(client, &SDL_IID_IAudioCaptureClient, (void **)&capture);
|
||||
if (FAILED(ret)) {
|
||||
@@ -720,7 +720,7 @@ static int mgmtthrtask_PrepDevice(void *userdata)
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't start capture", ret);
|
||||
}
|
||||
|
||||
WASAPI_FlushCapture(device); // MSDN says you should flush capture endpoint right after startup.
|
||||
WASAPI_FlushRecording(device); // MSDN says you should flush the recording endpoint right after startup.
|
||||
} else {
|
||||
IAudioRenderClient *render = NULL;
|
||||
ret = IAudioClient_GetService(client, &SDL_IID_IAudioRenderClient, (void **)&render);
|
||||
@@ -757,7 +757,7 @@ static int WASAPI_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
/* Ready, but possibly waiting for async device activation.
|
||||
Until activation is successful, we will report silence from capture
|
||||
Until activation is successful, we will report silence from recording
|
||||
devices and ignore data on playback devices. Upon activation, we'll make
|
||||
sure any bound audio streams are adjusted for the final device format. */
|
||||
|
||||
@@ -816,15 +816,15 @@ static SDL_bool WASAPI_Init(SDL_AudioDriverImpl *impl)
|
||||
impl->PlayDevice = WASAPI_PlayDevice;
|
||||
impl->WaitDevice = WASAPI_WaitDevice;
|
||||
impl->GetDeviceBuf = WASAPI_GetDeviceBuf;
|
||||
impl->WaitCaptureDevice = WASAPI_WaitDevice;
|
||||
impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
|
||||
impl->FlushCapture = WASAPI_FlushCapture;
|
||||
impl->WaitRecordingDevice = WASAPI_WaitDevice;
|
||||
impl->RecordDevice = WASAPI_RecordDevice;
|
||||
impl->FlushRecording = WASAPI_FlushRecording;
|
||||
impl->CloseDevice = WASAPI_CloseDevice;
|
||||
impl->DeinitializeStart = WASAPI_DeinitializeStart;
|
||||
impl->Deinitialize = WASAPI_Deinitialize;
|
||||
impl->FreeDeviceHandle = WASAPI_FreeDeviceHandle;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->HasRecordingSupport = SDL_TRUE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in
|
||||
int WASAPI_PlatformInit(void);
|
||||
void WASAPI_PlatformDeinit(void);
|
||||
void WASAPI_PlatformDeinitializeStart(void);
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
||||
int WASAPI_ActivateDevice(SDL_AudioDevice *device);
|
||||
void WASAPI_PlatformThreadInit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread.
|
||||
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread.
|
||||
|
||||
@@ -142,7 +142,7 @@ void WASAPI_PlatformThreadInit(SDL_AudioDevice *device)
|
||||
DWORD idx = 0;
|
||||
device->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
|
||||
} else {
|
||||
SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
SDL_SetThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -164,7 +164,7 @@ void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device)
|
||||
int WASAPI_ActivateDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
IMMDevice *immdevice = NULL;
|
||||
if (SDL_IMMDevice_Get(device, &immdevice, device->iscapture) < 0) {
|
||||
if (SDL_IMMDevice_Get(device, &immdevice, device->recording) < 0) {
|
||||
device->hidden->client = NULL;
|
||||
return -1; // This is already set by SDL_IMMDevice_Get
|
||||
}
|
||||
@@ -186,9 +186,9 @@ int WASAPI_ActivateDevice(SDL_AudioDevice *device)
|
||||
return 0; // good to go.
|
||||
}
|
||||
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_output, default_capture);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
}
|
||||
|
||||
void WASAPI_PlatformDeleteActivationHandler(void *handler)
|
||||
|
||||
@@ -66,7 +66,7 @@ static SDL_AudioDevice *FindWinRTAudioDevice(LPCWSTR devid)
|
||||
class SDL_WasapiDeviceEventHandler
|
||||
{
|
||||
public:
|
||||
SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture);
|
||||
SDL_WasapiDeviceEventHandler(const SDL_bool _recording);
|
||||
~SDL_WasapiDeviceEventHandler();
|
||||
void OnDeviceAdded(DeviceWatcher ^ sender, DeviceInformation ^ args);
|
||||
void OnDeviceRemoved(DeviceWatcher ^ sender, DeviceInformationUpdate ^ args);
|
||||
@@ -78,7 +78,7 @@ class SDL_WasapiDeviceEventHandler
|
||||
|
||||
private:
|
||||
SDL_Semaphore *completed_semaphore;
|
||||
const SDL_bool iscapture;
|
||||
const SDL_bool recording;
|
||||
DeviceWatcher ^ watcher;
|
||||
Windows::Foundation::EventRegistrationToken added_handler;
|
||||
Windows::Foundation::EventRegistrationToken removed_handler;
|
||||
@@ -87,14 +87,14 @@ class SDL_WasapiDeviceEventHandler
|
||||
Windows::Foundation::EventRegistrationToken default_changed_handler;
|
||||
};
|
||||
|
||||
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
|
||||
: iscapture(_iscapture), completed_semaphore(SDL_CreateSemaphore(0))
|
||||
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _recording)
|
||||
: recording(_recording), completed_semaphore(SDL_CreateSemaphore(0))
|
||||
{
|
||||
if (!completed_semaphore) {
|
||||
return; // uhoh.
|
||||
}
|
||||
|
||||
Platform::String ^ selector = _iscapture ? MediaDevice::GetAudioCaptureSelector() : MediaDevice::GetAudioRenderSelector();
|
||||
Platform::String ^ selector = _recording ? MediaDevice::GetAudioCaptureSelector() : MediaDevice::GetAudioRenderSelector();
|
||||
Platform::Collections::Vector<Platform::String ^> properties;
|
||||
properties.Append(SDL_PKEY_AudioEngine_DeviceFormat);
|
||||
watcher = DeviceInformation::CreateWatcher(selector, properties.GetView());
|
||||
@@ -106,7 +106,7 @@ SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscap
|
||||
removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher ^, DeviceInformationUpdate ^>([this](DeviceWatcher ^ sender, DeviceInformationUpdate ^ args) { OnDeviceRemoved(sender, args); });
|
||||
updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher ^, DeviceInformationUpdate ^>([this](DeviceWatcher ^ sender, DeviceInformationUpdate ^ args) { OnDeviceUpdated(sender, args); });
|
||||
completed_handler = watcher->EnumerationCompleted += ref new TypedEventHandler<DeviceWatcher ^, Platform::Object ^>([this](DeviceWatcher ^ sender, Platform::Object ^ args) { OnEnumerationCompleted(sender, args); });
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object ^, DefaultAudioCaptureDeviceChangedEventArgs ^>([this](Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args) { OnDefaultCaptureDeviceChanged(sender, args); });
|
||||
} else {
|
||||
default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler<Platform::Object ^, DefaultAudioRenderDeviceChangedEventArgs ^>([this](Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args) { OnDefaultRenderDeviceChanged(sender, args); });
|
||||
@@ -130,7 +130,7 @@ SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
|
||||
completed_semaphore = nullptr;
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
if (recording) {
|
||||
MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
|
||||
} else {
|
||||
MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
|
||||
@@ -165,7 +165,7 @@ void SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher ^ sender, DeviceI
|
||||
|
||||
LPWSTR devid = SDL_wcsdup(info->Id->Data());
|
||||
if (devid) {
|
||||
SDL_AddAudioDevice(this->iscapture, utf8dev, spec.channels ? &spec : NULL, devid);
|
||||
SDL_AddAudioDevice(this->recording, utf8dev, spec.channels ? &spec : NULL, devid);
|
||||
}
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
@@ -192,13 +192,13 @@ void SDL_WasapiDeviceEventHandler::OnEnumerationCompleted(DeviceWatcher ^ sender
|
||||
|
||||
void SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object ^ sender, DefaultAudioRenderDeviceChangedEventArgs ^ args)
|
||||
{
|
||||
SDL_assert(!this->iscapture);
|
||||
SDL_assert(!this->recording);
|
||||
SDL_DefaultAudioDeviceChanged(FindWinRTAudioDevice(args->Id->Data()));
|
||||
}
|
||||
|
||||
void SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object ^ sender, DefaultAudioCaptureDeviceChangedEventArgs ^ args)
|
||||
{
|
||||
SDL_assert(this->iscapture);
|
||||
SDL_assert(this->recording);
|
||||
SDL_DefaultAudioDeviceChanged(FindWinRTAudioDevice(args->Id->Data()));
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ void SDL_WasapiDeviceEventHandler::WaitForCompletion()
|
||||
}
|
||||
|
||||
static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
|
||||
static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
|
||||
static SDL_WasapiDeviceEventHandler *recording_device_event_handler;
|
||||
|
||||
int WASAPI_PlatformInit(void)
|
||||
{
|
||||
@@ -223,8 +223,8 @@ static void StopWasapiHotplug(void)
|
||||
{
|
||||
delete playback_device_event_handler;
|
||||
playback_device_event_handler = nullptr;
|
||||
delete capture_device_event_handler;
|
||||
capture_device_event_handler = nullptr;
|
||||
delete recording_device_event_handler;
|
||||
recording_device_event_handler = nullptr;
|
||||
}
|
||||
|
||||
void WASAPI_PlatformDeinit(void)
|
||||
@@ -238,7 +238,7 @@ void WASAPI_PlatformDeinitializeStart(void)
|
||||
}
|
||||
|
||||
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
Platform::String ^ defdevid;
|
||||
|
||||
@@ -249,14 +249,14 @@ void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice
|
||||
playback_device_event_handler->WaitForCompletion();
|
||||
defdevid = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
|
||||
if (defdevid) {
|
||||
*default_output = FindWinRTAudioDevice(defdevid->Data());
|
||||
*default_playback = FindWinRTAudioDevice(defdevid->Data());
|
||||
}
|
||||
|
||||
capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
|
||||
capture_device_event_handler->WaitForCompletion();
|
||||
recording_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
|
||||
recording_device_event_handler->WaitForCompletion();
|
||||
defdevid = MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default);
|
||||
if (defdevid) {
|
||||
*default_capture = FindWinRTAudioDevice(defdevid->Data());
|
||||
*default_recording = FindWinRTAudioDevice(defdevid->Data());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ int WASAPI_ActivateDevice(SDL_AudioDevice *device)
|
||||
void WASAPI_PlatformThreadInit(SDL_AudioDevice *device)
|
||||
{
|
||||
// !!! FIXME: set this thread to "Pro Audio" priority.
|
||||
SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
SDL_SetThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
|
||||
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device)
|
||||
|
||||
@@ -760,7 +760,7 @@ void SDL_CameraThreadSetup(SDL_CameraDevice *device)
|
||||
{
|
||||
// Set thread priority to THREAD_PRIORITY_VIDEO
|
||||
extern void Android_JNI_CameraSetThreadPriority(int, int);
|
||||
Android_JNI_CameraSetThreadPriority(device->iscapture, device);
|
||||
Android_JNI_CameraSetThreadPriority(device->recording, device);
|
||||
}*/
|
||||
#else
|
||||
// The camera capture is always a high priority thread
|
||||
@@ -897,7 +897,7 @@ SDL_bool SDL_CameraThreadIterate(SDL_CameraDevice *device)
|
||||
|
||||
void SDL_CameraThreadShutdown(SDL_CameraDevice *device)
|
||||
{
|
||||
//device->FlushCapture(device);
|
||||
//device->FlushRecording(device);
|
||||
//camera_driver.impl.ThreadDeinit(device);
|
||||
//SDL_CameraThreadFinalize(device);
|
||||
}
|
||||
|
||||
@@ -238,11 +238,11 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
|
||||
JNIEnv *env, jclass jcls);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture, jstring name,
|
||||
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean recording, jstring name,
|
||||
jint device_id);
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean recording,
|
||||
jint device_id);
|
||||
|
||||
static JNINativeMethod SDLAudioManager_tab[] = {
|
||||
@@ -364,11 +364,11 @@ static jmethodID midAudioWriteByteBuffer;
|
||||
static jmethodID midAudioWriteShortBuffer;
|
||||
static jmethodID midAudioWriteFloatBuffer;
|
||||
static jmethodID midAudioClose;
|
||||
static jmethodID midCaptureOpen;
|
||||
static jmethodID midCaptureReadByteBuffer;
|
||||
static jmethodID midCaptureReadShortBuffer;
|
||||
static jmethodID midCaptureReadFloatBuffer;
|
||||
static jmethodID midCaptureClose;
|
||||
static jmethodID midRecordingOpen;
|
||||
static jmethodID midRecordingReadByteBuffer;
|
||||
static jmethodID midRecordingReadShortBuffer;
|
||||
static jmethodID midRecordingReadFloatBuffer;
|
||||
static jmethodID midRecordingClose;
|
||||
static jmethodID midAudioSetThreadPriority;
|
||||
|
||||
/* controller manager */
|
||||
@@ -709,15 +709,15 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
|
||||
"audioWriteFloatBuffer", "([F)V");
|
||||
midAudioClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"audioClose", "()V");
|
||||
midCaptureOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
midRecordingOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"captureOpen", "(IIIII)[I");
|
||||
midCaptureReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
midRecordingReadByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"captureReadByteBuffer", "([BZ)I");
|
||||
midCaptureReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
midRecordingReadShortBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"captureReadShortBuffer", "([SZ)I");
|
||||
midCaptureReadFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
midRecordingReadFloatBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"captureReadFloatBuffer", "([FZ)I");
|
||||
midCaptureClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
midRecordingClose = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"captureClose", "()V");
|
||||
midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass,
|
||||
"audioSetThreadPriority", "(ZI)V");
|
||||
@@ -725,8 +725,8 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl
|
||||
if (!midRegisterAudioDeviceCallback || !midUnregisterAudioDeviceCallback || !midAudioOpen ||
|
||||
!midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer ||
|
||||
!midAudioClose ||
|
||||
!midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer ||
|
||||
!midCaptureReadFloatBuffer || !midCaptureClose || !midAudioSetThreadPriority) {
|
||||
!midRecordingOpen || !midRecordingReadByteBuffer || !midRecordingReadShortBuffer ||
|
||||
!midRecordingReadFloatBuffer || !midRecordingClose || !midAudioSetThreadPriority) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL",
|
||||
"Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
|
||||
}
|
||||
@@ -1009,7 +1009,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeAddTouch)(
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean recording,
|
||||
jstring name, jint device_id)
|
||||
{
|
||||
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
|
||||
@@ -1017,7 +1017,7 @@ SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_c
|
||||
void *handle = (void *)((size_t)device_id);
|
||||
if (!SDL_FindPhysicalAudioDeviceByHandle(handle)) {
|
||||
const char *utf8name = (*env)->GetStringUTFChars(env, name, NULL);
|
||||
SDL_AddAudioDevice(is_capture, SDL_strdup(utf8name), NULL, handle);
|
||||
SDL_AddAudioDevice(recording, SDL_strdup(utf8name), NULL, handle);
|
||||
(*env)->ReleaseStringUTFChars(env, name, utf8name);
|
||||
}
|
||||
}
|
||||
@@ -1025,12 +1025,12 @@ SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_c
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
|
||||
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean recording,
|
||||
jint device_id)
|
||||
{
|
||||
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
|
||||
if (SDL_GetCurrentAudioDriver() != NULL) {
|
||||
SDL_Log("Removing device with handle %d, capture %d", device_id, is_capture);
|
||||
SDL_Log("Removing device with handle %d, recording %d", device_id, recording);
|
||||
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)device_id)));
|
||||
}
|
||||
#endif
|
||||
@@ -1595,15 +1595,15 @@ SDL_bool Android_JNI_GetAccelerometerValues(float values[3])
|
||||
static int audioBufferFormat = 0;
|
||||
static jobject audioBuffer = NULL;
|
||||
static void *audioBufferPinned = NULL;
|
||||
static int captureBufferFormat = 0;
|
||||
static jobject captureBuffer = NULL;
|
||||
static int recordingBufferFormat = 0;
|
||||
static jobject recordingBuffer = NULL;
|
||||
|
||||
void Android_StartAudioHotplug(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
void Android_StartAudioHotplug(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
// this will fire the callback for each existing device right away (which will eventually SDL_AddAudioDevice), and again later when things change.
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midRegisterAudioDeviceCallback);
|
||||
*default_output = *default_capture = NULL; // !!! FIXME: how do you decide the default device id?
|
||||
*default_playback = *default_recording = NULL; // !!! FIXME: how do you decide the default device id?
|
||||
}
|
||||
|
||||
void Android_StopAudioHotplug(void)
|
||||
@@ -1614,7 +1614,7 @@ void Android_StopAudioHotplug(void)
|
||||
|
||||
int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
const SDL_bool iscapture = device->iscapture;
|
||||
const SDL_bool recording = device->recording;
|
||||
SDL_AudioSpec *spec = &device->spec;
|
||||
const int device_id = (int) ((size_t) device->handle);
|
||||
int audioformat;
|
||||
@@ -1639,11 +1639,11 @@ int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device)
|
||||
return SDL_SetError("Unsupported audio format: 0x%x", spec->format);
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
|
||||
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midCaptureOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id);
|
||||
if (recording) {
|
||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for recording");
|
||||
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midRecordingOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id);
|
||||
} 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 playback");
|
||||
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id);
|
||||
}
|
||||
if (!result) {
|
||||
@@ -1712,15 +1712,15 @@ int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device)
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
captureBufferFormat = audioformat;
|
||||
captureBuffer = jbufobj;
|
||||
if (recording) {
|
||||
recordingBufferFormat = audioformat;
|
||||
recordingBuffer = jbufobj;
|
||||
} else {
|
||||
audioBufferFormat = audioformat;
|
||||
audioBuffer = jbufobj;
|
||||
}
|
||||
|
||||
if (!iscapture) {
|
||||
if (!recording) {
|
||||
isCopy = JNI_FALSE;
|
||||
|
||||
switch (audioformat) {
|
||||
@@ -1780,103 +1780,103 @@ void Android_JNI_WriteAudioBuffer(void)
|
||||
/* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
|
||||
}
|
||||
|
||||
int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
|
||||
int Android_JNI_RecordAudioBuffer(void *buffer, int buflen)
|
||||
{
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
jboolean isCopy = JNI_FALSE;
|
||||
jint br = -1;
|
||||
|
||||
switch (captureBufferFormat) {
|
||||
switch (recordingBufferFormat) {
|
||||
case ENCODING_PCM_8BIT:
|
||||
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen);
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
|
||||
SDL_assert((*env)->GetArrayLength(env, (jshortArray)recordingBuffer) == buflen);
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadByteBuffer, (jbyteArray)recordingBuffer, JNI_TRUE);
|
||||
if (br > 0) {
|
||||
jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
|
||||
jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)recordingBuffer, &isCopy);
|
||||
SDL_memcpy(buffer, ptr, br);
|
||||
(*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, ptr, JNI_ABORT);
|
||||
(*env)->ReleaseByteArrayElements(env, (jbyteArray)recordingBuffer, ptr, JNI_ABORT);
|
||||
}
|
||||
break;
|
||||
case ENCODING_PCM_16BIT:
|
||||
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen / sizeof(Sint16)));
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
|
||||
SDL_assert((*env)->GetArrayLength(env, (jshortArray)recordingBuffer) == (buflen / sizeof(Sint16)));
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadShortBuffer, (jshortArray)recordingBuffer, JNI_TRUE);
|
||||
if (br > 0) {
|
||||
jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
|
||||
jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)recordingBuffer, &isCopy);
|
||||
br *= sizeof(Sint16);
|
||||
SDL_memcpy(buffer, ptr, br);
|
||||
(*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, ptr, JNI_ABORT);
|
||||
(*env)->ReleaseShortArrayElements(env, (jshortArray)recordingBuffer, ptr, JNI_ABORT);
|
||||
}
|
||||
break;
|
||||
case ENCODING_PCM_FLOAT:
|
||||
SDL_assert((*env)->GetArrayLength(env, (jfloatArray)captureBuffer) == (buflen / sizeof(float)));
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_TRUE);
|
||||
SDL_assert((*env)->GetArrayLength(env, (jfloatArray)recordingBuffer) == (buflen / sizeof(float)));
|
||||
br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadFloatBuffer, (jfloatArray)recordingBuffer, JNI_TRUE);
|
||||
if (br > 0) {
|
||||
jfloat *ptr = (*env)->GetFloatArrayElements(env, (jfloatArray)captureBuffer, &isCopy);
|
||||
jfloat *ptr = (*env)->GetFloatArrayElements(env, (jfloatArray)recordingBuffer, &isCopy);
|
||||
br *= sizeof(float);
|
||||
SDL_memcpy(buffer, ptr, br);
|
||||
(*env)->ReleaseFloatArrayElements(env, (jfloatArray)captureBuffer, ptr, JNI_ABORT);
|
||||
(*env)->ReleaseFloatArrayElements(env, (jfloatArray)recordingBuffer, ptr, JNI_ABORT);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: unhandled capture buffer format");
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: unhandled recording buffer format");
|
||||
break;
|
||||
}
|
||||
return br;
|
||||
}
|
||||
|
||||
void Android_JNI_FlushCapturedAudio(void)
|
||||
void Android_JNI_FlushRecordedAudio(void)
|
||||
{
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
#if 0 /* !!! FIXME: this needs API 23, or it'll do blocking reads and never end. */
|
||||
switch (captureBufferFormat) {
|
||||
switch (recordingBufferFormat) {
|
||||
case ENCODING_PCM_8BIT:
|
||||
{
|
||||
const jint len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
const jint len = (*env)->GetArrayLength(env, (jbyteArray)recordingBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midRecordingReadByteBuffer, (jbyteArray)recordingBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
}
|
||||
break;
|
||||
case ENCODING_PCM_16BIT:
|
||||
{
|
||||
const jint len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
const jint len = (*env)->GetArrayLength(env, (jshortArray)recordingBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midRecordingReadShortBuffer, (jshortArray)recordingBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
}
|
||||
break;
|
||||
case ENCODING_PCM_FLOAT:
|
||||
{
|
||||
const jint len = (*env)->GetArrayLength(env, (jfloatArray)captureBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
const jint len = (*env)->GetArrayLength(env, (jfloatArray)recordingBuffer);
|
||||
while ((*env)->CallStaticIntMethod(env, mActivityClass, midRecordingReadFloatBuffer, (jfloatArray)recordingBuffer, JNI_FALSE) == len) { /* spin */ }
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: flushing unhandled capture buffer format");
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: flushing unhandled recording buffer format");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (captureBufferFormat) {
|
||||
switch (recordingBufferFormat) {
|
||||
case ENCODING_PCM_8BIT:
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadByteBuffer, (jbyteArray)recordingBuffer, JNI_FALSE);
|
||||
break;
|
||||
case ENCODING_PCM_16BIT:
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadShortBuffer, (jshortArray)recordingBuffer, JNI_FALSE);
|
||||
break;
|
||||
case ENCODING_PCM_FLOAT:
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadFloatBuffer, (jfloatArray)captureBuffer, JNI_FALSE);
|
||||
(*env)->CallStaticIntMethod(env, mAudioManagerClass, midRecordingReadFloatBuffer, (jfloatArray)recordingBuffer, JNI_FALSE);
|
||||
break;
|
||||
default:
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: flushing unhandled capture buffer format");
|
||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: flushing unhandled recording buffer format");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Android_JNI_CloseAudioDevice(const int iscapture)
|
||||
void Android_JNI_CloseAudioDevice(const int recording)
|
||||
{
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
|
||||
if (iscapture) {
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midCaptureClose);
|
||||
if (captureBuffer) {
|
||||
(*env)->DeleteGlobalRef(env, captureBuffer);
|
||||
captureBuffer = NULL;
|
||||
if (recording) {
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midRecordingClose);
|
||||
if (recordingBuffer) {
|
||||
(*env)->DeleteGlobalRef(env, recordingBuffer);
|
||||
recordingBuffer = NULL;
|
||||
}
|
||||
} else {
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioClose);
|
||||
@@ -1888,15 +1888,15 @@ void Android_JNI_CloseAudioDevice(const int iscapture)
|
||||
}
|
||||
}
|
||||
|
||||
static void Android_JNI_AudioSetThreadPriority(int iscapture, int device_id)
|
||||
static void Android_JNI_AudioSetThreadPriority(int recording, int device_id)
|
||||
{
|
||||
JNIEnv *env = Android_JNI_GetEnv();
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioSetThreadPriority, iscapture, device_id);
|
||||
(*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioSetThreadPriority, recording, device_id);
|
||||
}
|
||||
|
||||
void Android_AudioThreadInit(SDL_AudioDevice *device)
|
||||
{
|
||||
Android_JNI_AudioSetThreadPriority((int) device->iscapture, (int)device->instance_id);
|
||||
Android_JNI_AudioSetThreadPriority((int) device->recording, (int)device->instance_id);
|
||||
}
|
||||
|
||||
/* Test for an exception and call SDL_SetError with its detail if one occurs */
|
||||
|
||||
@@ -52,15 +52,15 @@ extern SDL_DisplayOrientation Android_JNI_GetDisplayNaturalOrientation(void);
|
||||
extern SDL_DisplayOrientation Android_JNI_GetDisplayCurrentOrientation(void);
|
||||
|
||||
/* Audio support */
|
||||
void Android_StartAudioHotplug(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||
void Android_StartAudioHotplug(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
||||
void Android_StopAudioHotplug(void);
|
||||
extern void Android_AudioThreadInit(SDL_AudioDevice *device);
|
||||
extern int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device);
|
||||
extern void *Android_JNI_GetAudioBuffer(void);
|
||||
extern void Android_JNI_WriteAudioBuffer(void);
|
||||
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
|
||||
extern void Android_JNI_FlushCapturedAudio(void);
|
||||
extern void Android_JNI_CloseAudioDevice(const int iscapture);
|
||||
extern int Android_JNI_RecordAudioBuffer(void *buffer, int buflen);
|
||||
extern void Android_JNI_FlushRecordedAudio(void);
|
||||
extern void Android_JNI_CloseAudioDevice(const int recording);
|
||||
|
||||
/* Detecting device type */
|
||||
extern SDL_bool Android_IsDeXMode(void);
|
||||
|
||||
@@ -120,7 +120,7 @@ void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const SDL_bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
|
||||
{
|
||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||
@@ -164,7 +164,7 @@ static SDL_AudioDevice *SDL_IMMDevice_Add(const SDL_bool iscapture, const char *
|
||||
spec.freq = fmt->Format.nSamplesPerSec;
|
||||
spec.format = SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
|
||||
device = SDL_AddAudioDevice(iscapture, devname, &spec, handle);
|
||||
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
|
||||
if (!device) {
|
||||
SDL_free(handle->immdevice_id);
|
||||
SDL_free(handle);
|
||||
@@ -248,14 +248,14 @@ static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IM
|
||||
if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **)&endpoint))) {
|
||||
EDataFlow flow;
|
||||
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
|
||||
const SDL_bool iscapture = (flow == eCapture);
|
||||
const SDL_bool recording = (flow == eCapture);
|
||||
if (dwNewState == DEVICE_STATE_ACTIVE) {
|
||||
char *utf8dev;
|
||||
WAVEFORMATEXTENSIBLE fmt;
|
||||
GUID dsoundguid;
|
||||
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
|
||||
if (utf8dev) {
|
||||
SDL_IMMDevice_Add(iscapture, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
@@ -336,7 +336,7 @@ void SDL_IMMDevice_Quit(void)
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
|
||||
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool iscapture)
|
||||
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool recording)
|
||||
{
|
||||
const Uint64 timeout = SDL_GetTicks() + 8000; /* intel's audio drivers can fail for up to EIGHT SECONDS after a device is connected or we wake from sleep. */
|
||||
|
||||
@@ -361,13 +361,13 @@ int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool i
|
||||
|
||||
}
|
||||
|
||||
static void EnumerateEndpointsForFlow(const SDL_bool iscapture, SDL_AudioDevice **default_device)
|
||||
static void EnumerateEndpointsForFlow(const SDL_bool recording, SDL_AudioDevice **default_device)
|
||||
{
|
||||
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
|
||||
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
|
||||
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
if (FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(enumerator, iscapture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &collection))) {
|
||||
if (FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(enumerator, recording ? eCapture : eRender, DEVICE_STATE_ACTIVE, &collection))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ static void EnumerateEndpointsForFlow(const SDL_bool iscapture, SDL_AudioDevice
|
||||
LPWSTR default_devid = NULL;
|
||||
if (default_device) {
|
||||
IMMDevice *default_immdevice = NULL;
|
||||
const EDataFlow dataflow = iscapture ? eCapture : eRender;
|
||||
const EDataFlow dataflow = recording ? eCapture : eRender;
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_IMMDevice_role, &default_immdevice))) {
|
||||
LPWSTR devid = NULL;
|
||||
if (SUCCEEDED(IMMDevice_GetId(default_immdevice, &devid))) {
|
||||
@@ -403,7 +403,7 @@ static void EnumerateEndpointsForFlow(const SDL_bool iscapture, SDL_AudioDevice
|
||||
SDL_zero(dsoundguid);
|
||||
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
|
||||
if (devname) {
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(iscapture, devname, &fmt, devid, &dsoundguid);
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid);
|
||||
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
|
||||
*default_device = sdldevice;
|
||||
}
|
||||
@@ -420,10 +420,10 @@ static void EnumerateEndpointsForFlow(const SDL_bool iscapture, SDL_AudioDevice
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
EnumerateEndpointsForFlow(SDL_FALSE, default_output); /* playback */
|
||||
EnumerateEndpointsForFlow(SDL_TRUE, default_capture); /* capture */
|
||||
EnumerateEndpointsForFlow(SDL_FALSE, default_playback);
|
||||
EnumerateEndpointsForFlow(SDL_TRUE, default_recording);
|
||||
|
||||
/* if this fails, we just won't get hotplug events. Carry on anyhow. */
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)¬ification_client);
|
||||
|
||||
@@ -36,8 +36,8 @@ typedef struct SDL_IMMDevice_callbacks
|
||||
|
||||
int SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
|
||||
void SDL_IMMDevice_Quit(void);
|
||||
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool iscapture);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
|
||||
int SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, SDL_bool recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
||||
LPGUID SDL_IMMDevice_GetDirectSoundGUID(SDL_AudioDevice *device);
|
||||
LPCWSTR SDL_IMMDevice_GetDevID(SDL_AudioDevice *device);
|
||||
void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device);
|
||||
|
||||
@@ -166,11 +166,11 @@ SDL3_0.0.0 {
|
||||
SDL_GetAndroidSDKVersion;
|
||||
SDL_GetAssertionHandler;
|
||||
SDL_GetAssertionReport;
|
||||
SDL_GetAudioCaptureDevices;
|
||||
SDL_GetAudioDeviceFormat;
|
||||
SDL_GetAudioDeviceName;
|
||||
SDL_GetAudioDriver;
|
||||
SDL_GetAudioOutputDevices;
|
||||
SDL_GetAudioPlaybackDevices;
|
||||
SDL_GetAudioRecordingDevices;
|
||||
SDL_GetAudioStreamAvailable;
|
||||
SDL_GetAudioStreamData;
|
||||
SDL_GetAudioStreamDevice;
|
||||
|
||||
@@ -191,11 +191,11 @@
|
||||
#define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL
|
||||
#define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
|
||||
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
|
||||
#define SDL_GetAudioCaptureDevices SDL_GetAudioCaptureDevices_REAL
|
||||
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
|
||||
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
|
||||
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
|
||||
#define SDL_GetAudioOutputDevices SDL_GetAudioOutputDevices_REAL
|
||||
#define SDL_GetAudioPlaybackDevices SDL_GetAudioPlaybackDevices_REAL
|
||||
#define SDL_GetAudioRecordingDevices SDL_GetAudioRecordingDevices_REAL
|
||||
#define SDL_GetAudioStreamAvailable SDL_GetAudioStreamAvailable_REAL
|
||||
#define SDL_GetAudioStreamData SDL_GetAudioStreamData_REAL
|
||||
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
|
||||
|
||||
@@ -211,11 +211,11 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GamepadSensorEnabled,(SDL_Gamepad *a, SDL_SensorTyp
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAndroidSDKVersion,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),return)
|
||||
SDL_DYNAPI_PROC(const SDL_AssertData*,SDL_GetAssertionReport,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioCaptureDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDeviceName,(SDL_AudioDeviceID a),(a),return)
|
||||
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDriver,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioOutputDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioPlaybackDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioRecordingDevices,(int *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamAvailable,(SDL_AudioStream *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamData,(SDL_AudioStream *a, void *b, int c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_GetAudioStreamDevice,(SDL_AudioStream *a),(a),return)
|
||||
|
||||
@@ -581,7 +581,7 @@ static void SDL_LogEvent(const SDL_Event *event)
|
||||
break;
|
||||
#undef PRINT_DROP_EVENT
|
||||
|
||||
#define PRINT_AUDIODEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u iscapture=%s)", (uint)event->adevice.timestamp, (uint)event->adevice.which, event->adevice.iscapture ? "true" : "false")
|
||||
#define PRINT_AUDIODEV_EVENT(event) (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%u recording=%s)", (uint)event->adevice.timestamp, (uint)event->adevice.which, event->adevice.recording ? "true" : "false")
|
||||
SDL_EVENT_CASE(SDL_EVENT_AUDIO_DEVICE_ADDED)
|
||||
PRINT_AUDIODEV_EVENT(event);
|
||||
break;
|
||||
|
||||
@@ -1466,7 +1466,7 @@ SDL_bool SDLTest_CommonInit(SDLTest_CommonState *state)
|
||||
}
|
||||
|
||||
const SDL_AudioSpec spec = { state->audio_format, state->audio_channels, state->audio_freq };
|
||||
state->audio_id = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
|
||||
state->audio_id = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec);
|
||||
if (!state->audio_id) {
|
||||
SDL_Log("Couldn't open audio: %s\n", SDL_GetError());
|
||||
return SDL_FALSE;
|
||||
|
||||
Reference in New Issue
Block a user