This source file includes following definitions.
- OSS_Setup
- OSS_Shutdown
- OSS_ConfigureOutput
- OSS_WriteAudio
- OSS_SetVolume
- OSS_SetPan
- OSS_SetPriority
- OSS_GetAudioDelay
- OSS_QueryOutputSampleRate
- NewOSSRender
- DeleteOSSRender
- QueryInterfaces
- LoadInterface
- ShutdownInterface
#if defined(__DARWIN__) || defined(__APPLE__)
#include <soundcard.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#else
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef OSS_FIX_INC
#include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif
#endif
#include <gpac/modules/audio_out.h>
#define OSS_AUDIO_DEVICE "/dev/dsp"
typedef struct
{
int audio_dev, sr, nb_ch;
u32 buf_size, delay, num_buffers, total_duration;
u32 force_sr;
char *wav_buf;
} OSSContext;
#define OSSCTX() OSSContext *ctx = (OSSContext *)dr->opaque;
static GF_Err OSS_Setup(GF_AudioOutput*dr, void *os_handle, u32 num_buffers, u32 total_duration)
{
int audio;
const char *opt;
OSSCTX();
opt = gf_modules_get_option((GF_BaseInterface *)dr, "OSS", "ForceSampleRate");
if (opt) ctx->force_sr = atoi(opt);
audio = open(OSS_AUDIO_DEVICE, 0);
if (audio < 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[OSS] Cannot open audio device\n"));
return GF_NOT_SUPPORTED;
}
ctx->audio_dev=audio;
ctx->num_buffers = num_buffers;
ctx->total_duration = total_duration;
return GF_OK;
}
static void OSS_Shutdown(GF_AudioOutput*dr)
{
OSSCTX();
ioctl(ctx->audio_dev,SNDCTL_DSP_RESET,NULL);
close(ctx->audio_dev);
if (ctx->wav_buf) gf_free(ctx->wav_buf);
ctx->wav_buf = NULL;
}
static GF_Err OSS_ConfigureOutput(GF_AudioOutput*dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg)
{
int format, blockalign, nb_bufs, frag_spec;
long flags;
OSSCTX();
if (!ctx) return GF_BAD_PARAM;
ioctl(ctx->audio_dev,SNDCTL_DSP_RESET,NULL);
close(ctx->audio_dev);
if (ctx->wav_buf) gf_free(ctx->wav_buf);
ctx->wav_buf = NULL;
ctx->audio_dev=open(OSS_AUDIO_DEVICE,O_WRONLY|O_NONBLOCK);
if (!ctx->audio_dev) return GF_IO_ERR;
flags = fcntl(ctx->audio_dev, F_GETFL);
flags &= ~O_NONBLOCK;
if (fcntl(ctx->audio_dev, F_SETFL, flags) < 0 ) return GF_IO_ERR;
ctx->nb_ch = (int) (*NbChannels);
if (ioctl(ctx->audio_dev, SNDCTL_DSP_CHANNELS, &ctx->nb_ch)==-1) return GF_IO_ERR;
blockalign = ctx->nb_ch;
if ((*nbBitsPerSample) == 16) {
blockalign *= 2;
format = AFMT_S16_LE;
} else {
format = AFMT_S8;
}
if(ioctl(ctx->audio_dev, SNDCTL_DSP_SETFMT,&format)==-1) return GF_IO_ERR;
ctx->sr = (*SampleRate);
if(ioctl(ctx->audio_dev, SNDCTL_DSP_SPEED,&ctx->sr)==-1) return GF_IO_ERR;
nb_bufs = ctx->num_buffers ? ctx->num_buffers : 8;
ctx->buf_size = (*SampleRate * blockalign * ctx->total_duration) / (1000 * nb_bufs);
frag_spec = 4;
while (ctx->buf_size > (1<<(frag_spec+1)))
frag_spec++;
ctx->buf_size = 1<<frag_spec;
ctx->delay = (1000*ctx->buf_size) / (*SampleRate * blockalign);
frag_spec = ((nb_bufs<<16) & 0xFFFF0000) | frag_spec;
ctx->delay = (1000*ctx->buf_size*nb_bufs) / (*SampleRate * blockalign);
if ( ioctl(ctx->audio_dev, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) return GF_IO_ERR;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[OSS] setup %d buffers %d bytes each (%d ms buffer delay)", nb_bufs, ctx->buf_size, ctx->delay));
ctx->wav_buf = gf_realloc(ctx->wav_buf, ctx->buf_size*sizeof(char));
if(!ctx->wav_buf) return GF_OUT_OF_MEM;
memset(ctx->wav_buf, 0, ctx->buf_size*sizeof(char));
return GF_OK;
}
static void OSS_WriteAudio(GF_AudioOutput*dr)
{
u32 written;
OSSCTX();
written = dr->FillBuffer(dr->audio_renderer, ctx->wav_buf, ctx->buf_size);
if (written) {
u32 reallyWritten = write(ctx->audio_dev, ctx->wav_buf, written);
if (reallyWritten != written) {
GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[OSS] Failed to write all audio to device, has written %u, should have %u", reallyWritten, written));
}
}
}
static void OSS_SetVolume(GF_AudioOutput*dr, u32 Volume) {}
static void OSS_SetPan(GF_AudioOutput*dr, u32 Pan) {}
static void OSS_SetPriority(GF_AudioOutput*dr, u32 Priority) {}
static u32 OSS_GetAudioDelay(GF_AudioOutput*dr)
{
OSSCTX()
return ctx->delay;
}
static GF_Err OSS_QueryOutputSampleRate(GF_AudioOutput*dr, u32 *desired_sr, u32 *NbChannels, u32 *nbBitsPerSample)
{
#ifdef FORCE_SR_LIMIT
*NbChannels = 2;
if (!( *desired_sr % 11025)) return GF_OK;
if (*desired_sr<22050) *desired_sr = 22050;
else *desired_sr = 44100;
return GF_OK;
#else
int i;
OSSCTX();
if (ctx->force_sr) {
*desired_sr = ctx->force_sr;
return GF_OK;
}
i=*desired_sr;
if(ioctl(ctx->audio_dev, SNDCTL_DSP_SPEED,&i)==-1) return GF_IO_ERR;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[OSS] uses samplerate %d for desired sr %d\n", i, *desired_sr));
*desired_sr = i;
i = *NbChannels;
if(ioctl(ctx->audio_dev,SNDCTL_DSP_CHANNELS, &i)==-1) return GF_IO_ERR;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[OSS] uses %d channels for %d desired ones\n", i, *NbChannels));
*NbChannels = i;
if(ioctl(ctx->audio_dev, SNDCTL_DSP_SPEED,&ctx->sr)==-1) return GF_OK;
if(ioctl(ctx->audio_dev,SNDCTL_DSP_CHANNELS, &ctx->nb_ch)==-1) return GF_OK;
return GF_OK;
#endif
}
void *NewOSSRender()
{
OSSContext *ctx;
GF_AudioOutput*driv;
ctx = gf_malloc(sizeof(OSSContext));
if(!ctx)
return NULL;
memset(ctx, 0, sizeof(OSSContext));
driv = gf_malloc(sizeof(GF_AudioOutput));
if(!driv)
{
gf_free(ctx);
ctx=NULL;
return NULL;
}
memset(driv, 0, sizeof(GF_AudioOutput));
driv->opaque = ctx;
driv->SelfThreaded = 0;
driv->Setup = OSS_Setup;
driv->Shutdown = OSS_Shutdown;
driv->ConfigureOutput = OSS_ConfigureOutput;
driv->GetAudioDelay = OSS_GetAudioDelay;
driv->SetVolume = OSS_SetVolume;
driv->SetPan = OSS_SetPan;
driv->SetPriority = OSS_SetPriority;
driv->QueryOutputSampleRate = OSS_QueryOutputSampleRate;
driv->WriteAudio = OSS_WriteAudio;
GF_REGISTER_MODULE_INTERFACE(driv, GF_AUDIO_OUTPUT_INTERFACE, "OSS Audio Output", "gpac distribution");
return driv;
}
void DeleteOSSRender(void *ifce)
{
GF_AudioOutput*dr = (GF_AudioOutput*) ifce;
OSSContext *ctx = (OSSContext *)dr->opaque;
gf_free(ctx);
gf_free(dr);
}
GPAC_MODULE_EXPORT
const u32 *QueryInterfaces()
{
static u32 si [] = {
GF_AUDIO_OUTPUT_INTERFACE,
0
};
return si;
}
GPAC_MODULE_EXPORT
GF_BaseInterface *LoadInterface(u32 InterfaceType)
{
if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE)
return NewOSSRender();
return NULL;
}
GPAC_MODULE_EXPORT
void ShutdownInterface(GF_BaseInterface *ifce)
{
if (ifce->InterfaceType==GF_AUDIO_OUTPUT_INTERFACE)
DeleteOSSRender((GF_AudioOutput*)ifce);
}
GPAC_MODULE_STATIC_DECLARATION( oss )