mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-09 01:59:49 -10:00
Audio and record initializations are unified by providing helper functions for opening the audio device and for setting the device parameters. The ioctl calls are properly checked for errors and log an appropriate error message. The init fails if the requested parameters are not supported by the device, i.e. 44.1kHz 16bit stereo for playback. This provides consistent behavior with all the other audio backends.
152 lines
2.7 KiB
C++
152 lines
2.7 KiB
C++
#ifdef USE_OSS
|
|
#include "audiostream.h"
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/soundcard.h>
|
|
#include <unistd.h>
|
|
|
|
class OSSAudioBackend : public AudioBackend
|
|
{
|
|
int audioFD = -1;
|
|
int recordFD = -1;
|
|
|
|
static int openDevice(int flags)
|
|
{
|
|
const char* path = "/dev/dsp";
|
|
int fd = open(path, flags);
|
|
|
|
if (fd < 0)
|
|
ERROR_LOG(AUDIO, "OSS: open(%s) failed: %s", path, strerror(errno));
|
|
|
|
return fd;
|
|
}
|
|
|
|
static bool setRate(int fd, int rate)
|
|
{
|
|
int tmp = rate;
|
|
|
|
if (ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SPEED) failed: %s", strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
if (tmp != rate)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: sample rate unsupported: %d => %d", rate, tmp);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool setChannels(int fd, int channels)
|
|
{
|
|
int tmp = channels;
|
|
|
|
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_CHANNELS) failed: %s", strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
if (tmp != channels)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: channels unsupported: %d => %d", channels, tmp);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool setFormat(int fd, int format)
|
|
{
|
|
int tmp = format;
|
|
|
|
if (ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: ioctl(SNDCTL_DSP_SETFMT) failed: %s", strerror(errno));
|
|
return false;
|
|
}
|
|
|
|
if (tmp != format)
|
|
{
|
|
ERROR_LOG(AUDIO, "OSS: sample format unsupported: %#.8x => %#.8x", format, tmp);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public:
|
|
OSSAudioBackend()
|
|
: AudioBackend("oss", "Open Sound System") {}
|
|
|
|
bool init() override
|
|
{
|
|
audioFD = openDevice(O_WRONLY);
|
|
|
|
if (audioFD < 0 || !setRate(audioFD, 44100) || !setChannels(audioFD, 2) || !setFormat(audioFD, AFMT_S16_LE))
|
|
{
|
|
term();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
u32 push(const void* frame, u32 samples, bool wait) override
|
|
{
|
|
write(audioFD, frame, samples * 4);
|
|
return 1;
|
|
}
|
|
|
|
void term() override
|
|
{
|
|
if (audioFD >= 0)
|
|
close(audioFD);
|
|
audioFD = -1;
|
|
}
|
|
|
|
// recording untested
|
|
|
|
bool initRecord(u32 sampling_freq) override
|
|
{
|
|
recordFD = openDevice(O_RDONLY);
|
|
|
|
if (recordFD < 0 || !setRate(recordFD, sampling_freq) || !setChannels(recordFD, 1) || !setFormat(recordFD, AFMT_S16_NE /* Native 16 bits */ ))
|
|
{
|
|
termRecord();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void termRecord() override
|
|
{
|
|
if (recordFD >= 0)
|
|
close(recordFD);
|
|
recordFD = -1;
|
|
}
|
|
|
|
u32 record(void *buffer, u32 samples) override
|
|
{
|
|
samples *= 2;
|
|
int l = read(recordFD, buffer, samples);
|
|
if (l < (int)samples)
|
|
{
|
|
if (l < 0)
|
|
{
|
|
INFO_LOG(AUDIO, "OSS: Recording error");
|
|
l = 0;
|
|
}
|
|
memset((u8 *)buffer + l, 0, samples - l);
|
|
}
|
|
return l / 2;
|
|
}
|
|
};
|
|
static OSSAudioBackend ossAudioBackend;
|
|
|
|
#endif
|