Store the frame size for the SDL2 backend
[openal-soft.git] / Alc / backends / sdl2.c
blobf301cf481cfac5e0e3bccb16c443a72dc36aa0df
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2018 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <SDL2/SDL.h>
26 #include "alMain.h"
27 #include "alu.h"
28 #include "threads.h"
29 #include "compat.h"
31 #include "backends/base.h"
34 typedef struct ALCsdl2Backend {
35 DERIVE_FROM_TYPE(ALCbackend);
37 SDL_AudioDeviceID deviceID;
38 ALsizei frameSize;
40 ALuint Frequency;
41 enum DevFmtChannels FmtChans;
42 enum DevFmtType FmtType;
43 ALuint UpdateSize;
44 } ALCsdl2Backend;
46 static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device);
47 static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self);
48 static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name);
49 static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self);
50 static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self);
51 static void ALCsdl2Backend_stop(ALCsdl2Backend *self);
52 static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
53 static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples)
54 static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency)
55 static void ALCsdl2Backend_lock(ALCsdl2Backend *self);
56 static void ALCsdl2Backend_unlock(ALCsdl2Backend *self);
57 DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend)
59 DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend);
61 static const ALCchar defaultDeviceName[] = "Default device";
63 static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device)
65 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
66 SET_VTABLE2(ALCsdl2Backend, ALCbackend, self);
68 self->deviceID = 0;
69 self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
70 self->Frequency = device->Frequency;
71 self->FmtChans = device->FmtChans;
72 self->FmtType = device->FmtType;
73 self->UpdateSize = device->UpdateSize;
76 static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self)
78 if(self->deviceID)
79 SDL_CloseAudioDevice(self->deviceID);
80 self->deviceID = 0;
82 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
86 static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len)
88 ALCsdl2Backend *self = (ALCsdl2Backend*)ptr;
89 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
91 assert((len % self->frameSize) == 0);
92 aluMixData(device, stream, len / self->frameSize);
95 static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name)
97 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
98 SDL_AudioSpec want, have;
99 SDL_zero(want);
100 want.freq = device->Frequency;
101 want.format = AUDIO_F32;
102 want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2;
103 want.samples = device->UpdateSize;
104 want.callback = ALCsdl2Backend_audioCallback;
105 want.userdata = self;
107 if (name && strcmp(name, defaultDeviceName) == 0)
108 name = NULL; // Passing NULL to SDL_OpenAudioDevice is special and will NOT select the first
109 // device in the list.
110 self->deviceID = SDL_OpenAudioDevice(name, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
111 if(self->deviceID == 0)
112 return ALC_INVALID_VALUE;
114 device->Frequency = have.freq;
115 if(have.channels == 1)
116 device->FmtChans = DevFmtMono;
117 else if(have.channels == 2)
118 device->FmtChans = DevFmtStereo;
119 else
121 ERR("Got unhandled SDL channel count: %d\n", (int)have.channels);
122 return ALC_INVALID_VALUE;
124 switch(have.format)
126 case AUDIO_U8: device->FmtType = DevFmtUByte; break;
127 case AUDIO_S8: device->FmtType = DevFmtByte; break;
128 case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break;
129 case AUDIO_S16SYS: device->FmtType = DevFmtShort; break;
130 case AUDIO_S32SYS: device->FmtType = DevFmtInt; break;
131 case AUDIO_F32SYS: device->FmtType = DevFmtFloat; break;
132 default:
133 ERR("Got unsupported SDL format: 0x%04x\n", have.format);
134 return ALC_INVALID_VALUE;
136 device->UpdateSize = have.samples;
137 device->NumUpdates = 2; /* SDL always (tries to) use two periods. */
139 self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
140 self->Frequency = device->Frequency;
141 self->FmtChans = device->FmtChans;
142 self->FmtType = device->FmtType;
143 self->UpdateSize = device->UpdateSize;
145 alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName);
147 return ALC_NO_ERROR;
150 static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self)
152 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
153 device->Frequency = self->Frequency;
154 device->FmtChans = self->FmtChans;
155 device->FmtType = self->FmtType;
156 device->UpdateSize = self->UpdateSize;
157 device->NumUpdates = 2;
158 SetDefaultWFXChannelOrder(device);
159 return ALC_TRUE;
162 static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self)
164 SDL_PauseAudioDevice(self->deviceID, 0);
165 return ALC_TRUE;
168 static void ALCsdl2Backend_stop(ALCsdl2Backend *self)
170 SDL_PauseAudioDevice(self->deviceID, 1);
173 static void ALCsdl2Backend_lock(ALCsdl2Backend *self)
175 SDL_LockAudioDevice(self->deviceID);
178 static void ALCsdl2Backend_unlock(ALCsdl2Backend *self)
180 SDL_UnlockAudioDevice(self->deviceID);
184 typedef struct ALCsdl2BackendFactory {
185 DERIVE_FROM_TYPE(ALCbackendFactory);
186 } ALCsdl2BackendFactory;
187 #define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } }
189 ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void);
191 static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self);
192 static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self);
193 static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type);
194 static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type);
195 static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type);
196 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory);
199 ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void)
201 static ALCsdl2BackendFactory factory = ALCsdl2BACKENDFACTORY_INITIALIZER;
202 return STATIC_CAST(ALCbackendFactory, &factory);
206 static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self))
208 if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0)
209 return AL_TRUE;
210 return ALC_FALSE;
213 static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self))
215 SDL_QuitSubSystem(SDL_INIT_AUDIO);
218 static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type)
220 if(type == ALCbackend_Playback)
221 return ALC_TRUE;
222 return ALC_FALSE;
225 static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type)
227 int num_devices, i;
229 if(type != ALL_DEVICE_PROBE)
230 return;
232 num_devices = SDL_GetNumAudioDevices(SDL_FALSE);
234 AppendAllDevicesList(defaultDeviceName);
235 for(i = 0;i < num_devices;++i)
236 AppendAllDevicesList(SDL_GetAudioDeviceName(i, SDL_FALSE));
239 static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
241 if(type == ALCbackend_Playback)
243 ALCsdl2Backend *backend;
244 NEW_OBJ(backend, ALCsdl2Backend)(device);
245 if(!backend) return NULL;
246 return STATIC_CAST(ALCbackend, backend);
249 return NULL;