ossaudio.c revision 6118dbd9bcc98e911ff1007153dee8113337d10d
/*
* QEMU OSS audio driver
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef VBOX
#define LOG_GROUP LOG_GROUP_DEV_AUDIO
#endif
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/soundcard.h>
#include "Builtins.h"
#include "../../vl_vbox.h"
#include "audio.h"
#define AUDIO_CAP "oss"
#include "audio_int.h"
typedef struct OSSVoiceOut {
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
#ifndef RT_OS_L4
int mmapped;
#endif
int old_optr;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int old_optr;
} OSSVoiceIn;
static struct {
#ifndef RT_OS_L4
int try_mmap;
#endif
int nfrags;
int fragsize;
const char *devpath_out;
const char *devpath_in;
int debug;
} conf = {
#ifndef RT_OS_L4
INIT_FIELD (try_mmap =) 0,
#endif
INIT_FIELD (debug =) 0,
};
struct oss_params {
int freq;
int nchannels;
int nfrags;
int fragsize;
};
{
}
#ifndef VBOX
int err,
const char *typ,
const char *fmt,
...
)
{
}
#endif
static void oss_anal_close (int *fdp)
{
if (err) {
}
*fdp = -1;
}
{
}
{
switch (fmt) {
case AUD_FMT_S8:
return AFMT_S8;
case AUD_FMT_U8:
return AFMT_U8;
case AUD_FMT_S16:
return AFMT_S16_LE;
case AUD_FMT_U16:
return AFMT_U16_LE;
default:
#ifdef DEBUG_AUDIO
abort ();
#endif
return AFMT_U8;
}
}
{
switch (ossfmt) {
case AFMT_S8:
*endianness = 0;
*fmt = AUD_FMT_S8;
break;
case AFMT_U8:
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case AFMT_S16_LE:
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_LE:
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case AFMT_S16_BE:
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_BE:
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
default:
return -1;
}
return 0;
}
#if defined DEBUG_MISMATCHES || defined DEBUG
{
dolog ("parameter | requested value | obtained value\n");
dolog ("channels | %10d | %10d\n",
dolog ("fragsize | %10d | %10d\n",
}
#endif
{
int fd;
int mmmmssss;
if (-1 == fd) {
#ifndef VBOX
#else
LogRel(("OSS: Failed to open %s for %s (%s)\n",
#endif
return -1;
}
#ifdef VBOX
#endif
#ifndef VBOX
#else
LogRel(("OSS: Failed to set sample size %d (%s)\n",
#endif
goto err;
}
#ifndef VBOX
#else
LogRel(("OSS: Failed to set nchannels=%d (%s)\n",
#endif
goto err;
}
#ifndef VBOX
#else
#endif
goto err;
}
#ifndef VBOX
#else
#endif
goto err;
}
#ifndef VBOX
#else
LogRel(("OSS: Failed to set buffer_length=%d,%d (%s)\n",
#endif
goto err;
}
#ifndef VBOX
#else
#endif
goto err;
}
#ifdef DEBUG_MISMATCHES
dolog ("Audio parameters mismatch\n");
}
#endif
#ifdef DEBUG
#endif
return 0;
err:
oss_anal_close (&fd);
#ifdef VBOX
LogRel(("OSS: Closed %s for %s\n",
#endif
return -1;
}
{
int samples;
struct audio_buf_info abinfo;
#ifndef RT_OS_L4
struct count_info cntinfo;
#endif
int bufsize;
if (!live) {
return 0;
}
#ifndef RT_OS_L4
int bytes;
if (err < 0) {
return 0;
}
dolog ("warning: Overrun\n");
}
return 0;
}
}
else {
}
}
else {
#endif
if (err < 0) {
return 0;
}
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
}
}
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
}
return 0;
}
if (!decr) {
return 0;
}
#ifndef RT_OS_L4
}
#endif
while (samples) {
#ifdef RT_OS_L4
{
#else
#endif
int written;
/* XXX: follow errno recommendations ? */
if (written == -1) {
"Failed to write %d bytes of audio data from %p\n",
);
continue;
}
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
}
#if 0
#endif
break;
}
}
#if 0
#endif
}
#ifndef RT_OS_L4
}
#endif
return decr;
}
{
#ifndef RT_OS_L4
int err;
#endif
ldebug ("oss_fini\n");
#ifdef VBOX
#endif
#ifdef RT_OS_L4
#else
if (err) {
}
}
else {
}
#endif
}
}
{
int endianness;
int err;
int fd;
return -1;
}
if (err) {
oss_anal_close (&fd);
#ifdef VBOX
#endif
return -1;
}
dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
}
#ifndef RT_OS_L4
0,
fd,
0
);
} else {
int err;
int trig = 0;
}
else {
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
}
else {
}
}
if (err) {
}
}
}
}
#endif
#ifndef RT_OS_L4
#endif
);
dolog (
"Could not allocate DAC buffer (%d samples, each %d bytes)\n",
);
oss_anal_close (&fd);
#ifdef VBOX
#endif
return -1;
}
#ifndef RT_OS_L4
}
#endif
return 0;
}
{
int trig;
#ifdef RT_OS_L4
return 0;
#else
return 0;
}
#endif
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
return -1;
}
break;
case VOICE_DISABLE:
ldebug ("disabling voice\n");
trig = 0;
return -1;
}
break;
}
return 0;
}
{
int endianness;
int err;
int fd;
return -1;
}
if (err) {
oss_anal_close (&fd);
#ifdef VBOX
#endif
return -1;
}
dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
}
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
oss_anal_close (&fd);
#ifdef VBOX
#endif
return -1;
}
return 0;
}
{
#ifdef VBOX
#endif
}
}
{
int i;
size_t read_samples = 0;
struct {
int add;
int len;
} bufs[2];
if (!dead) {
return 0;
}
}
else {
}
for (i = 0; i < 2; ++i) {
if (nread > 0) {
dolog ("warning: Misaligned read %"
FMTZ "d (requested %d), "
}
#ifndef VBOX
#else
#endif
}
if (nread == -1) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
"Failed to read %d bytes of audio (to %p)\n",
);
break;
}
}
break;
}
}
}
return read_samples;
}
{
}
{
(void) hw;
(void) cmd;
return 0;
}
static void *oss_audio_init (void)
{
return &conf;
}
static void oss_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option oss_options[] = {
"Fragment size in bytes", NULL, 0},
"Number of fragments", NULL, 0},
#ifndef RT_OS_L4
"Try using memory mapped access", NULL, 0},
#endif
"Path to DAC device", NULL, 0},
"Path to ADC device", NULL, 0},
"Turn on some debugging messages", NULL, 0},
};
static struct audio_pcm_ops oss_pcm_ops = {
};
struct audio_driver oss_audio_driver = {
};