Merge the SDL3 audio subsystem redesign!

This rips up the entire SDL audio subsystem! While we still feed the audio device from a separate thread, the audio callback into the app is now gone a totally optional alternative.

Now the app will bind an SDL_AudioStream to a given device and feed data to it. As many streams as one likes can be bound to a device; SDL will mix them all into a single buffer and feed the device from there.

So not only does this function as a basic mixer, it also means that multiple device opens are handled seamlessly (so if you want to open the device for your game, but you also link to a library that provides VoIP and it wants to open the device separately, you don't have to worry about stepping on each other, or that the OS will fail to allow multiple opens of the same device, etc).

Merged from pull request #7704.

Fixes #7379.
Reference Issue #6889.
Reference Issue #6632.
This commit is contained in:
Ryan C. Gordon
2023-08-03 21:27:54 -04:00
committed by GitHub
87 changed files with 8340 additions and 8236 deletions
+5 -1
View File
@@ -122,6 +122,7 @@
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>SDL_internal.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -153,6 +154,7 @@
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>SDL_internal.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -188,6 +190,7 @@
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>SDL_internal.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -220,6 +223,7 @@
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>SDL_internal.h</PrecompiledHeaderFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@@ -656,4 +660,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+5 -1
View File
@@ -100,6 +100,7 @@
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<OmitDefaultLibName>true</OmitDefaultLibName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -116,6 +117,7 @@
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<OmitDefaultLibName>true</OmitDefaultLibName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -134,6 +136,7 @@
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<OmitDefaultLibName>true</OmitDefaultLibName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -150,6 +153,7 @@
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
<OmitDefaultLibName>true</OmitDefaultLibName>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
@@ -168,4 +172,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
@@ -21,8 +21,6 @@ public class SDLAudioManager {
protected static AudioRecord mAudioRecord;
protected static Context mContext;
private static final int[] NO_DEVICES = {};
private static AudioDeviceCallback mAudioDeviceCallback;
public static void initialize() {
@@ -36,7 +34,7 @@ public class SDLAudioManager {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
for (AudioDeviceInfo deviceInfo : addedDevices) {
addAudioDevice(deviceInfo.isSink(), deviceInfo.getId());
addAudioDevice(deviceInfo.isSink(), deviceInfo.getProductName().toString(), deviceInfo.getId());
}
}
@@ -52,13 +50,10 @@ public class SDLAudioManager {
public static void setContext(Context context) {
mContext = context;
if (context != null) {
registerAudioDeviceCallback();
}
}
public static void release(Context context) {
unregisterAudioDeviceCallback(context);
// no-op atm
}
// Audio
@@ -311,65 +306,30 @@ public class SDLAudioManager {
return null;
}
private static void registerAudioDeviceCallback() {
public static void registerAudioDeviceCallback() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
// get an initial list now, before hotplug callbacks fire.
for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
if (dev.getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
continue; // Device cannot be opened
}
addAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
}
for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
addAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
}
audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
}
}
private static void unregisterAudioDeviceCallback(Context context) {
public static void unregisterAudioDeviceCallback() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
}
}
private static int[] ArrayListToArray(ArrayList<Integer> integers)
{
int[] ret = new int[integers.size()];
for (int i=0; i < ret.length; i++) {
ret[i] = integers.get(i).intValue();
}
return ret;
}
/**
* This method is called by SDL using JNI.
*/
public static int[] getAudioOutputDevices() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
ArrayList<Integer> arrlist = new ArrayList<Integer>();
for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
/* Device cannot be opened */
if (dev.getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
continue;
}
arrlist.add(dev.getId());
}
return ArrayListToArray(arrlist);
} else {
return NO_DEVICES;
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] getAudioInputDevices() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
ArrayList<Integer> arrlist = new ArrayList<Integer>();
for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
arrlist.add(dev.getId());
}
return ArrayListToArray(arrlist);
} else {
return NO_DEVICES;
}
}
/**
* This method is called by SDL using JNI.
*/
@@ -535,6 +495,6 @@ public class SDLAudioManager {
public static native void removeAudioDevice(boolean isCapture, int deviceId);
public static native void addAudioDevice(boolean isCapture, int deviceId);
public static native void addAudioDevice(boolean isCapture, String name, int deviceId);
}
+3 -3
View File
@@ -308,10 +308,10 @@ expression e;
+ SDL_PauseAudioDevice(e)
|
- SDL_PauseAudioDevice(e, 0)
+ SDL_PlayAudioDevice(e)
+ SDL_UnpauseAudioDevice(e)
|
- SDL_PauseAudioDevice(e, SDL_FALSE)
+ SDL_PlayAudioDevice(e)
+ SDL_UnpauseAudioDevice(e)
)
@@
@@ -321,7 +321,7 @@ expression e, pause_on;
+ if (pause_on) {
+ SDL_PauseAudioDevice(e);
+ } else {
+ SDL_PlayAudioDevice(e);
+ SDL_UnpauseAudioDevice(e);
+ }
+135 -7
View File
@@ -53,13 +53,128 @@ The following structures have been renamed:
## SDL_audio.h
The audio subsystem in SDL3 is dramatically different than SDL2. The primary way to play audio is no longer an audio callback; instead you bind SDL_AudioStreams to devices.
The SDL 1.2 audio compatibility API has also been removed, as it was a simplified version of the audio callback interface.
SDL3 will not implicitly initialize the audio subsystem on your behalf if you open a device without doing so. Please explicitly call SDL_Init(SDL_INIT_AUDIO) at some point.
If your app depends on the callback method, there is a similar approach you can take. But first, this is the new approach:
In SDL2, you might have done something like this to play audio:
```c
void SDLCALL MyAudioCallback(void *userdata, Uint8 * stream, int len)
{
/* calculate a little more audio here, maybe using `userdata`, write it to `stream` */
}
/* ...somewhere near startup... */
SDL_AudioSpec my_desired_audio_format;
SDL_zero(my_desired_audio_format);
my_desired_audio_format.format = AUDIO_S16;
my_desired_audio_format.channels = 2;
my_desired_audio_format.freq = 44100;
my_desired_audio_format.samples = 1024;
my_desired_audio_format.callback = MyAudioCallback;
my_desired_audio_format.userdata = &my_audio_callback_user_data;
SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(NULL, 0, &my_desired_audio_format, NULL, 0);
SDL_PauseAudioDevice(my_audio_device, 0);
```
in SDL3:
```c
/* ...somewhere near startup... */
SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
/* ...in your main loop... */
/* calculate a little more audio into `buf`, add it to `stream` */
SDL_PutAudioStreamData(stream, buf, buflen);
```
If you absolutely require the callback method, SDL_AudioStreams can use a callback whenever more data is to be read from them, which can be used to simulate SDL2 semantics:
```c
void SDLCALL MyAudioCallback(SDL_AudioStream *stream, int len, void *userdata)
{
/* calculate a little more audio here, maybe using `userdata`, write it to `stream` */
SDL_PutAudioStreamData(stream, newdata, len);
}
/* ...somewhere near startup... */
SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec);
SDL_AudioSteam *stream = SDL_CreateAndBindAudioStream(my_audio_device, &spec);
SDL_SetAudioStreamGetCallback(stream, MyAudioCallback);
/* MyAudioCallback will be called whenever the device requests more audio data. */
```
SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_InitSubSystem() and SDL_QuitSubSystem() with SDL_INIT_AUDIO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_AUDIO_DRIVER hint.
SDL_PauseAudioDevice() is only used to pause audio playback. Use SDL_PlayAudioDevice() to start playing audio.
The `SDL_AUDIO_ALLOW_*` symbols have been removed; now one may request the format they desire from the audio device, but ultimately SDL_AudioStream will manage the difference. One can use SDL_GetAudioDeviceFormat() to see what the final format is, if any "allowed" changes should be accomodated by the app.
SDL_AudioDeviceID now represents both an open audio device's handle (a "logical" device) and the instance ID that the hardware owns as long as it exists on the system (a "physical" device). The separation between device instances and device indexes is gone.
Devices are opened by physical device instance ID, and a new logical instance ID is generated by the open operation; This allows any device to be opened multiple times, possibly by unrelated pieces of code. SDL will manage the logical devices to provide a single stream of audio to the physical device behind the scenes.
Devices are not opened by an arbitrary string name anymore, but by device instance ID (or magic numbers to request a reasonable default, like a NULL string in SDL2). In SDL2, the string was used to open both a standard list of system devices, but also allowed for arbitrary devices, such as hostnames of network sound servers. In SDL3, many of the backends that supported arbitrary device names are obsolete and have been removed; of those that remain, arbitrary devices will be opened with a default device ID and an SDL_hint, so specific end-users can set an environment variable to fit their needs and apps don't have to concern themselves with it.
Many functions that would accept a device index and an `iscapture` parameter now just take an SDL_AudioDeviceID, as they are unique across all devices, instead of separate indices into output and capture device lists.
Rather than iterating over audio devices using a device index, there is a new function, SDL_GetAudioDevices(), to get the current list of devices, and new functions to get information about devices from their instance ID:
```c
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
int i, num_devices;
SDL_AudioDeviceID *devices = SDL_GetAudioDevices(/*iscapture=*/SDL_FALSE, &num_devices);
if (devices) {
for (i = 0; i < num_devices; ++i) {
SDL_AudioDeviceID instance_id = devices[i];
char *name = SDL_GetAudioDeviceName(instance_id);
SDL_Log("AudioDevice %" SDL_PRIu32 ": %s\n", instance_id, name);
SDL_free(name);
}
SDL_free(devices);
}
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
}
```
SDL_LockAudioDevice() and SDL_UnlockAudioDevice() have been removed, since there is no callback in another thread to protect. SDL's audio subsystem and SDL_AudioStream maintain their own locks internally, so audio streams are safe to use from any thread. If the app assigns a callback to a specific stream, it can use the stream's lock through SDL_LockAudioStream() if necessary.
SDL_PauseAudioDevice() no longer takes a second argument; it always pauses the device. To unpause, use SDL_UnpauseAudioDevice().
Audio devices, opened by SDL_OpenAudioDevice(), no longer start in a paused state, as they don't begin processing audio until a stream is bound.
SDL_GetAudioDeviceStatus() has been removed; there is now SDL_IsAudioDevicePaused().
SDL_QueueAudio(), SDL_DequeueAudio, and SDL_ClearQueuedAudio and SDL_GetQueuedAudioSize() have been removed; an SDL_AudioStream bound to a device provides the exact same functionality.
APIs that use channel counts used to use a Uint8 for the channel; now they use int.
SDL_AudioSpec has been reduced; now it only holds format, channel, and sample rate. SDL_GetSilenceValueForFormat() can provide the information from the SDL_AudioSpec's `silence` field. The other SDL2 SDL_AudioSpec fields aren't relevant anymore.
SDL_GetAudioDeviceSpec() is removed; use SDL_GetAudioDeviceFormat() instead.
SDL_GetDefaultAudioInfo() is removed; SDL_GetAudioDeviceFormat() with SDL_AUDIO_DEVICE_DEFAULT_OUTPUT or SDL_AUDIO_DEVICE_DEFAULT_CAPTURE. There is no replacement for querying the default device name; the string is no longer used to open devices, and SDL3 will migrate between physical devices on the fly if the system default changes, so if you must show this to the user, a generic name like "System default" is recommended.
SDL_MixAudio() has been removed, as it relied on legacy SDL 1.2 quirks; SDL_MixAudioFormat() remains and offers the same functionality.
SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_InitSubSystem() and SDL_QuitSubSystem() with SDL_INIT_AUDIO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_AUDIO_DRIVER hint.
SDL_FreeWAV has been removed and calls can be replaced with SDL_free.
SDL_AudioCVT interface is removed, SDL_AudioStream interface or SDL_ConvertAudioSamples() helper function can be used.
SDL_LoadWAV() is a proper function now and no longer a macro (but offers the same functionality otherwise).
SDL_LoadWAV_RW() and SDL_LoadWAV() return an int now: zero on success, -1 on error, like most of SDL. They no longer return a pointer to an SDL_AudioSpec.
SDL_AudioCVT interface has been removed, the SDL_AudioStream interface (for audio supplied in pieces) or the new SDL_ConvertAudioSamples() function (for converting a complete audio buffer in one call) can be used instead.
Code that used to look like this:
```c
@@ -75,8 +190,9 @@ should be changed to:
```c
Uint8 *dst_data = NULL;
int dst_len = 0;
if (SDL_ConvertAudioSamples(src_format, src_channels, src_rate, src_data, src_len
dst_format, dst_channels, dst_rate, &dst_data, &dst_len) < 0) {
const SDL_AudioSpec src_spec = { src_format, src_channels, src_rate };
const SDL_AudioSpec dst_spec = { dst_format, dst_channels, dst_rate };
if (SDL_ConvertAudioSamples(&src_spec, src_data, src_len, &dst_spec, &dst_data, &dst_len) < 0) {
/* error */
}
do_something(dst_data, dst_len);
@@ -103,9 +219,13 @@ If you need to convert U16 audio data to a still-supported format at runtime, th
}
```
In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamPut in SDL2. The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
All remaining `AUDIO_*` symbols have been renamed to `SDL_AUDIO_*` for API consistency, but othewise are identical in value and usage.
In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamGet in SDL2). The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
In SDL2, SDL_AudioStreamAvailable() returns 0 if passed a NULL stream. In SDL3, the equivalent SDL_GetAudioStreamAvailable() call returns -1 and sets an error string, which matches other audiostream APIs' behavior.
In SDL2, SDL_AUDIODEVICEREMOVED events would fire for open devices with the `which` field set to the SDL_AudioDeviceID of the lost device, and in later SDL2 releases, would also fire this event with a `which` field of zero for unopened devices, to signify that the app might want to refresh the available device list. In SDL3, this event works the same, except it won't ever fire with a zero; in this case it'll return the physical device's SDL_AudioDeviceID. Any still-open SDL_AudioDeviceIDs generated from this device with SDL_OpenAudioDevice() will also fire a separate event.
The following functions have been renamed:
* SDL_AudioStreamAvailable() => SDL_GetAudioStreamAvailable()
@@ -118,17 +238,25 @@ The following functions have been renamed:
The following functions have been removed:
* SDL_GetNumAudioDevices()
* SDL_GetAudioDeviceSpec()
* SDL_ConvertAudio()
* SDL_BuildAudioCVT()
* SDL_OpenAudio()
* SDL_CloseAudio()
* SDL_PauseAudio()
* SDL_GetAudioStatus()
* SDL_GetAudioDeviceStatus()
* SDL_GetDefaultAudioInfo()
* SDL_LockAudio()
* SDL_LockAudioDevice()
* SDL_UnlockAudio()
* SDL_UnlockAudioDevice()
* SDL_MixAudio()
Use the SDL_AudioDevice functions instead.
* SDL_QueueAudio()
* SDL_DequeueAudio()
* SDL_ClearAudioQueue()
* SDL_GetQueuedAudioSize()
The following symbols have been renamed:
* AUDIO_F32 => SDL_AUDIO_F32
+720 -708
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -493,7 +493,7 @@ typedef struct SDL_AudioDeviceEvent
{
Uint32 type; /**< ::SDL_EVENT_AUDIO_DEVICE_ADDED, or ::SDL_EVENT_AUDIO_DEVICE_REMOVED */
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_AudioDeviceID which; /**< The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event */
SDL_AudioDeviceID which; /**< SDL_AudioDeviceID for the device being added or removed */
Uint8 iscapture; /**< zero if an output device, non-zero if a capture device. */
Uint8 padding1;
Uint8 padding2;
+3 -1
View File
@@ -97,7 +97,9 @@ typedef struct
/* Audio info */
const char *audiodriver;
SDL_AudioSpec audiospec;
SDL_AudioFormat audio_format;
int audio_channels;
int audio_freq;
SDL_AudioDeviceID audio_id;
/* GL settings */
+1434 -1301
View File
File diff suppressed because it is too large Load Diff
+2 -53
View File
@@ -22,59 +22,8 @@
#ifndef SDL_audio_c_h_
#define SDL_audio_c_h_
#include "SDL_internal.h"
/* !!! FIXME: remove this header and have things just include SDL_sysaudio.h directly. */
#define DEBUG_AUDIOSTREAM 0
#define DEBUG_AUDIO_CONVERT 0
#if DEBUG_AUDIO_CONVERT
#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.\n", from, to);
#else
#define LOG_DEBUG_AUDIO_CONVERT(from, to)
#endif
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
/* Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results. */
const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format);
/* Function to calculate the size and silence for a SDL_AudioSpec */
extern Uint8 SDL_GetSilenceValueForFormat(const SDL_AudioFormat format);
extern void SDL_CalculateAudioSpec(SDL_AudioSpec *spec);
/* Must be called at least once before using converters (SDL_CreateAudioStream will call it). */
extern void SDL_ChooseAudioConverters(void);
/* These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations. */
extern void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples);
extern void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples);
extern void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples);
extern void (*SDL_Convert_S32_to_F32)(float *dst, const Sint32 *src, int num_samples);
extern void (*SDL_Convert_F32_to_S8)(Sint8 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples);
/**
* Use this function to initialize a particular audio driver.
*
* This function is used internally, and should not be used unless you have a
* specific need to designate the audio driver you want to use. You should
* normally use SDL_Init() or SDL_InitSubSystem().
*
* \param driver_name the name of the desired audio driver
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*/
extern int SDL_InitAudio(const char *driver_name);
/**
* Use this function to shut down audio if you initialized it with SDL_InitAudio().
*
* This function is used internally, and should not be used unless you have a
* specific need to specify the audio driver you want to use. You should
* normally use SDL_Quit() or SDL_QuitSubSystem().
*/
extern void SDL_QuitAudio(void);
#include "SDL_sysaudio.h"
#endif /* SDL_audio_c_h_ */
+346 -263
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -45,13 +45,13 @@
#define SDL_PATH_DEV_AUDIO "/dev/audio"
#endif
static void test_device(const int iscapture, const char *fname, int flags, int (*test)(int fd))
static void test_device(const SDL_bool iscapture, const char *fname, int flags, SDL_bool (*test)(int fd))
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
if (audio_fd >= 0) {
const int okay = test(audio_fd);
const SDL_bool okay = test(audio_fd);
close(audio_fd);
if (okay) {
static size_t dummyhandle = 0;
@@ -69,12 +69,12 @@ static void test_device(const int iscapture, const char *fname, int flags, int (
}
}
static int test_stub(int fd)
static SDL_bool test_stub(int fd)
{
return 1;
return SDL_TRUE;
}
static void SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int))
static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool iscapture, const SDL_bool classic, SDL_bool (*test)(int))
{
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
const char *audiodev;
@@ -116,7 +116,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int cla
}
}
void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int))
void SDL_EnumUnixAudioDevices(const SDL_bool classic, SDL_bool (*test)(int))
{
SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test);
SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test);
+1 -1
View File
@@ -36,6 +36,6 @@
#define OPEN_FLAGS_INPUT (O_RDONLY | O_NONBLOCK)
#endif
extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int));
extern void SDL_EnumUnixAudioDevices(const SDL_bool classic, SDL_bool (*test)(int));
#endif /* SDL_audiodev_c_h_ */
+221 -103
View File
@@ -18,151 +18,269 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_sysaudio_h_
#define SDL_sysaudio_h_
#include "../SDL_dataqueue.h"
#include "./SDL_audio_c.h"
/* !!! FIXME: These are wordy and unlocalized... */
#define DEBUG_AUDIOSTREAM 0
#define DEBUG_AUDIO_CONVERT 0
#if DEBUG_AUDIO_CONVERT
#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.\n", from, to);
#else
#define LOG_DEBUG_AUDIO_CONVERT(from, to)
#endif
// These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations.
extern void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples);
extern void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples);
extern void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples);
extern void (*SDL_Convert_S32_to_F32)(float *dst, const Sint32 *src, int num_samples);
extern void (*SDL_Convert_F32_to_S8)(Sint8 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples);
extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples);
// !!! FIXME: These are wordy and unlocalized...
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
/* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice;
// 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
/* Audio targets should call this as devices are added to the system (such as
#define DEFAULT_AUDIO_CAPTURE_FORMAT SDL_AUDIO_S16
#define DEFAULT_AUDIO_CAPTURE_CHANNELS 1
#define DEFAULT_AUDIO_CAPTURE_FREQUENCY 44100
typedef struct SDL_AudioDevice SDL_AudioDevice;
typedef struct SDL_LogicalAudioDevice SDL_LogicalAudioDevice;
// Used by src/SDL.c to initialize a particular audio driver.
extern int SDL_InitAudio(const char *driver_name);
// Used by src/SDL.c to shut down previously-initialized audio.
extern void SDL_QuitAudio(void);
// Function to get a list of audio formats, ordered most similar to `format` to least, 0-terminated. Don't free results.
const SDL_AudioFormat *SDL_ClosestAudioFormats(SDL_AudioFormat format);
// Must be called at least once before using converters (SDL_CreateAudioStream will call it !!! FIXME but probably shouldn't).
extern void SDL_ChooseAudioConverters(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 void SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle);
extern SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, const SDL_AudioSpec *spec, void *handle);
/* Audio targets should call this as devices are removed, so SDL can update
its list of available devices. */
extern void SDL_RemoveAudioDevice(const SDL_bool iscapture, 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. */
extern void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device);
/* Audio targets should call this if an opened audio device is lost while
being used. This can happen due to i/o errors, or a device being unplugged,
etc. If the device is totally gone, please also call SDL_RemoveAudioDevice()
as appropriate so SDL's list of devices is accurate. */
extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
// Backends should call this if the system default device changes.
extern void SDL_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device);
/* This is the size of a packet when using SDL_QueueAudio(). We allocate
these as necessary and pool them, under the assumption that we'll
eventually end up with a handful that keep recycling, meeting whatever
the app needs. We keep packing data tightly as more arrives to avoid
wasting space, and if we get a giant block of data, we'll split them
into multiple packets behind the scenes. My expectation is that most
apps will have 2-3 of these in the pool. 8k should cover most needs, but
if this is crippling for some embedded system, we can #ifdef this.
The system preallocates enough packets for 2 callbacks' worth of data. */
#define SDL_AUDIOBUFFERQUEUE_PACKETLEN (8 * 1024)
// Backends should call this if a device's format is changing (opened or not); SDL will update state and carry on with the new format.
extern int SDL_AudioDeviceFormatChanged(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames);
// Same as above, but assume the device is already locked.
extern int SDL_AudioDeviceFormatChangedAlreadyLocked(SDL_AudioDevice *device, const SDL_AudioSpec *newspec, int new_sample_frames);
// Find the SDL_AudioDevice associated with the handle supplied to SDL_AddAudioDevice. NULL if not found. DOES NOT LOCK THE DEVICE.
extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByHandle(void *handle);
// Find an SDL_AudioDevice, selected by a callback. NULL if not found. DOES NOT LOCK THE DEVICE.
extern SDL_AudioDevice *SDL_FindPhysicalAudioDeviceByCallback(SDL_bool (*callback)(SDL_AudioDevice *device, void *userdata), void *userdata);
// Backends should call this if they change the device format, channels, freq, or sample_frames to keep other state correct.
extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device);
// Backends can call this to get a standardized name for a thread to power a specific audio device.
char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
// 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_AudioThreadFinalize(SDL_AudioDevice *device);
typedef struct SDL_AudioDriverImpl
{
void (*DetectDevices)(void);
int (*OpenDevice)(SDL_AudioDevice *_this, const char *devname);
void (*ThreadInit)(SDL_AudioDevice *_this); /* Called by audio thread at start */
void (*ThreadDeinit)(SDL_AudioDevice *_this); /* Called by audio thread at end */
void (*WaitDevice)(SDL_AudioDevice *_this);
void (*PlayDevice)(SDL_AudioDevice *_this);
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *_this);
int (*CaptureFromDevice)(SDL_AudioDevice *_this, void *buffer, int buflen);
void (*FlushCapture)(SDL_AudioDevice *_this);
void (*CloseDevice)(SDL_AudioDevice *_this);
void (*LockDevice)(SDL_AudioDevice *_this);
void (*UnlockDevice)(SDL_AudioDevice *_this);
void (*FreeDeviceHandle)(void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
void (*DetectDevices)(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
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
void (*WaitDevice)(SDL_AudioDevice *device);
void (*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);
void (*WaitCaptureDevice)(SDL_AudioDevice *device);
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
void (*FlushCapture)(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 (*Deinitialize)(void);
int (*GetDefaultAudioInfo)(char **name, SDL_AudioSpec *spec, int iscapture);
/* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */
/* Some flags to push duplicate code into the core and reduce #ifdefs. */
SDL_bool ProvidesOwnCallbackThread;
// 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;
SDL_bool AllowsArbitraryDeviceNames;
SDL_bool SupportsNonPow2Samples;
} SDL_AudioDriverImpl;
typedef struct SDL_AudioDeviceItem
{
void *handle;
char *name;
char *original_name;
SDL_AudioSpec spec;
int dupenum;
struct SDL_AudioDeviceItem *next;
} SDL_AudioDeviceItem;
typedef struct SDL_AudioDriver
{
/* * * */
/* The name of this audio driver */
const char *name;
/* * * */
/* The description of this audio driver */
const char *desc;
SDL_AudioDriverImpl impl;
/* A mutex for device detection */
SDL_Mutex *detectionLock;
SDL_bool captureDevicesRemoved;
SDL_bool outputDevicesRemoved;
int outputDeviceCount;
int inputDeviceCount;
SDL_AudioDeviceItem *outputDevices;
SDL_AudioDeviceItem *inputDevices;
const char *name; // The name of this audio driver
const char *desc; // The description of this audio driver
SDL_AudioDriverImpl impl; // the backend's interface
SDL_RWLock *device_list_lock; // A mutex for device detection
SDL_AudioDevice *output_devices; // the list of currently-available audio output devices.
SDL_AudioDevice *capture_devices; // the list of currently-available audio capture devices.
SDL_AudioDeviceID default_output_device_id;
SDL_AudioDeviceID default_capture_device_id;
SDL_AtomicInt output_device_count;
SDL_AtomicInt capture_device_count;
SDL_AtomicInt last_device_instance_id; // increments on each device add to provide unique instance IDs
SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
} SDL_AudioDriver;
/* Define the SDL audio driver structure */
struct SDL_AudioStream
{
SDL_DataQueue *queue;
SDL_Mutex *lock; // this is just a copy of `queue`'s mutex. We share a lock.
SDL_AudioStreamRequestCallback get_callback;
void *get_callback_userdata;
SDL_AudioStreamRequestCallback put_callback;
void *put_callback_userdata;
Uint8 *work_buffer; // used for scratch space during data conversion/resampling.
Uint8 *history_buffer; // history for left padding and future sample rate changes.
Uint8 *future_buffer; // stuff that left the queue for the right padding and will be next read's data.
float *left_padding; // left padding for resampling.
float *right_padding; // right padding for resampling.
SDL_bool flushed;
size_t work_buffer_allocation;
size_t history_buffer_allocation;
size_t future_buffer_allocation;
size_t resampler_padding_allocation;
int resampler_padding_frames;
int history_buffer_frames;
int future_buffer_filled_frames;
SDL_AudioSpec src_spec;
SDL_AudioSpec dst_spec;
int src_sample_frame_size;
int dst_sample_frame_size;
int max_sample_frame_size;
int pre_resample_channels;
int packetlen;
SDL_LogicalAudioDevice *bound_device;
SDL_AudioStream *next_binding;
SDL_AudioStream *prev_binding;
};
/* Logical devices are an abstraction in SDL3; you can open the same physical
device multiple times, and each will result in an object with its own set
of bound audio streams, etc, even though internally these are all processed
as a group when mixing the final output for the physical device. */
struct SDL_LogicalAudioDevice
{
// the unique instance ID of this device.
SDL_AudioDeviceID instance_id;
// The physical device associated with this opened device.
SDL_AudioDevice *physical_device;
// If whole logical device is paused (process no streams bound to this device).
SDL_AtomicInt paused;
// double-linked list of all audio streams currently bound to this opened device.
SDL_AudioStream *bound_streams;
// SDL_TRUE if this was opened as a default device.
SDL_bool is_default;
// double-linked list of opened devices on the same physical device.
SDL_LogicalAudioDevice *next;
SDL_LogicalAudioDevice *prev;
};
struct SDL_AudioDevice
{
/* * * */
/* Data common to all devices */
SDL_AudioDeviceID id;
// A mutex for locking access to this struct
SDL_Mutex *lock;
/* The device's current audio specification */
// human-readable name of the device. ("SoundBlaster Pro 16")
char *name;
// the unique instance ID of this device.
SDL_AudioDeviceID instance_id;
// a way for the backend to identify this device _when not opened_
void *handle;
// The device's current audio specification
SDL_AudioSpec spec;
int buffer_size;
/* The callback's expected audio specification (converted vs device's spec). */
SDL_AudioSpec callbackspec;
// The device's default audio specification
SDL_AudioSpec default_spec;
/* Stream that converts and resamples. NULL if not needed. */
SDL_AudioStream *stream;
// Number of sample frames the devices wants per-buffer.
int sample_frames;
/* Current state flags */
SDL_AtomicInt shutdown; /* true if we are signaling the play thread to end. */
SDL_AtomicInt enabled; /* true if device is functioning and connected. */
SDL_AtomicInt paused;
// Value to use for SDL_memset to silence a buffer in this device's format
int silence_value;
// non-zero if we are signaling the audio thread to end.
SDL_AtomicInt shutdown;
// non-zero if we want the device to be destroyed (so audio thread knows to do it on termination).
SDL_AtomicInt condemned;
// non-zero if this was a disconnected default device and we're waiting for its replacement.
SDL_AtomicInt zombie;
// non-zero if this has a thread running (which might be `thread` or something provided by the backend!)
SDL_AtomicInt thread_alive;
// SDL_TRUE if this is a capture device instead of an output device
SDL_bool iscapture;
/* Scratch buffer used in the bridge between SDL and the user callback. */
// Scratch buffer used for mixing.
Uint8 *work_buffer;
/* Size, in bytes, of work_buffer. */
Uint32 work_buffer_len;
/* A mutex for locking the mixing buffers */
SDL_Mutex *mixer_lock;
/* A thread to feed the audio device */
// A thread to feed the audio device
SDL_Thread *thread;
SDL_threadID threadid;
/* Queued buffers (if app not using callback). */
SDL_DataQueue *buffer_queue;
// SDL_TRUE if this physical device is currently opened by the backend.
SDL_bool is_opened;
/* * * */
/* Data private to this driver */
// Data private to this driver
struct SDL_PrivateAudioData *hidden;
void *handle;
// All logical devices associated with this physical device.
SDL_LogicalAudioDevice *logical_devices;
// double-linked list of all physical devices.
struct SDL_AudioDevice *prev;
struct SDL_AudioDevice *next;
};
typedef struct AudioBootStrap
@@ -170,10 +288,10 @@ typedef struct AudioBootStrap
const char *name;
const char *desc;
SDL_bool (*init)(SDL_AudioDriverImpl *impl);
SDL_bool demand_only; /* 1==request explicitly, or it won't be available. */
SDL_bool demand_only; // if SDL_TRUE: request explicitly, or it won't be available.
} AudioBootStrap;
/* Not all of these are available in a given build. Use #ifdefs, etc. */
// Not all of these are available in a given build. Use #ifdefs, etc.
extern AudioBootStrap PIPEWIRE_bootstrap;
extern AudioBootStrap PULSEAUDIO_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
@@ -188,8 +306,8 @@ extern AudioBootStrap HAIKUAUDIO_bootstrap;
extern AudioBootStrap COREAUDIO_bootstrap;
extern AudioBootStrap DISKAUDIO_bootstrap;
extern AudioBootStrap DUMMYAUDIO_bootstrap;
extern AudioBootStrap aaudio_bootstrap;
extern AudioBootStrap openslES_bootstrap;
extern AudioBootStrap AAUDIO_bootstrap;
extern AudioBootStrap openslES_bootstrap; // !!! FIXME: capitalize this to match the others
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
@@ -201,4 +319,4 @@ extern AudioBootStrap QSAAUDIO_bootstrap;
extern SDL_AudioDevice *get_audio_dev(SDL_AudioDeviceID id);
extern int get_max_num_audio_dev(void);
#endif /* SDL_sysaudio_h_ */
#endif // SDL_sysaudio_h_
+18 -31
View File
@@ -1241,7 +1241,7 @@ static int LAW_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
dst = (Sint16 *)src;
/* Work backwards, since we're expanding in-place. SDL_AudioSpec.format will
/* Work backwards, since we're expanding in-place. `format` will
* inform the caller about the byte order.
*/
i = sample_count;
@@ -1667,15 +1667,11 @@ static int WaveCheckFormat(WaveFile *file, size_t datalength)
if (format->channels == 0) {
return SDL_SetError("Invalid number of channels");
} else if (format->channels > 255) {
/* Limit given by SDL_AudioSpec.channels. */
return SDL_SetError("Number of channels exceeds limit of 255");
}
if (format->frequency == 0) {
return SDL_SetError("Invalid sample rate");
} else if (format->frequency > INT_MAX) {
/* Limit given by SDL_AudioSpec.freq. */
return SDL_SetError("Sample rate exceeds limit of %d", INT_MAX);
}
@@ -2025,13 +2021,12 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
break;
}
/* Setting up the SDL_AudioSpec. All unsupported formats were filtered out
/* Setting up the specs. All unsupported formats were filtered out
* by checks earlier in this function.
*/
SDL_zerop(spec);
spec->freq = format->frequency;
spec->channels = (Uint8)format->channels;
spec->samples = 4096; /* Good default buffer size */
spec->format = 0;
switch (format->encoding) {
case MS_ADPCM_CODE:
@@ -2061,10 +2056,10 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
return SDL_SetError("Unexpected %u-bit PCM data format", (unsigned int)format->bitspersample);
}
break;
default:
return SDL_SetError("Unexpected data format");
}
spec->silence = SDL_GetSilenceValueForFormat(spec->format);
/* Report the end position back to the cleanup code. */
if (RIFFlengthknown) {
chunk->position = RIFFend;
@@ -2075,31 +2070,26 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
return 0;
}
SDL_AudioSpec *SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
int SDL_LoadWAV_RW(SDL_RWops *src, int freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
int result = -1;
WaveFile file;
SDL_zero(file);
/* Make sure we are passed a valid data source */
if (src == NULL) {
/* Error may come from RWops. */
goto done;
return -1; /* Error may come from RWops. */
} else if (spec == NULL) {
SDL_InvalidParamError("spec");
goto done;
return SDL_InvalidParamError("spec");
} else if (audio_buf == NULL) {
SDL_InvalidParamError("audio_buf");
goto done;
return SDL_InvalidParamError("audio_buf");
} else if (audio_len == NULL) {
SDL_InvalidParamError("audio_len");
goto done;
return SDL_InvalidParamError("audio_len");
}
*audio_buf = NULL;
*audio_len = 0;
SDL_zero(file);
file.riffhint = WaveGetRiffSizeHint();
file.trunchint = WaveGetTruncationHint();
file.facthint = WaveGetFactChunkHint();
@@ -2107,7 +2097,6 @@ SDL_AudioSpec *SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *s
result = WaveLoad(src, &file, spec, audio_buf, audio_len);
if (result < 0) {
SDL_free(*audio_buf);
spec = NULL;
audio_buf = NULL;
audio_len = 0;
}
@@ -2119,13 +2108,11 @@ SDL_AudioSpec *SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *s
WaveFreeChunkData(&file.chunk);
SDL_free(file.decoderdata);
done:
if (freesrc && src) {
SDL_RWclose(src);
}
if (result == 0) {
return spec;
} else {
return NULL;
}
return result;
}
int SDL_LoadWAV(const char *path, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
return SDL_LoadWAV_RW(SDL_RWFromFile(path, "rb"), 1, spec, audio_buf, audio_len);
}
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -25,15 +25,15 @@
#ifdef SDL_AUDIO_DRIVER_AAUDIO
void aaudio_ResumeDevices(void);
void aaudio_PauseDevices(void);
SDL_bool aaudio_DetectBrokenPlayState(void);
void AAUDIO_ResumeDevices(void);
void AAUDIO_PauseDevices(void);
SDL_bool AAUDIO_DetectBrokenPlayState(void);
#else
static void aaudio_ResumeDevices(void) {}
static void aaudio_PauseDevices(void) {}
static SDL_bool aaudio_DetectBrokenPlayState(void) { return SDL_FALSE; }
#define AAUDIO_ResumeDevices()
#define AAUDIO_PauseDevices()
#define AAUDIO_DetectBrokenPlayState() (SDL_FALSE)
#endif
+11 -8
View File
@@ -32,15 +32,15 @@ SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder * builder, aa
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_UNUSED(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
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 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setInputPreset, (AAudioStreamBuilder * builder, aaudio_input_preset_t inputPreset)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setAllowedCapturePolicy, (AAudioStreamBuilder * builder, aaudio_allowed_capture_policy_t capturePolicy)) /* API 29 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSessionId, (AAudioStreamBuilder * builder, aaudio_session_id_t sessionId)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setPrivacySensitive, (AAudioStreamBuilder * builder, bool privacySensitive)) /* API 30 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDataCallback, (AAudioStreamBuilder * builder, AAudioStream_dataCallback callback, void *userData))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setFramesPerDataCallback, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setDataCallback, (AAudioStreamBuilder * builder, AAudioStream_dataCallback callback, void *userData))
SDL_PROC(void, AAudioStreamBuilder_setFramesPerDataCallback, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setErrorCallback, (AAudioStreamBuilder * builder, AAudioStream_errorCallback callback, void *userData))
SDL_PROC(aaudio_result_t, AAudioStreamBuilder_openStream, (AAudioStreamBuilder * builder, AAudioStream **stream))
SDL_PROC(aaudio_result_t, AAudioStreamBuilder_delete, (AAudioStreamBuilder * builder))
@@ -52,14 +52,14 @@ SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_requestFlush, (AAudioStream * stre
SDL_PROC(aaudio_result_t, AAudioStream_requestStop, (AAudioStream * stream))
SDL_PROC(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream * stream))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_waitForStateChange, (AAudioStream * stream, aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_read, (AAudioStream * stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_write, (AAudioStream * stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_read, (AAudioStream * stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_write, (AAudioStream * stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_setBufferSizeInFrames, (AAudioStream * stream, int32_t numFrames))
SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferSizeInFrames, (AAudioStream * stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerBurst, (AAudioStream * stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferCapacityInFrames, (AAudioStream * stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerDataCallback, (AAudioStream * stream))
SDL_PROC(int32_t, AAudioStream_getXRunCount, (AAudioStream * stream))
SDL_PROC(int32_t, AAudioStream_getBufferCapacityInFrames, (AAudioStream * stream))
SDL_PROC(int32_t, AAudioStream_getFramesPerDataCallback, (AAudioStream * stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getXRunCount, (AAudioStream * stream))
SDL_PROC(int32_t, AAudioStream_getSampleRate, (AAudioStream * stream))
SDL_PROC(int32_t, AAudioStream_getChannelCount, (AAudioStream * stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getSamplesPerFrame, (AAudioStream * stream))
@@ -77,3 +77,6 @@ SDL_PROC_UNUSED(aaudio_content_type_t, AAudioStream_getContentType, (AAudioStrea
SDL_PROC_UNUSED(aaudio_input_preset_t, AAudioStream_getInputPreset, (AAudioStream * stream)) /* API 28 */
SDL_PROC_UNUSED(aaudio_allowed_capture_policy_t, AAudioStream_getAllowedCapturePolicy, (AAudioStream * stream)) /* API 29 */
SDL_PROC_UNUSED(bool, AAudioStream_isPrivacySensitive, (AAudioStream * stream)) /* API 30 */
#undef SDL_PROC
#undef SDL_PROC_UNUSED
File diff suppressed because it is too large Load Diff
-1
View File
@@ -34,7 +34,6 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* swizzle function */
void (*swizzle_func)(SDL_AudioDevice *_this, void *buffer, Uint32 bufferlen);
+83 -110
View File
@@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_ANDROID
/* Output audio to Android */
// Output audio to Android (legacy interface)
#include "../SDL_sysaudio.h"
#include "../SDL_audio_c.h"
@@ -34,185 +34,158 @@
struct SDL_PrivateAudioData
{
/* Resume device if it was paused automatically */
int resume;
int resume; // Resume device if it was paused automatically
};
static SDL_AudioDevice *audioDevice = NULL;
static SDL_AudioDevice *captureDevice = NULL;
static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
SDL_bool iscapture = _this->iscapture;
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
const SDL_bool iscapture = device->iscapture;
if (iscapture) {
if (captureDevice) {
return SDL_SetError("An audio capture device is already opened");
}
}
if (!iscapture) {
captureDevice = device;
} else {
if (audioDevice) {
return SDL_SetError("An audio playback device is already opened");
}
audioDevice = device;
}
if (iscapture) {
captureDevice = _this;
} else {
audioDevice = _this;
}
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
if (_this->hidden == NULL) {
return SDL_OutOfMemory();
}
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
if ((test_format == SDL_AUDIO_U8) ||
(test_format == SDL_AUDIO_S16) ||
(test_format == SDL_AUDIO_F32)) {
_this->spec.format = test_format;
device->spec.format = test_format;
break;
}
}
if (!test_format) {
/* Didn't find a compatible format :( */
return SDL_SetError("%s: Unsupported audio format", "android");
return SDL_SetError("android: Unsupported audio format");
}
{
int audio_device_id = 0;
if (devname != NULL) {
audio_device_id = SDL_atoi(devname);
}
if (Android_JNI_OpenAudioDevice(iscapture, audio_device_id, &_this->spec) < 0) {
return -1;
}
if (Android_JNI_OpenAudioDevice(device) < 0) {
return -1;
}
SDL_CalculateAudioSpec(&_this->spec);
SDL_UpdatedAudioDeviceFormat(device);
return 0;
}
static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *_this)
// !!! FIXME: this needs a WaitDevice implementation.
static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
Android_JNI_WriteAudioBuffer();
}
static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return Android_JNI_GetAudioBuffer();
}
static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
}
static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *_this)
static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *device)
{
Android_JNI_FlushCapturedAudio();
}
static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *device)
{
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
so it's safe to terminate the Java side buffer and AudioTrack
*/
Android_JNI_CloseAudioDevice(_this->iscapture);
if (_this->iscapture) {
SDL_assert(captureDevice == _this);
captureDevice = NULL;
} else {
SDL_assert(audioDevice == _this);
audioDevice = NULL;
if (device->hidden) {
Android_JNI_CloseAudioDevice(device->iscapture);
if (device->iscapture) {
SDL_assert(captureDevice == device);
captureDevice = NULL;
} else {
SDL_assert(audioDevice == device);
audioDevice = NULL;
}
SDL_free(device->hidden);
device->hidden = NULL;
}
}
// Pause (block) all non already paused audio devices by taking their mixer lock
void ANDROIDAUDIO_PauseDevices(void)
{
// TODO: Handle multiple devices?
struct SDL_PrivateAudioData *hidden;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
SDL_LockMutex(audioDevice->lock);
hidden->resume = SDL_TRUE;
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
SDL_LockMutex(captureDevice->lock);
hidden->resume = SDL_TRUE;
}
}
// Resume (unblock) all non already paused audio devices by releasing their mixer lock
void ANDROIDAUDIO_ResumeDevices(void)
{
// TODO: Handle multiple devices?
struct SDL_PrivateAudioData *hidden;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (hidden->resume) {
hidden->resume = SDL_FALSE;
SDL_UnlockMutex(audioDevice->lock);
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
if (hidden->resume) {
hidden->resume = SDL_FALSE;
SDL_UnlockMutex(captureDevice->lock);
}
}
SDL_free(_this->hidden);
}
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = Android_DetectDevices;
// !!! 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+.
impl->ThreadInit = Android_AudioThreadInit;
impl->DetectDevices = Android_StartAudioHotplug;
impl->Deinitialize = Android_StopAudioHotplug;
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_FALSE;
impl->OnlyHasDefaultCaptureDevice = SDL_FALSE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap ANDROIDAUDIO_bootstrap = {
"android", "SDL Android audio driver", ANDROIDAUDIO_Init, SDL_FALSE
};
/* Pause (block) all non already paused audio devices by taking their mixer lock */
void ANDROIDAUDIO_PauseDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (SDL_AtomicGet(&audioDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
} else {
SDL_LockMutex(audioDevice->mixer_lock);
SDL_AtomicSet(&audioDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden;
if (SDL_AtomicGet(&captureDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
} else {
SDL_LockMutex(captureDevice->mixer_lock);
SDL_AtomicSet(&captureDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
}
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
void ANDROIDAUDIO_ResumeDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&audioDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(audioDevice->mixer_lock);
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&captureDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(captureDevice->mixer_lock);
}
}
}
#endif /* SDL_AUDIO_DRIVER_ANDROID */
#endif // SDL_AUDIO_DRIVER_ANDROID
+1 -4
View File
@@ -53,15 +53,12 @@ struct SDL_PrivateAudioData
AudioQueueRef audioQueue;
int numAudioBuffers;
AudioQueueBufferRef *audioBuffer;
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
AudioQueueBufferRef current_buffer;
AudioStreamBasicDescription strdesc;
SDL_Semaphore *ready_semaphore;
char *thread_error;
#ifdef MACOSX_COREAUDIO
AudioDeviceID deviceID;
SDL_AtomicInt device_change_flag;
#else
SDL_bool interrupted;
CFTypeRef interruption_listener;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -27,9 +27,10 @@
#include "../SDL_sysaudio.h"
/* The DirectSound objects */
// The DirectSound objects
struct SDL_PrivateAudioData
{
// !!! FIXME: make this a union with capture/playback sections?
LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf;
LPDIRECTSOUNDCAPTURE capture;
@@ -39,4 +40,4 @@ struct SDL_PrivateAudioData
Uint8 *locked_buf;
};
#endif /* SDL_directsound_h_ */
#endif // SDL_directsound_h_
+57 -77
View File
@@ -22,171 +22,151 @@
#ifdef SDL_AUDIO_DRIVER_DISK
/* Output raw audio data to a file. */
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
// Output raw audio data to a file.
#include "../SDL_audio_c.h"
#include "SDL_diskaudio.h"
/* !!! FIXME: these should be SDL hints, not environment variables. */
/* environment variables and defaults. */
// !!! FIXME: these should be SDL hints, not environment variables.
// environment variables and defaults.
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN"
#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
/* This function waits until it is possible to write a full sound buffer */
static void DISKAUDIO_WaitDevice(SDL_AudioDevice *_this)
static void DISKAUDIO_WaitDevice(SDL_AudioDevice *device)
{
SDL_Delay(_this->hidden->io_delay);
SDL_Delay(device->hidden->io_delay);
}
static void DISKAUDIO_PlayDevice(SDL_AudioDevice *_this)
static void DISKAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
const Sint64 written = SDL_RWwrite(_this->hidden->io,
_this->hidden->mixbuf,
_this->spec.size);
/* If we couldn't write, assume fatal error for now */
if (written != _this->spec.size) {
SDL_OpenedAudioDeviceDisconnected(_this);
const Sint64 written = SDL_RWwrite(device->hidden->io, buffer, buffer_size);
if (written != buffer_size) { // If we couldn't write, assume fatal error for now
SDL_AudioDeviceDisconnected(device);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", (int) written);
SDL_Log("DISKAUDIO: Wrote %d bytes of audio data", (int) written);
#endif
}
static Uint8 *DISKAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *DISKAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbuf;
return device->hidden->mixbuf;
}
static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = _this->hidden;
struct SDL_PrivateAudioData *h = device->hidden;
const int origbuflen = buflen;
SDL_Delay(h->io_delay);
if (h->io) {
const int br = (int) SDL_RWread(h->io, buffer, (Sint64) buflen);
buflen -= br;
buffer = ((Uint8 *)buffer) + br;
if (buflen > 0) { /* EOF (or error, but whatever). */
if (buflen > 0) { // EOF (or error, but whatever).
SDL_RWclose(h->io);
h->io = NULL;
}
}
/* if we ran out of file, just write silence. */
SDL_memset(buffer, _this->spec.silence, buflen);
// if we ran out of file, just write silence.
SDL_memset(buffer, device->silence_value, buflen);
return origbuflen;
}
static void DISKAUDIO_FlushCapture(SDL_AudioDevice *_this)
static void DISKAUDIO_FlushCapture(SDL_AudioDevice *device)
{
/* no op...we don't advance the file pointer or anything. */
// no op...we don't advance the file pointer or anything.
}
static void DISKAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void DISKAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->io != NULL) {
SDL_RWclose(_this->hidden->io);
}
SDL_free(_this->hidden->mixbuf);
SDL_free(_this->hidden);
}
static const char *get_filename(const SDL_bool iscapture, const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
if (devname == NULL) {
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
if (device->hidden) {
if (device->hidden->io != NULL) {
SDL_RWclose(device->hidden->io);
}
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
device->hidden = NULL;
}
}
static const char *get_filename(const SDL_bool iscapture)
{
const char *devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
if (devname == NULL) {
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
}
return devname;
}
static int DISKAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
{
void *handle = _this->handle;
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
SDL_bool iscapture = _this->iscapture;
const char *fname = get_filename(iscapture, handle ? NULL : devname);
SDL_bool iscapture = device->iscapture;
const char *fname = get_filename(iscapture);
const char *envr = SDL_getenv(DISKENVR_IODELAY);
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
if (envr != NULL) {
_this->hidden->io_delay = SDL_atoi(envr);
device->hidden->io_delay = SDL_atoi(envr);
} else {
_this->hidden->io_delay = ((_this->spec.samples * 1000) / _this->spec.freq);
device->hidden->io_delay = ((device->sample_frames * 1000) / device->spec.freq);
}
/* Open the audio device */
_this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (_this->hidden->io == NULL) {
// Open the "audio device"
device->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (device->hidden->io == NULL) {
return -1;
}
/* Allocate mixing buffer */
// Allocate mixing buffer
if (!iscapture) {
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->spec.size);
if (_this->hidden->mixbuf == NULL) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
"You are using the SDL disk i/o audio driver!\n");
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
fname);
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);
/* We're ready to rock and roll. :-) */
return 0;
return 0; // We're ready to rock and roll. :-)
}
static void DISKAUDIO_DetectDevices(void)
static void DISKAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
*default_output = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
*default_capture = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
}
static SDL_bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = DISKAUDIO_OpenDevice;
impl->WaitDevice = DISKAUDIO_WaitDevice;
impl->WaitCaptureDevice = DISKAUDIO_WaitDevice;
impl->PlayDevice = DISKAUDIO_PlayDevice;
impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
impl->FlushCapture = DISKAUDIO_FlushCapture;
impl->CloseDevice = DISKAUDIO_CloseDevice;
impl->DetectDevices = DISKAUDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
impl->SupportsNonPow2Samples = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap DISKAUDIO_bootstrap = {
"disk", "direct-to-disk audio", DISKAUDIO_Init, SDL_TRUE
};
#endif /* SDL_AUDIO_DRIVER_DISK */
#endif // SDL_AUDIO_DRIVER_DISK
+110 -105
View File
@@ -20,9 +20,9 @@
*/
#include "SDL_internal.h"
#ifdef SDL_AUDIO_DRIVER_OSS
// !!! FIXME: clean out perror and fprintf calls in here.
/* Allow access to a raw mixing buffer */
#ifdef SDL_AUDIO_DRIVER_OSS
#include <stdio.h> /* For perror() */
#include <string.h> /* For strerror() */
@@ -38,82 +38,69 @@
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../../SDL_utils_c.h"
#include "SDL_dspaudio.h"
static void DSP_DetectDevices(void)
static void DSP_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
SDL_EnumUnixAudioDevices(0, NULL);
SDL_EnumUnixAudioDevices(SDL_FALSE, NULL);
}
static void DSP_CloseDevice(SDL_AudioDevice *_this)
static void DSP_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->audio_fd >= 0) {
close(_this->hidden->audio_fd);
}
SDL_free(_this->hidden->mixbuf);
SDL_free(_this->hidden);
}
static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
{
SDL_bool iscapture = _this->iscapture;
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format = 0;
int value;
int frag_spec;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
if (device->hidden) {
if (device->hidden->audio_fd >= 0) {
close(device->hidden->audio_fd);
}
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
}
}
static int DSP_OpenDevice(SDL_AudioDevice *device)
{
// Make sure fragment size stays a power of 2, or OSS fails.
// (I don't know which of these are actually legal values, though...)
if (device->spec.channels > 8) {
device->spec.channels = 8;
} else if (device->spec.channels > 4) {
device->spec.channels = 4;
} else if (device->spec.channels > 2) {
device->spec.channels = 2;
}
/* Make sure fragment size stays a power of 2, or OSS fails. */
/* I don't know which of these are actually legal values, though... */
if (_this->spec.channels > 8) {
_this->spec.channels = 8;
} else if (_this->spec.channels > 4) {
_this->spec.channels = 4;
} else if (_this->spec.channels > 2) {
_this->spec.channels = 2;
}
/* Initialize all variables that we clean on shutdown */
_this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
/* Open the audio device */
_this->hidden->audio_fd = open(devname, flags | O_CLOEXEC, 0);
if (_this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
// 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);
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));
}
/* Make the file descriptor use blocking i/o with fcntl() */
// Make the file descriptor use blocking i/o with fcntl()
{
long ctlflags;
ctlflags = fcntl(_this->hidden->audio_fd, F_GETFL);
ctlflags &= ~O_NONBLOCK;
if (fcntl(_this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
const long ctlflags = fcntl(device->hidden->audio_fd, F_GETFL) & ~O_NONBLOCK;
if (fcntl(device->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
return SDL_SetError("Couldn't set audio blocking mode");
}
}
/* Get a list of supported hardware formats */
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
// Get a list of supported hardware formats
int value;
if (ioctl(device->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
perror("SNDCTL_DSP_GETFMTS");
return SDL_SetError("Couldn't get audio format list");
}
/* Try for a closest match on audio format */
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
int format = 0;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
@@ -134,17 +121,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
format = AFMT_S16_BE;
}
break;
#if 0
/*
* These formats are not used by any real life systems so they are not
* needed here.
*/
case SDL_AUDIO_S8:
if (value & AFMT_S8) {
format = AFMT_S8;
}
break;
#endif
default:
continue;
}
@@ -153,40 +130,43 @@ static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
if (format == 0) {
return SDL_SetError("Couldn't find any hardware audio formats");
}
_this->spec.format = test_format;
device->spec.format = test_format;
/* Set the audio format */
// Set the audio format
value = format;
if ((ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
if ((ioctl(device->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format)) {
perror("SNDCTL_DSP_SETFMT");
return SDL_SetError("Couldn't set audio format");
}
/* Set the number of channels of output */
value = _this->spec.channels;
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
// Set the number of channels of output
value = device->spec.channels;
if (ioctl(device->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
perror("SNDCTL_DSP_CHANNELS");
return SDL_SetError("Cannot set the number of channels");
}
_this->spec.channels = value;
device->spec.channels = value;
/* Set the DSP frequency */
value = _this->spec.freq;
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
// Set the DSP frequency
value = device->spec.freq;
if (ioctl(device->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
perror("SNDCTL_DSP_SPEED");
return SDL_SetError("Couldn't set audio frequency");
}
_this->spec.freq = value;
device->spec.freq = value;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
SDL_UpdatedAudioDeviceFormat(device);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01U << frag_spec) < _this->spec.size; ++frag_spec) {
}
if ((0x01U << frag_spec) != _this->spec.size) {
return SDL_SetError("Fragment size must be a power of two");
/* Determine the power of two of the fragment size
Since apps don't control this in SDL3, and this driver only accepts 8, 16
bit formats and 1, 2, 4, 8 channels, this should always be a power of 2 already. */
SDL_assert(SDL_powerof2(device->buffer_size) == device->buffer_size);
int frag_spec = 0;
while ((0x01U << frag_spec) < device->buffer_size) {
frag_spec++;
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
@@ -195,13 +175,13 @@ static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
#endif
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
if (ioctl(device->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#ifdef DEBUG_AUDIO
{
audio_buf_info info;
ioctl(_this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
ioctl(device->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
fprintf(stderr, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize);
@@ -210,44 +190,67 @@ static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
#endif
/* Allocate mixing buffer */
if (!iscapture) {
_this->hidden->mixlen = _this->spec.size;
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
if (_this->hidden->mixbuf == NULL) {
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
/* We're ready to rock and roll. :-) */
return 0;
return 0; // We're ready to rock and roll. :-)
}
static void DSP_PlayDevice(SDL_AudioDevice *_this)
static void DSP_WaitDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = _this->hidden;
if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
const unsigned long ioctlreq = device->iscapture ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE;
struct SDL_PrivateAudioData *h = device->hidden;
while (!SDL_AtomicGet(&device->shutdown)) {
audio_buf_info info;
const int rc = ioctl(h->audio_fd, ioctlreq, &info);
if (rc < 0) {
if (errno == EAGAIN) {
continue;
}
// Hmm, not much we can do - abort
fprintf(stderr, "dsp WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
SDL_AudioDeviceDisconnected(device);
return;
} else if (info.bytes < device->buffer_size) {
SDL_Delay(10);
} else {
break; // ready to go!
}
}
}
static void DSP_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = device->hidden;
if (write(h->audio_fd, buffer, buflen) == -1) {
perror("Audio write");
SDL_OpenedAudioDeviceDisconnected(_this);
SDL_AudioDeviceDisconnected(device);
return;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
#endif
}
static Uint8 *DSP_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *DSP_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbuf;
return device->hidden->mixbuf;
}
static int DSP_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int DSP_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
return (int)read(_this->hidden->audio_fd, buffer, buflen);
return (int)read(device->hidden->audio_fd, buffer, buflen);
}
static void DSP_FlushCapture(SDL_AudioDevice *_this)
static void DSP_FlushCapture(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = _this->hidden;
struct SDL_PrivateAudioData *h = device->hidden;
audio_buf_info info;
if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
while (info.bytes > 0) {
@@ -263,17 +266,17 @@ static void DSP_FlushCapture(SDL_AudioDevice *_this)
}
static SDL_bool InitTimeDevicesExist = SDL_FALSE;
static int look_for_devices_test(int fd)
static SDL_bool look_for_devices_test(int fd)
{
InitTimeDevicesExist = SDL_TRUE; /* note that _something_ exists. */
/* Don't add to the device list, we're just seeing if any devices exist. */
return 0;
return SDL_FALSE;
}
static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
{
InitTimeDevicesExist = SDL_FALSE;
SDL_EnumUnixAudioDevices(0, look_for_devices_test);
SDL_EnumUnixAudioDevices(SDL_FALSE, look_for_devices_test);
if (!InitTimeDevicesExist) {
SDL_SetError("dsp: No such audio device");
return SDL_FALSE; /* maybe try a different backend. */
@@ -282,9 +285,11 @@ static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->OpenDevice = DSP_OpenDevice;
impl->WaitDevice = DSP_WaitDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->WaitCaptureDevice = DSP_WaitDevice;
impl->CaptureFromDevice = DSP_CaptureFromDevice;
impl->FlushCapture = DSP_FlushCapture;
@@ -295,7 +300,7 @@ static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
}
AudioBootStrap DSP_bootstrap = {
"dsp", "OSS /dev/dsp standard audio", DSP_Init, SDL_FALSE
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_OSS */
-2
View File
@@ -32,8 +32,6 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* SDL_dspaudio_h_ */
+48 -12
View File
@@ -20,39 +20,75 @@
*/
#include "SDL_internal.h"
/* Output audio to nowhere... */
// Output audio to nowhere...
#include "../SDL_audio_c.h"
#include "SDL_dummyaudio.h"
static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
{
_this->hidden = (void *)0x1; /* just something non-NULL */
// !!! FIXME: this should be an SDL hint, not an environment variable.
#define DUMMYENVR_IODELAY "SDL_DUMMYAUDIODELAY"
return 0; /* always succeeds. */
static void DUMMYAUDIO_WaitDevice(SDL_AudioDevice *device)
{
SDL_Delay(device->hidden->io_delay);
}
static int DUMMYAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *device)
{
/* Delay to make this sort of simulate real audio input. */
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
const char *envr = SDL_getenv(DUMMYENVR_IODELAY);
/* always return a full buffer of silence. */
SDL_memset(buffer, _this->spec.silence, buflen);
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (!device->hidden) {
return SDL_OutOfMemory();
}
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *) SDL_malloc(device->buffer_size);
if (!device->hidden->mixbuf) {
return SDL_OutOfMemory();
}
}
device->hidden->io_delay = (Uint32) (envr ? SDL_atoi(envr) : ((device->sample_frames * 1000) / device->spec.freq));
return 0; // we're good; don't change reported device format.
}
static void DUMMYAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
device->hidden = NULL;
}
}
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)
{
// always return a full buffer of silence.
SDL_memset(buffer, device->silence_value, buflen);
return buflen;
}
static SDL_bool DUMMYAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = DUMMYAUDIO_OpenDevice;
impl->CloseDevice = DUMMYAUDIO_CloseDevice;
impl->WaitDevice = DUMMYAUDIO_WaitDevice;
impl->GetDeviceBuf = DUMMYAUDIO_GetDeviceBuf;
impl->WaitCaptureDevice = DUMMYAUDIO_WaitDevice;
impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap DUMMYAUDIO_bootstrap = {
+3 -6
View File
@@ -27,11 +27,8 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
Uint32 initial_calls;
Uint8 *mixbuf; // The file descriptor for the audio device
Uint32 io_delay; // miliseconds to sleep in WaitDevice.
};
#endif /* SDL_dummyaudio_h_ */
#endif // SDL_dummyaudio_h_
+77 -152
View File
@@ -27,15 +27,18 @@
#include <emscripten/emscripten.h>
/* !!! FIXME: this currently expects that the audio callback runs in the main thread,
!!! FIXME: in intervals when the application isn't running, but that may not be
!!! FIXME: true always once pthread support becomes widespread. Revisit this code
!!! FIXME: at some point and see what needs to be done for that! */
// just turn off clang-format for this whole file, this INDENT_OFF stuff on
// each EM_ASM section is ugly.
/* *INDENT-OFF* */ /* clang-format off */
static void FeedAudioDevice(SDL_AudioDevice *_this, const void *buf, const int buflen)
static Uint8 *EMSCRIPTENAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
const int framelen = (SDL_AUDIO_BITSIZE(_this->spec.format) / 8) * _this->spec.channels;
/* *INDENT-OFF* */ /* clang-format off */
return device->hidden->mixbuf;
}
static void EMSCRIPTENAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
const int framelen = (SDL_AUDIO_BITSIZE(device->spec.format) / 8) * device->spec.channels;
MAIN_THREAD_EM_ASM({
var SDL3 = Module['SDL3'];
var numChannels = SDL3.audio.currentOutputBuffer['numberOfChannels'];
@@ -46,65 +49,25 @@ static void FeedAudioDevice(SDL_AudioDevice *_this, const void *buf, const int b
}
for (var j = 0; j < $1; ++j) {
channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; /* !!! FIXME: why are these shifts here? */
channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; // !!! FIXME: why are these shifts here?
}
}
}, buf, buflen / framelen);
/* *INDENT-ON* */ /* clang-format on */
}, buffer, buffer_size / framelen);
}
static void HandleAudioProcess(SDL_AudioDevice *_this)
static void HandleAudioProcess(SDL_AudioDevice *device) // this fires when the main thread is idle.
{
SDL_AudioCallback callback = _this->callbackspec.callback;
const int stream_len = _this->callbackspec.size;
/* Only do something if audio is enabled */
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
if (_this->stream) {
SDL_ClearAudioStream(_this->stream);
}
SDL_memset(_this->work_buffer, _this->spec.silence, _this->spec.size);
FeedAudioDevice(_this, _this->work_buffer, _this->spec.size);
return;
}
if (_this->stream == NULL) { /* no conversion necessary. */
SDL_assert(_this->spec.size == stream_len);
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
} else { /* streaming/converting */
int got;
while (SDL_GetAudioStreamAvailable(_this->stream) < ((int)_this->spec.size)) {
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
if (SDL_PutAudioStreamData(_this->stream, _this->work_buffer, stream_len) == -1) {
SDL_ClearAudioStream(_this->stream);
SDL_AtomicSet(&_this->enabled, 0);
break;
}
}
got = SDL_GetAudioStreamData(_this->stream, _this->work_buffer, _this->spec.size);
SDL_assert((got < 0) || (got == _this->spec.size));
if (got != _this->spec.size) {
SDL_memset(_this->work_buffer, _this->spec.silence, _this->spec.size);
}
}
FeedAudioDevice(_this, _this->work_buffer, _this->spec.size);
SDL_OutputAudioThreadIterate(device);
}
static void HandleCaptureProcess(SDL_AudioDevice *_this)
static void EMSCRIPTENAUDIO_FlushCapture(SDL_AudioDevice *device)
{
SDL_AudioCallback callback = _this->callbackspec.callback;
const int stream_len = _this->callbackspec.size;
// Do nothing, the new data will just be dropped.
}
/* Only do something if audio is enabled */
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
SDL_ClearAudioStream(_this->stream);
return;
}
/* *INDENT-OFF* */ /* clang-format off */
static int EMSCRIPTENAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
MAIN_THREAD_EM_ASM({
var SDL3 = Module['SDL3'];
var numChannels = SDL3.capture.currentCaptureBuffer.numberOfChannels;
@@ -114,7 +77,7 @@ static void HandleCaptureProcess(SDL_AudioDevice *_this)
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
}
if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
if (numChannels == 1) { // fastpath this a little for the common (mono) case.
for (var j = 0; j < $1; ++j) {
setValue($0 + (j * 4), channelData[j], 'float');
}
@@ -124,33 +87,22 @@ static void HandleCaptureProcess(SDL_AudioDevice *_this)
}
}
}
}, _this->work_buffer, (_this->spec.size / sizeof(float)) / _this->spec.channels);
/* *INDENT-ON* */ /* clang-format on */
}, buffer, (buflen / sizeof(float)) / device->spec.channels);
/* okay, we've got an interleaved float32 array in C now. */
if (_this->stream == NULL) { /* no conversion necessary. */
SDL_assert(_this->spec.size == stream_len);
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
} else { /* streaming/converting */
if (SDL_PutAudioStreamData(_this->stream, _this->work_buffer, _this->spec.size) == -1) {
SDL_AtomicSet(&_this->enabled, 0);
}
while (SDL_GetAudioStreamAvailable(_this->stream) >= stream_len) {
const int got = SDL_GetAudioStreamData(_this->stream, _this->work_buffer, stream_len);
SDL_assert((got < 0) || (got == stream_len));
if (got != stream_len) {
SDL_memset(_this->work_buffer, _this->callbackspec.silence, stream_len);
}
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len); /* Send it to the app. */
}
}
return buflen;
}
static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void HandleCaptureProcess(SDL_AudioDevice *device) // this fires when the main thread is idle.
{
/* *INDENT-OFF* */ /* clang-format off */
SDL_CaptureAudioThreadIterate(device);
}
static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (!device->hidden) {
return;
}
MAIN_THREAD_EM_ASM({
var SDL3 = Module['SDL3'];
if ($0) {
@@ -188,29 +140,23 @@ static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *_this)
SDL3.audioContext.close();
SDL3.audioContext = undefined;
}
}, _this->iscapture);
/* *INDENT-ON* */ /* clang-format on */
}, device->iscapture);
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
SDL_free(_this->hidden);
#endif
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
device->hidden = NULL;
SDL_AudioThreadFinalize(device);
}
EM_JS_DEPS(sdlaudio, "$autoResumeAudioContext,$dynCall");
static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
SDL_bool iscapture = _this->iscapture;
int result;
// based on parts of library_sdl.js
/* based on parts of library_sdl.js */
/* *INDENT-OFF* */ /* clang-format off */
/* create context */
result = MAIN_THREAD_EM_ASM_INT({
// create context
const int result = MAIN_THREAD_EM_ASM_INT({
if (typeof(Module['SDL3']) === 'undefined') {
Module['SDL3'] = {};
}
@@ -232,57 +178,41 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devnam
}
}
return SDL3.audioContext === undefined ? -1 : 0;
}, iscapture);
/* *INDENT-ON* */ /* clang-format on */
}, device->iscapture);
if (result < 0) {
return SDL_SetError("Web Audio API is not available!");
}
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
while ((test_format = *(closefmts++)) != 0) {
switch (test_format) {
case SDL_AUDIO_F32: /* web audio only supports floats */
break;
default:
continue;
}
break;
}
device->spec.format = SDL_AUDIO_F32; // web audio only supports floats
if (!test_format) {
/* Didn't find a compatible format :( */
return SDL_SetError("%s: Unsupported audio format", "emscripten");
}
_this->spec.format = test_format;
/* Initialize all variables that we clean on shutdown */
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
#endif
_this->hidden = (struct SDL_PrivateAudioData *)0x1;
/* limit to native freq */
_this->spec.freq = EM_ASM_INT({
var SDL3 = Module['SDL3'];
return SDL3.audioContext.sampleRate;
});
// limit to native freq
device->spec.freq = EM_ASM_INT({ return Module['SDL3'].audioContext.sampleRate; });
SDL_CalculateAudioSpec(&_this->spec);
SDL_UpdatedAudioDeviceFormat(device);
/* *INDENT-OFF* */ /* clang-format off */
if (iscapture) {
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
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
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. */
and forget about it.
/* This should, strictly speaking, use MediaRecorder for capture, but
This should, strictly speaking, use MediaRecorder for capture, 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
@@ -317,7 +247,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devnam
//console.log('SDL audio capture: 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). */
// 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);
var silence_callback = function() {
@@ -332,9 +262,9 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devnam
} else if (navigator.webkitGetUserMedia !== undefined) {
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
}
}, _this->spec.channels, _this->spec.samples, HandleCaptureProcess, _this);
}, device->spec.channels, device->sample_frames, HandleCaptureProcess, device);
} else {
/* setup a ScriptProcessorNode */
// setup a ScriptProcessorNode
MAIN_THREAD_EM_ASM({
var SDL3 = Module['SDL3'];
SDL3.audio.scriptProcessorNode = SDL3.audioContext['createScriptProcessor']($1, 0, $0);
@@ -344,33 +274,29 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devnam
dynCall('vi', $2, [$3]);
};
SDL3.audio.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
}, _this->spec.channels, _this->spec.samples, HandleAudioProcess, _this);
}, device->spec.channels, device->sample_frames, HandleAudioProcess, device);
}
/* *INDENT-ON* */ /* clang-format on */
return 0;
}
static void EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice *device)
{
}
static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
{
SDL_bool available, capture_available;
/* Set the function pointers */
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->OnlyHasDefaultOutputDevice = SDL_TRUE;
/* no threads here */
impl->LockDevice = impl->UnlockDevice = EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock;
// 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;
/* *INDENT-OFF* */ /* clang-format off */
/* check availability */
// check availability
available = MAIN_THREAD_EM_ASM_INT({
if (typeof(AudioContext) !== 'undefined') {
return true;
@@ -378,14 +304,12 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
return true;
}
return false;
});
/* *INDENT-ON* */ /* clang-format on */
}) ? SDL_TRUE : SDL_FALSE;
if (!available) {
SDL_SetError("No audio context available");
}
/* *INDENT-OFF* */ /* clang-format off */
capture_available = available && MAIN_THREAD_EM_ASM_INT({
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
return true;
@@ -393,8 +317,7 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
return true;
}
return false;
});
/* *INDENT-ON* */ /* clang-format on */
}) ? SDL_TRUE : SDL_FALSE;
impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE;
@@ -406,4 +329,6 @@ AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
/* *INDENT-ON* */ /* clang-format on */
#endif // SDL_AUDIO_DRIVER_EMSCRIPTEN
+1 -1
View File
@@ -27,7 +27,7 @@
struct SDL_PrivateAudioData
{
int unused;
Uint8 *mixbuf;
};
#endif /* SDL_emscriptenaudio_h_ */
+68 -84
View File
@@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_HAIKU
/* Allow access to the audio stream on Haiku */
// Allow access to the audio stream on Haiku
#include <SoundPlayer.h>
#include <signal.h>
@@ -38,58 +38,45 @@ extern "C"
}
/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
/* The Haiku callback for handling the audio buffer */
static void FillSound(void *device, void *stream, size_t len,
const media_raw_audio_format & format)
static Uint8 *HAIKUAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
SDL_AudioCallback callback = audio->callbackspec.callback;
SDL_LockMutex(audio->mixer_lock);
/* Only do something if audio is enabled */
if (!SDL_AtomicGet(&audio->enabled) || SDL_AtomicGet(&audio->paused)) {
if (audio->stream) {
SDL_ClearAudioStream(audio->stream);
}
SDL_memset(stream, audio->spec.silence, len);
} else {
SDL_assert(audio->spec.size == len);
if (audio->stream == NULL) { /* no conversion necessary. */
callback(audio->callbackspec.userdata, (Uint8 *) stream, len);
} else { /* streaming/converting */
const int stream_len = audio->callbackspec.size;
const int ilen = (int) len;
while (SDL_GetAudioStreamAvailable(audio->stream) < ilen) {
callback(audio->callbackspec.userdata, audio->work_buffer, stream_len);
if (SDL_PutAudioStreamData(audio->stream, audio->work_buffer, stream_len) == -1) {
SDL_ClearAudioStream(audio->stream);
SDL_AtomicSet(&audio->enabled, 0);
break;
}
}
const int got = SDL_GetAudioStreamData(audio->stream, stream, ilen);
SDL_assert((got < 0) || (got == ilen));
if (got != ilen) {
SDL_memset(stream, audio->spec.silence, len);
}
}
}
SDL_UnlockMutex(audio->mixer_lock);
SDL_assert(device->hidden->current_buffer != NULL);
SDL_assert(device->hidden->current_buffer_len > 0);
*buffer_size = device->hidden->current_buffer_len;
return device->hidden->current_buffer;
}
static void HAIKUAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void HAIKUAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
if (_this->hidden->audio_obj) {
_this->hidden->audio_obj->Stop();
delete _this->hidden->audio_obj;
// We already wrote our output right into the BSoundPlayer's callback's stream. Just clean up our stuff.
SDL_assert(device->hidden->current_buffer != NULL);
SDL_assert(device->hidden->current_buffer_len > 0);
device->hidden->current_buffer = NULL;
device->hidden->current_buffer_len = 0;
}
// The Haiku callback for handling the audio buffer
static void FillSound(void *data, void *stream, size_t len, const media_raw_audio_format & format)
{
SDL_AudioDevice *device = (SDL_AudioDevice *)data;
SDL_assert(device->hidden->current_buffer == NULL);
SDL_assert(device->hidden->current_buffer_len == 0);
device->hidden->current_buffer = (Uint8 *) stream;
device->hidden->current_buffer_len = (int) len;
SDL_OutputAudioThreadIterate(device);
}
static void HAIKUAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->audio_obj) {
device->hidden->audio_obj->Stop();
delete device->hidden->audio_obj;
}
delete device->hidden;
device->hidden = NULL;
SDL_AudioThreadFinalize(device);
}
delete _this->hidden;
}
@@ -115,26 +102,24 @@ static inline void UnmaskSignals(sigset_t * omask)
}
static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *device)
{
media_raw_audio_format format;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
/* Initialize all variables that we clean on shutdown */
_this->hidden = new SDL_PrivateAudioData;
if (_this->hidden == NULL) {
// Initialize all variables that we clean on shutdown
device->hidden = new SDL_PrivateAudioData;
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
SDL_zerop(device->hidden);
/* Parse the audio format and fill the Be raw audio format */
// Parse the audio format and fill the Be raw audio format
media_raw_audio_format format;
SDL_zero(format);
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) _this->spec.freq;
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
format.frame_rate = (float) device->spec.freq;
format.channel_count = device->spec.channels; // !!! FIXME: support > 2?
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
switch (test_format) {
case SDL_AUDIO_S8:
@@ -178,31 +163,30 @@ static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
break;
}
if (!test_format) { /* shouldn't happen, but just in case... */
return SDL_SetError("%s: Unsupported audio format", "haiku");
if (!test_format) { // shouldn't happen, but just in case...
return SDL_SetError("HAIKU: Unsupported audio format");
}
_this->spec.format = test_format;
device->spec.format = test_format;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
// Calculate the final parameters for this audio specification
SDL_UpdatedAudioDeviceFormat(device);
format.buffer_size = _this->spec.size;
format.buffer_size = device->buffer_size;
/* Subscribe to the audio stream (creates a new thread) */
// Subscribe to the audio stream (creates a new thread)
sigset_t omask;
MaskSignals(&omask);
_this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
FillSound, NULL, _this);
device->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
FillSound, NULL, device);
UnmaskSignals(&omask);
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
_this->hidden->audio_obj->SetHasData(true);
if (device->hidden->audio_obj->Start() == B_NO_ERROR) {
device->hidden->audio_obj->SetHasData(true);
} else {
return SDL_SetError("Unable to start Be audio");
return SDL_SetError("Unable to start Haiku audio");
}
/* We're running! */
return 0;
return 0; // We're running!
}
static void HAIKUAUDIO_Deinitialize(void)
@@ -210,29 +194,29 @@ static void HAIKUAUDIO_Deinitialize(void)
SDL_QuitBeApp();
}
static SDL_bool HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
static SDL_bool HAIKUAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return SDL_FALSE;
}
/* Set the function pointers */
// Set the function pointers
impl->OpenDevice = HAIKUAUDIO_OpenDevice;
impl->GetDeviceBuf = HAIKUAUDIO_GetDeviceBuf;
impl->PlayDevice = HAIKUAUDIO_PlayDevice;
impl->CloseDevice = HAIKUAUDIO_CloseDevice;
impl->Deinitialize = HAIKUAUDIO_Deinitialize;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
extern "C"
{
extern AudioBootStrap HAIKUAUDIO_bootstrap;
}
extern "C" { extern AudioBootStrap HAIKUAUDIO_bootstrap; }
AudioBootStrap HAIKUAUDIO_bootstrap = {
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_HAIKU */
#endif // SDL_AUDIO_DRIVER_HAIKU
+2
View File
@@ -28,6 +28,8 @@
struct SDL_PrivateAudioData
{
BSoundPlayer *audio_obj;
Uint8 *current_buffer;
int current_buffer_len;
};
#endif /* SDL_haikuaudio_h_ */
+93 -106
View File
@@ -135,9 +135,7 @@ static int load_jack_syms(void)
static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
{
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
SDL_OpenedAudioDeviceDisconnected(_this);
SDL_PostSemaphore(_this->hidden->iosem); /* unblock the SDL thread. */
SDL_AudioDeviceDisconnected((SDL_AudioDevice *)arg);
}
// !!! FIXME: implement and register these!
@@ -146,124 +144,117 @@ static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. *
static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
{
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
jack_port_t **ports = _this->hidden->sdlports;
const int total_channels = _this->spec.channels;
const int total_frames = _this->spec.samples;
int channelsi;
SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
SDL_OutputAudioThreadIterate((SDL_AudioDevice *)arg);
return 0;
}
if (!SDL_AtomicGet(&_this->enabled)) {
/* silence the buffer to avoid repeats and corruption. */
SDL_memset(_this->hidden->iobuffer, '\0', _this->spec.size);
}
static void JACK_PlayDevice(SDL_AudioDevice *device, const Uint8 *ui8buffer, int buflen)
{
const float *buffer = (float *) ui8buffer;
jack_port_t **ports = device->hidden->sdlports;
const int total_channels = device->spec.channels;
const int total_frames = device->sample_frames;
const jack_nframes_t nframes = (jack_nframes_t) device->sample_frames;
for (channelsi = 0; channelsi < total_channels; channelsi++) {
for (int channelsi = 0; channelsi < total_channels; channelsi++) {
float *dst = (float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
if (dst) {
const float *src = _this->hidden->iobuffer + channelsi;
int framesi;
for (framesi = 0; framesi < total_frames; framesi++) {
const float *src = buffer + channelsi;
for (int framesi = 0; framesi < total_frames; framesi++) {
*(dst++) = *src;
src += total_channels;
}
}
}
SDL_PostSemaphore(_this->hidden->iosem); /* tell SDL thread we're done; refill the buffer. */
return 0;
}
/* This function waits until it is possible to write a full sound buffer */
static void JACK_WaitDevice(SDL_AudioDevice *_this)
static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
if (SDL_AtomicGet(&_this->enabled)) {
if (SDL_WaitSemaphore(_this->hidden->iosem) == -1) {
SDL_OpenedAudioDeviceDisconnected(_this);
}
}
}
static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *_this)
{
return (Uint8 *)_this->hidden->iobuffer;
return (Uint8 *)device->hidden->iobuffer;
}
static int jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
{
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
if (SDL_AtomicGet(&_this->enabled)) {
jack_port_t **ports = _this->hidden->sdlports;
const int total_channels = _this->spec.channels;
const int total_frames = _this->spec.samples;
int channelsi;
for (channelsi = 0; channelsi < total_channels; channelsi++) {
const float *src = (const float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
if (src) {
float *dst = _this->hidden->iobuffer + channelsi;
int framesi;
for (framesi = 0; framesi < total_frames; framesi++) {
*dst = *(src++);
dst += total_channels;
}
}
}
}
SDL_PostSemaphore(_this->hidden->iosem); /* tell SDL thread we're done; new buffer is ready! */
SDL_assert(nframes == ((SDL_AudioDevice *)arg)->sample_frames);
SDL_CaptureAudioThreadIterate((SDL_AudioDevice *)arg);
return 0;
}
static int JACK_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int JACK_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
{
SDL_assert(buflen == _this->spec.size); /* we always fill a full buffer. */
float *buffer = (float *) vbuffer;
jack_port_t **ports = device->hidden->sdlports;
const int total_channels = device->spec.channels;
const int total_frames = device->sample_frames;
const jack_nframes_t nframes = (jack_nframes_t) device->sample_frames;
/* Wait for JACK to fill the iobuffer */
if (SDL_WaitSemaphore(_this->hidden->iosem) == -1) {
return -1;
for (int channelsi = 0; channelsi < total_channels; channelsi++) {
const float *src = (const float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
if (src) {
float *dst = buffer + channelsi;
for (int framesi = 0; framesi < total_frames; framesi++) {
*dst = *(src++);
dst += total_channels;
}
}
}
SDL_memcpy(buffer, _this->hidden->iobuffer, buflen);
return buflen;
}
static void JACK_FlushCapture(SDL_AudioDevice *_this)
static void JACK_FlushCapture(SDL_AudioDevice *device)
{
SDL_WaitSemaphore(_this->hidden->iosem);
// do nothing, the data will just be replaced next callback.
}
static void JACK_CloseDevice(SDL_AudioDevice *_this)
static void JACK_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->client) {
JACK_jack_deactivate(_this->hidden->client);
if (device->hidden) {
if (device->hidden->client) {
JACK_jack_deactivate(device->hidden->client);
if (_this->hidden->sdlports) {
const int channels = _this->spec.channels;
int i;
for (i = 0; i < channels; i++) {
JACK_jack_port_unregister(_this->hidden->client, _this->hidden->sdlports[i]);
if (device->hidden->sdlports) {
const int channels = device->spec.channels;
int i;
for (i = 0; i < channels; i++) {
JACK_jack_port_unregister(device->hidden->client, device->hidden->sdlports[i]);
}
SDL_free(device->hidden->sdlports);
}
SDL_free(_this->hidden->sdlports);
JACK_jack_client_close(device->hidden->client);
}
JACK_jack_client_close(_this->hidden->client);
}
SDL_free(device->hidden->iobuffer);
SDL_free(device->hidden);
device->hidden = NULL;
if (_this->hidden->iosem) {
SDL_DestroySemaphore(_this->hidden->iosem);
SDL_AudioThreadFinalize(device);
}
SDL_free(_this->hidden->iobuffer);
SDL_free(_this->hidden);
}
static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
// !!! FIXME: unify this (PulseAudio has a getAppName, Pipewire has a thing, etc
static const char *GetJackAppName(void)
{
const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (retval && *retval) {
return retval;
}
retval = SDL_GetHint(SDL_HINT_APP_NAME);
if (retval && *retval) {
return retval;
}
return "SDL Application";
}
static int JACK_OpenDevice(SDL_AudioDevice *device)
{
/* Note that JACK uses "output" for capture 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 = _this->iscapture;
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;
@@ -277,14 +268,13 @@ static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
int i;
/* Initialize all variables that we clean on shutdown */
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
/* !!! FIXME: we _still_ need an API to specify an app name */
client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
_this->hidden->client = client;
client = JACK_jack_client_open(GetJackAppName(), JackNoStartServer, &status, NULL);
device->hidden->client = client;
if (client == NULL) {
return SDL_SetError("Can't open JACK client");
}
@@ -317,28 +307,24 @@ static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
/* Jack pretty much demands what it wants. */
_this->spec.format = SDL_AUDIO_F32SYS;
_this->spec.freq = JACK_jack_get_sample_rate(client);
_this->spec.channels = channels;
_this->spec.samples = JACK_jack_get_buffer_size(client);
device->spec.format = SDL_AUDIO_F32SYS;
device->spec.freq = JACK_jack_get_sample_rate(client);
device->spec.channels = channels;
device->sample_frames = JACK_jack_get_buffer_size(client);
SDL_CalculateAudioSpec(&_this->spec);
SDL_UpdatedAudioDeviceFormat(device);
_this->hidden->iosem = SDL_CreateSemaphore(0);
if (!_this->hidden->iosem) {
SDL_free(audio_ports);
return -1; /* error was set by SDL_CreateSemaphore */
}
_this->hidden->iobuffer = (float *)SDL_calloc(1, _this->spec.size);
if (!_this->hidden->iobuffer) {
SDL_free(audio_ports);
return SDL_OutOfMemory();
if (!device->iscapture) {
device->hidden->iobuffer = (float *)SDL_calloc(1, device->buffer_size);
if (!device->hidden->iobuffer) {
SDL_free(audio_ports);
return SDL_OutOfMemory();
}
}
/* Build SDL's ports, which we will connect to the device ports. */
_this->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
if (_this->hidden->sdlports == NULL) {
device->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
if (device->hidden->sdlports == NULL) {
SDL_free(audio_ports);
return SDL_OutOfMemory();
}
@@ -346,19 +332,19 @@ static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
for (i = 0; i < channels; i++) {
char portname[32];
(void)SDL_snprintf(portname, sizeof(portname), "sdl_jack_%s_%d", sdlportstr, i);
_this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
if (_this->hidden->sdlports[i] == NULL) {
device->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
if (device->hidden->sdlports[i] == NULL) {
SDL_free(audio_ports);
return SDL_SetError("jack_port_register failed");
}
}
if (JACK_jack_set_process_callback(client, callback, _this) != 0) {
if (JACK_jack_set_process_callback(client, callback, device) != 0) {
SDL_free(audio_ports);
return SDL_SetError("JACK: Couldn't set process callback");
}
JACK_jack_on_shutdown(client, jackShutdownCallback, _this);
JACK_jack_on_shutdown(client, jackShutdownCallback, device);
if (JACK_jack_activate(client) != 0) {
SDL_free(audio_ports);
@@ -367,7 +353,7 @@ static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
/* once activated, we can connect all the ports. */
for (i = 0; i < channels; i++) {
const char *sdlport = JACK_jack_port_name(_this->hidden->sdlports[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]];
if (JACK_jack_connect(client, srcport, dstport) != 0) {
@@ -406,8 +392,8 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
/* Set the function pointers */
impl->OpenDevice = JACK_OpenDevice;
impl->WaitDevice = JACK_WaitDevice;
impl->GetDeviceBuf = JACK_GetDeviceBuf;
impl->PlayDevice = JACK_PlayDevice;
impl->CloseDevice = JACK_CloseDevice;
impl->Deinitialize = JACK_Deinitialize;
impl->CaptureFromDevice = JACK_CaptureFromDevice;
@@ -415,6 +401,7 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
}
+1 -2
View File
@@ -28,9 +28,8 @@
struct SDL_PrivateAudioData
{
jack_client_t *client;
SDL_Semaphore *iosem;
float *iobuffer;
jack_port_t **sdlports;
float *iobuffer;
};
#endif /* SDL_jackaudio_h_ */
+106 -159
View File
@@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_N3DS
/* N3DS Audio driver */
// N3DS Audio driver
#include "../SDL_sysaudio.h"
#include "SDL_n3dsaudio.h"
@@ -32,27 +32,14 @@
static dspHookCookie dsp_hook;
static SDL_AudioDevice *audio_device;
static void FreePrivateData(SDL_AudioDevice *_this);
static int FindAudioFormat(SDL_AudioDevice *_this);
static SDL_INLINE void contextLock(SDL_AudioDevice *_this)
static SDL_INLINE void contextLock(SDL_AudioDevice *device)
{
LightLock_Lock(&_this->hidden->lock);
LightLock_Lock(&device->hidden->lock);
}
static SDL_INLINE void contextUnlock(SDL_AudioDevice *_this)
static SDL_INLINE void contextUnlock(SDL_AudioDevice *device)
{
LightLock_Unlock(&_this->hidden->lock);
}
static void N3DSAUD_LockAudio(SDL_AudioDevice *_this)
{
contextLock(_this);
}
static void N3DSAUD_UnlockAudio(SDL_AudioDevice *_this)
{
contextUnlock(_this);
LightLock_Unlock(&device->hidden->lock);
}
static void N3DSAUD_DspHook(DSP_HookType hook)
@@ -60,46 +47,46 @@ static void N3DSAUD_DspHook(DSP_HookType hook)
if (hook == DSPHOOK_ONCANCEL) {
contextLock(audio_device);
audio_device->hidden->isCancelled = SDL_TRUE;
SDL_AtomicSet(&audio_device->enabled, SDL_FALSE);
SDL_AudioDeviceDisconnected(audio_device);
CondVar_Broadcast(&audio_device->hidden->cv);
contextUnlock(audio_device);
}
}
static void AudioFrameFinished(void *device)
static void AudioFrameFinished(void *vdevice)
{
bool shouldBroadcast = false;
unsigned i;
SDL_AudioDevice *_this = (SDL_AudioDevice *)device;
SDL_AudioDevice *device = (SDL_AudioDevice *)vdevice;
contextLock(_this);
contextLock(device);
for (i = 0; i < NUM_BUFFERS; i++) {
if (_this->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
_this->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
if (device->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
device->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
shouldBroadcast = SDL_TRUE;
}
}
if (shouldBroadcast) {
CondVar_Broadcast(&_this->hidden->cv);
CondVar_Broadcast(&device->hidden->cv);
}
contextUnlock(_this);
contextUnlock(device);
}
static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
{
Result ndsp_init_res;
Uint8 *data_vaddr;
float mix[12];
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
/* Initialise the DSP service */
// Initialise the DSP service
ndsp_init_res = ndspInit();
if (R_FAILED(ndsp_init_res)) {
if ((R_SUMMARY(ndsp_init_res) == RS_NOTFOUND) && (R_MODULE(ndsp_init_res) == RM_DSP)) {
@@ -110,173 +97,180 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
return -1;
}
/* Initialise internal state */
LightLock_Init(&_this->hidden->lock);
CondVar_Init(&_this->hidden->cv);
// Initialise internal state
LightLock_Init(&device->hidden->lock);
CondVar_Init(&device->hidden->cv);
if (_this->spec.channels > 2) {
_this->spec.channels = 2;
if (device->spec.channels > 2) {
device->spec.channels = 2;
}
/* Should not happen but better be safe. */
if (FindAudioFormat(_this) < 0) {
Uint32 format = 0;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
if (test_format == SDL_AUDIO_S8) { // Signed 8-bit audio supported
format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
break;
} else if (test_format == SDL_AUDIO_S16) { // Signed 16-bit audio supported
format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
break;
}
}
if (!test_format) { // shouldn't happen, but just in case...
return SDL_SetError("No supported audio format found.");
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&_this->spec);
device->spec.format = test_format;
/* Allocate mixing buffer */
if (_this->spec.size >= SDL_MAX_UINT32 / 2) {
// Update the fragment size as size in bytes
SDL_UpdatedAudioDeviceFormat(device);
// Allocate mixing buffer
if (device->buffer_size >= SDL_MAX_UINT32 / 2) {
return SDL_SetError("Mixing buffer is too large.");
}
_this->hidden->mixlen = _this->spec.size;
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->spec.size);
if (_this->hidden->mixbuf == NULL) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
data_vaddr = (Uint8 *)linearAlloc(_this->hidden->mixlen * NUM_BUFFERS);
data_vaddr = (Uint8 *)linearAlloc(device->buffer_size * NUM_BUFFERS);
if (data_vaddr == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(data_vaddr, 0, _this->hidden->mixlen * NUM_BUFFERS);
DSP_FlushDataCache(data_vaddr, _this->hidden->mixlen * NUM_BUFFERS);
SDL_memset(data_vaddr, 0, device->buffer_size * NUM_BUFFERS);
DSP_FlushDataCache(data_vaddr, device->buffer_size * NUM_BUFFERS);
_this->hidden->nextbuf = 0;
_this->hidden->channels = _this->spec.channels;
_this->hidden->samplerate = _this->spec.freq;
device->hidden->nextbuf = 0;
ndspChnReset(0);
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
ndspChnSetRate(0, _this->spec.freq);
ndspChnSetFormat(0, _this->hidden->format);
ndspChnSetRate(0, device->spec.freq);
ndspChnSetFormat(0, format);
SDL_memset(mix, 0, sizeof(mix));
mix[0] = 1.0;
mix[1] = 1.0;
SDL_zeroa(mix);
mix[0] = mix[1] = 1.0f;
ndspChnSetMix(0, mix);
SDL_memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
const int sample_frame_size = device->spec.channels * (SDL_AUDIO_BITSIZE(device->spec.format) / 8);
for (unsigned i = 0; i < NUM_BUFFERS; i++) {
_this->hidden->waveBuf[i].data_vaddr = data_vaddr;
_this->hidden->waveBuf[i].nsamples = _this->hidden->mixlen / _this->hidden->bytePerSample;
data_vaddr += _this->hidden->mixlen;
device->hidden->waveBuf[i].data_vaddr = data_vaddr;
device->hidden->waveBuf[i].nsamples = device->buffer_size / sample_frame_size;
data_vaddr += device->buffer_size;
}
/* Setup callback */
audio_device = _this;
ndspSetCallback(AudioFrameFinished, _this);
// Setup callback
audio_device = device;
ndspSetCallback(AudioFrameFinished, device);
dspHook(&dsp_hook, N3DSAUD_DspHook);
return 0;
}
static int N3DSAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
/* Delay to make this sort of simulate real audio input. */
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
contextLock(device);
/* always return a full buffer of silence. */
SDL_memset(buffer, _this->spec.silence, buflen);
return buflen;
}
const size_t nextbuf = device->hidden->nextbuf;
static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *_this)
{
size_t nextbuf;
size_t sampleLen;
contextLock(_this);
nextbuf = _this->hidden->nextbuf;
sampleLen = _this->hidden->mixlen;
if (_this->hidden->isCancelled ||
_this->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
contextUnlock(_this);
if (device->hidden->isCancelled ||
device->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
contextUnlock(device);
return;
}
_this->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
device->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
contextUnlock(_this);
contextUnlock(device);
SDL_memcpy((void *)_this->hidden->waveBuf[nextbuf].data_vaddr,
_this->hidden->mixbuf, sampleLen);
DSP_FlushDataCache(_this->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
SDL_memcpy((void *)device->hidden->waveBuf[nextbuf].data_vaddr, buffer, buflen);
DSP_FlushDataCache(device->hidden->waveBuf[nextbuf].data_vaddr, buflen);
ndspChnWaveBufAdd(0, &_this->hidden->waveBuf[nextbuf]);
ndspChnWaveBufAdd(0, &device->hidden->waveBuf[nextbuf]);
}
static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *_this)
static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
{
contextLock(_this);
while (!_this->hidden->isCancelled &&
_this->hidden->waveBuf[_this->hidden->nextbuf].status != NDSP_WBUF_FREE) {
CondVar_Wait(&_this->hidden->cv, &_this->hidden->lock);
contextLock(device);
while (!device->hidden->isCancelled && !SDL_AtomicGet(&device->shutdown) &&
device->hidden->waveBuf[device->hidden->nextbuf].status != NDSP_WBUF_FREE) {
CondVar_Wait(&device->hidden->cv, &device->hidden->lock);
}
contextUnlock(_this);
contextUnlock(device);
}
static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbuf;
return device->hidden->mixbuf;
}
static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *device)
{
contextLock(_this);
if (!device->hidden) {
return;
}
contextLock(device);
dspUnhook(&dsp_hook);
ndspSetCallback(NULL, NULL);
if (!_this->hidden->isCancelled) {
if (!device->hidden->isCancelled) {
ndspChnReset(0);
SDL_memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
CondVar_Broadcast(&_this->hidden->cv);
SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
CondVar_Broadcast(&device->hidden->cv);
}
contextUnlock(_this);
contextUnlock(device);
ndspExit();
FreePrivateData(_this);
if (device->hidden->waveBuf[0].data_vaddr) {
linearFree((void *)device->hidden->waveBuf[0].data_vaddr);
}
if (device->hidden->mixbuf) {
SDL_free(device->hidden->mixbuf);
device->hidden->mixbuf = NULL;
}
SDL_free(device->hidden);
device->hidden = NULL;
}
static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *_this)
static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *device)
{
s32 current_priority;
svcGetThreadPriority(&current_priority, CUR_THREAD_HANDLE);
current_priority--;
/* 0x18 is reserved for video, 0x30 is the default for main thread */
// 0x18 is reserved for video, 0x30 is the default for main thread
current_priority = SDL_clamp(current_priority, 0x19, 0x2F);
svcSetThreadPriority(CUR_THREAD_HANDLE, current_priority);
}
static SDL_bool N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = N3DSAUDIO_OpenDevice;
impl->PlayDevice = N3DSAUDIO_PlayDevice;
impl->WaitDevice = N3DSAUDIO_WaitDevice;
impl->GetDeviceBuf = N3DSAUDIO_GetDeviceBuf;
impl->CloseDevice = N3DSAUDIO_CloseDevice;
impl->ThreadInit = N3DSAUDIO_ThreadInit;
impl->LockDevice = N3DSAUD_LockAudio;
impl->UnlockDevice = N3DSAUD_UnlockAudio;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
/* Should be possible, but micInit would fail */
// Should be possible, but micInit would fail
impl->HasCaptureSupport = SDL_FALSE;
impl->CaptureFromDevice = N3DSAUDIO_CaptureFromDevice;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap N3DSAUDIO_bootstrap = {
@@ -286,51 +280,4 @@ AudioBootStrap N3DSAUDIO_bootstrap = {
0
};
/**
* Cleans up all allocated memory, safe to call with null pointers
*/
static void FreePrivateData(SDL_AudioDevice *_this)
{
if (!_this->hidden) {
return;
}
if (_this->hidden->waveBuf[0].data_vaddr) {
linearFree((void *)_this->hidden->waveBuf[0].data_vaddr);
}
if (_this->hidden->mixbuf) {
SDL_free(_this->hidden->mixbuf);
_this->hidden->mixbuf = NULL;
}
SDL_free(_this->hidden);
_this->hidden = NULL;
}
static int FindAudioFormat(SDL_AudioDevice *_this)
{
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(_this->spec.format);
while ((test_format = *(closefmts++)) != 0) {
_this->spec.format = test_format;
switch (test_format) {
case SDL_AUDIO_S8:
/* Signed 8-bit audio supported */
_this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
_this->hidden->isSigned = 1;
_this->hidden->bytePerSample = _this->spec.channels;
return 0;
case SDL_AUDIO_S16:
/* Signed 16-bit audio supported */
_this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
_this->hidden->isSigned = 1;
_this->hidden->bytePerSample = _this->spec.channels * 2;
return 0;
}
}
return -1;
}
#endif /* SDL_AUDIO_DRIVER_N3DS */
#endif // SDL_AUDIO_DRIVER_N3DS
-6
View File
@@ -30,12 +30,6 @@ struct SDL_PrivateAudioData
{
/* Speaker data */
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 format;
Uint32 samplerate;
Uint32 channels;
Uint8 bytePerSample;
Uint32 isSigned;
Uint32 nextbuf;
ndspWaveBuf waveBuf[NUM_BUFFERS];
LightLock lock;
+107 -102
View File
@@ -22,10 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_NETBSD
/*
* Driver for native NetBSD audio(4).
* nia@NetBSD.org
*/
// Driver for native NetBSD audio(4).
#include <errno.h>
#include <unistd.h>
@@ -41,26 +38,26 @@
#include "../SDL_audiodev_c.h"
#include "SDL_netbsdaudio.h"
/* #define DEBUG_AUDIO */
//#define DEBUG_AUDIO
static void NETBSDAUDIO_DetectDevices(void)
static void NETBSDAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
SDL_EnumUnixAudioDevices(0, NULL);
SDL_EnumUnixAudioDevices(SDL_FALSE, NULL);
}
static void NETBSDAUDIO_Status(SDL_AudioDevice *_this)
static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
{
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */ /* clang-format off */
audio_info_t info;
const struct audio_prinfo *prinfo;
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
prinfo = _this->iscapture ? &info.record : &info.play;
prinfo = device->iscapture ? &info.record : &info.play;
fprintf(stderr, "\n"
"[%s info]\n"
@@ -77,7 +74,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *_this)
"waiting : %s\n"
"active : %s\n"
"",
_this->iscapture ? "record" : "play",
device->iscapture ? "record" : "play",
prinfo->buffer_size,
prinfo->sample_rate,
prinfo->channels,
@@ -103,7 +100,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *_this)
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
fprintf(stderr, "\n"
@@ -111,23 +108,46 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *_this)
"format : 0x%x\n"
"size : %u\n"
"",
_this->spec.format,
_this->spec.size);
device->spec.format,
device->buffer_size);
/* *INDENT-ON* */ /* clang-format on */
#endif /* DEBUG_AUDIO */
#endif // DEBUG_AUDIO
}
static void NETBSDAUDIO_PlayDevice(SDL_AudioDevice *_this)
static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = _this->hidden;
int written;
const SDL_bool iscapture = device->iscapture;
while (!SDL_AtomicGet(&device->shutdown)) {
audio_info_t info;
const int rc = ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info);
if (rc < 0) {
if (errno == EAGAIN) {
continue;
}
// Hmm, not much we can do - abort
fprintf(stderr, "netbsdaudio WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
SDL_AudioDeviceDisconnected(device);
return;
}
const size_t remain = (size_t)((iscapture ? info.record.seek : info.play.seek) * (SDL_AUDIO_BITSIZE(device->spec.format) / 8));
if (!iscapture && (remain >= device->buffer_size)) {
SDL_Delay(10);
} else if (iscapture && (remain < device->buffer_size)) {
SDL_Delay(10);
} else {
break; /* ready to go! */
}
}
}
/* Write the audio data */
written = write(h->audio_fd, h->mixbuf, h->mixlen);
static void NETBSDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = device->hidden;
const int written = write(h->audio_fd, buffer, buflen);
if (written == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
SDL_OpenedAudioDeviceDisconnected(_this);
// Non recoverable error has occurred. It should be reported!!!
SDL_AudioDeviceDisconnected(device);
perror("audio");
return;
}
@@ -137,19 +157,17 @@ static void NETBSDAUDIO_PlayDevice(SDL_AudioDevice *_this)
#endif
}
static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbuf;
return device->hidden->mixbuf;
}
static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *_buffer, int buflen)
static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *vbuffer, int buflen)
{
Uint8 *buffer = (Uint8 *)_buffer;
int br;
br = read(_this->hidden->audio_fd, buffer, buflen);
Uint8 *buffer = (Uint8 *)vbuffer;
const int br = read(device->hidden->audio_fd, buffer, buflen);
if (br == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
// Non recoverable error has occurred. It should be reported!!!
perror("audio");
return -1;
}
@@ -157,86 +175,73 @@ static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *_buffer,
#ifdef DEBUG_AUDIO
fprintf(stderr, "Captured %d bytes of audio data\n", br);
#endif
return 0;
return br;
}
static void NETBSDAUDIO_FlushCapture(SDL_AudioDevice *_this)
static void NETBSDAUDIO_FlushCapture(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = device->hidden;
audio_info_t info;
size_t remain;
Uint8 buf[512];
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return; /* oh well. */
}
remain = (size_t)(info.record.samples * (SDL_AUDIO_BITSIZE(_this->spec.format) / 8));
while (remain > 0) {
const size_t len = SDL_min(sizeof(buf), remain);
const int br = read(_this->hidden->audio_fd, buf, len);
if (br <= 0) {
return; /* oh well. */
if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) == 0) {
size_t remain = (size_t)(info.record.seek * (SDL_AUDIO_BITSIZE(device->spec.format) / 8));
while (remain > 0) {
char buf[512];
const size_t len = SDL_min(sizeof(buf), remain);
const ssize_t br = read(h->audio_fd, buf, len);
if (br <= 0) {
break;
}
remain -= br;
}
remain -= br;
}
}
static void NETBSDAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void NETBSDAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->audio_fd >= 0) {
close(_this->hidden->audio_fd);
if (device->hidden) {
if (device->hidden->audio_fd >= 0) {
close(device->hidden->audio_fd);
}
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
device->hidden = NULL;
}
SDL_free(_this->hidden->mixbuf);
SDL_free(_this->hidden);
}
static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_bool iscapture = _this->iscapture;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
const SDL_bool iscapture = device->iscapture;
int encoding = AUDIO_ENCODING_NONE;
audio_info_t info, hwinfo;
struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Initialize all variables that we clean on shutdown */
_this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
/* Open the audio device */
_this->hidden->audio_fd = open(devname, (iscapture ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
if (_this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
// 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);
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));
}
AUDIO_INITINFO(&info);
#ifdef AUDIO_GETFORMAT /* Introduced in NetBSD 9.0 */
if (ioctl(_this->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
/*
* Use the device's native sample rate so the kernel doesn't have to
* resample.
*/
_this->spec.freq = iscapture ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
#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;
}
#endif
prinfo->sample_rate = _this->spec.freq;
prinfo->channels = _this->spec.channels;
prinfo->sample_rate = device->spec.freq;
prinfo->channels = device->spec.channels;
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
switch (test_format) {
case SDL_AUDIO_U8:
@@ -271,56 +276,56 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
info.hiwat = 5;
info.lowat = 3;
if (ioctl(_this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
return SDL_SetError("AUDIO_SETINFO failed for %s: %s", devname, strerror(errno));
if (ioctl(device->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
return SDL_SetError("AUDIO_SETINFO failed for %s: %s", device->name, strerror(errno));
}
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return SDL_SetError("AUDIO_GETINFO failed for %s: %s", devname, strerror(errno));
if (ioctl(device->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return SDL_SetError("AUDIO_GETINFO failed for %s: %s", device->name, strerror(errno));
}
/* Final spec used for the device. */
_this->spec.format = test_format;
_this->spec.freq = prinfo->sample_rate;
_this->spec.channels = prinfo->channels;
// Final spec used for the device.
device->spec.format = test_format;
device->spec.freq = prinfo->sample_rate;
device->spec.channels = prinfo->channels;
SDL_CalculateAudioSpec(&_this->spec);
SDL_UpdatedAudioDeviceFormat(device);
if (!iscapture) {
/* Allocate mixing buffer */
_this->hidden->mixlen = _this->spec.size;
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
if (_this->hidden->mixbuf == NULL) {
// Allocate mixing buffer
device->hidden->mixlen = device->buffer_size;
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->hidden->mixlen);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
NETBSDAUDIO_Status(_this);
NETBSDAUDIO_Status(device);
/* We're ready to rock and roll. :-) */
return 0;
return 0; // We're ready to rock and roll. :-)
}
static SDL_bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->DetectDevices = NETBSDAUDIO_DetectDevices;
impl->OpenDevice = NETBSDAUDIO_OpenDevice;
impl->WaitDevice = NETBSDAUDIO_WaitDevice;
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->HasCaptureSupport = SDL_TRUE;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap NETBSDAUDIO_bootstrap = {
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_NETBSD */
#endif // SDL_AUDIO_DRIVER_NETBSD
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -32,11 +32,12 @@ struct SDL_PrivateAudioData
struct pw_thread_loop *loop;
struct pw_stream *stream;
struct pw_context *context;
struct SDL_DataQueue *buffer;
size_t input_buffer_packet_size;
Sint32 stride; /* Bytes-per-frame */
int stream_init_status;
// Set in GetDeviceBuf, filled in AudioThreadIterate, queued in PlayDevice
struct pw_buffer *pw_buf;
};
#endif /* SDL_pipewire_h_ */
+48 -63
View File
@@ -20,8 +20,6 @@
*/
#include "SDL_internal.h"
/* Output audio to nowhere... */
#include "../SDL_audio_c.h"
#include "SDL_ps2audio.h"
@@ -29,23 +27,15 @@
#include <audsrv.h>
#include <ps2_audio_driver.h>
/* The tag name used by PS2 audio */
#define PS2AUDIO_DRIVER_NAME "ps2"
static int PS2AUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int PS2AUDIO_OpenDevice(SDL_AudioDevice *device)
{
int i, mixlen;
struct audsrv_fmt_t format;
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
/* These are the native supported audio PS2 configs */
switch (_this->spec.freq) {
// These are the native supported audio PS2 configs
switch (device->spec.freq) {
case 11025:
case 12000:
case 22050:
@@ -53,93 +43,89 @@ static int PS2AUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
case 32000:
case 44100:
case 48000:
_this->spec.freq = _this->spec.freq;
break;
break; // acceptable value, keep it
default:
_this->spec.freq = 48000;
device->spec.freq = 48000;
break;
}
_this->spec.samples = 512;
_this->spec.channels = _this->spec.channels == 1 ? 1 : 2;
_this->spec.format = _this->spec.format == SDL_AUDIO_S8 ? SDL_AUDIO_S8 : SDL_AUDIO_S16;
device->sample_frames = 512;
device->spec.channels = device->spec.channels == 1 ? 1 : 2;
device->spec.format = device->spec.format == SDL_AUDIO_S8 ? SDL_AUDIO_S8 : SDL_AUDIO_S16;
SDL_CalculateAudioSpec(&_this->spec);
struct audsrv_fmt_t format;
format.bits = device->spec.format == SDL_AUDIO_S8 ? 8 : 16;
format.freq = device->spec.freq;
format.channels = device->spec.channels;
format.bits = _this->spec.format == SDL_AUDIO_S8 ? 8 : 16;
format.freq = _this->spec.freq;
format.channels = _this->spec.channels;
_this->hidden->channel = audsrv_set_format(&format);
device->hidden->channel = audsrv_set_format(&format);
audsrv_set_volume(MAX_VOLUME);
if (_this->hidden->channel < 0) {
SDL_aligned_free(_this->hidden->rawbuf);
_this->hidden->rawbuf = NULL;
if (device->hidden->channel < 0) {
return SDL_SetError("Couldn't reserve hardware channel");
}
/* Update the fragment size as size in bytes. */
SDL_CalculateAudioSpec(&_this->spec);
// Update the fragment size as size in bytes.
SDL_UpdatedAudioDeviceFormat(device);
/* Allocate the mixing buffer. Its size and starting address must
be a multiple of 64 bytes. Our sample count is already a multiple of
64, so spec->size should be a multiple of 64 as well. */
mixlen = _this->spec.size * NUM_BUFFERS;
_this->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (_this->hidden->rawbuf == NULL) {
const int mixlen = device->buffer_size * NUM_BUFFERS;
device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (device->hidden->rawbuf == NULL) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
SDL_memset(_this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
_this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size];
SDL_memset(device->hidden->rawbuf, device->silence_value, mixlen);
for (int i = 0; i < NUM_BUFFERS; i++) {
device->hidden->mixbufs[i] = &device->hidden->rawbuf[i * device->buffer_size];
}
_this->hidden->next_buffer = 0;
return 0;
}
static void PS2AUDIO_PlayDevice(SDL_AudioDevice *_this)
static void PS2AUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
uint8_t *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer];
audsrv_play_audio((char *)mixbuf, _this->spec.size);
_this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS;
audsrv_play_audio((char *)buffer, buflen);
}
/* This function waits until it is possible to write a full sound buffer */
static void PS2AUDIO_WaitDevice(SDL_AudioDevice *_this)
static void PS2AUDIO_WaitDevice(SDL_AudioDevice *device)
{
audsrv_wait_audio(_this->spec.size);
audsrv_wait_audio(device->buffer_size);
}
static Uint8 *PS2AUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *PS2AUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbufs[_this->hidden->next_buffer];
Uint8 *buffer = device->hidden->mixbufs[device->hidden->next_buffer];
device->hidden->next_buffer = (device->hidden->next_buffer + 1) % NUM_BUFFERS;
return buffer;
}
static void PS2AUDIO_CloseDevice(SDL_AudioDevice *_this)
static void PS2AUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->channel >= 0) {
audsrv_stop_audio();
_this->hidden->channel = -1;
}
if (device->hidden) {
if (device->hidden->channel >= 0) {
audsrv_stop_audio();
device->hidden->channel = -1;
}
if (_this->hidden->rawbuf != NULL) {
SDL_aligned_free(_this->hidden->rawbuf);
_this->hidden->rawbuf = NULL;
if (device->hidden->rawbuf != NULL) {
SDL_aligned_free(device->hidden->rawbuf);
device->hidden->rawbuf = NULL;
}
SDL_free(device->hidden);
device->hidden = NULL;
}
}
static void PS2AUDIO_ThreadInit(SDL_AudioDevice *_this)
static void PS2AUDIO_ThreadInit(SDL_AudioDevice *device)
{
/* Increase the priority of this audio thread by 1 to put it
ahead of other SDL threads. */
int32_t thid;
const int32_t thid = GetThreadId();
ee_thread_status_t status;
thid = GetThreadId();
if (ReferThreadStatus(GetThreadId(), &status) == 0) {
if (ReferThreadStatus(thid, &status) == 0) {
ChangeThreadPriority(thid, status.current_priority - 1);
}
}
@@ -155,7 +141,6 @@ static SDL_bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl)
return SDL_FALSE;
}
/* Set the function pointers */
impl->OpenDevice = PS2AUDIO_OpenDevice;
impl->PlayDevice = PS2AUDIO_PlayDevice;
impl->WaitDevice = PS2AUDIO_WaitDevice;
@@ -164,7 +149,7 @@ static SDL_bool PS2AUDIO_Init(SDL_AudioDriverImpl *impl)
impl->ThreadInit = PS2AUDIO_ThreadInit;
impl->Deinitialize = PS2AUDIO_Deinitialize;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE; // this audio target is available.
}
AudioBootStrap PS2AUDIO_bootstrap = {
+61 -76
View File
@@ -34,41 +34,34 @@
#include <pspaudio.h>
#include <pspthreadman.h>
/* The tag name used by PSP audio */
#define PSPAUDIO_DRIVER_NAME "psp"
static inline SDL_bool isBasicAudioConfig(const SDL_AudioSpec *spec)
{
return spec->freq == 44100;
}
static int PSPAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int PSPAUDIO_OpenDevice(SDL_AudioDevice *device)
{
int format, mixlen, i;
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
/* device only natively supports S16LSB */
_this->spec.format = SDL_AUDIO_S16LSB;
// device only natively supports S16LSB
device->spec.format = SDL_AUDIO_S16LSB;
/* PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
however with frequencies different than 44.1KHz, it just supports Stereo,
so a resampler must be done for these scenarios */
if (isBasicAudioConfig(&_this->spec)) {
/* The sample count must be a multiple of 64. */
_this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(_this->spec.samples);
/* The number of channels (1 or 2). */
_this->spec.channels = _this->spec.channels == 1 ? 1 : 2;
format = _this->spec.channels == 1 ? PSP_AUDIO_FORMAT_MONO : PSP_AUDIO_FORMAT_STEREO;
_this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, _this->spec.samples, format);
if (isBasicAudioConfig(&device->spec)) {
// The sample count must be a multiple of 64.
device->sample_frames = PSP_AUDIO_SAMPLE_ALIGN(device->sample_frames);
// The number of channels (1 or 2).
device->spec.channels = device->spec.channels == 1 ? 1 : 2;
const int format = (device->spec.channels == 1) ? PSP_AUDIO_FORMAT_MONO : PSP_AUDIO_FORMAT_STEREO;
device->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, device->sample_frames, format);
} else {
/* 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11050, 8000 */
switch (_this->spec.freq) {
// 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11050, 8000
switch (device->spec.freq) {
case 8000:
case 11025:
case 12000:
@@ -78,93 +71,90 @@ static int PSPAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
case 32000:
case 44100:
case 48000:
_this->spec.freq = _this->spec.freq;
break;
break; // acceptable, keep it
default:
_this->spec.freq = 48000;
device->spec.freq = 48000;
break;
}
/* The number of samples to output in one output call (min 17, max 4111). */
_this->spec.samples = _this->spec.samples < 17 ? 17 : (_this->spec.samples > 4111 ? 4111 : _this->spec.samples);
_this->spec.channels = 2; /* we're forcing the hardware to stereo. */
_this->hidden->channel = sceAudioSRCChReserve(_this->spec.samples, _this->spec.freq, 2);
// The number of samples to output in one output call (min 17, max 4111).
device->sample_frames = device->sample_frames < 17 ? 17 : (device->sample_frames > 4111 ? 4111 : device->sample_frames);
device->spec.channels = 2; // we're forcing the hardware to stereo.
device->hidden->channel = sceAudioSRCChReserve(device->sample_frames, device->spec.freq, 2);
}
if (_this->hidden->channel < 0) {
SDL_aligned_free(_this->hidden->rawbuf);
_this->hidden->rawbuf = NULL;
if (device->hidden->channel < 0) {
return SDL_SetError("Couldn't reserve hardware channel");
}
/* Update the fragment size as size in bytes. */
SDL_CalculateAudioSpec(&_this->spec);
// Update the fragment size as size in bytes.
SDL_UpdatedAudioDeviceFormat(device);
/* Allocate the mixing buffer. Its size and starting address must
be a multiple of 64 bytes. Our sample count is already a multiple of
64, so spec->size should be a multiple of 64 as well. */
mixlen = _this->spec.size * NUM_BUFFERS;
_this->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (_this->hidden->rawbuf == NULL) {
const int mixlen = device->buffer_size * NUM_BUFFERS;
device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (device->hidden->rawbuf == NULL) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
SDL_memset(_this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
_this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size];
SDL_memset(device->hidden->rawbuf, device->silence_value, mixlen);
for (int i = 0; i < NUM_BUFFERS; i++) {
device->hidden->mixbufs[i] = &device->hidden->rawbuf[i * device->buffer_size];
}
_this->hidden->next_buffer = 0;
return 0;
}
static void PSPAUDIO_PlayDevice(SDL_AudioDevice *_this)
static void PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
Uint8 *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer];
if (!isBasicAudioConfig(&_this->spec)) {
SDL_assert(_this->spec.channels == 2);
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, mixbuf);
if (!isBasicAudioConfig(&device->spec)) {
SDL_assert(device->spec.channels == 2);
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, (void *) buffer);
} else {
sceAudioOutputPannedBlocking(_this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
sceAudioOutputPannedBlocking(device->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, (void *) buffer);
}
_this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
/* This function waits until it is possible to write a full sound buffer */
static void PSPAUDIO_WaitDevice(SDL_AudioDevice *_this)
static void PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
// Because we block when sending audio, there's no need for this function to do anything.
}
static Uint8 *PSPAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *PSPAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbufs[_this->hidden->next_buffer];
Uint8 *buffer = device->hidden->mixbufs[device->hidden->next_buffer];
device->hidden->next_buffer = (device->hidden->next_buffer + 1) % NUM_BUFFERS;
return buffer;
}
static void PSPAUDIO_CloseDevice(SDL_AudioDevice *_this)
static void PSPAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->channel >= 0) {
if (!isBasicAudioConfig(&_this->spec)) {
sceAudioSRCChRelease();
} else {
sceAudioChRelease(_this->hidden->channel);
if (device->hidden) {
if (device->hidden->channel >= 0) {
if (!isBasicAudioConfig(&device->spec)) {
sceAudioSRCChRelease();
} else {
sceAudioChRelease(device->hidden->channel);
}
device->hidden->channel = -1;
}
_this->hidden->channel = -1;
}
if (_this->hidden->rawbuf != NULL) {
SDL_aligned_free(_this->hidden->rawbuf);
_this->hidden->rawbuf = NULL;
if (device->hidden->rawbuf != NULL) {
SDL_aligned_free(device->hidden->rawbuf);
device->hidden->rawbuf = NULL;
}
SDL_free(device->hidden);
device->hidden = NULL;
}
}
static void PSPAUDIO_ThreadInit(SDL_AudioDevice *_this)
static void PSPAUDIO_ThreadInit(SDL_AudioDevice *device)
{
/* Increase the priority of this audio thread by 1 to put it
ahead of other SDL threads. */
SceUID thid;
const SceUID thid = sceKernelGetThreadId();
SceKernelThreadInfo status;
thid = sceKernelGetThreadId();
status.size = sizeof(SceKernelThreadInfo);
if (sceKernelReferThreadStatus(thid, &status) == 0) {
sceKernelChangeThreadPriority(thid, status.currentPriority - 1);
@@ -173,25 +163,20 @@ static void PSPAUDIO_ThreadInit(SDL_AudioDevice *_this)
static SDL_bool PSPAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = PSPAUDIO_OpenDevice;
impl->PlayDevice = PSPAUDIO_PlayDevice;
impl->WaitDevice = PSPAUDIO_WaitDevice;
impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf;
impl->CloseDevice = PSPAUDIO_CloseDevice;
impl->ThreadInit = PSPAUDIO_ThreadInit;
/* PSP audio device */
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
/*
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
*/
return SDL_TRUE; /* this audio target is available. */
//impl->HasCaptureSupport = SDL_TRUE;
//impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
return SDL_TRUE;
}
AudioBootStrap PSPAUDIO_bootstrap = {
"psp", "PSP audio driver", PSPAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_PSP */
#endif // SDL_AUDIO_DRIVER_PSP
File diff suppressed because it is too large Load Diff
-1
View File
@@ -36,7 +36,6 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
int bytes_requested; /* bytes of data the hardware wants _now_. */
File diff suppressed because it is too large Load Diff
+4 -17
View File
@@ -30,23 +30,10 @@
struct SDL_PrivateAudioData
{
/* SDL capture state */
SDL_bool iscapture;
/* The audio device handle */
int cardno;
int deviceno;
snd_pcm_t *audio_handle;
/* The audio file descriptor */
int audio_fd;
/* Select timeout status */
uint32_t timeout_on_wait;
/* Raw mixing buffer */
Uint8 *pcm_buf;
Uint32 pcm_len;
snd_pcm_t *audio_handle; // The audio device handle
int audio_fd; // The audio file descriptor, for selecting on
SDL_bool timeout_on_wait; // Select timeout status
Uint8 *pcm_buf; // Raw mixing buffer
};
#endif /* __SDL_QSA_AUDIO_H__ */
+101 -106
View File
@@ -23,7 +23,7 @@
#ifdef SDL_AUDIO_DRIVER_SNDIO
/* OpenBSD sndio target */
// OpenBSD sndio target
#ifdef HAVE_STDIO_H
#include <stdio.h>
@@ -72,14 +72,13 @@ static int load_sndio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(sndio_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return 0;
return 0; // Don't call SDL_SetError(): SDL_LoadFunction already did.
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
// cast funcs to char* first, to please GCC's strict aliasing rules.
#define SDL_SNDIO_SYM(x) \
if (!load_sndio_sym(#x, (void **)(char *)&SNDIO_##x)) \
return -1
@@ -123,8 +122,7 @@ static int LoadSNDIOLibrary(void)
if (sndio_handle == NULL) {
sndio_handle = SDL_LoadObject(sndio_library);
if (sndio_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
retval = -1; // Don't call SDL_SetError(): SDL_LoadObject already did.
} else {
retval = load_sndio_syms();
if (retval < 0) {
@@ -147,129 +145,128 @@ static int LoadSNDIOLibrary(void)
return 0;
}
#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
#endif // SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static void SNDIO_WaitDevice(SDL_AudioDevice *_this)
static void SNDIO_WaitDevice(SDL_AudioDevice *device)
{
/* no-op; SNDIO_sio_write() blocks if necessary. */
const SDL_bool iscapture = device->iscapture;
while (!SDL_AtomicGet(&device->shutdown)) {
if (SNDIO_sio_eof(device->hidden->dev)) {
SDL_AudioDeviceDisconnected(device);
return;
}
const int nfds = SNDIO_sio_pollfd(device->hidden->dev, device->hidden->pfd, iscapture ? POLLIN : POLLOUT);
if (nfds <= 0 || poll(device->hidden->pfd, nfds, 10) < 0) {
SDL_AudioDeviceDisconnected(device);
return;
}
const int revents = SNDIO_sio_revents(device->hidden->dev, device->hidden->pfd);
if (iscapture && (revents & POLLIN)) {
return;
} else if (!iscapture && (revents & POLLOUT)) {
return;
} else if (revents & POLLHUP) {
SDL_AudioDeviceDisconnected(device);
return;
}
}
}
static void SNDIO_PlayDevice(SDL_AudioDevice *_this)
static void SNDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
const int written = SNDIO_sio_write(_this->hidden->dev,
_this->hidden->mixbuf,
_this->hidden->mixlen);
/* If we couldn't write, assume fatal error for now */
if (written == 0) {
SDL_OpenedAudioDeviceDisconnected(_this);
// !!! FIXME: this should be non-blocking so we can check device->shutdown.
// this is set to blocking, because we _have_ to send the entire buffer down, but hopefully WaitDevice took most of the delay time.
if (SNDIO_sio_write(device->hidden->dev, buffer, buflen) != buflen) {
SDL_AudioDeviceDisconnected(device); // If we couldn't write, assume fatal error for now
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static int SNDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
static int SNDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
size_t r;
int revents;
int nfds;
/* Emulate a blocking read */
r = SNDIO_sio_read(_this->hidden->dev, buffer, buflen);
while (r == 0 && !SNDIO_sio_eof(_this->hidden->dev)) {
nfds = SNDIO_sio_pollfd(_this->hidden->dev, _this->hidden->pfd, POLLIN);
if (nfds <= 0 || poll(_this->hidden->pfd, nfds, INFTIM) < 0) {
return -1;
}
revents = SNDIO_sio_revents(_this->hidden->dev, _this->hidden->pfd);
if (revents & POLLIN) {
r = SNDIO_sio_read(_this->hidden->dev, buffer, buflen);
}
if (revents & POLLHUP) {
break;
}
// We set capture 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;
}
return (int)r;
return (int) br;
}
static void SNDIO_FlushCapture(SDL_AudioDevice *_this)
static void SNDIO_FlushCapture(SDL_AudioDevice *device)
{
char buf[512];
while (SNDIO_sio_read(_this->hidden->dev, buf, sizeof(buf)) != 0) {
/* do nothing */;
while (!SDL_AtomicGet(&device->shutdown) && (SNDIO_sio_read(device->hidden->dev, buf, sizeof(buf)) > 0)) {
// do nothing
}
}
static Uint8 *SNDIO_GetDeviceBuf(SDL_AudioDevice *_this)
static Uint8 *SNDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
return _this->hidden->mixbuf;
return device->hidden->mixbuf;
}
static void SNDIO_CloseDevice(SDL_AudioDevice *_this)
static void SNDIO_CloseDevice(SDL_AudioDevice *device)
{
if (_this->hidden->pfd != NULL) {
SDL_free(_this->hidden->pfd);
if (device->hidden) {
if (device->hidden->dev != NULL) {
SNDIO_sio_stop(device->hidden->dev);
SNDIO_sio_close(device->hidden->dev);
}
SDL_free(device->hidden->pfd);
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden);
device->hidden = NULL;
}
if (_this->hidden->dev != NULL) {
SNDIO_sio_stop(_this->hidden->dev);
SNDIO_sio_close(_this->hidden->dev);
}
SDL_free(_this->hidden->mixbuf);
SDL_free(_this->hidden);
}
static int SNDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
static int SNDIO_OpenDevice(SDL_AudioDevice *device)
{
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts;
struct sio_par par;
SDL_bool iscapture = _this->iscapture;
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(_this->hidden);
_this->hidden->mixlen = _this->spec.size;
// !!! 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 */
_this->hidden->dev = SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
iscapture ? SIO_REC : SIO_PLAY, iscapture);
if (_this->hidden->dev == NULL) {
// Capture devices must be non-blocking for SNDIO_FlushCapture
device->hidden->dev = SNDIO_sio_open(audiodev != NULL ? audiodev : SIO_DEVANY,
device->iscapture ? SIO_REC : SIO_PLAY, device->iscapture);
if (device->hidden->dev == NULL) {
return SDL_SetError("sio_open() failed");
}
/* Allocate the pollfd array for capture devices */
if (iscapture) {
_this->hidden->pfd = SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(_this->hidden->dev));
if (_this->hidden->pfd == NULL) {
return SDL_OutOfMemory();
}
device->hidden->pfd = SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(device->hidden->dev));
if (device->hidden->pfd == NULL) {
return SDL_OutOfMemory();
}
struct sio_par par;
SNDIO_sio_initpar(&par);
par.rate = _this->spec.freq;
par.pchan = _this->spec.channels;
par.round = _this->spec.samples;
par.rate = device->spec.freq;
par.pchan = device->spec.channels;
par.round = device->sample_frames;
par.appbufsz = par.round * 2;
/* Try for a closest match on audio format */
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
// Try for a closest match on audio format
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
if (!SDL_AUDIO_ISFLOAT(test_format)) {
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
par.bits = SDL_AUDIO_BITSIZE(test_format);
if (SNDIO_sio_setpar(_this->hidden->dev, &par) == 0) {
if (SNDIO_sio_setpar(device->hidden->dev, &par) == 0) {
continue;
}
if (SNDIO_sio_getpar(_this->hidden->dev, &par) == 0) {
if (SNDIO_sio_getpar(device->hidden->dev, &par) == 0) {
return SDL_SetError("sio_getpar() failed");
}
if (par.bps != SIO_BPS(par.bits)) {
@@ -282,46 +279,44 @@ static int SNDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
}
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "sndio");
return SDL_SetError("sndio: Unsupported audio format");
}
if ((par.bps == 4) && (par.sig) && (par.le)) {
_this->spec.format = SDL_AUDIO_S32LSB;
device->spec.format = SDL_AUDIO_S32LSB;
} else if ((par.bps == 4) && (par.sig) && (!par.le)) {
_this->spec.format = SDL_AUDIO_S32MSB;
device->spec.format = SDL_AUDIO_S32MSB;
} else if ((par.bps == 2) && (par.sig) && (par.le)) {
_this->spec.format = SDL_AUDIO_S16LSB;
device->spec.format = SDL_AUDIO_S16LSB;
} else if ((par.bps == 2) && (par.sig) && (!par.le)) {
_this->spec.format = SDL_AUDIO_S16MSB;
device->spec.format = SDL_AUDIO_S16MSB;
} else if ((par.bps == 1) && (par.sig)) {
_this->spec.format = SDL_AUDIO_S8;
device->spec.format = SDL_AUDIO_S8;
} else if ((par.bps == 1) && (!par.sig)) {
_this->spec.format = SDL_AUDIO_U8;
device->spec.format = SDL_AUDIO_U8;
} else {
return SDL_SetError("sndio: Got unsupported hardware audio format.");
}
_this->spec.freq = par.rate;
_this->spec.channels = par.pchan;
_this->spec.samples = par.round;
device->spec.freq = par.rate;
device->spec.channels = par.pchan;
device->sample_frames = par.round;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
// Calculate the final parameters for this audio specification
SDL_UpdatedAudioDeviceFormat(device);
/* Allocate mixing buffer */
_this->hidden->mixlen = _this->spec.size;
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
if (_this->hidden->mixbuf == NULL) {
// Allocate mixing buffer
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->hidden->mixlen);
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
if (!SNDIO_sio_start(_this->hidden->dev)) {
if (!SNDIO_sio_start(device->hidden->dev)) {
return SDL_SetError("sio_start() failed");
}
/* We're ready to rock and roll. :-) */
return 0;
return 0; // We're ready to rock and roll. :-)
}
static void SNDIO_Deinitialize(void)
@@ -329,10 +324,10 @@ static void SNDIO_Deinitialize(void)
UnloadSNDIOLibrary();
}
static void SNDIO_DetectDevices(void)
static void SNDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
*default_output = SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *)0x1);
*default_capture = SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *)0x2);
}
static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
@@ -341,12 +336,12 @@ static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
return SDL_FALSE;
}
/* Set the function pointers */
impl->OpenDevice = SNDIO_OpenDevice;
impl->WaitDevice = SNDIO_WaitDevice;
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->Deinitialize = SNDIO_Deinitialize;
@@ -355,11 +350,11 @@ static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap SNDIO_bootstrap = {
"sndio", "OpenBSD sndio", SNDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_SNDIO */
#endif // SDL_AUDIO_DRIVER_SNDIO
+3 -9
View File
@@ -30,15 +30,9 @@
struct SDL_PrivateAudioData
{
/* The audio device handle */
struct sio_hdl *dev;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Polling structures for non-blocking sndio devices */
struct pollfd *pfd;
struct sio_hdl *dev; // The audio device handle
Uint8 *mixbuf; // Raw mixing buffer
struct pollfd *pfd; // Polling structures for non-blocking sndio devices
};
#endif /* SDL_sndioaudio_h_ */

Some files were not shown because too many files have changed in this diff Show More