ref: 623f5427f2e5d9cbc7540e8e2a72981c973e4cac
dir: /libnpe_sdl2/audio.c/
#include <SDL2/SDL.h>
enum {
Aout = 2,
Arec,
Audiobufsz = 8192,
};
typedef struct Audiodev Audiodev;
struct Audiodev {
QLock;
void (*cb)(void *, Uint8 *, int);
void *userdata;
char *name;
Channel *wait;
int paused;
int fd;
int pid;
int mode;
Uint8 buf[Audiobufsz];
};
/* FIXME extra USB audio devices? */
static Audiodev au[4] = {
[0] = {.fd = -1, .mode = -1},
[1] = {.fd = -1, .mode = -1},
[Aout] = {.name = "/dev/audio", .fd = -1, .pid = -1, .mode = OWRITE},
[Arec] = {.name = "/dev/audio", .fd = -1, .pid = -1, .mode = OREAD},
};
int
SDL_GetNumAudioDevices(int iscapture)
{
/* FIXME look for extra USB devices? */
USED(iscapture);
return 1;
}
char *
SDL_GetAudioDeviceName(int index, int iscapture)
{
/* FIXME look for extra USB devices? */
USED(index);
return au[iscapture ? Arec : Aout].name;
}
void
SDL_LockAudioDevice(SDL_AudioDeviceID id)
{
qlock(&au[id]);
}
void
SDL_UnlockAudioDevice(SDL_AudioDeviceID id)
{
qunlock(&au[id]);
}
static void
audiothread(void *p)
{
Audiodev *a;
a = p;
threadsetname("%s (%s)", a->name, a->mode == OREAD ? "out" : "in");
for(;;){
qlock(a);
if(a->paused)
memset(a->buf, 0, sizeof(a->buf));
else
a->cb(a->userdata, a->buf, sizeof(a->buf));
qunlock(a);
if(write(a->fd, a->buf, sizeof(a->buf)) != sizeof(a->buf))
break;
}
sendul(a->wait, 0);
threadexits(nil);
}
void
SDL_PauseAudioDevice(SDL_AudioDeviceID id, SDL_bool pause)
{
Audiodev *a;
a = &au[id];
if(a->paused && !pause){
if(a->pid < 0)
a->pid = proccreate(audiothread, a, mainstacksize);
a->paused = 0;
}else if(!a->paused && pause){
a->paused = 1;
}
}
SDL_AudioDeviceID
SDL_OpenAudioDevice(char *dev, int rec, SDL_AudioSpec *want, SDL_AudioSpec *have, u32int change)
{
Audiodev *a;
SDL_AudioDeviceID id;
/* FIXME look for extra USB devices? */
USED(dev);
if(change != SDL_AUDIO_ALLOW_ANY_CHANGE){ /* FIXME sampling in mono */
werrstr("SDL_OpenAudioDevice: changes not implemented");
return 0;
}
have->freq = 44100;
have->format = AUDIO_S16;
have->channels = 2;
have->samples = want->samples;
id = rec ? Arec : Aout;
a = &au[id];
if(a->fd < 0 && (a->fd = open("/dev/audio", a->mode|OCEXEC)) < 0){
werrstr("SDL_OpenAudioDevice: %r");
return 0;
}
a->userdata = want->userdata;
a->cb = want->callback;
a->paused = 1;
a->wait = chancreate(sizeof(ulong), 0);
return id;
}
void
SDL_CloseAudioDevice(SDL_AudioDeviceID id)
{
Audiodev *a;
a = &au[id];
qlock(a);
close(a->fd);
a->fd = -1;
a->pid = -1;
a->userdata = nil;
a->cb = nil;
qunlock(a);
recvul(a->wait);
chanfree(a->wait);
}