Update SDL3 from 3.2.4 to 3.2.20
This commit is contained in:
+173
-101
@@ -136,6 +136,7 @@ const char *SDL_GetAudioDriver(int index)
|
||||
if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
|
||||
return deduped_bootstrap[index]->name;
|
||||
}
|
||||
SDL_InvalidParamError("index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -409,6 +410,7 @@ static SDL_LogicalAudioDevice *ObtainLogicalAudioDevice(SDL_AudioDeviceID devid,
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &logdev);
|
||||
if (logdev) {
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
device = logdev->physical_device;
|
||||
SDL_assert(device != NULL);
|
||||
RefPhysicalAudioDevice(device); // reference it, in case the logical device migrates to a new default.
|
||||
@@ -458,6 +460,7 @@ static SDL_AudioDevice *ObtainPhysicalAudioDevice(SDL_AudioDeviceID devid) // !
|
||||
} else {
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
|
||||
SDL_assert(device->instance_id == devid);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
if (!device) {
|
||||
@@ -650,7 +653,7 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, bool recordi
|
||||
device->instance_id = AssignAudioDeviceInstanceId(recording, /*islogical=*/false);
|
||||
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
|
||||
if (SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) device->instance_id, device, false)) {
|
||||
SDL_AddAtomicInt(device_count, 1);
|
||||
} else {
|
||||
SDL_DestroyCondition(device->close_cond);
|
||||
@@ -864,50 +867,48 @@ static void CompleteAudioEntryPoints(void)
|
||||
#undef FILL_STUB
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
typedef struct FindLowestDeviceIDData
|
||||
{
|
||||
SDL_AudioDeviceID highest = (SDL_AudioDeviceID) SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
SDL_AudioDevice *result = NULL;
|
||||
const bool recording;
|
||||
SDL_AudioDeviceID highest;
|
||||
SDL_AudioDevice *result;
|
||||
} FindLowestDeviceIDData;
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
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 playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == recording) && (devid < highest)) {
|
||||
highest = devid;
|
||||
result = (SDL_AudioDevice *) value;
|
||||
}
|
||||
static bool SDLCALL FindLowestDeviceID(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindLowestDeviceIDData *data = (FindLowestDeviceIDData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// 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 bool devid_recording = !(devid & (1 << 0));
|
||||
const bool isphysical = !!(devid & (1 << 1));
|
||||
if (isphysical && (devid_recording == data->recording) && (devid < data->highest)) {
|
||||
data->highest = devid;
|
||||
data->result = (SDL_AudioDevice *) value;
|
||||
SDL_assert(data->result->instance_id == devid);
|
||||
}
|
||||
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return result;
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static Uint32 HashAudioDeviceID(const void *key, void *data)
|
||||
static SDL_AudioDevice *GetFirstAddedAudioDevice(const bool recording)
|
||||
{
|
||||
const SDL_AudioDeviceID highest = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; // According to AssignAudioDeviceInstanceId, nothing can have a value this large.
|
||||
|
||||
// (Device IDs increase as new devices are added, so the first device added has the lowest SDL_AudioDeviceID value.)
|
||||
FindLowestDeviceIDData data = { recording, highest, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindLowestDeviceID, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return data.result;
|
||||
}
|
||||
|
||||
static Uint32 SDLCALL HashAudioDeviceID(void *userdata, const void *key)
|
||||
{
|
||||
// shift right 2, to dump the first two bits, since these are flags
|
||||
// (recording vs playback, logical vs physical) and the rest are unique incrementing integers.
|
||||
return ((Uint32) ((uintptr_t) key)) >> 2;
|
||||
}
|
||||
|
||||
static bool MatchAudioDeviceID(const void *a, const void *b, void *data)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
static void NukeAudioDeviceHashItem(const void *key, const void *value, void *data)
|
||||
{
|
||||
// no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here.
|
||||
}
|
||||
|
||||
// !!! FIXME: the video subsystem does SDL_VideoInit, not SDL_InitVideo. Make this match.
|
||||
bool SDL_InitAudio(const char *driver_name)
|
||||
{
|
||||
@@ -926,7 +927,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashAudioDeviceID, MatchAudioDeviceID, NukeAudioDeviceHashItem, false, false);
|
||||
SDL_HashTable *device_hash = SDL_CreateHashTable(0, false, HashAudioDeviceID, SDL_KeyMatchID, NULL, NULL);
|
||||
if (!device_hash) {
|
||||
SDL_DestroyRWLock(device_hash_lock);
|
||||
return false;
|
||||
@@ -964,7 +965,7 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
}
|
||||
|
||||
for (int i = 0; bootstrap[i]; ++i) {
|
||||
if (SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
if (!bootstrap[i]->is_preferred && SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
|
||||
tried_to_init = true;
|
||||
SDL_zero(current_audio);
|
||||
current_audio.pending_events_tail = ¤t_audio.pending_events;
|
||||
@@ -1047,6 +1048,20 @@ bool SDL_InitAudio(const char *driver_name)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SDLCALL DestroyOnePhysicalAudioDevice(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *dev = (SDL_AudioDevice *) value;
|
||||
|
||||
SDL_assert(dev->instance_id == devid);
|
||||
DestroyPhysicalAudioDevice(dev);
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
void SDL_QuitAudio(void)
|
||||
{
|
||||
if (!current_audio.name) { // not initialized?!
|
||||
@@ -1076,17 +1091,7 @@ void SDL_QuitAudio(void)
|
||||
SDL_free(i);
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) {
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
DestroyPhysicalAudioDevice((SDL_AudioDevice *) value);
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(device_hash, DestroyOnePhysicalAudioDevice, NULL);
|
||||
|
||||
// Free the driver data
|
||||
current_audio.impl.Deinitialize();
|
||||
@@ -1148,7 +1153,10 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec, NULL, NULL));
|
||||
|
||||
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
const int br = SDL_GetAtomicInt(&logdev->paused) ? 0 : SDL_GetAudioStreamDataAdjustGain(stream, device_buffer, buffer_size, logdev->gain);
|
||||
|
||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||
failed = true;
|
||||
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
|
||||
@@ -1190,6 +1198,8 @@ bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
||||
// We should have updated this elsewhere if the format changed!
|
||||
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &outspec, NULL, NULL));
|
||||
|
||||
SDL_assert(stream->src_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
/* this will hold a lock on `stream` while getting. We don't explicitly lock the streams
|
||||
for iterating here because the binding linked list can only change while the device lock is held.
|
||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||
@@ -1257,11 +1267,11 @@ static int SDLCALL PlaybackAudioThread(void *devicep) // thread entry point
|
||||
SDL_assert(!device->recording);
|
||||
SDL_PlaybackAudioThreadSetup(device);
|
||||
|
||||
do {
|
||||
while (SDL_PlaybackAudioThreadIterate(device)) {
|
||||
if (!device->WaitDevice(device)) {
|
||||
SDL_AudioDeviceDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
|
||||
}
|
||||
} while (SDL_PlaybackAudioThreadIterate(device));
|
||||
}
|
||||
|
||||
SDL_PlaybackAudioThreadShutdown(device);
|
||||
return 0;
|
||||
@@ -1325,6 +1335,7 @@ bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
|
||||
SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
|
||||
SDL_assert(stream->src_spec.channels == device->spec.channels);
|
||||
SDL_assert(stream->src_spec.freq == device->spec.freq);
|
||||
SDL_assert(stream->dst_spec.format != SDL_AUDIO_UNKNOWN);
|
||||
|
||||
void *final_buf = output_buffer;
|
||||
|
||||
@@ -1383,6 +1394,35 @@ static int SDLCALL RecordingAudioThread(void *devicep) // thread entry point
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct CountAudioDevicesData
|
||||
{
|
||||
int devs_seen;
|
||||
int devs_skipped;
|
||||
const int num_devices;
|
||||
SDL_AudioDeviceID *result;
|
||||
const bool recording;
|
||||
} CountAudioDevicesData;
|
||||
|
||||
static bool SDLCALL CountAudioDevices(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
CountAudioDevicesData *data = (CountAudioDevicesData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// 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 bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == data->recording)) {
|
||||
SDL_assert(data->devs_seen < data->num_devices);
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value; // this is normally risky, but we hold the device_hash_lock here.
|
||||
const bool zombie = SDL_GetAtomicInt(&device->zombie) != 0;
|
||||
if (zombie) {
|
||||
data->devs_skipped++;
|
||||
} else {
|
||||
data->result[data->devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
{
|
||||
@@ -1395,24 +1435,11 @@ static SDL_AudioDeviceID *GetAudioDevices(int *count, bool recording)
|
||||
num_devices = SDL_GetAtomicInt(recording ? ¤t_audio.recording_device_count : ¤t_audio.playback_device_count);
|
||||
result = (SDL_AudioDeviceID *) SDL_malloc((num_devices + 1) * sizeof (SDL_AudioDeviceID));
|
||||
if (result) {
|
||||
int devs_seen = 0;
|
||||
const void *key;
|
||||
const void *value;
|
||||
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 playback devices and unset for recording.
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool devid_recording = !(devid & (1<<0));
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical && (devid_recording == recording)) {
|
||||
SDL_assert(devs_seen < num_devices);
|
||||
result[devs_seen++] = devid;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(devs_seen == num_devices);
|
||||
result[devs_seen] = 0; // null-terminated.
|
||||
CountAudioDevicesData data = { 0, 0, num_devices, result, recording };
|
||||
SDL_IterateHashTable(current_audio.device_hash, CountAudioDevices, &data);
|
||||
SDL_assert((data.devs_seen + data.devs_skipped) == num_devices);
|
||||
num_devices = data.devs_seen; // might be less if we skipped any.
|
||||
result[num_devices] = 0; // null-terminated.
|
||||
}
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
@@ -1440,7 +1467,31 @@ SDL_AudioDeviceID *SDL_GetAudioRecordingDevices(int *count)
|
||||
return GetAudioDevices(count, true);
|
||||
}
|
||||
|
||||
typedef struct FindAudioDeviceByCallbackData
|
||||
{
|
||||
bool (*callback)(SDL_AudioDevice *device, void *userdata);
|
||||
void *userdata;
|
||||
SDL_AudioDevice *retval;
|
||||
} FindAudioDeviceByCallbackData;
|
||||
|
||||
static bool SDLCALL FindAudioDeviceByCallback(void *userdata, const SDL_HashTable *table, const void *key, const void *value)
|
||||
{
|
||||
FindAudioDeviceByCallbackData *data = (FindAudioDeviceByCallbackData *) userdata;
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (data->callback(device, data->userdata)) { // found it?
|
||||
data->retval = device;
|
||||
SDL_assert(data->retval->instance_id == devid);
|
||||
return false; // stop iterating, we found it.
|
||||
}
|
||||
}
|
||||
return true; // keep iterating.
|
||||
}
|
||||
|
||||
// !!! FIXME: SDL convention is for userdata to come first in the callback's params. Fix this at some point.
|
||||
SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata)
|
||||
{
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
@@ -1448,27 +1499,16 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(bool (*callback)(SDL_Audi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *key;
|
||||
const void *value;
|
||||
void *iter = NULL;
|
||||
|
||||
FindAudioDeviceByCallbackData data = { callback, userdata, NULL };
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
while (SDL_IterateHashTable(current_audio.device_hash, &key, &value, &iter)) {
|
||||
const SDL_AudioDeviceID devid = (SDL_AudioDeviceID) (uintptr_t) key;
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool isphysical = !!(devid & (1<<1));
|
||||
if (isphysical) {
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) value;
|
||||
if (callback(device, userdata)) { // found it?
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_IterateHashTable(current_audio.device_hash, FindAudioDeviceByCallback, &data);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
|
||||
SDL_SetError("Device not found");
|
||||
return NULL;
|
||||
if (!data.retval) {
|
||||
SDL_SetError("Device not found");
|
||||
}
|
||||
|
||||
return data.retval;
|
||||
}
|
||||
|
||||
static bool TestDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
|
||||
@@ -1483,12 +1523,33 @@ SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle)
|
||||
|
||||
const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
{
|
||||
// bit #1 of devid is set for physical devices and unset for logical.
|
||||
const bool islogical = !(devid & (1<<1));
|
||||
const char *result = NULL;
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
|
||||
if (device) {
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
const void *vdev = NULL;
|
||||
|
||||
if (!SDL_GetCurrentAudioDriver()) {
|
||||
SDL_SetError("Audio subsystem is not initialized");
|
||||
} else {
|
||||
// This does not call ObtainPhysicalAudioDevice() because the device's name never changes, so
|
||||
// it doesn't have to lock the whole device. However, just to make sure the device pointer itself
|
||||
// remains valid (in case the device is unplugged at the wrong moment), we hold the
|
||||
// device_hash_lock while we copy the string.
|
||||
SDL_LockRWLockForReading(current_audio.device_hash_lock);
|
||||
SDL_FindInHashTable(current_audio.device_hash, (const void *) (uintptr_t) devid, &vdev);
|
||||
if (!vdev) {
|
||||
SDL_SetError("Invalid audio device instance ID");
|
||||
} else if (islogical) {
|
||||
const SDL_LogicalAudioDevice *logdev = (const SDL_LogicalAudioDevice *) vdev;
|
||||
SDL_assert(logdev->instance_id == devid);
|
||||
result = SDL_GetPersistentString(logdev->physical_device->name);
|
||||
} else {
|
||||
const SDL_AudioDevice *device = (const SDL_AudioDevice *) vdev;
|
||||
SDL_assert(device->instance_id == devid);
|
||||
result = SDL_GetPersistentString(device->name);
|
||||
}
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1520,7 +1581,9 @@ int *SDL_GetAudioDeviceChannelMap(SDL_AudioDeviceID devid, int *count)
|
||||
SDL_AudioDevice *device = ObtainPhysicalAudioDeviceDefaultAllowed(devid);
|
||||
if (device) {
|
||||
channels = device->spec.channels;
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
if (channels > 0 && device->chmap) {
|
||||
result = SDL_ChannelMapDup(device->chmap, channels);
|
||||
}
|
||||
}
|
||||
ReleaseAudioDevice(device);
|
||||
|
||||
@@ -1696,13 +1759,18 @@ static bool OpenPhysicalAudioDevice(SDL_AudioDevice *device, const SDL_AudioSpec
|
||||
SDL_copyp(&spec, inspec ? inspec : &device->default_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.
|
||||
(or some VoIP library that opens for mono output ruining your surround-sound game because it got there first).
|
||||
/* We impose a simple minimum on device formats. 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, or some VoIP library that opens for mono output
|
||||
ruining your surround-sound game because it got there first.
|
||||
These are just requests! The backend may change any of these values during OpenDevice method! */
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(device->default_spec.format) >= SDL_AUDIO_BITSIZE(spec.format)) ? device->default_spec.format : spec.format;
|
||||
device->spec.freq = SDL_max(device->default_spec.freq, spec.freq);
|
||||
device->spec.channels = SDL_max(device->default_spec.channels, spec.channels);
|
||||
|
||||
const SDL_AudioFormat minimum_format = device->recording ? DEFAULT_AUDIO_RECORDING_FORMAT : DEFAULT_AUDIO_PLAYBACK_FORMAT;
|
||||
const int minimum_channels = device->recording ? DEFAULT_AUDIO_RECORDING_CHANNELS : DEFAULT_AUDIO_PLAYBACK_CHANNELS;
|
||||
const int minimum_freq = device->recording ? DEFAULT_AUDIO_RECORDING_FREQUENCY : DEFAULT_AUDIO_PLAYBACK_FREQUENCY;
|
||||
|
||||
device->spec.format = (SDL_AUDIO_BITSIZE(minimum_format) >= SDL_AUDIO_BITSIZE(spec.format)) ? minimum_format : spec.format;
|
||||
device->spec.channels = SDL_max(minimum_channels, spec.channels);
|
||||
device->spec.freq = SDL_max(minimum_freq, spec.freq);
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq);
|
||||
SDL_UpdatedAudioDeviceFormat(device); // start this off sane.
|
||||
|
||||
@@ -1794,7 +1862,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
||||
|
||||
if (result) {
|
||||
SDL_LockRWLockForWriting(current_audio.device_hash_lock);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev);
|
||||
const bool inserted = SDL_InsertIntoHashTable(current_audio.device_hash, (const void *) (uintptr_t) result, logdev, false);
|
||||
SDL_UnlockRWLock(current_audio.device_hash_lock);
|
||||
if (!inserted) {
|
||||
SDL_CloseAudioDevice(result);
|
||||
@@ -1913,10 +1981,6 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
|
||||
} else if (logdev->simplified) {
|
||||
result = SDL_SetError("Cannot change stream bindings on device opened with SDL_OpenAudioDeviceStream");
|
||||
} else {
|
||||
|
||||
// !!! FIXME: We'll set the device's side's format below, but maybe we should refuse to bind a stream if the app's side doesn't have a format set yet.
|
||||
// !!! FIXME: Actually, why do we allow there to be an invalid format, again?
|
||||
|
||||
// make sure start of list is sane.
|
||||
SDL_assert(!logdev->bound_streams || (logdev->bound_streams->prev_binding == NULL));
|
||||
|
||||
@@ -1951,9 +2015,17 @@ bool SDL_BindAudioStreams(SDL_AudioDeviceID devid, SDL_AudioStream * const *stre
|
||||
|
||||
if (result) {
|
||||
// Now that everything is verified, chain everything together.
|
||||
const 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...
|
||||
// if the stream never had its non-device-end format set, just set it to the device end's format.
|
||||
if (recording && (stream->dst_spec.format == SDL_AUDIO_UNKNOWN)) {
|
||||
SDL_copyp(&stream->dst_spec, &device->spec);
|
||||
} else if (!recording && (stream->src_spec.format == SDL_AUDIO_UNKNOWN)) {
|
||||
SDL_copyp(&stream->src_spec, &device->spec);
|
||||
}
|
||||
|
||||
stream->bound_device = logdev;
|
||||
stream->prev_binding = NULL;
|
||||
stream->next_binding = logdev->bound_streams;
|
||||
|
||||
@@ -444,7 +444,7 @@ static void SincTable(float *table, int len)
|
||||
}
|
||||
|
||||
// Calculate Sinc(x/y), using a lookup table
|
||||
static float Sinc(float *table, int x, int y)
|
||||
static float Sinc(const float *table, int x, int y)
|
||||
{
|
||||
float s = table[x % y];
|
||||
s = ((x / y) & 1) ? -s : s;
|
||||
@@ -587,7 +587,18 @@ Sint64 SDL_GetResampleRate(int src_rate, int dst_rate)
|
||||
SDL_assert(src_rate > 0);
|
||||
SDL_assert(dst_rate > 0);
|
||||
|
||||
Sint64 sample_rate = ((Sint64)src_rate << 32) / (Sint64)dst_rate;
|
||||
Sint64 numerator = (Sint64)src_rate << 32;
|
||||
Sint64 denominator = (Sint64)dst_rate;
|
||||
|
||||
// Generally it's expected that `dst_frames = (src_frames * dst_rate) / src_rate`
|
||||
// To match this as closely as possible without infinite precision, always round up the resample rate.
|
||||
// For example, without rounding up, a sample ratio of 2:3 would have `sample_rate = 0xAAAAAAAA`
|
||||
// After 3 frames, the position would be 0x1.FFFFFFFE, meaning we haven't fully consumed the second input frame.
|
||||
// By rounding up to 0xAAAAAAAB, we would instead reach 0x2.00000001, fulling consuming the second frame.
|
||||
// Technically you could say this is kicking the can 0x100000000 steps down the road, but I'm fine with that :)
|
||||
// sample_rate = div_ceil(numerator, denominator)
|
||||
Sint64 sample_rate = ((numerator - 1) / denominator) + 1;
|
||||
|
||||
SDL_assert(sample_rate > 0);
|
||||
|
||||
return sample_rate;
|
||||
@@ -657,7 +668,7 @@ Sint64 SDL_GetResamplerOutputFrames(Sint64 input_frames, Sint64 resample_rate, S
|
||||
}
|
||||
|
||||
// output_frames = div_ceil(input_offset, resample_rate)
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset + resample_rate * 3 / 4) / resample_rate) : 0;
|
||||
Sint64 output_frames = (input_offset > 0) ? ((input_offset - 1) / resample_rate) + 1 : 0;
|
||||
|
||||
*inout_resample_offset = (output_frames * resample_rate) - input_offset;
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "SDL_sysaudio.h"
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
#include <fenv.h>
|
||||
#endif
|
||||
|
||||
#define DIVBY2147483648 0.0000000004656612873077392578125f // 0x1p-31f
|
||||
|
||||
// start fallback scalar converters
|
||||
@@ -527,9 +531,29 @@ static void SDL_TARGETING("ssse3") SDL_Convert_Swap32_SSSE3(Uint32* dst, const U
|
||||
#endif
|
||||
|
||||
#ifdef SDL_NEON_INTRINSICS
|
||||
|
||||
// C99 requires that all code modifying floating point environment should
|
||||
// be guarded by the STDC FENV_ACCESS pragma; otherwise, it's undefined
|
||||
// behavior. However, the compiler support for this pragma is bad.
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#if defined(__aarch64__)
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (on)
|
||||
#elif defined(__GNUC__)
|
||||
// GCC does not support the pragma at all
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
|
||||
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 7), 0);
|
||||
@@ -549,11 +573,14 @@ static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("U8", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -575,11 +602,14 @@ static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_sam
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S16", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_REV({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vdup_n_s32(src[i]), 15), 0);
|
||||
@@ -597,11 +627,14 @@ static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_f32(&dst[i], vcvt_n_f32_s32(vld1_dup_s32(&src[i]), 31), 0);
|
||||
@@ -621,11 +654,14 @@ static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_s
|
||||
vst1q_f32(&dst[i + 8], floats2);
|
||||
vst1q_f32(&dst[i + 12], floats3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s8(&dst[i], vreinterpret_s8_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 3);
|
||||
@@ -647,11 +683,14 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_s8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "U8 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
uint8x16_t flipper = vdupq_n_u8(0x80);
|
||||
|
||||
@@ -679,11 +718,14 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
|
||||
|
||||
vst1q_u8(&dst[i], bytes);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S16 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s16(&dst[i], vreinterpret_s16_s32(vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31)), 1);
|
||||
@@ -704,11 +746,14 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
|
||||
vst1q_s16(&dst[i], shorts0);
|
||||
vst1q_s16(&dst[i + 8], shorts1);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_samples)
|
||||
{
|
||||
LOG_DEBUG_AUDIO_CONVERT("F32", "S32 (using NEON)");
|
||||
fenv_t fenv;
|
||||
feholdexcept(&fenv);
|
||||
|
||||
CONVERT_16_FWD({
|
||||
vst1_lane_s32(&dst[i], vcvt_n_s32_f32(vld1_dup_f32(&src[i]), 31), 0);
|
||||
@@ -728,6 +773,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
|
||||
vst1q_s32(&dst[i + 8], ints2);
|
||||
vst1q_s32(&dst[i + 12], ints3);
|
||||
})
|
||||
fesetenv(&fenv);
|
||||
}
|
||||
|
||||
static void SDL_Convert_Swap16_NEON(Uint16* dst, const Uint16* src, int num_samples)
|
||||
@@ -767,6 +813,21 @@ static void SDL_Convert_Swap32_NEON(Uint32* dst, const Uint32* src, int num_samp
|
||||
vst1q_u8((Uint8*)&dst[i + 12], ints3);
|
||||
})
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ >= 12
|
||||
#if defined(__aarch64__)
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma fenv_access (off)
|
||||
#elif defined(__GNUC__)
|
||||
//
|
||||
#else
|
||||
#pragma STDC FENV_ACCESS DEFAULT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#undef CONVERT_16_FWD
|
||||
|
||||
@@ -360,6 +360,7 @@ typedef struct AudioBootStrap
|
||||
const char *desc;
|
||||
bool (*init)(SDL_AudioDriverImpl *impl);
|
||||
bool demand_only; // if true: request explicitly, or it won't be available.
|
||||
bool is_preferred;
|
||||
} AudioBootStrap;
|
||||
|
||||
// Not all of these are available in a given build. Use #ifdefs, etc.
|
||||
|
||||
@@ -2114,8 +2114,8 @@ bool SDL_LoadWAV_IO(SDL_IOStream *src, bool closeio, SDL_AudioSpec *spec, Uint8
|
||||
result = WaveLoad(src, &file, spec, audio_buf, audio_len);
|
||||
if (!result) {
|
||||
SDL_free(*audio_buf);
|
||||
audio_buf = NULL;
|
||||
audio_len = 0;
|
||||
*audio_buf = NULL;
|
||||
*audio_len = 0;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
|
||||
@@ -308,6 +308,12 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
ctx.AAudioStreamBuilder_setFormat(builder, format);
|
||||
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
|
||||
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
|
||||
|
||||
// If no specific buffer size has been requested, the device will pick the optimal
|
||||
if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
|
||||
ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
|
||||
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames); // twice the size of the data callback buffer size
|
||||
}
|
||||
|
||||
const aaudio_direction_t direction = (recording ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
|
||||
ctx.AAudioStreamBuilder_setDirection(builder, direction);
|
||||
@@ -366,7 +372,7 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
|
||||
hidden->processed_bytes = 0;
|
||||
hidden->callback_bytes = 0;
|
||||
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers);
|
||||
hidden->semaphore = SDL_CreateSemaphore(recording ? 0 : hidden->num_buffers - 1);
|
||||
if (!hidden->semaphore) {
|
||||
LOGI("SDL Failed SDL_CreateSemaphore %s recording:%d", SDL_GetError(), recording);
|
||||
return false;
|
||||
@@ -545,7 +551,7 @@ static bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap AAUDIO_bootstrap = {
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false
|
||||
"AAudio", "AAudio audio driver", AAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_AAUDIO
|
||||
|
||||
@@ -31,7 +31,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuild
|
||||
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aaudio_format_t format))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder * builder, aaudio_sharing_mode_t sharingMode))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
|
||||
|
||||
@@ -566,7 +566,7 @@ static enum snd_pcm_chmap_position sdl_channel_maps[SDL_AUDIO_ALSA__SDL_CHMAPS_N
|
||||
};
|
||||
|
||||
// Helper for the function right below.
|
||||
static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
static bool has_pos(const unsigned int *chmap, unsigned int pos)
|
||||
{
|
||||
for (unsigned int chan_idx = 0; ; chan_idx++) {
|
||||
if (chan_idx == 6) {
|
||||
@@ -586,7 +586,7 @@ static bool has_pos(unsigned int *chmap, unsigned int pos)
|
||||
#define HAVE_REAR 1
|
||||
#define HAVE_SIDE 2
|
||||
#define HAVE_BOTH 3
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, unsigned int *alsa_6chans)
|
||||
static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *sdl_6chans, const unsigned int *alsa_6chans)
|
||||
{
|
||||
// For alsa channel maps with 6 channels and with SND_CHMAP_FL,SND_CHMAP_FR,SND_CHMAP_FC,
|
||||
// SND_CHMAP_LFE, reduce our 6 channels maps to a uniq one.
|
||||
@@ -638,7 +638,7 @@ static void sdl_6chans_set_rear_or_side_channels_from_alsa_6chans(unsigned int *
|
||||
#undef HAVE_SIDE
|
||||
#undef HAVE_BOTH
|
||||
|
||||
static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
static void swizzle_map_compute_alsa_subscan(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, unsigned int sdl_pos_idx)
|
||||
{
|
||||
swizzle_map[sdl_pos_idx] = -1;
|
||||
for (unsigned int alsa_pos_idx = 0; ; alsa_pos_idx++) {
|
||||
@@ -652,7 +652,7 @@ static void swizzle_map_compute_alsa_subscan(struct ALSA_pcm_cfg_ctx *ctx, int *
|
||||
}
|
||||
|
||||
// XXX: this must stay playback/recording symetric.
|
||||
static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
static void swizzle_map_compute(const struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map, bool *needs_swizzle)
|
||||
{
|
||||
*needs_swizzle = false;
|
||||
for (unsigned int sdl_pos_idx = 0; sdl_pos_idx != ctx->chans_n; sdl_pos_idx++) {
|
||||
@@ -668,7 +668,7 @@ static void swizzle_map_compute(struct ALSA_pcm_cfg_ctx *ctx, int *swizzle_map,
|
||||
#define CHMAP_NOT_FOUND 2
|
||||
// Should always be a queried alsa channel map unless the queried alsa channel map was of type VAR,
|
||||
// namely we can program the channel positions directly from the SDL channel map.
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *chmap)
|
||||
{
|
||||
bool isstack;
|
||||
snd_pcm_chmap_t *chmap_to_install = (snd_pcm_chmap_t*)SDL_small_alloc(unsigned int, 1 + ctx->chans_n, &isstack);
|
||||
@@ -698,7 +698,7 @@ static int alsa_chmap_install(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *chmap)
|
||||
|
||||
// We restrict the alsa channel maps because in the unordered matches we do only simple accounting.
|
||||
// In the end, this will handle mostly alsa channel maps with more than one SND_CHMAP_NA position fillers.
|
||||
static bool alsa_chmap_has_duplicate_position(struct ALSA_pcm_cfg_ctx *ctx, unsigned int *pos)
|
||||
static bool alsa_chmap_has_duplicate_position(const struct ALSA_pcm_cfg_ctx *ctx, const unsigned int *pos)
|
||||
{
|
||||
if (ctx->chans_n < 2) {// we need at least 2 positions
|
||||
LOGDEBUG("channel map:no duplicate");
|
||||
@@ -1156,7 +1156,7 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
#if SDL_ALSA_DEBUG
|
||||
snd_pcm_uframes_t bufsize;
|
||||
ALSA_snd_pcm_hw_params_get_buffer_size(cfg_ctx.hwparams, &bufsize);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO,
|
||||
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
|
||||
cfg_ctx.persize, cfg_ctx.periods, bufsize);
|
||||
#endif
|
||||
@@ -1187,7 +1187,6 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
|
||||
ALSA_snd_pcm_nonblock(cfg_ctx.device->hidden->pcm, 0);
|
||||
}
|
||||
#endif
|
||||
ALSA_snd_pcm_start(cfg_ctx.device->hidden->pcm);
|
||||
return true; // We're ready to rock and roll. :-)
|
||||
|
||||
err_cleanup_ctx:
|
||||
@@ -1200,6 +1199,13 @@ err_free_device_hidden:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ALSA_ThreadInit(SDL_AudioDevice *device)
|
||||
{
|
||||
SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
|
||||
// do snd_pcm_start as close to the first time we PlayDevice as possible to prevent an underrun at startup.
|
||||
ALSA_snd_pcm_start(device->hidden->pcm);
|
||||
}
|
||||
|
||||
static ALSA_Device *hotplug_devices = NULL;
|
||||
|
||||
static int hotplug_device_process(snd_ctl_t *ctl, snd_ctl_card_info_t *ctl_card_info, int dev_idx,
|
||||
@@ -1497,6 +1503,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
|
||||
impl->DetectDevices = ALSA_DetectDevices;
|
||||
impl->OpenDevice = ALSA_OpenDevice;
|
||||
impl->ThreadInit = ALSA_ThreadInit;
|
||||
impl->WaitDevice = ALSA_WaitDevice;
|
||||
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
|
||||
impl->PlayDevice = ALSA_PlayDevice;
|
||||
@@ -1513,7 +1520,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap ALSA_bootstrap = {
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false
|
||||
"alsa", "ALSA PCM audio", ALSA_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_ALSA
|
||||
|
||||
@@ -1034,7 +1034,7 @@ static bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap COREAUDIO_bootstrap = {
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false
|
||||
"coreaudio", "CoreAudio", COREAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_COREAUDIO
|
||||
|
||||
@@ -206,7 +206,7 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDe
|
||||
{
|
||||
#ifdef HAVE_MMDEVICEAPI_H
|
||||
if (SupportsIMMDevice) {
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -674,7 +674,7 @@ static bool DSOUND_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSOUND_bootstrap = {
|
||||
"directsound", "DirectSound", DSOUND_Init, false
|
||||
"directsound", "DirectSound", DSOUND_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DSOUND
|
||||
|
||||
@@ -165,7 +165,7 @@ static bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DISKAUDIO_bootstrap = {
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true
|
||||
"disk", "direct-to-disk audio", DISKAUDIO_Init, true, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_DISK
|
||||
|
||||
@@ -297,7 +297,7 @@ static bool DSP_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DSP_bootstrap = {
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false
|
||||
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_OSS
|
||||
|
||||
@@ -131,5 +131,5 @@ static bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap DUMMYAUDIO_bootstrap = {
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true
|
||||
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, true, false
|
||||
};
|
||||
|
||||
@@ -189,7 +189,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
}
|
||||
|
||||
// limit to native freq
|
||||
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->spec.freq = MAIN_THREAD_EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
|
||||
device->sample_frames = SDL_GetDefaultSampleFramesFromFreq(device->spec.freq) * 2; // double the buffer size, some browsers need more, and we'll just have to live with the latency.
|
||||
|
||||
SDL_UpdatedAudioDeviceFormat(device);
|
||||
@@ -234,7 +234,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
if ((SDL3 === undefined) || (SDL3.audio_recording === undefined)) { return; }
|
||||
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
|
||||
SDL3.audio_recording.currentRecordingBuffer = audioProcessingEvent.inputBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
SDL3.audio_recording.mediaStreamNode.connect(SDL3.audio_recording.scriptProcessorNode);
|
||||
SDL3.audio_recording.scriptProcessorNode.connect(SDL3.audioContext.destination);
|
||||
@@ -250,7 +250,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audio_recording.silenceBuffer.getChannelData(0).fill(0.0);
|
||||
var silence_callback = function() {
|
||||
SDL3.audio_recording.currentRecordingBuffer = SDL3.audio_recording.silenceBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio_recording.silenceTimer = setInterval(silence_callback, ($1 / SDL3.audioContext.sampleRate) * 1000);
|
||||
@@ -275,7 +275,7 @@ static bool EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
SDL3.audio_playback.silenceBuffer = undefined;
|
||||
}
|
||||
SDL3.audio_playback.currentPlaybackBuffer = e['outputBuffer'];
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
};
|
||||
|
||||
SDL3.audio_playback.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||
@@ -293,7 +293,7 @@ static bool 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_playback.currentPlaybackBuffer = SDL3.audio_playback.silenceBuffer;
|
||||
dynCall('ii', $2, [$3]);
|
||||
dynCall('ip', $2, [$3]);
|
||||
SDL3.audio_playback.currentPlaybackBuffer = undefined;
|
||||
};
|
||||
|
||||
@@ -351,7 +351,7 @@ static bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
|
||||
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false
|
||||
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
@@ -216,7 +216,7 @@ static bool HAIKUAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
extern "C" { extern AudioBootStrap HAIKUAUDIO_bootstrap; }
|
||||
|
||||
AudioBootStrap HAIKUAUDIO_bootstrap = {
|
||||
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false
|
||||
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_HAIKU
|
||||
|
||||
@@ -429,7 +429,7 @@ static bool JACK_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap JACK_bootstrap = {
|
||||
"jack", "JACK Audio Connection Kit", JACK_Init, false
|
||||
"jack", "JACK Audio Connection Kit", JACK_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_JACK
|
||||
|
||||
@@ -280,7 +280,8 @@ AudioBootStrap N3DSAUDIO_bootstrap = {
|
||||
N3DSAUDIO_DRIVER_NAME,
|
||||
"SDL N3DS audio driver",
|
||||
N3DSAUDIO_Init,
|
||||
0
|
||||
false,
|
||||
false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_N3DS
|
||||
|
||||
@@ -322,7 +322,7 @@ static bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap NETBSDAUDIO_bootstrap = {
|
||||
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, false
|
||||
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_NETBSD
|
||||
|
||||
@@ -779,7 +779,7 @@ static bool OPENSLES_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap OPENSLES_bootstrap = {
|
||||
"openslES", "OpenSL ES audio driver", OPENSLES_Init, false
|
||||
"openslES", "OpenSL ES audio driver", OPENSLES_Init, false, false
|
||||
};
|
||||
|
||||
void OPENSLES_ResumeDevices(void)
|
||||
|
||||
@@ -44,7 +44,9 @@ enum PW_READY_FLAGS
|
||||
{
|
||||
PW_READY_FLAG_BUFFER_ADDED = 0x1,
|
||||
PW_READY_FLAG_STREAM_READY = 0x2,
|
||||
PW_READY_FLAG_ALL_BITS = 0x3
|
||||
PW_READY_FLAG_ALL_PREOPEN_BITS = 0x3,
|
||||
PW_READY_FLAG_OPEN_COMPLETE = 0x4,
|
||||
PW_READY_FLAG_ALL_BITS = 0x7
|
||||
};
|
||||
|
||||
#define PW_ID_TO_HANDLE(x) (void *)((uintptr_t)x)
|
||||
@@ -1116,7 +1118,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
||||
if (!stream_name || *stream_name == '\0') {
|
||||
stream_name = "Audio Stream";
|
||||
if (app_name) {
|
||||
stream_name = app_name;
|
||||
} else if (app_id) {
|
||||
stream_name = app_id;
|
||||
} else {
|
||||
stream_name = "SDL Audio Stream";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1185,7 +1193,11 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", device->sample_frames, device->spec.freq);
|
||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", device->spec.freq);
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
|
||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); // Requesting a specific device, don't migrate to new default hardware.
|
||||
|
||||
// UPDATE: This prevents users from moving the audio to a new sink (device) using standard tools. This is slightly in conflict
|
||||
// with how SDL wants to manage audio devices, but if people want to do it, we should let them, so this is commented out
|
||||
// for now. We might revisit later.
|
||||
//PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DONT_RECONNECT, "true"); // Requesting a specific device, don't migrate to new default hardware.
|
||||
|
||||
if (node_id != PW_ID_ANY) {
|
||||
PIPEWIRE_pw_thread_loop_lock(hotplug_loop);
|
||||
@@ -1215,12 +1227,13 @@ static bool PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
|
||||
return SDL_SetError("Pipewire: Failed to start stream loop");
|
||||
}
|
||||
|
||||
// Wait until all init flags are set or the stream has failed.
|
||||
// Wait until all pre-open init flags are set or the stream has failed.
|
||||
PIPEWIRE_pw_thread_loop_lock(priv->loop);
|
||||
while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS &&
|
||||
while (priv->stream_init_status != PW_READY_FLAG_ALL_PREOPEN_BITS &&
|
||||
PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) {
|
||||
PIPEWIRE_pw_thread_loop_wait(priv->loop);
|
||||
}
|
||||
priv->stream_init_status |= PW_READY_FLAG_OPEN_COMPLETE;
|
||||
PIPEWIRE_pw_thread_loop_unlock(priv->loop);
|
||||
|
||||
if (PIPEWIRE_pw_stream_get_state(priv->stream, &error) == PW_STREAM_STATE_ERROR) {
|
||||
@@ -1337,10 +1350,10 @@ static bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = {
|
||||
"pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false
|
||||
"pipewire", "Pipewire", PIPEWIRE_PREFERRED_Init, false, true
|
||||
};
|
||||
AudioBootStrap PIPEWIRE_bootstrap = {
|
||||
"pipewire", "Pipewire", PIPEWIRE_Init, false
|
||||
"pipewire", "Pipewire", PIPEWIRE_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PIPEWIRE
|
||||
|
||||
@@ -155,5 +155,5 @@ static bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PS2AUDIO_bootstrap = {
|
||||
"ps2", "PS2 audio driver", PS2AUDIO_Init, false
|
||||
"ps2", "PS2 audio driver", PS2AUDIO_Init, false, false
|
||||
};
|
||||
|
||||
@@ -114,7 +114,7 @@ static bool PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
|
||||
} else {
|
||||
rc = sceAudioOutputPannedBlocking(device->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, (void *) buffer);
|
||||
}
|
||||
return (rc == 0);
|
||||
return (rc >= 0);
|
||||
}
|
||||
|
||||
static bool PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
@@ -177,7 +177,7 @@ static bool PSPAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PSPAUDIO_bootstrap = {
|
||||
"psp", "PSP audio driver", PSPAUDIO_Init, false
|
||||
"psp", "PSP audio driver", PSPAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PSP
|
||||
|
||||
@@ -409,7 +409,7 @@ static bool PULSEAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
bool result = true;
|
||||
|
||||
//SDL_Log("PULSEAUDIO PLAYDEVICE START! mixlen=%d", available);
|
||||
//SDL_Log("PULSEAUDIO WAITDEVICE START! mixlen=%d", available);
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
@@ -543,7 +543,7 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = device->hidden;
|
||||
const void *data = NULL;
|
||||
size_t nbytes = 0;
|
||||
size_t nbytes = 0, buflen = 0;
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
|
||||
|
||||
@@ -553,7 +553,8 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
h->recordinglen = 0;
|
||||
}
|
||||
|
||||
while (!SDL_GetAtomicInt(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0)) {
|
||||
buflen = PULSEAUDIO_pa_stream_readable_size(h->stream);
|
||||
while (!SDL_GetAtomicInt(&device->shutdown) && (buflen > 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 FLUSHRECORDING!");
|
||||
@@ -561,11 +562,11 @@ static void PULSEAUDIO_FlushRecording(SDL_AudioDevice *device)
|
||||
break;
|
||||
}
|
||||
|
||||
if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) {
|
||||
// a new fragment is available! Just dump it.
|
||||
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||
PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment.
|
||||
}
|
||||
// a fragment of audio present before FlushCapture was call is
|
||||
// still available! Just drop it.
|
||||
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||
PULSEAUDIO_pa_stream_drop(h->stream);
|
||||
buflen -= nbytes;
|
||||
}
|
||||
|
||||
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
|
||||
@@ -671,7 +672,8 @@ static bool 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 recording devices, according to PulseAudio docs!
|
||||
|
||||
paattr.fragsize = device->buffer_size * 2; // despite the name, this is only used for recording devices, according to PulseAudio docs! (times 2 because we want _more_ than our buffer size sent from the server at a time, which helps some drivers).
|
||||
paattr.tlength = device->buffer_size;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
@@ -700,7 +702,10 @@ static bool PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
|
||||
PULSEAUDIO_pa_stream_set_state_callback(h->stream, PulseStreamStateChangeCallback, NULL);
|
||||
|
||||
// SDL manages device moves if the default changes, so don't ever let Pulse automatically migrate this stream.
|
||||
flags |= PA_STREAM_DONT_MOVE;
|
||||
// UPDATE: This prevents users from moving the audio to a new sink (device) using standard tools. This is slightly in conflict
|
||||
// with how SDL wants to manage audio devices, but if people want to do it, we should let them, so this is commented out
|
||||
// for now. We might revisit later.
|
||||
//flags |= PA_STREAM_DONT_MOVE;
|
||||
|
||||
const char *device_path = ((PulseDeviceHandle *) device->handle)->device_path;
|
||||
if (recording) {
|
||||
@@ -778,8 +783,8 @@ static void AddPulseAudioDevice(const bool recording, const char *description, c
|
||||
SDL_free(handle);
|
||||
} else {
|
||||
handle->device_index = index;
|
||||
SDL_AddAudioDevice(recording, description, &spec, handle);
|
||||
}
|
||||
SDL_AddAudioDevice(recording, description, &spec, handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,7 +1035,7 @@ static bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap PULSEAUDIO_bootstrap = {
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, false
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_PULSEAUDIO
|
||||
|
||||
@@ -444,7 +444,7 @@ static bool QSA_Init(SDL_AudioDriverImpl * impl)
|
||||
}
|
||||
|
||||
AudioBootStrap QSAAUDIO_bootstrap = {
|
||||
"qsa", "QNX QSA Audio", QSA_Init, 0
|
||||
"qsa", "QNX QSA Audio", QSA_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_QNX
|
||||
|
||||
@@ -350,7 +350,7 @@ static bool SNDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap SNDIO_bootstrap = {
|
||||
"sndio", "OpenBSD sndio", SNDIO_Init, false
|
||||
"sndio", "OpenBSD sndio", SNDIO_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_SNDIO
|
||||
|
||||
@@ -130,7 +130,8 @@ static bool VITAAUD_OpenDevice(SDL_AudioDevice *device)
|
||||
|
||||
static bool VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
|
||||
{
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) == 0);
|
||||
// sceAudioOutOutput returns amount of samples queued or < 0 on error
|
||||
return (sceAudioOutOutput(device->hidden->port, buffer) >= 0);
|
||||
}
|
||||
|
||||
// This function waits until it is possible to write a full sound buffer
|
||||
@@ -232,7 +233,7 @@ static bool VITAAUD_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap VITAAUD_bootstrap = {
|
||||
"vita", "VITA audio driver", VITAAUD_Init, false
|
||||
"vita", "VITA audio driver", VITAAUD_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_VITA
|
||||
|
||||
@@ -337,7 +337,7 @@ typedef struct
|
||||
static bool mgmtthrtask_DetectDevices(void *userdata)
|
||||
{
|
||||
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording);
|
||||
SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording, SDL_AUDIO_F32);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -957,7 +957,7 @@ static bool WASAPI_Init(SDL_AudioDriverImpl *impl)
|
||||
}
|
||||
|
||||
AudioBootStrap WASAPI_bootstrap = {
|
||||
"wasapi", "WASAPI", WASAPI_Init, false
|
||||
"wasapi", "WASAPI", WASAPI_Init, false, false
|
||||
};
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_WASAPI
|
||||
|
||||
Reference in New Issue
Block a user