Built SDL2_image and _mixer static
This commit is contained in:
59
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/Makemodule.am
vendored
Normal file
59
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/Makemodule.am
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# Module for non-recursive mpg123 build system.
|
||||
|
||||
include src/libout123/modules/Makemodule.am
|
||||
|
||||
# Precursor to the proper libout123.
|
||||
# For now only wrapping the module loader or the legacy module.
|
||||
noinst_LTLIBRARIES += src/libout123/libmodule.la
|
||||
|
||||
lib_LTLIBRARIES += src/libout123/libout123.la
|
||||
src_libout123_libout123_la_SOURCES = \
|
||||
src/libout123/libout123.c \
|
||||
src/libout123/stringlists.h \
|
||||
src/libout123/stringlists.c \
|
||||
src/libout123/out123_int.h \
|
||||
src/libout123/wav.c \
|
||||
src/libout123/wav.h \
|
||||
src/libout123/wavhead.h
|
||||
|
||||
if BUILD_BUFFER
|
||||
src_libout123_libout123_la_SOURCES += \
|
||||
src/libout123/buffer.c \
|
||||
src/libout123/buffer.h \
|
||||
src/libout123/xfermem.c \
|
||||
src/libout123/xfermem.h
|
||||
endif
|
||||
|
||||
src_libout123_libout123_la_LDFLAGS = \
|
||||
-no-undefined -version-info @LIBOUT123_VERSION@ -export-symbols-regex '^out123_'
|
||||
|
||||
src_libout123_libout123_la_LIBADD = \
|
||||
src/libout123/libmodule.la \
|
||||
src/compat/libcompat.la
|
||||
|
||||
if !HAVE_MODULES
|
||||
src_libout123_libout123_la_LIBADD += \
|
||||
src/libout123/modules/libdefaultmodule.la
|
||||
endif
|
||||
|
||||
src_libout123_libmodule_la_SOURCES = src/libout123/module.h
|
||||
|
||||
if HAVE_MODULES
|
||||
|
||||
src_libout123_libmodule_la_SOURCES += src/libout123/module.c
|
||||
|
||||
else
|
||||
|
||||
src_libout123_libmodule_la_SOURCES += src/libout123/legacy_module.c
|
||||
|
||||
endif
|
||||
|
||||
|
||||
# The sfifo code is directly used in some modules.
|
||||
EXTRA_DIST += \
|
||||
src/libout123/out123.h.in \
|
||||
src/libout123/sfifo.c \
|
||||
src/libout123/sfifo.h
|
||||
|
||||
nodist_include_HEADERS += \
|
||||
src/libout123/out123.h
|
||||
974
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/buffer.c
vendored
Normal file
974
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/buffer.c
vendored
Normal file
@@ -0,0 +1,974 @@
|
||||
/*
|
||||
buffer.c: output buffer
|
||||
|
||||
copyright 1997-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Oliver Fromme
|
||||
|
||||
I (ThOr) am reviewing this file at about the same daytime as Oliver's timestamp here:
|
||||
Mon Apr 14 03:53:18 MET DST 1997
|
||||
- dammed night coders;-)
|
||||
|
||||
This has been heavily reworked to be barely recognizable for the creation of
|
||||
libout123. There is more structure in the communication, as is necessary if
|
||||
the libout123 functionality is offered via some API to unknown client
|
||||
programs instead of being used from mpg123 alone. The basic idea is the same,
|
||||
the xfermem part only sligthly modified for more synchronization, as I sensed
|
||||
potential deadlocks. --ThOr
|
||||
*/
|
||||
|
||||
/*
|
||||
Communication to the buffer is normally via xfermem_putcmd() and blocking
|
||||
on a response, relying on the buffer process periodically checking for
|
||||
pending commands.
|
||||
|
||||
For more immediate concerns, you can send SIGINT. The only result is that this
|
||||
interrupts a current device writing operation and causes the buffer to wait
|
||||
for a following command.
|
||||
*/
|
||||
|
||||
/* Needed for kill() from signal.h. */
|
||||
#define _POSIX_SOURCE
|
||||
|
||||
#include "buffer.h"
|
||||
#include "out123_int.h"
|
||||
#include "xfermem.h"
|
||||
#include <errno.h>
|
||||
#include "debug.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_SIGNAL_H
|
||||
#include <sys/signal.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define BUF_CMD_OPEN XF_CMD_CUSTOM1
|
||||
#define BUF_CMD_CLOSE XF_CMD_CUSTOM2
|
||||
#define BUF_CMD_START XF_CMD_CUSTOM3
|
||||
#define BUF_CMD_STOP XF_CMD_CUSTOM4
|
||||
#define BUF_CMD_AUDIOCAP XF_CMD_CUSTOM5
|
||||
#define BUF_CMD_PARAM XF_CMD_CUSTOM6
|
||||
#define BUF_CMD_NDRAIN XF_CMD_CUSTOM7
|
||||
#define BUF_CMD_AUDIOFMT XF_CMD_CUSTOM8
|
||||
|
||||
/* TODO: Dynamically allocate that to allow multiple instances. */
|
||||
int outburst = 32768;
|
||||
|
||||
/* This is static and global for the forked buffer process.
|
||||
Another forked buffer process will have its on value. */
|
||||
static int intflag = FALSE;
|
||||
|
||||
static void catch_interrupt (void)
|
||||
{
|
||||
intflag = TRUE;
|
||||
}
|
||||
|
||||
static int read_record(out123_handle *ao
|
||||
, int who, void **buf, byte *prebuf, int *preoff, int presize, size_t *recsize);
|
||||
static int buffer_loop(out123_handle *ao);
|
||||
|
||||
static void catch_child(void)
|
||||
{
|
||||
/* Disabled for now. We do not really need that.
|
||||
Rather get return status in a controlled way in buffer_exit(). */
|
||||
/* while (waitpid(-1, NULL, WNOHANG) > 0); */
|
||||
}
|
||||
|
||||
/*
|
||||
Functions called from the controlling process.
|
||||
*/
|
||||
|
||||
/* Start a buffer process. */
|
||||
int buffer_init(out123_handle *ao, size_t bytes)
|
||||
{
|
||||
buffer_exit(ao);
|
||||
if(bytes < outburst) bytes = 2*outburst;
|
||||
|
||||
#ifdef DONT_CATCH_SIGNALS
|
||||
#error I really need to catch signals here!
|
||||
#endif
|
||||
xfermem_init(&ao->buffermem, bytes, 0, 0);
|
||||
/* Is catch_child() really useful? buffer_exit() does waitpid().
|
||||
And if buffer_exit() is not called, the main process might be
|
||||
killed off and not be able to run a signal handler anyway. */
|
||||
catchsignal(SIGCHLD, catch_child);
|
||||
switch((ao->buffer_pid = fork()))
|
||||
{
|
||||
case -1: /* error */
|
||||
if(!AOQUIET)
|
||||
error("cannot fork!");
|
||||
goto buffer_init_bad;
|
||||
case 0: /* child */
|
||||
{
|
||||
int ret;
|
||||
/*
|
||||
Ensure the normal default value for buffer_pid to be able
|
||||
to call normal out123 routines from the buffer proess.
|
||||
One could keep it at zero and even use this for detecting the
|
||||
buffer process and do special stuff for that. But the point
|
||||
is that there shouldn't be special stuff.
|
||||
*/
|
||||
ao->buffer_pid = -1;
|
||||
/* Not preparing audio output anymore, that comes later. */
|
||||
xfermem_init_reader(ao->buffermem);
|
||||
ret = buffer_loop(ao); /* Here the work happens. */
|
||||
xfermem_done_reader(ao->buffermem);
|
||||
xfermem_done(ao->buffermem);
|
||||
/* Proper cleanup of output handle, including out123_close(). */
|
||||
out123_del(ao);
|
||||
exit(ret);
|
||||
}
|
||||
default: /* parent */
|
||||
{
|
||||
int cmd;
|
||||
xfermem_init_writer(ao->buffermem);
|
||||
debug("waiting for inital pong from buffer process");
|
||||
if( (cmd=xfermem_getcmd(ao->buffermem->fd[XF_WRITER], TRUE))
|
||||
!= XF_CMD_PONG )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error2("Got %i instead of expected initial response %i. Killing rogue buffer process."
|
||||
, cmd, XF_CMD_PONG);
|
||||
kill(ao->buffer_pid, SIGKILL);
|
||||
buffer_exit(ao);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
buffer_init_bad:
|
||||
if(ao->buffermem)
|
||||
{
|
||||
xfermem_done(ao->buffermem);
|
||||
ao->buffermem = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* End a buffer process. */
|
||||
void buffer_exit(out123_handle *ao)
|
||||
{
|
||||
int status = 0;
|
||||
if(ao->buffer_pid == -1) return;
|
||||
|
||||
debug("ending buffer");
|
||||
buffer_stop(ao); /* Puts buffer into waiting-for-command mode. */
|
||||
buffer_end(ao); /* Gives command to end operation. */
|
||||
xfermem_done_writer(ao->buffermem);
|
||||
waitpid(ao->buffer_pid, &status, 0);
|
||||
xfermem_done(ao->buffermem);
|
||||
ao->buffermem = NULL;
|
||||
ao->buffer_pid = -1;
|
||||
if(WIFEXITED(status))
|
||||
{
|
||||
int ret = WEXITSTATUS(status);
|
||||
if(ret && !AOQUIET)
|
||||
error1("Buffer process isses arose, non-zero return value %i.", ret);
|
||||
}
|
||||
else if(!AOQUIET)
|
||||
error("Buffer process did not exit normally.");
|
||||
}
|
||||
|
||||
/*
|
||||
Communication from writer to reader (buffer process).
|
||||
Remember: The ao struct here is the writer's instance.
|
||||
*/
|
||||
|
||||
static int buffer_cmd_finish(out123_handle *ao)
|
||||
{
|
||||
/* Only if buffer returns XF_CMD_OK we got lucky. Otherwise, we expect
|
||||
the buffer to deliver a reason right after XF_CMD_ERROR. */
|
||||
switch(xfermem_getcmd(ao->buffermem->fd[XF_WRITER], TRUE))
|
||||
{
|
||||
case XF_CMD_OK: return 0;
|
||||
case XF_CMD_ERROR:
|
||||
if(!GOOD_READVAL(ao->buffermem->fd[XF_WRITER], ao->errcode))
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int buffer_sync_param(out123_handle *ao)
|
||||
{
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_PARAM) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
/* Calling an external serialization routine to avoid forgetting
|
||||
any fresh parameters here. */
|
||||
if(write_parameters(ao, XF_WRITER))
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
return buffer_cmd_finish(ao);
|
||||
}
|
||||
|
||||
int buffer_open(out123_handle *ao, const char* driver, const char* device)
|
||||
{
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_OPEN) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
/* Passing over driver and device name. */
|
||||
if( xfer_write_string(ao, XF_WRITER, driver)
|
||||
|| xfer_write_string(ao, XF_WRITER, device) )
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(buffer_cmd_finish(ao) == 0)
|
||||
/* Retrieve driver and device name. */
|
||||
return ( xfer_read_string(ao, XF_WRITER, &ao->driver)
|
||||
|| xfer_read_string(ao, XF_WRITER, &ao->device)
|
||||
|| xfer_read_string(ao, XF_WRITER, &ao->realname) );
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int buffer_encodings(out123_handle *ao)
|
||||
{
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_AUDIOCAP) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
/* Now shoving over the parameters for opening the device. */
|
||||
if(
|
||||
!GOOD_WRITEVAL(writerfd, ao->channels)
|
||||
|| !GOOD_WRITEVAL(writerfd, ao->rate)
|
||||
)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(buffer_cmd_finish(ao) == 0)
|
||||
{
|
||||
int encodings;
|
||||
/* If all good, the answer can be read how. */
|
||||
if(!GOOD_READVAL(writerfd, encodings))
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
else return encodings;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int buffer_formats( out123_handle *ao, const long *rates, int ratecount
|
||||
, int minchannels, int maxchannels
|
||||
, struct mpg123_fmt **fmtlist )
|
||||
{
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
size_t ratesize;
|
||||
|
||||
debug("buffer_formats");
|
||||
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_AUDIOFMT) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ratesize = ratecount*sizeof(rates);
|
||||
|
||||
if(
|
||||
!GOOD_WRITEVAL(writerfd, maxchannels)
|
||||
|| !GOOD_WRITEVAL(writerfd, minchannels)
|
||||
|| !GOOD_WRITEVAL(writerfd, ratesize)
|
||||
|| !GOOD_WRITEBUF(writerfd, rates, ratesize)
|
||||
){
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if(buffer_cmd_finish(ao) == 0)
|
||||
{
|
||||
int fmtcount;
|
||||
size_t fmtsize;
|
||||
if(
|
||||
!GOOD_READVAL(writerfd, fmtcount)
|
||||
|| read_record(ao, XF_WRITER, (void**)fmtlist, NULL, NULL, 0, &fmtsize)
|
||||
){
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
} else
|
||||
return fmtsize/sizeof(struct mpg123_fmt);
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int buffer_start(out123_handle *ao)
|
||||
{
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_START) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
/* Now shoving over the parameters for opening the device. */
|
||||
if(
|
||||
!GOOD_WRITEVAL(writerfd, ao->format)
|
||||
|| !GOOD_WRITEVAL(writerfd, ao->channels)
|
||||
|| !GOOD_WRITEVAL(writerfd, ao->rate)
|
||||
)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return buffer_cmd_finish(ao);
|
||||
}
|
||||
|
||||
#define BUFFER_SIMPLE_CONTROL(name, cmd) \
|
||||
void name(out123_handle *ao) \
|
||||
{ \
|
||||
xfermem_putcmd(ao->buffermem->fd[XF_WRITER], cmd); \
|
||||
xfermem_getcmd(ao->buffermem->fd[XF_WRITER], TRUE); \
|
||||
}
|
||||
|
||||
BUFFER_SIMPLE_CONTROL(buffer_stop, BUF_CMD_STOP)
|
||||
BUFFER_SIMPLE_CONTROL(buffer_continue, XF_CMD_CONTINUE)
|
||||
BUFFER_SIMPLE_CONTROL(buffer_ignore_lowmem, XF_CMD_IGNLOW)
|
||||
BUFFER_SIMPLE_CONTROL(buffer_drain, XF_CMD_DRAIN)
|
||||
BUFFER_SIMPLE_CONTROL(buffer_end, XF_CMD_TERMINATE)
|
||||
BUFFER_SIMPLE_CONTROL(buffer_close, BUF_CMD_CLOSE)
|
||||
|
||||
#define BUFFER_SIGNAL_CONTROL(name, cmd) \
|
||||
void name(out123_handle *ao) \
|
||||
{ \
|
||||
kill(ao->buffer_pid, SIGINT); \
|
||||
xfermem_putcmd(ao->buffermem->fd[XF_WRITER], cmd); \
|
||||
xfermem_getcmd(ao->buffermem->fd[XF_WRITER], TRUE); \
|
||||
}
|
||||
|
||||
BUFFER_SIGNAL_CONTROL(buffer_pause, XF_CMD_PAUSE)
|
||||
BUFFER_SIGNAL_CONTROL(buffer_drop, XF_CMD_DROP)
|
||||
|
||||
size_t buffer_fill(out123_handle *ao)
|
||||
{
|
||||
return xfermem_get_usedspace(ao->buffermem);
|
||||
}
|
||||
|
||||
void buffer_ndrain(out123_handle *ao, size_t bytes)
|
||||
{
|
||||
size_t oldfill;
|
||||
int writerfd = ao->buffermem->fd[XF_WRITER];
|
||||
|
||||
oldfill = buffer_fill(ao);
|
||||
if(xfermem_putcmd(writerfd, BUF_CMD_NDRAIN) != 1)
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return;
|
||||
}
|
||||
/* Now shoving over the parameters for opening the device. */
|
||||
if( !GOOD_WRITEVAL(writerfd, bytes)
|
||||
|| !GOOD_WRITEVAL(writerfd, oldfill) )
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_cmd_finish(ao);
|
||||
}
|
||||
|
||||
/* The workhorse: Send data to the buffer with some synchronization and even
|
||||
error checking. */
|
||||
size_t buffer_write(out123_handle *ao, void *buffer, size_t bytes)
|
||||
{
|
||||
/*
|
||||
Writing the whole buffer in one piece is no good as that means
|
||||
waiting for the buffer being empty. That is called a buffer underrun.
|
||||
We want to refill the buffer before that happens. So, what is sane?
|
||||
*/
|
||||
size_t written = 0;
|
||||
size_t max_piece = ao->buffermem->size / 2;
|
||||
while(bytes)
|
||||
{
|
||||
size_t count_piece = bytes > max_piece
|
||||
? max_piece
|
||||
: bytes;
|
||||
int ret = xfermem_write(ao->buffermem
|
||||
, (char*)buffer+written, count_piece);
|
||||
if(ret)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("writing to buffer memory failed (%i)", ret);
|
||||
if(ret == XF_CMD_ERROR)
|
||||
{
|
||||
/* Buffer tells me that it has an error waiting. */
|
||||
if(!GOOD_READVAL(ao->buffermem->fd[XF_WRITER], ao->errcode))
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bytes -= count_piece;
|
||||
written += count_piece;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Code for the buffer process itself.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
buffer loop:
|
||||
|
||||
{
|
||||
1. normal operation: get data, feed to audio device
|
||||
(if device open and alive, if data there, if no other command pending)
|
||||
2. command response: pause/unpause, open module/device, query caps
|
||||
|
||||
One command at a time, synchronized ... writer process blocks, waiting for
|
||||
response.
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Fill buffer to that value when starting playback from stopped state or after
|
||||
experiencing a serious underrun.
|
||||
One might also define intermediate preload to recover from underruns. Earlier
|
||||
code used 1/8 of the buffer.
|
||||
*/
|
||||
static size_t preload_size(out123_handle *ao)
|
||||
{
|
||||
size_t preload = 0;
|
||||
txfermem *xf = ao->buffermem;
|
||||
/* Fill configured part of buffer on first run before starting to play.
|
||||
* Live mp3 streams constantly approach buffer underrun otherwise. [dk]
|
||||
*/
|
||||
if(ao->preload > 0.) preload = (size_t)(ao->preload*xf->size);
|
||||
if(preload > xf->size/2) preload = xf->size/2;
|
||||
|
||||
return preload;
|
||||
}
|
||||
|
||||
/* Play one piece of audio from the buffer after settling preload etc.
|
||||
On error, the device is closed and this naturally stops playback
|
||||
as that depends on ao->state == play_live.
|
||||
This plays _at_ _most_ the given amount of bytes, usually less. */
|
||||
static void buffer_play(out123_handle *ao, size_t bytes)
|
||||
{
|
||||
size_t written;
|
||||
txfermem *xf = ao->buffermem;
|
||||
/* Settle amount of bytes accessible in one block. */
|
||||
if (bytes > xf->size - xf->readindex)
|
||||
bytes = xf->size - xf->readindex;
|
||||
/* Not more than configured output block. */
|
||||
if (bytes > outburst)
|
||||
bytes = outburst;
|
||||
/* The output can only take multiples of framesize. */
|
||||
bytes -= bytes % ao->framesize;
|
||||
/* Actual work by out123_play to ensure logic like automatic continue. */
|
||||
written = out123_play(ao, (unsigned char*)xf->data+xf->readindex, bytes);
|
||||
/* Advance read pointer by the amount of written bytes. */
|
||||
xf->readindex = (xf->readindex + written) % xf->size;
|
||||
/* Detect a fatal error by proxy. */
|
||||
if(ao->errcode == OUT123_DEV_PLAY)
|
||||
out123_close(ao);
|
||||
}
|
||||
|
||||
/* Now I'm getting really paranoid: Helper to skip bytes from command
|
||||
channel if we cannot allocate enough memory to hold the data. */
|
||||
static void skip_bytes(int fd, size_t count)
|
||||
{
|
||||
while(count)
|
||||
{
|
||||
char buf[1024];
|
||||
if(!unintr_read(fd, buf, (count < sizeof(buf) ? count : sizeof(buf))))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a string to command channel.
|
||||
Return 0 on success, set ao->errcode on issues. */
|
||||
int xfer_write_string(out123_handle *ao, int who, const char *buf)
|
||||
{
|
||||
txfermem *xf = ao->buffermem;
|
||||
int my_fd = xf->fd[who];
|
||||
size_t len;
|
||||
|
||||
/* A NULL string is passed als zero bytes. */
|
||||
len = buf ? (strlen(buf)+1) : 0;
|
||||
if( !GOOD_WRITEVAL(my_fd, len)
|
||||
|| !GOOD_WRITEBUF(my_fd, buf, len) )
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int xfer_read_string(out123_handle *ao, int who, char **buf)
|
||||
{
|
||||
/* ao->errcode set in read_record() */
|
||||
return read_record(ao, who, (void**)buf, NULL, NULL, 0, NULL)
|
||||
? -1 /* read_record could return 2, normalize to -1 */
|
||||
: 0;
|
||||
}
|
||||
|
||||
/* Read a value from command channel with prebuffer.
|
||||
This assumes responsible use and avoids needless checking of input.
|
||||
And, yes, it modifies the preoff argument!
|
||||
Returns 0 on success, modifies prebuffer fill. */
|
||||
int read_buf(int fd, void *addr, size_t size, byte *prebuf, int *preoff, int presize)
|
||||
{
|
||||
size_t need = size;
|
||||
|
||||
if(prebuf)
|
||||
{
|
||||
int have = presize - *preoff;
|
||||
if(have > need)
|
||||
have = need;
|
||||
memcpy(addr, prebuf+*preoff, have);
|
||||
*preoff += have;
|
||||
addr = (char*)addr+have;
|
||||
need -= have;
|
||||
}
|
||||
if(need)
|
||||
return !GOOD_READBUF(fd, addr, need);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read a record of unspecified type from command channel.
|
||||
Return 0 on success, set ao->errcode on issues. */
|
||||
static int read_record(out123_handle *ao
|
||||
, int who, void **buf, byte *prebuf, int *preoff, int presize
|
||||
, size_t *reclen)
|
||||
{
|
||||
txfermem *xf = ao->buffermem;
|
||||
int my_fd = xf->fd[who];
|
||||
size_t len;
|
||||
|
||||
if(*buf)
|
||||
free(*buf);
|
||||
*buf = NULL;
|
||||
|
||||
if(read_buf(my_fd, &len, sizeof(len), prebuf, preoff, presize))
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
return 2;
|
||||
}
|
||||
if(reclen)
|
||||
*reclen = len;
|
||||
/* If there is an insane length of given, that shall be handled. */
|
||||
if(len && !(*buf = malloc(len)))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
skip_bytes(my_fd, len);
|
||||
return -1;
|
||||
}
|
||||
if(read_buf(my_fd, *buf, len, prebuf, preoff, presize))
|
||||
{
|
||||
ao->errcode = OUT123_BUFFER_ERROR;
|
||||
free(*buf);
|
||||
*buf = NULL;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The main loop, returns 0 when no issue occured. */
|
||||
int buffer_loop(out123_handle *ao)
|
||||
{
|
||||
txfermem *xf = ao->buffermem;
|
||||
int my_fd = xf->fd[XF_READER];
|
||||
int preloading = FALSE;
|
||||
int draining = FALSE;
|
||||
/* The buffer loop maintains a playback state that can differ from
|
||||
the underlying device's. During prebuffering, the device is paused,
|
||||
but we are playing (as soon as enough data is there, the device is,
|
||||
too). */
|
||||
enum playstate mystate = ao->state;
|
||||
|
||||
ao->flags &= ~OUT123_KEEP_PLAYING; /* No need for that here. */
|
||||
/* Be prepared to use SIGINT for communication. */
|
||||
catchsignal (SIGINT, catch_interrupt);
|
||||
/* sigprocmask (SIG_SETMASK, oldsigset, NULL); */
|
||||
/* Say hello to the writer. */
|
||||
xfermem_putcmd(my_fd, XF_CMD_PONG);
|
||||
|
||||
debug1("buffer with preload %g", ao->preload);
|
||||
while(1)
|
||||
{
|
||||
/* If a device is opened and playing, it is our first duty to keep it playing. */
|
||||
if(mystate == play_live)
|
||||
{
|
||||
size_t bytes = xfermem_get_usedspace(xf);
|
||||
debug4( "Play or preload? Got %"SIZE_P" B / %"SIZE_P" B (%i,%i)."
|
||||
, (size_p)bytes, (size_p)preload_size(ao), preloading, draining );
|
||||
if(preloading)
|
||||
preloading = (bytes < preload_size(ao));
|
||||
if(!preloading)
|
||||
{
|
||||
if(!draining && bytes < outburst)
|
||||
preloading = TRUE;
|
||||
else
|
||||
{
|
||||
buffer_play(ao, bytes);
|
||||
mystate = ao->state; /* Maybe changed, must be in sync now. */
|
||||
}
|
||||
}
|
||||
/* Be nice and pause the device on preloading. */
|
||||
if(preloading && ao->state == play_live)
|
||||
out123_pause(ao);
|
||||
}
|
||||
/* Now always check for a pending command, in a blocking way if there is
|
||||
no playback. */
|
||||
debug2("Buffer cmd? (Interruped: %i) (mystate=%i)", intflag, (int)mystate);
|
||||
/*
|
||||
The writer only ever signals before sending a command and also waiting
|
||||
for a response. So, the right place to reset the flag is any time
|
||||
before giving the response. But let's ensure two things:
|
||||
1. The flag really is only cleared when a command response is given.
|
||||
2. Command parsing does not stop until a command demanding a response
|
||||
was handled.
|
||||
*/
|
||||
do
|
||||
{
|
||||
/* Getting a whole block of commands to efficiently process those
|
||||
XF_CMD_DATA messages. */
|
||||
byte cmd[100];
|
||||
int cmdcount;
|
||||
int i;
|
||||
|
||||
cmdcount = xfermem_getcmds( my_fd
|
||||
, (preloading || intflag || (mystate != play_live))
|
||||
, cmd
|
||||
, sizeof(cmd) );
|
||||
if(cmdcount < 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Reading a command set returned %i, my link is broken.", cmdcount);
|
||||
return 1;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for(i=0; i<cmdcount; ++i)
|
||||
debug2("cmd[%i]=%u", i, cmd[i]);
|
||||
#endif
|
||||
/*
|
||||
These actions should rely heavily on calling the normal out123
|
||||
API functions, just with some parameter passing and error checking
|
||||
wrapped around. If there is much code here, it is wrong.
|
||||
*/
|
||||
for(i=0; i<cmdcount;) switch(cmd[i++])
|
||||
{
|
||||
#define GOOD_READVAL_BUF(fd, val) \
|
||||
!read_buf(my_fd, &val, sizeof(val), cmd, &i, cmdcount)
|
||||
case XF_CMD_DATA:
|
||||
debug("got new data");
|
||||
/* Other states should not happen. */
|
||||
if(mystate == play_paused)
|
||||
mystate = play_live;
|
||||
/* When new data arrives, we are obviously not draining. */
|
||||
draining = FALSE;
|
||||
break;
|
||||
case XF_CMD_PING:
|
||||
intflag = FALSE;
|
||||
/* Expecting ping-pong only while playing! Otherwise, the writer
|
||||
could get stuck waiting for free space forever. */
|
||||
if(mystate == play_live)
|
||||
xfermem_putcmd(my_fd, XF_CMD_PONG);
|
||||
else
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
if(ao->errcode == OUT123_OK)
|
||||
ao->errcode = OUT123_NOT_LIVE;
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case BUF_CMD_PARAM:
|
||||
intflag = FALSE;
|
||||
/* If that does not work, communication is broken anyway and
|
||||
writer will notice soon enough. */
|
||||
read_parameters(ao, XF_READER, cmd, &i, cmdcount);
|
||||
ao->flags &= ~OUT123_KEEP_PLAYING; /* No need for that here. */
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case BUF_CMD_OPEN:
|
||||
{
|
||||
char *driver = NULL;
|
||||
char *device = NULL;
|
||||
int success;
|
||||
|
||||
intflag = FALSE;
|
||||
success = (
|
||||
!read_record( ao, XF_READER, (void**)&driver
|
||||
, cmd, &i, cmdcount, NULL )
|
||||
&& !read_record( ao, XF_READER, (void**)&device
|
||||
, cmd, &i, cmdcount, NULL )
|
||||
&& !out123_open(ao, driver, device)
|
||||
);
|
||||
free(device);
|
||||
free(driver);
|
||||
draining = FALSE;
|
||||
mystate = ao->state;
|
||||
if(success)
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
if( xfer_write_string(ao, XF_READER, ao->driver)
|
||||
|| xfer_write_string(ao, XF_READER, ao->device)
|
||||
|| xfer_write_string(ao, XF_READER, ao->realname ) )
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
/* Again, no sense to bitch around about communication errors,
|
||||
just quit. */
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BUF_CMD_CLOSE:
|
||||
intflag = FALSE;
|
||||
out123_close(ao);
|
||||
draining = FALSE;
|
||||
mystate = ao->state;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case BUF_CMD_AUDIOCAP:
|
||||
{
|
||||
int encodings;
|
||||
|
||||
intflag = FALSE;
|
||||
if(
|
||||
!GOOD_READVAL_BUF(my_fd, ao->channels)
|
||||
|| !GOOD_READVAL_BUF(my_fd, ao->rate)
|
||||
)
|
||||
return 2;
|
||||
encodings = out123_encodings(ao, ao->rate, ao->channels);
|
||||
mystate = ao->state;
|
||||
if(encodings >= 0)
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
if(!GOOD_WRITEVAL(my_fd, encodings))
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BUF_CMD_AUDIOFMT:
|
||||
{
|
||||
size_t blocksize;
|
||||
long *rates = NULL;
|
||||
int minchannels;
|
||||
int maxchannels;
|
||||
struct mpg123_fmt *fmtlist;
|
||||
int fmtcount = -1;
|
||||
|
||||
if(
|
||||
!GOOD_READVAL_BUF(my_fd, maxchannels)
|
||||
|| !GOOD_READVAL_BUF(my_fd, minchannels)
|
||||
)
|
||||
return 2;
|
||||
if(
|
||||
read_record( ao, XF_READER, (void**)&rates
|
||||
, cmd, &i, cmdcount, &blocksize )
|
||||
){
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
fmtcount = out123_formats( ao, rates
|
||||
, (int)(blocksize/sizeof(*rates))
|
||||
, minchannels, maxchannels, &fmtlist );
|
||||
mystate = ao->state;
|
||||
free(rates);
|
||||
if(fmtcount >= 0)
|
||||
{
|
||||
int success;
|
||||
|
||||
blocksize = sizeof(*fmtlist)*fmtcount;
|
||||
debug2("responding with %i formats (block: %"SIZE_P")"
|
||||
, fmtcount, (size_p)blocksize);
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
success =
|
||||
GOOD_WRITEVAL(my_fd, fmtcount)
|
||||
&& GOOD_WRITEVAL(my_fd, blocksize)
|
||||
&& GOOD_WRITEBUF(my_fd, fmtlist, blocksize);
|
||||
free(fmtlist);
|
||||
if(!success)
|
||||
return 2;
|
||||
} else
|
||||
{
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BUF_CMD_START:
|
||||
intflag = FALSE;
|
||||
draining = FALSE;
|
||||
if(
|
||||
!GOOD_READVAL_BUF(my_fd, ao->format)
|
||||
|| !GOOD_READVAL_BUF(my_fd, ao->channels)
|
||||
|| !GOOD_READVAL_BUF(my_fd, ao->rate)
|
||||
)
|
||||
return 2;
|
||||
if(!out123_start(ao, ao->rate, ao->channels, ao->format))
|
||||
{
|
||||
out123_pause(ao); /* Be nice, start only on buffer_play(). */
|
||||
mystate = play_live;
|
||||
preloading = TRUE;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
mystate = ao->state;
|
||||
xfermem_putcmd(my_fd, XF_CMD_ERROR);
|
||||
if(!GOOD_WRITEVAL(my_fd, ao->errcode))
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case BUF_CMD_STOP:
|
||||
intflag = FALSE;
|
||||
if(mystate == play_live)
|
||||
{ /* Drain is implied! */
|
||||
size_t bytes;
|
||||
while((bytes = xfermem_get_usedspace(xf)))
|
||||
buffer_play(ao, bytes);
|
||||
}
|
||||
out123_stop(ao);
|
||||
draining = FALSE;
|
||||
mystate = ao->state;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case XF_CMD_CONTINUE:
|
||||
intflag = FALSE;
|
||||
debug("continuing");
|
||||
mystate = play_live; /* We'll get errors reported later if that is not right. */
|
||||
preloading = FALSE; /* It should continue without delay. */
|
||||
draining = FALSE; /* But outburst should be cared for. */
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case XF_CMD_IGNLOW:
|
||||
intflag = FALSE;
|
||||
preloading = FALSE;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case XF_CMD_DRAIN:
|
||||
debug("buffer drain");
|
||||
intflag = FALSE;
|
||||
if(mystate == play_live)
|
||||
{
|
||||
size_t bytes;
|
||||
while(
|
||||
(bytes = xfermem_get_usedspace(xf))
|
||||
&& bytes > ao->framesize
|
||||
)
|
||||
buffer_play(ao, bytes);
|
||||
out123_drain(ao);
|
||||
mystate = ao->state;
|
||||
}
|
||||
draining = FALSE;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case BUF_CMD_NDRAIN:
|
||||
{
|
||||
size_t limit;
|
||||
size_t oldfill;
|
||||
|
||||
debug("buffer ndrain");
|
||||
intflag = FALSE;
|
||||
/* Expect further calls to ndrain, avoid prebuffering. */
|
||||
draining = TRUE;
|
||||
preloading = FALSE;
|
||||
if(
|
||||
!GOOD_READVAL_BUF(my_fd, limit)
|
||||
|| !GOOD_READVAL_BUF(my_fd, oldfill)
|
||||
)
|
||||
return 2;
|
||||
if(mystate == play_live)
|
||||
{
|
||||
size_t bytes;
|
||||
while(
|
||||
(bytes = xfermem_get_usedspace(xf))
|
||||
&& bytes > ao->framesize
|
||||
&& oldfill >= bytes /* paranoia, overflow would handle it anyway */
|
||||
&& (oldfill-bytes) < limit
|
||||
)
|
||||
buffer_play(ao, bytes > limit ? limit : bytes);
|
||||
/* Only drain hardware if the end was reached. */
|
||||
if(!xfermem_get_usedspace(xf))
|
||||
{
|
||||
out123_drain(ao);
|
||||
mystate = ao->state;
|
||||
draining = FALSE;
|
||||
}
|
||||
debug2( "buffer drained %"SIZE_P" / %"SIZE_P
|
||||
, oldfill-bytes, limit );
|
||||
}
|
||||
else
|
||||
debug("drain without playback ... not good");
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
}
|
||||
break;
|
||||
case XF_CMD_TERMINATE:
|
||||
intflag = FALSE;
|
||||
/* Will that response always reach the writer? Well, at worst,
|
||||
it's an ignored error on xfermem_getcmd(). */
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
return 0;
|
||||
case XF_CMD_PAUSE:
|
||||
intflag = FALSE;
|
||||
draining = FALSE;
|
||||
out123_pause(ao);
|
||||
mystate = ao->state;
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
case XF_CMD_DROP:
|
||||
intflag = FALSE;
|
||||
draining = FALSE;
|
||||
xf->readindex = xf->freeindex;
|
||||
out123_drop(ao);
|
||||
xfermem_putcmd(my_fd, XF_CMD_OK);
|
||||
break;
|
||||
default:
|
||||
if(!AOQUIET)
|
||||
error1("Unknown command %u encountered. Confused Suicide!", cmd[i]);
|
||||
return 1;
|
||||
#undef GOOD_READVAL_BUF
|
||||
}
|
||||
} /* Ensure that an interrupt-giving command has been received. */
|
||||
while(intflag);
|
||||
if(intflag && !AOQUIET)
|
||||
error("buffer: The intflag should not be set anymore.");
|
||||
intflag = FALSE; /* Any possible harm by _not_ ensuring that the flag is cleared here? */
|
||||
}
|
||||
}
|
||||
66
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/buffer.h
vendored
Normal file
66
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/buffer.h
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
buffer.h: output buffer
|
||||
|
||||
copyright 1999-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Daniel Kobras / Oliver Fromme
|
||||
*/
|
||||
|
||||
/*
|
||||
* Application specific interaction between main and buffer
|
||||
* process. This is much less generic than the functions in
|
||||
* xfermem so I chose to put it in buffer.[hc].
|
||||
* 01/28/99 [dk]
|
||||
*/
|
||||
|
||||
#ifndef _MPG123_BUFFER_H_
|
||||
#define _MPG123_BUFFER_H_
|
||||
|
||||
#include "out123_int.h"
|
||||
#include "compat.h"
|
||||
|
||||
int buffer_init(out123_handle *ao, size_t bytes);
|
||||
void buffer_exit(out123_handle *ao);
|
||||
|
||||
/* Messages with payload. */
|
||||
|
||||
int buffer_sync_param(out123_handle *ao);
|
||||
int buffer_open(out123_handle *ao, const char* driver, const char* device);
|
||||
int buffer_encodings(out123_handle *ao);
|
||||
int buffer_formats( out123_handle *ao, const long *rates, int ratecount
|
||||
, int minchannels, int maxchannels
|
||||
, struct mpg123_fmt **fmtlist );
|
||||
int buffer_start(out123_handle *ao);
|
||||
void buffer_ndrain(out123_handle *ao, size_t bytes);
|
||||
|
||||
/* Simple messages to be deal with after playback. */
|
||||
|
||||
void buffer_stop(out123_handle *ao);
|
||||
void buffer_close(out123_handle *ao);
|
||||
void buffer_continue(out123_handle *ao);
|
||||
/* Still undecided if that one is to be used anywhere. */
|
||||
void buffer_ignore_lowmem(out123_handle *ao);
|
||||
void buffer_drain(out123_handle *ao);
|
||||
void buffer_end(out123_handle *ao);
|
||||
|
||||
/* Simple messages with interruption of playback. */
|
||||
|
||||
void buffer_pause(out123_handle *ao);
|
||||
void buffer_drop(out123_handle *ao);
|
||||
|
||||
/* The actual work: Hand over audio data. */
|
||||
size_t buffer_write(out123_handle *ao, void *buffer, size_t bytes);
|
||||
|
||||
/* Thin wrapper over xfermem giving the current buffer fill. */
|
||||
size_t buffer_fill(out123_handle *ao);
|
||||
|
||||
/* Special handler to safely read values from command channel with
|
||||
an additional buffer handed in. Exported for read_parameters(). */
|
||||
int read_buf(int fd, void *addr, size_t size
|
||||
, byte *prebuf, int *preoff, int presize);
|
||||
|
||||
/* Read/write strings from/to command channel. 0 on success. */
|
||||
int xfer_write_string(out123_handle *ao, int who, const char *buf);
|
||||
int xfer_read_string(out123_handle *ao, int who, char* *buf);
|
||||
|
||||
#endif
|
||||
96
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/legacy_module.c
vendored
Normal file
96
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/legacy_module.c
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
legacy_module.c: dummy interface to modular code loader for legacy build system
|
||||
|
||||
copyright 2008 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J Humfrey
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* A single module is staticly compiled in for each type */
|
||||
extern mpg123_module_t mpg123_output_module_info;
|
||||
/* extern mpg123_module_t mpg123_input_module_info; */
|
||||
|
||||
|
||||
/* Open a module */
|
||||
mpg123_module_t*
|
||||
open_module(const char* type, const char* name, int verbose, const char *bindir)
|
||||
{
|
||||
mpg123_module_t *mod = NULL;
|
||||
|
||||
/* Select the module info structure, based on the desired type */
|
||||
if (strcmp(type, "output")==0) {
|
||||
mod = &mpg123_output_module_info;
|
||||
/*
|
||||
} else if (strcmp(type, "input")==0) {
|
||||
mod = &mpg123_input_module_info;
|
||||
*/
|
||||
} else {
|
||||
if(verbose >= 0)
|
||||
error1("Unable to open module type '%s'.", type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the module compiled in is the module requested */
|
||||
if (strcmp(name, mod->name)!=0) {
|
||||
if(verbose >= 0)
|
||||
{
|
||||
error1("Unable to open requested module '%s'.", name);
|
||||
error1("The only available statically compiled module is '%s'."
|
||||
, mod->name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Debugging info */
|
||||
debug1("Details of static module type '%s':", type);
|
||||
debug1(" api_version=%d", mod->api_version);
|
||||
debug1(" name=%s", mod->name);
|
||||
debug1(" description=%s", mod->description);
|
||||
debug1(" revision=%s", mod->revision);
|
||||
debug1(" handle=%p", (void*)mod->handle);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
||||
void close_module(mpg123_module_t* module, int verbose)
|
||||
{
|
||||
debug("close_module()");
|
||||
|
||||
/* Module was never really 'loaded', so nothing to do here. */
|
||||
}
|
||||
|
||||
|
||||
int list_modules(const char *type, char ***names, char ***descr, int verbose
|
||||
, const char *bindir)
|
||||
{
|
||||
debug("list_modules()" );
|
||||
|
||||
*names = NULL;
|
||||
*descr = NULL;
|
||||
|
||||
if(
|
||||
(*names=malloc(sizeof(char*)))
|
||||
&& !((*names)[0]=NULL) /* for safe cleanup */
|
||||
&& ((*names)[0]=compat_strdup(mpg123_output_module_info.name))
|
||||
&& (*descr=malloc(sizeof(char*)))
|
||||
&& !((*descr)[0]=NULL) /* for safe cleanup */
|
||||
&& ((*descr)[0]=compat_strdup(mpg123_output_module_info.description))
|
||||
)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
if(*names)
|
||||
free((*names)[0]);
|
||||
free(*names);
|
||||
if(*descr)
|
||||
free((*descr)[0]);
|
||||
free(*descr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1220
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/libout123.c
vendored
Normal file
1220
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/libout123.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
303
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/module.c
vendored
Normal file
303
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/module.c
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
module.c: modular code loader
|
||||
|
||||
copyright 1995-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J Humfrey
|
||||
*/
|
||||
|
||||
/* Need snprintf(). */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#include "config.h"
|
||||
#include "intsym.h"
|
||||
#include "stringlists.h"
|
||||
#include "compat.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "module.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef USE_MODULES
|
||||
#error This is a build without modules. Why am I here?
|
||||
#endif
|
||||
|
||||
#define MODULE_SYMBOL_PREFIX "mpg123_"
|
||||
#define MODULE_SYMBOL_SUFFIX "_module_info"
|
||||
|
||||
/* Windows code can convert these from UTF-8 (or ASCII, does not matter)
|
||||
to wide and then replace / by \. No need to define another list. */
|
||||
static const char* modulesearch[] =
|
||||
{
|
||||
"../lib/mpg123"
|
||||
,"plugins"
|
||||
,"libout123/modules/.libs"
|
||||
,"libout123/modules"
|
||||
,"../libout123/modules/.libs"
|
||||
,"../libout123/modules"
|
||||
};
|
||||
|
||||
static char *get_module_dir(int verbose, const char* bindir)
|
||||
{
|
||||
char *moddir = NULL;
|
||||
char *defaultdir;
|
||||
/* First the environment override, then relative to bindir, then installation prefix. */
|
||||
defaultdir = compat_getenv("MPG123_MODDIR");
|
||||
if(defaultdir)
|
||||
{
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Trying module directory from environment: %s\n", defaultdir);
|
||||
if(compat_isdir(defaultdir))
|
||||
moddir = defaultdir;
|
||||
else
|
||||
free(defaultdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bindir) /* Search relative to binary. */
|
||||
{
|
||||
size_t i;
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Module dir search relative to: %s\n", bindir);
|
||||
for(i=0; i<sizeof(modulesearch)/sizeof(char*); ++i)
|
||||
{
|
||||
moddir = compat_catpath(bindir, modulesearch[i]);
|
||||
if(!moddir)
|
||||
continue;
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Looking for module dir: %s\n", moddir);
|
||||
if(compat_isdir(moddir))
|
||||
break; /* found it! */
|
||||
else
|
||||
{
|
||||
free(moddir);
|
||||
moddir=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!moddir) /* Resort to installation prefix. */
|
||||
{
|
||||
if(compat_isdir(PKGLIBDIR))
|
||||
{
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Using default module dir: %s\n", PKGLIBDIR);
|
||||
moddir = compat_strdup(PKGLIBDIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Module dir: %s\n", moddir != NULL ? moddir : "<nil>");
|
||||
return moddir;
|
||||
}
|
||||
|
||||
/* Open a module in given directory. */
|
||||
mpg123_module_t* open_module_here( const char *dir, const char* type
|
||||
, const char* name, int verbose )
|
||||
{
|
||||
void *handle = NULL;
|
||||
mpg123_module_t *module = NULL;
|
||||
char *module_file = NULL;
|
||||
size_t module_file_len = 0;
|
||||
char *module_symbol = NULL;
|
||||
size_t module_symbol_len = 0;
|
||||
char *module_path = NULL;
|
||||
|
||||
/* Work out the path of the module to open */
|
||||
module_file_len = strlen(type) + 1 + strlen(name) + strlen(LT_MODULE_EXT) + 1;
|
||||
module_file = malloc(module_file_len);
|
||||
if(!module_file)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error1( "Failed to allocate memory for module name: %s", strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
snprintf(module_file, module_file_len, "%s_%s%s", type, name, LT_MODULE_EXT);
|
||||
module_path = compat_catpath(dir, module_file);
|
||||
free(module_file);
|
||||
if(!module_path)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error("Failed to construct full path (out of memory?).");
|
||||
return NULL;
|
||||
}
|
||||
if(verbose > 1)
|
||||
fprintf(stderr, "Module path: %s\n", module_path );
|
||||
|
||||
/* Open the module */
|
||||
handle = compat_dlopen(module_path);
|
||||
free(module_path);
|
||||
if (handle==NULL)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error1("Failed to open module %s.", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Work out the symbol name */
|
||||
module_symbol_len = strlen( MODULE_SYMBOL_PREFIX ) +
|
||||
strlen( type ) +
|
||||
strlen( MODULE_SYMBOL_SUFFIX ) + 1;
|
||||
module_symbol = malloc(module_symbol_len);
|
||||
if (module_symbol == NULL) {
|
||||
if(verbose > -1)
|
||||
error1( "Failed to allocate memory for module symbol: %s", strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
snprintf( module_symbol, module_symbol_len, "%s%s%s", MODULE_SYMBOL_PREFIX, type, MODULE_SYMBOL_SUFFIX );
|
||||
debug1( "Module symbol: %s", module_symbol );
|
||||
|
||||
/* Get the information structure from the module */
|
||||
module = (mpg123_module_t*)compat_dlsym(handle, module_symbol);
|
||||
free( module_symbol );
|
||||
if (module==NULL) {
|
||||
if(verbose > -1)
|
||||
error("Failed to get module symbol.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the API version */
|
||||
if (MPG123_MODULE_API_VERSION != module->api_version)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error2( "API version of module does not match (got %i, expected %i).", module->api_version, MPG123_MODULE_API_VERSION);
|
||||
compat_dlclose(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Store handle in the data structure */
|
||||
module->handle = handle;
|
||||
return module;
|
||||
}
|
||||
|
||||
|
||||
/* Open a module, including directory search. */
|
||||
mpg123_module_t* open_module( const char* type, const char* name, int verbose
|
||||
, const char* bindir )
|
||||
{
|
||||
mpg123_module_t *module = NULL;
|
||||
char *moddir = NULL;
|
||||
|
||||
moddir = get_module_dir(verbose, bindir);
|
||||
if(!moddir)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error("Failure getting module directory! (Perhaps set MPG123_MODDIR?)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
module = open_module_here(moddir, type, name, verbose);
|
||||
|
||||
free(moddir);
|
||||
return module;
|
||||
}
|
||||
|
||||
void close_module( mpg123_module_t* module, int verbose )
|
||||
{
|
||||
compat_dlclose(module->handle);
|
||||
}
|
||||
|
||||
int list_modules( const char *type, char ***names, char ***descr, int verbose
|
||||
, const char* bindir )
|
||||
{
|
||||
char *moddir = NULL;
|
||||
int count = 0;
|
||||
struct compat_dir *dir;
|
||||
char *filename;
|
||||
|
||||
debug1("verbose:%i", verbose);
|
||||
|
||||
*names = NULL;
|
||||
*descr = NULL;
|
||||
|
||||
moddir = get_module_dir(verbose, bindir);
|
||||
if(moddir == NULL)
|
||||
{
|
||||
if(verbose > -1)
|
||||
error("Failure getting module directory! (Perhaps set MPG123_MODDIR?)");
|
||||
return -1;
|
||||
}
|
||||
debug1("module dir: %s", moddir);
|
||||
|
||||
/* Open the module directory */
|
||||
dir = compat_diropen(moddir);
|
||||
if (dir==NULL) {
|
||||
if(verbose > -1)
|
||||
error2("Failed to open the module directory (%s): %s\n"
|
||||
, moddir, strerror(errno));
|
||||
free(moddir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while((filename=compat_nextfile(dir)))
|
||||
{
|
||||
/* Pointers to the pieces. */
|
||||
char *module_name = NULL;
|
||||
char *module_type = NULL;
|
||||
char *uscore_pos = NULL;
|
||||
mpg123_module_t *module = NULL;
|
||||
char* ext;
|
||||
size_t name_len;
|
||||
|
||||
/* Various checks as loop shortcuts, avoiding too much nesting. */
|
||||
debug1("checking entry: %s", filename);
|
||||
|
||||
name_len = strlen(filename);
|
||||
if(name_len < strlen(LT_MODULE_EXT))
|
||||
goto list_modules_continue;
|
||||
ext = filename
|
||||
+ name_len
|
||||
- strlen(LT_MODULE_EXT);
|
||||
if(strcmp(ext, LT_MODULE_EXT))
|
||||
goto list_modules_continue;
|
||||
debug("has suffix");
|
||||
|
||||
/* Extract the module type and name */
|
||||
uscore_pos = strchr( filename, '_' );
|
||||
if( uscore_pos==NULL
|
||||
|| (uscore_pos>=filename+name_len+1) )
|
||||
{
|
||||
debug("no underscore");
|
||||
goto list_modules_continue;
|
||||
}
|
||||
*uscore_pos = '\0';
|
||||
module_type = filename;
|
||||
module_name = uscore_pos+1;
|
||||
/* Only list modules of desired type. */
|
||||
if(strcmp(type, module_type))
|
||||
{
|
||||
debug("wrong type");
|
||||
goto list_modules_continue;
|
||||
}
|
||||
debug("has type");
|
||||
|
||||
/* Extract the short name of the module */
|
||||
name_len -= uscore_pos - filename + 1;
|
||||
if(name_len <= strlen(LT_MODULE_EXT))
|
||||
{
|
||||
debug("name too short");
|
||||
goto list_modules_continue;
|
||||
}
|
||||
name_len -= strlen(LT_MODULE_EXT);
|
||||
module_name[name_len] = '\0';
|
||||
|
||||
debug("opening module");
|
||||
/* Open the module
|
||||
Yes, this re-builds the file name we chopped to pieces just now. */
|
||||
if((module=open_module_here(moddir, module_type, module_name, verbose)))
|
||||
{
|
||||
if( stringlists_add( names, descr
|
||||
, module->name, module->description, &count) )
|
||||
if(verbose > -1)
|
||||
error("OOM");
|
||||
/* Close the module again */
|
||||
close_module(module, verbose);
|
||||
}
|
||||
list_modules_continue:
|
||||
free(filename);
|
||||
}
|
||||
compat_dirclose(dir);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
44
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/module.h
vendored
Normal file
44
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/module.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
module: module loading and listing interface
|
||||
|
||||
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J. Humphfrey
|
||||
*/
|
||||
|
||||
#ifndef _MPG123_MODULE_H_
|
||||
#define _MPG123_MODULE_H_
|
||||
|
||||
#include "out123.h"
|
||||
|
||||
/* TODO: put that into out123_int.h instead? */
|
||||
#define MPG123_MODULE_API_VERSION (2)
|
||||
|
||||
/* The full structure is delared in audio.h */
|
||||
struct audio_output_struct;
|
||||
|
||||
typedef struct mpg123_module_struct {
|
||||
const int api_version; /* module API version number */
|
||||
|
||||
const char* name; /* short name of the module */
|
||||
const char* description; /* description of what the module does */
|
||||
const char* revision; /* source code revision */
|
||||
|
||||
void* handle; /* dynamic loader handle */
|
||||
|
||||
/* Initialisers - set to NULL if unsupported by module */
|
||||
int (*init_output)(out123_handle *ao); /* audio output - returns 0 on success */
|
||||
|
||||
} mpg123_module_t;
|
||||
|
||||
|
||||
|
||||
/* ------ Declarations from "module.c" ------ */
|
||||
|
||||
mpg123_module_t* open_module( const char* type, const char* name, int verbose
|
||||
, const char* bindir );
|
||||
void close_module(mpg123_module_t* module, int verbose);
|
||||
int list_modules( const char *type, char ***names, char ***descr, int verbose
|
||||
, const char* bindir );
|
||||
|
||||
#endif
|
||||
791
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/Makemodule.am
vendored
Normal file
791
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/Makemodule.am
vendored
Normal file
@@ -0,0 +1,791 @@
|
||||
# Module for non-recursive mpg123 build system.
|
||||
# Gah! Not even re-defining that variable is allowed in automake!
|
||||
# I WANT TO USE PROPER MAKE!
|
||||
# makedir := src/libout123/modules
|
||||
# Experiment: Does automake pick that up in a Make variable?
|
||||
# Damn, no! It complains wildly.
|
||||
# I just want to use GNU Make and be done with it!
|
||||
# Perhaps the next build system rewrite ...
|
||||
#makenam=src_libout123_modules
|
||||
|
||||
# Optionally containing the one static module to use.
|
||||
if !HAVE_MODULES
|
||||
noinst_LTLIBRARIES += src/libout123/modules/libdefaultmodule.la
|
||||
endif
|
||||
|
||||
# Do not include uneeded headers from mpg123app.h .
|
||||
libout123_mod_cppflags = -DBUILDING_OUTPUT_MODULES=1
|
||||
|
||||
# These are not tested and _very_ likely need work: aix alib hp os2 sgi mint
|
||||
|
||||
# Use that sh/perl script to generate the module entries:
|
||||
# Confused as to when to use _LIBADD and when _LDADD.
|
||||
# _LDADD gives errors from autotools.
|
||||
#echo \
|
||||
#dummy tinyalsa alsa qsa coreaudio esd jack nas oss portaudio \
|
||||
#pulse sdl sndio sun win32 win32_wasapi aix alib arts hp os2 \
|
||||
#sgi mint openal \
|
||||
#| tr ' ' '\n' |
|
||||
#perl -ne 'chomp; $big = uc($_); print <<EOT;
|
||||
#
|
||||
#if HAVE_MODULES
|
||||
#if HAVE_$big
|
||||
#pkglib_LTLIBRARIES += \src/libout123/modules/output_$_.la
|
||||
#src_libout123_modules_output_${_}_la_SOURCES = \\
|
||||
# src/libout123/modules/$_.c
|
||||
#src_libout123_modules_output_${_}_la_LDFLAGS = \\
|
||||
# -module -no-undefined -avoid-version \\
|
||||
# -export-dynamic -export-symbols-regex '"'"'^mpg123_'"'"' \\
|
||||
# \@${big}_LDFLAGS\@
|
||||
#src_libout123_modules_output_${_}_la_CFLAGS = \@${big}_CFLAGS\@
|
||||
#src_libout123_modules_output_${_}_la_LIBADD = \\
|
||||
# src/compat/libcompat_str.la \\
|
||||
# \@${big}_LIBS\@
|
||||
#src_libout123_modules_outout_${_}_la_CPPFLAGS = \\
|
||||
# \$(AM_CPPFLAGS) \\
|
||||
# \$(libout123_mod_cppflags)
|
||||
#endif
|
||||
#else
|
||||
#if BUILD_$big
|
||||
#src_libout123_modules_libdefaultmodule_la_SOURCES = \\
|
||||
# src/libout123/modules/$_.c
|
||||
#src_libout123_modules_libdefaultmodule_la_CFLAGS = \@${big}_CFLAGS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_LDFLAGS = \@${big}_LDFLAGS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_LIBADD = \@${big}_LIBS\@
|
||||
#src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \\
|
||||
# \$(AM_CPPFLAGS) \\
|
||||
# \$(libout123_mod_cppflags)
|
||||
#endif
|
||||
#endif
|
||||
#EOT
|
||||
#'
|
||||
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_DUMMY
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_dummy.la
|
||||
src_libout123_modules_output_dummy_la_SOURCES = \
|
||||
src/libout123/modules/dummy.c
|
||||
src_libout123_modules_output_dummy_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@DUMMY_LDFLAGS@
|
||||
src_libout123_modules_output_dummy_la_CFLAGS = @DUMMY_CFLAGS@
|
||||
src_libout123_modules_output_dummy_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@DUMMY_LIBS@
|
||||
src_libout123_modules_outout_dummy_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_DUMMY
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/dummy.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @DUMMY_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @DUMMY_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @DUMMY_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_TINYALSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_tinyalsa.la
|
||||
src_libout123_modules_output_tinyalsa_la_SOURCES = \
|
||||
src/libout123/modules/tinyalsa.c
|
||||
src_libout123_modules_output_tinyalsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@TINYALSA_LDFLAGS@
|
||||
src_libout123_modules_output_tinyalsa_la_CFLAGS = @TINYALSA_CFLAGS@
|
||||
src_libout123_modules_output_tinyalsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@TINYALSA_LIBS@
|
||||
src_libout123_modules_outout_tinyalsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_TINYALSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/tinyalsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @TINYALSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @TINYALSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @TINYALSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ALSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_alsa.la
|
||||
src_libout123_modules_output_alsa_la_SOURCES = \
|
||||
src/libout123/modules/alsa.c
|
||||
src_libout123_modules_output_alsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ALSA_LDFLAGS@
|
||||
src_libout123_modules_output_alsa_la_CFLAGS = @ALSA_CFLAGS@
|
||||
src_libout123_modules_output_alsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ALSA_LIBS@
|
||||
src_libout123_modules_outout_alsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ALSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/alsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ALSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ALSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ALSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_QSA
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_qsa.la
|
||||
src_libout123_modules_output_qsa_la_SOURCES = \
|
||||
src/libout123/modules/qsa.c
|
||||
src_libout123_modules_output_qsa_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@QSA_LDFLAGS@
|
||||
src_libout123_modules_output_qsa_la_CFLAGS = @QSA_CFLAGS@
|
||||
src_libout123_modules_output_qsa_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@QSA_LIBS@
|
||||
src_libout123_modules_outout_qsa_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_QSA
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/qsa.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @QSA_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @QSA_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @QSA_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_COREAUDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_coreaudio.la
|
||||
src_libout123_modules_output_coreaudio_la_SOURCES = \
|
||||
src/libout123/modules/coreaudio.c
|
||||
src_libout123_modules_output_coreaudio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@COREAUDIO_LDFLAGS@
|
||||
src_libout123_modules_output_coreaudio_la_CFLAGS = @COREAUDIO_CFLAGS@
|
||||
src_libout123_modules_output_coreaudio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@COREAUDIO_LIBS@
|
||||
src_libout123_modules_outout_coreaudio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_COREAUDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/coreaudio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @COREAUDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @COREAUDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @COREAUDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ESD
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_esd.la
|
||||
src_libout123_modules_output_esd_la_SOURCES = \
|
||||
src/libout123/modules/esd.c
|
||||
src_libout123_modules_output_esd_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ESD_LDFLAGS@
|
||||
src_libout123_modules_output_esd_la_CFLAGS = @ESD_CFLAGS@
|
||||
src_libout123_modules_output_esd_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ESD_LIBS@
|
||||
src_libout123_modules_outout_esd_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ESD
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/esd.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ESD_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ESD_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ESD_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_JACK
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_jack.la
|
||||
src_libout123_modules_output_jack_la_SOURCES = \
|
||||
src/libout123/modules/jack.c
|
||||
src_libout123_modules_output_jack_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@JACK_LDFLAGS@
|
||||
src_libout123_modules_output_jack_la_CFLAGS = @JACK_CFLAGS@
|
||||
src_libout123_modules_output_jack_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@JACK_LIBS@
|
||||
src_libout123_modules_outout_jack_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_JACK
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/jack.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @JACK_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @JACK_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @JACK_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_NAS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_nas.la
|
||||
src_libout123_modules_output_nas_la_SOURCES = \
|
||||
src/libout123/modules/nas.c
|
||||
src_libout123_modules_output_nas_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@NAS_LDFLAGS@
|
||||
src_libout123_modules_output_nas_la_CFLAGS = @NAS_CFLAGS@
|
||||
src_libout123_modules_output_nas_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@NAS_LIBS@
|
||||
src_libout123_modules_outout_nas_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_NAS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/nas.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @NAS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @NAS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @NAS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OSS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_oss.la
|
||||
src_libout123_modules_output_oss_la_SOURCES = \
|
||||
src/libout123/modules/oss.c
|
||||
src_libout123_modules_output_oss_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OSS_LDFLAGS@
|
||||
src_libout123_modules_output_oss_la_CFLAGS = @OSS_CFLAGS@
|
||||
src_libout123_modules_output_oss_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OSS_LIBS@
|
||||
src_libout123_modules_outout_oss_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OSS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/oss.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OSS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OSS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OSS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_PORTAUDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_portaudio.la
|
||||
src_libout123_modules_output_portaudio_la_SOURCES = \
|
||||
src/libout123/modules/portaudio.c
|
||||
src_libout123_modules_output_portaudio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@PORTAUDIO_LDFLAGS@
|
||||
src_libout123_modules_output_portaudio_la_CFLAGS = @PORTAUDIO_CFLAGS@
|
||||
src_libout123_modules_output_portaudio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@PORTAUDIO_LIBS@
|
||||
src_libout123_modules_outout_portaudio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_PORTAUDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/portaudio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @PORTAUDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @PORTAUDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @PORTAUDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_PULSE
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_pulse.la
|
||||
src_libout123_modules_output_pulse_la_SOURCES = \
|
||||
src/libout123/modules/pulse.c
|
||||
src_libout123_modules_output_pulse_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@PULSE_LDFLAGS@
|
||||
src_libout123_modules_output_pulse_la_CFLAGS = @PULSE_CFLAGS@
|
||||
src_libout123_modules_output_pulse_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@PULSE_LIBS@
|
||||
src_libout123_modules_outout_pulse_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_PULSE
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/pulse.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @PULSE_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @PULSE_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @PULSE_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SDL
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sdl.la
|
||||
src_libout123_modules_output_sdl_la_SOURCES = \
|
||||
src/libout123/modules/sdl.c
|
||||
src_libout123_modules_output_sdl_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SDL_LDFLAGS@
|
||||
src_libout123_modules_output_sdl_la_CFLAGS = @SDL_CFLAGS@
|
||||
src_libout123_modules_output_sdl_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SDL_LIBS@
|
||||
src_libout123_modules_outout_sdl_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SDL
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sdl.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SDL_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SDL_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SDL_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SNDIO
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sndio.la
|
||||
src_libout123_modules_output_sndio_la_SOURCES = \
|
||||
src/libout123/modules/sndio.c
|
||||
src_libout123_modules_output_sndio_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SNDIO_LDFLAGS@
|
||||
src_libout123_modules_output_sndio_la_CFLAGS = @SNDIO_CFLAGS@
|
||||
src_libout123_modules_output_sndio_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SNDIO_LIBS@
|
||||
src_libout123_modules_outout_sndio_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SNDIO
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sndio.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SNDIO_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SNDIO_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SNDIO_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SUN
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sun.la
|
||||
src_libout123_modules_output_sun_la_SOURCES = \
|
||||
src/libout123/modules/sun.c
|
||||
src_libout123_modules_output_sun_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SUN_LDFLAGS@
|
||||
src_libout123_modules_output_sun_la_CFLAGS = @SUN_CFLAGS@
|
||||
src_libout123_modules_output_sun_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SUN_LIBS@
|
||||
src_libout123_modules_outout_sun_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SUN
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sun.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SUN_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SUN_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SUN_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_WIN32
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_win32.la
|
||||
src_libout123_modules_output_win32_la_SOURCES = \
|
||||
src/libout123/modules/win32.c
|
||||
src_libout123_modules_output_win32_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@WIN32_LDFLAGS@
|
||||
src_libout123_modules_output_win32_la_CFLAGS = @WIN32_CFLAGS@
|
||||
src_libout123_modules_output_win32_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@WIN32_LIBS@
|
||||
src_libout123_modules_outout_win32_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_WIN32
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/win32.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @WIN32_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @WIN32_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @WIN32_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_WIN32_WASAPI
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_win32_wasapi.la
|
||||
src_libout123_modules_output_win32_wasapi_la_SOURCES = \
|
||||
src/libout123/modules/win32_wasapi.c
|
||||
src_libout123_modules_output_win32_wasapi_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@WIN32_WASAPI_LDFLAGS@
|
||||
src_libout123_modules_output_win32_wasapi_la_CFLAGS = @WIN32_WASAPI_CFLAGS@
|
||||
src_libout123_modules_output_win32_wasapi_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@WIN32_WASAPI_LIBS@
|
||||
src_libout123_modules_outout_win32_wasapi_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_WIN32_WASAPI
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/win32_wasapi.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @WIN32_WASAPI_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @WIN32_WASAPI_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @WIN32_WASAPI_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_AIX
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_aix.la
|
||||
src_libout123_modules_output_aix_la_SOURCES = \
|
||||
src/libout123/modules/aix.c
|
||||
src_libout123_modules_output_aix_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@AIX_LDFLAGS@
|
||||
src_libout123_modules_output_aix_la_CFLAGS = @AIX_CFLAGS@
|
||||
src_libout123_modules_output_aix_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@AIX_LIBS@
|
||||
src_libout123_modules_outout_aix_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_AIX
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/aix.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @AIX_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @AIX_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @AIX_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ALIB
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_alib.la
|
||||
src_libout123_modules_output_alib_la_SOURCES = \
|
||||
src/libout123/modules/alib.c
|
||||
src_libout123_modules_output_alib_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ALIB_LDFLAGS@
|
||||
src_libout123_modules_output_alib_la_CFLAGS = @ALIB_CFLAGS@
|
||||
src_libout123_modules_output_alib_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ALIB_LIBS@
|
||||
src_libout123_modules_outout_alib_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ALIB
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/alib.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ALIB_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ALIB_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ALIB_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_ARTS
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_arts.la
|
||||
src_libout123_modules_output_arts_la_SOURCES = \
|
||||
src/libout123/modules/arts.c
|
||||
src_libout123_modules_output_arts_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@ARTS_LDFLAGS@
|
||||
src_libout123_modules_output_arts_la_CFLAGS = @ARTS_CFLAGS@
|
||||
src_libout123_modules_output_arts_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@ARTS_LIBS@
|
||||
src_libout123_modules_outout_arts_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_ARTS
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/arts.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @ARTS_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @ARTS_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @ARTS_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_HP
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_hp.la
|
||||
src_libout123_modules_output_hp_la_SOURCES = \
|
||||
src/libout123/modules/hp.c
|
||||
src_libout123_modules_output_hp_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@HP_LDFLAGS@
|
||||
src_libout123_modules_output_hp_la_CFLAGS = @HP_CFLAGS@
|
||||
src_libout123_modules_output_hp_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@HP_LIBS@
|
||||
src_libout123_modules_outout_hp_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_HP
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/hp.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @HP_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @HP_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @HP_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OS2
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_os2.la
|
||||
src_libout123_modules_output_os2_la_SOURCES = \
|
||||
src/libout123/modules/os2.c
|
||||
src_libout123_modules_output_os2_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OS2_LDFLAGS@
|
||||
src_libout123_modules_output_os2_la_CFLAGS = @OS2_CFLAGS@
|
||||
src_libout123_modules_output_os2_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OS2_LIBS@
|
||||
src_libout123_modules_outout_os2_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OS2
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/os2.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OS2_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OS2_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OS2_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_SGI
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_sgi.la
|
||||
src_libout123_modules_output_sgi_la_SOURCES = \
|
||||
src/libout123/modules/sgi.c
|
||||
src_libout123_modules_output_sgi_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@SGI_LDFLAGS@
|
||||
src_libout123_modules_output_sgi_la_CFLAGS = @SGI_CFLAGS@
|
||||
src_libout123_modules_output_sgi_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@SGI_LIBS@
|
||||
src_libout123_modules_outout_sgi_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_SGI
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/sgi.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @SGI_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @SGI_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @SGI_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_MINT
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_mint.la
|
||||
src_libout123_modules_output_mint_la_SOURCES = \
|
||||
src/libout123/modules/mint.c
|
||||
src_libout123_modules_output_mint_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@MINT_LDFLAGS@
|
||||
src_libout123_modules_output_mint_la_CFLAGS = @MINT_CFLAGS@
|
||||
src_libout123_modules_output_mint_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@MINT_LIBS@
|
||||
src_libout123_modules_outout_mint_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_MINT
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/mint.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @MINT_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @MINT_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @MINT_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
if HAVE_OPENAL
|
||||
pkglib_LTLIBRARIES += src/libout123/modules/output_openal.la
|
||||
src_libout123_modules_output_openal_la_SOURCES = \
|
||||
src/libout123/modules/openal.c
|
||||
src_libout123_modules_output_openal_la_LDFLAGS = \
|
||||
-module -no-undefined -avoid-version \
|
||||
-export-dynamic -export-symbols-regex '^mpg123_' \
|
||||
@OPENAL_LDFLAGS@
|
||||
src_libout123_modules_output_openal_la_CFLAGS = @OPENAL_CFLAGS@
|
||||
src_libout123_modules_output_openal_la_LIBADD = \
|
||||
src/compat/libcompat_str.la \
|
||||
@OPENAL_LIBS@
|
||||
src_libout123_modules_outout_openal_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
else
|
||||
if BUILD_OPENAL
|
||||
src_libout123_modules_libdefaultmodule_la_SOURCES = \
|
||||
src/libout123/modules/openal.c
|
||||
src_libout123_modules_libdefaultmodule_la_CFLAGS = @OPENAL_CFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LDFLAGS = @OPENAL_LDFLAGS@
|
||||
src_libout123_modules_libdefaultmodule_la_LIBADD = @OPENAL_LIBS@
|
||||
src_libout123_modules_libdefaultmodule_la_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
$(libout123_mod_cppflags)
|
||||
endif
|
||||
endif
|
||||
|
||||
if HAVE_MODULES
|
||||
# Get rid of .la files, at least _after_ install.
|
||||
install-exec-hook:
|
||||
cd $(DESTDIR)$(pkglibdir) && rm -f @output_modules_la@
|
||||
# The above breaks uninstall of module .so files?
|
||||
uninstall-hook:
|
||||
for m in @output_modules_la@; do eval $$(grep dlname= src/libout123/modules/$$m) && rm -f $(DESTDIR)$(pkglibdir)/$$dlname; done
|
||||
endif
|
||||
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/aix.c
vendored
Normal file
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/aix.c
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
aix: Driver for IBM RS/6000 with AIX Ultimedia Services
|
||||
|
||||
copyright ?-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Juergen Schoew and Tomas Oegren
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/audio.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* use AUDIO_BSIZE to set the msec for audio buffering in Ultimedia library
|
||||
*/
|
||||
/* #define AUDIO_BSIZE AUDIO_IGNORE */
|
||||
#define AUDIO_BSIZE ( ao->device_buffer > 0. \
|
||||
? (long)(ao->device_buffer*1000) \
|
||||
: 200 )
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
static long valid [ ] = { 5510, 6620, 8000, 9600, 11025, 16000, 18900,
|
||||
22050, 27420, 32000, 33075, 37800, 44100, 48000, 0 };
|
||||
int i = 0;
|
||||
long best = 8000;
|
||||
|
||||
if(!ao || ao->fn < 0 || ao->rate < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (valid [i]) {
|
||||
if (abs(valid[i] - ao->rate) < abs(best - ao->rate))
|
||||
{
|
||||
best = valid [i];
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
ao->rate = best;
|
||||
return best;
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
audio_control acontrol;
|
||||
audio_change achange;
|
||||
audio_init ainit;
|
||||
int ret;
|
||||
|
||||
memset ( & achange, '\0', sizeof (achange));
|
||||
memset ( & acontrol, '\0', sizeof (acontrol));
|
||||
|
||||
achange.balance = 0x3fff0000;
|
||||
achange.balance_delay = 0;
|
||||
achange.volume = (long) (0x7fff << 16);
|
||||
achange.volume_delay = 0;
|
||||
achange.input = AUDIO_IGNORE;
|
||||
if (ao->flags == -1) achange.output = INTERNAL_SPEAKER;
|
||||
else achange.output = 0;
|
||||
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
achange.output |= INTERNAL_SPEAKER;
|
||||
if(ao->flags & OUT123_HEADPHONES)
|
||||
achange.output |= EXTERNAL_SPEAKER;
|
||||
if(ao->flags & OUT123_LINE_OUT)
|
||||
achange.output |= OUTPUT_1;
|
||||
if(ao->flags == 0)
|
||||
achange.output = AUDIO_IGNORE;
|
||||
|
||||
achange.treble = AUDIO_IGNORE;
|
||||
achange.bass = AUDIO_IGNORE;
|
||||
achange.pitch = AUDIO_IGNORE;
|
||||
achange.monitor = AUDIO_IGNORE;
|
||||
achange.dev_info = (char *) NULL;
|
||||
|
||||
acontrol.ioctl_request = AUDIO_CHANGE;
|
||||
acontrol.position = 0;
|
||||
acontrol.request_info = (char *) & achange;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_CONTROL, & acontrol);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Init Device for new values */
|
||||
if (ao->rate >0) {
|
||||
memset ( & ainit, '\0', sizeof (ainit));
|
||||
ainit.srate = rate_best_match(ao);
|
||||
if (ao->channels > 0)
|
||||
ainit.channels = ao->channels;
|
||||
else
|
||||
ainit.channels = 1;
|
||||
switch (ao->format) {
|
||||
default :
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ainit.mode = MU_LAW;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ainit.mode = A_LAW;
|
||||
ainit.bits_per_sample = 8;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
break;
|
||||
}
|
||||
ainit.operation = PLAY;
|
||||
ainit.bsize = AUDIO_BSIZE;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_INIT, & ainit);
|
||||
if (ret < 0) {
|
||||
error("Can't set new audio parameters!");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
acontrol.ioctl_request = AUDIO_START;
|
||||
acontrol.request_info = NULL;
|
||||
acontrol.position = 0;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_CONTROL, & acontrol);
|
||||
if (ret < 0) {
|
||||
error("Can't reset audio!");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_aix(out123_handle *ao)
|
||||
{
|
||||
audio_init ainit;
|
||||
int ret;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!dev) {
|
||||
if(getenv("AUDIODEV")) {
|
||||
dev = getenv("AUDIODEV");
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
} else {
|
||||
dev = "/dev/paud0/1"; /* paud0 for PCI */
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if ((ao->fn == -1) & (errno == ENOENT)) {
|
||||
dev = "/dev/baud0/1"; /* baud0 for MCA */
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
}
|
||||
}
|
||||
} else ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0) {
|
||||
error("Can't open audio device!");
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
/* Init to default values */
|
||||
memset ( & ainit, '\0', sizeof (ainit));
|
||||
ainit.srate = 44100;
|
||||
ainit.channels = 2;
|
||||
ainit.mode = PCM;
|
||||
ainit.bits_per_sample = 16;
|
||||
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
|
||||
ainit.operation = PLAY;
|
||||
ainit.bsize = AUDIO_BSIZE;
|
||||
|
||||
ret = ioctl (ao->fn, AUDIO_INIT, & ainit);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
reset_parameters(ao);
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int get_formats_aix(out123_handle *ao)
|
||||
{
|
||||
/* ULTIMEDIA DOCUMENTATION SAYS:
|
||||
The Ultimedia Audio Adapter supports fourteen sample rates you can use to
|
||||
capture and playback audio data. The rates are (in kHz): 5.51, 6.62, 8.0,
|
||||
9.6, 11.025, 16.0, 18.9, 22.050, 27.42, 32.0, 33.075, 37.8, 44.1, and 48.0.
|
||||
These rates are supported for mono and stereo PCM (8- and 16-bit), mu-law,
|
||||
and A-law.
|
||||
*/
|
||||
|
||||
long rate;
|
||||
|
||||
rate = ao->rate;
|
||||
rate_best_match(ao);
|
||||
if (ao->rate == rate)
|
||||
return (MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_16|
|
||||
MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_8|
|
||||
MPG123_ENC_ULAW_8|MPG123_ENC_ALAW_8);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_aix(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_aix(out123_handle *ao)
|
||||
{
|
||||
audio_control acontrol;
|
||||
audio_buffer abuffer;
|
||||
int ret,i;
|
||||
|
||||
/* Don't close the audio-device until it's played all its contents */
|
||||
memset ( & acontrol, '\0', sizeof ( acontrol ) );
|
||||
acontrol.request_info = &abuffer;
|
||||
acontrol.position = 0;
|
||||
i=50; /* Don't do this forever on a bad day :-) */
|
||||
|
||||
while (i-- > 0) {
|
||||
if ((ioctl(ao->fn, AUDIO_BUFFER, &acontrol))< 0) {
|
||||
error1("buffer read failed: %d", errno);
|
||||
break;
|
||||
} else {
|
||||
if (abuffer.flags <= 0) break;
|
||||
}
|
||||
usleep(200000); /* sleep 0.2 sec */
|
||||
}
|
||||
|
||||
memset ( & acontrol, '\0', sizeof ( acontrol ) );
|
||||
acontrol.ioctl_request = AUDIO_STOP;
|
||||
acontrol.request_info = NULL;
|
||||
acontrol.position = 0;
|
||||
|
||||
ret = ioctl ( ao->fn, AUDIO_CONTROL, & acontrol );
|
||||
if (ret < 0) error("Can't close audio!");
|
||||
|
||||
ret = close (ao->fn);
|
||||
if (ret < 0) error("Can't close audio!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_aix(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
static int init_aix(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_aix;
|
||||
ao->flush = flush_aix;
|
||||
ao->write = write_aix;
|
||||
ao->get_formats = get_formats_aix;
|
||||
ao->close = close_aix;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "aix",
|
||||
/* description */ "Output audio on IBM RS/6000 with AIX Ultimedia Services.",
|
||||
/* revision */ "$Rev: 932 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_aix,
|
||||
};
|
||||
|
||||
209
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alib.c
vendored
Normal file
209
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alib.c
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
alib: audio output for HP-UX using alib
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Erwan Ducroquet
|
||||
based on source code from HP (Audio SDK)
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* for mpg123 :
|
||||
* hpux:
|
||||
* $(MAKE) \
|
||||
* CC=cc \
|
||||
* LDFLAGS=-L/opt/audio/lib \
|
||||
* AUDIO_LIB=-lAlib \
|
||||
* OBJECTS=decode.o dct64.o \
|
||||
* CFLAGS=-Ae +O3 -DREAL_IS_FLOAT -D_HPUX_SOURCE -DHPUX -I/opt/audio/include \
|
||||
* mpg123
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* For the user :
|
||||
* If you launch mpg123 on a XTerm with sound capabilities, it's OK
|
||||
* Else, you have to set the environment variable "AUDIO" to the name of
|
||||
* an HP Xterm with sound card.
|
||||
*/
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include <Alib.h> /* /opt/audio/include */
|
||||
#include <CUlib.h> /* /opt/audio/include */
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/* FIXME: These globals should be moved into a structure */
|
||||
static Audio *audioServer = (Audio *) NULL;
|
||||
static struct protoent *tcpProtocolEntry;
|
||||
static ATransID xid;
|
||||
|
||||
static void printAudioError(Audio *audio,char *message,int errorCode) {
|
||||
char errorbuff[132];
|
||||
AGetErrorText(audio, errorCode, errorbuff, 131);
|
||||
error2("%s: %s", message, errorbuff);
|
||||
}
|
||||
static long myHandler(Audio *audio,AErrorEvent *err_event) {
|
||||
printAudioError( audio, "Audio error", err_event->error_code );
|
||||
/* we cannot just do random exists, that messes terminal up
|
||||
need proper error propagation in that case for future, setting intflag or such */
|
||||
/* exit(1); */
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
* Set the fn element of ai
|
||||
* Use ao->rate and ao->channels
|
||||
* Doesn't set any volume
|
||||
*/
|
||||
|
||||
/* return on error leaves stuff dirty here... */
|
||||
static int open_alib(out123_handle *ao)
|
||||
{
|
||||
AudioAttributes Attribs;
|
||||
AudioAttrMask AttribsMask;
|
||||
AGainEntry gainEntry[4];
|
||||
SSPlayParams playParams;
|
||||
SStream audioStream;
|
||||
AErrorHandler prevHandler;
|
||||
char server[1];
|
||||
int i;
|
||||
long status;
|
||||
|
||||
if (audioServer) {
|
||||
error("openAudio: audio already open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
prevHandler = ASetErrorHandler(myHandler);
|
||||
|
||||
server[0] = '\0';
|
||||
audioServer = AOpenAudio( server, NULL );
|
||||
if (audioServer==NULL) {
|
||||
error("Error: could not open audio\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ao->fn = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
if(ao->fn<0) {
|
||||
error("Socket creation failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Attribs.type = ATSampled;
|
||||
Attribs.attr.sampled_attr.sampling_rate = ao->rate;
|
||||
Attribs.attr.sampled_attr.channels = ao->channels;
|
||||
Attribs.attr.sampled_attr.data_format = ADFLin16;
|
||||
AttribsMask = ASSamplingRateMask | ASChannelsMask | ASDataFormatMask;
|
||||
|
||||
gainEntry[0].gain = AUnityGain;
|
||||
gainEntry[0].u.o.out_ch = AOCTMono;
|
||||
gainEntry[0].u.o.out_dst = AODTDefaultOutput;
|
||||
|
||||
playParams.gain_matrix.type = AGMTOutput; /* gain matrix */
|
||||
playParams.gain_matrix.num_entries = 1;
|
||||
playParams.gain_matrix.gain_entries = gainEntry;
|
||||
playParams.play_volume = AUnityGain; /* play volume */
|
||||
playParams.priority = APriorityNormal; /* normal priority */
|
||||
playParams.event_mask = 0; /* don't solicit any events */
|
||||
|
||||
xid=APlaySStream(audioServer,AttribsMask,&Attribs,
|
||||
&playParams,&audioStream,NULL);
|
||||
|
||||
status=connect(ao->fn,
|
||||
(struct sockaddr *) &audioStream.tcp_sockaddr,
|
||||
sizeof(struct sockaddr_in) );
|
||||
if (status<0) {
|
||||
error("Connect failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i=-1;
|
||||
tcpProtocolEntry=getprotobyname("tcp");
|
||||
setsockopt(ao->fn,tcpProtocolEntry->p_proto,TCP_NODELAY,&i,sizeof(i));
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int close_alib(out123_handle *ao)
|
||||
{
|
||||
close(ao->fn);
|
||||
ASetCloseDownMode( audioServer, AKeepTransactions, NULL );
|
||||
ACloseAudio( audioServer, NULL );
|
||||
audioServer = (Audio *) NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/*
|
||||
* very simple
|
||||
* deserv to be inline
|
||||
*/
|
||||
|
||||
static int write_alib(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len*2);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int get_formats_alib(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static void flush_alib(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_alib(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_alib;
|
||||
ao->flush = flush_alib;
|
||||
ao->write = write_alib;
|
||||
ao->get_formats = get_formats_alib;
|
||||
ao->close = close_alib;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "alib",
|
||||
/* description */ "Output audio HP-UX using alib.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_alib,
|
||||
};
|
||||
|
||||
309
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alsa.c
vendored
Normal file
309
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/alsa.c
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
alsa: sound output with Advanced Linux Sound Architecture 1.x API
|
||||
|
||||
copyright 2006-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
initially written by Clemens Ladisch <clemens@ladisch.de>
|
||||
*/
|
||||
|
||||
/* ALSA headers define struct timeval if no POSIX macro is set,
|
||||
nicely in conflict with definitions in system headers. They had
|
||||
a discussion about that a long time ago:
|
||||
http://mailman.alsa-project.org/pipermail/alsa-devel/2007-June/001684.html
|
||||
... seems like the conclusion was not carried through.
|
||||
*/
|
||||
#define _POSIX_SOURCE
|
||||
/* Things are still missing if _DEFAULT_SOURCE is not defined (for recent
|
||||
glibc, I presume. */
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
/* make ALSA 0.9.x compatible to the 1.0.x API */
|
||||
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||
#define ALSA_PCM_NEW_SW_PARAMS_API
|
||||
|
||||
#include <alloca.h> /* GCC complains about missing declaration of alloca. */
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* Total buffer size in seconds, 0.2 is more true to what ALSA maximally uses
|
||||
here (8192 samples). The earlier default of 0.5 was never true. */
|
||||
#define BUFFER_LENGTH (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
|
||||
static const struct {
|
||||
snd_pcm_format_t alsa;
|
||||
int mpg123;
|
||||
} format_map[] = {
|
||||
{ SND_PCM_FORMAT_S16, MPG123_ENC_SIGNED_16 },
|
||||
{ SND_PCM_FORMAT_U16, MPG123_ENC_UNSIGNED_16 },
|
||||
{ SND_PCM_FORMAT_U8, MPG123_ENC_UNSIGNED_8 },
|
||||
{ SND_PCM_FORMAT_S8, MPG123_ENC_SIGNED_8 },
|
||||
{ SND_PCM_FORMAT_A_LAW, MPG123_ENC_ALAW_8 },
|
||||
{ SND_PCM_FORMAT_MU_LAW, MPG123_ENC_ULAW_8 },
|
||||
{ SND_PCM_FORMAT_S32, MPG123_ENC_SIGNED_32 },
|
||||
{ SND_PCM_FORMAT_U32, MPG123_ENC_UNSIGNED_32 },
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{ SND_PCM_FORMAT_S24_3BE, MPG123_ENC_SIGNED_24 },
|
||||
{ SND_PCM_FORMAT_U24_3BE, MPG123_ENC_UNSIGNED_24 },
|
||||
#else
|
||||
{ SND_PCM_FORMAT_S24_3LE, MPG123_ENC_SIGNED_24 },
|
||||
{ SND_PCM_FORMAT_U24_3LE, MPG123_ENC_UNSIGNED_24 },
|
||||
#endif
|
||||
{ SND_PCM_FORMAT_FLOAT, MPG123_ENC_FLOAT_32 },
|
||||
{ SND_PCM_FORMAT_FLOAT64, MPG123_ENC_FLOAT_64 }
|
||||
};
|
||||
#define NUM_FORMATS (sizeof format_map / sizeof format_map[0])
|
||||
|
||||
|
||||
static int rates_match(long int desired, unsigned int actual)
|
||||
{
|
||||
return actual * 100 > desired * (100 - AUDIO_RATE_TOLERANCE) &&
|
||||
actual * 100 < desired * (100 + AUDIO_RATE_TOLERANCE);
|
||||
}
|
||||
|
||||
static int initialize_device(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_hw_params_t *hw=NULL;
|
||||
snd_pcm_sw_params_t *sw=NULL;
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
unsigned int rate;
|
||||
int i;
|
||||
|
||||
snd_pcm_hw_params_alloca(&hw); /* Ignore GCC warning here... alsa-lib>=1.0.16 doesn't trigger that anymore, too. */
|
||||
if (snd_pcm_hw_params_any(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): no configuration available");
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): device does not support interleaved access");
|
||||
return -1;
|
||||
}
|
||||
format = SND_PCM_FORMAT_UNKNOWN;
|
||||
for (i = 0; i < NUM_FORMATS; ++i) {
|
||||
if (ao->format == format_map[i].mpg123) {
|
||||
format = format_map[i].alsa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (format == SND_PCM_FORMAT_UNKNOWN) {
|
||||
if(!AOQUIET) error1("initialize_device(): invalid sample format %d", ao->format);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_format(pcm, hw, format) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set format %s", snd_pcm_format_name(format));
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_channels(pcm, hw, ao->channels) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set %d channels", ao->channels);
|
||||
return -1;
|
||||
}
|
||||
rate = ao->rate;
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, NULL) < 0) {
|
||||
if(!AOQUIET) error1("initialize_device(): cannot set rate %u", rate);
|
||||
return -1;
|
||||
}
|
||||
if (!rates_match(ao->rate, rate)) {
|
||||
if(!AOQUIET) error2("initialize_device(): rate %ld not available, using %u", ao->rate, rate);
|
||||
/* return -1; */
|
||||
}
|
||||
buffer_size = rate * BUFFER_LENGTH;
|
||||
if (snd_pcm_hw_params_set_buffer_size_near(pcm, hw, &buffer_size) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set buffer size");
|
||||
return -1;
|
||||
}
|
||||
debug1("buffer_size=%lu", (unsigned long)buffer_size);
|
||||
period_size = buffer_size / 3; /* 3 periods is so much more common. */
|
||||
if (snd_pcm_hw_params_set_period_size_near(pcm, hw, &period_size, NULL) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set period size");
|
||||
return -1;
|
||||
}
|
||||
debug1("period_size=%lu", (unsigned long)period_size);
|
||||
if (snd_pcm_hw_params(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set hw params");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snd_pcm_sw_params_alloca(&sw);
|
||||
if (snd_pcm_sw_params_current(pcm, sw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot get sw params");
|
||||
return -1;
|
||||
}
|
||||
/* start playing right away */
|
||||
if (snd_pcm_sw_params_set_start_threshold(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set start threshold");
|
||||
return -1;
|
||||
}
|
||||
/* wake up on every interrupt */
|
||||
if (snd_pcm_sw_params_set_avail_min(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set min available");
|
||||
return -1;
|
||||
}
|
||||
#if SND_LIB_VERSION < ((1<<16)|16)
|
||||
/* Always write as many frames as possible (deprecated since alsa-lib 1.0.16) */
|
||||
if (snd_pcm_sw_params_set_xfer_align(pcm, sw, 1) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set transfer alignment");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (snd_pcm_sw_params(pcm, sw) < 0) {
|
||||
if(!AOQUIET) error("initialize_device(): cannot set sw params");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
static void error_ignorer(const char *file, int line, const char *function, int err, const char *fmt,...)
|
||||
{
|
||||
/* I can make ALSA silent. */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int open_alsa(out123_handle *ao)
|
||||
{
|
||||
const char *pcm_name;
|
||||
snd_pcm_t *pcm=NULL;
|
||||
debug1("open_alsa with %p", ao->userptr);
|
||||
|
||||
#ifndef DEBUG
|
||||
if(AOQUIET) snd_lib_error_set_handler(error_ignorer);
|
||||
#endif
|
||||
|
||||
pcm_name = ao->device ? ao->device : "default";
|
||||
if (snd_pcm_open(&pcm, pcm_name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
if(!AOQUIET) error1("cannot open device %s", pcm_name);
|
||||
return -1;
|
||||
}
|
||||
ao->userptr = pcm;
|
||||
if (ao->format != -1) {
|
||||
/* we're going to play: initalize sample format */
|
||||
return initialize_device(ao);
|
||||
} else {
|
||||
/* query mode; sample format will be set for each query */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
snd_pcm_hw_params_t *hw;
|
||||
unsigned int rate;
|
||||
int supported_formats, i;
|
||||
|
||||
snd_pcm_hw_params_alloca(&hw);
|
||||
if (snd_pcm_hw_params_any(pcm, hw) < 0) {
|
||||
if(!AOQUIET) error("get_formats_alsa(): no configuration available");
|
||||
return -1;
|
||||
}
|
||||
if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
|
||||
return -1;
|
||||
if (snd_pcm_hw_params_set_channels(pcm, hw, ao->channels) < 0)
|
||||
return 0;
|
||||
rate = ao->rate;
|
||||
if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, NULL) < 0)
|
||||
return -1;
|
||||
if (!rates_match(ao->rate, rate))
|
||||
return 0;
|
||||
supported_formats = 0;
|
||||
for (i = 0; i < NUM_FORMATS; ++i) {
|
||||
if (snd_pcm_hw_params_test_format(pcm, hw, format_map[i].alsa) == 0)
|
||||
supported_formats |= format_map[i].mpg123;
|
||||
}
|
||||
return supported_formats;
|
||||
}
|
||||
|
||||
static int write_alsa(out123_handle *ao, unsigned char *buf, int bytes)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
snd_pcm_uframes_t frames;
|
||||
snd_pcm_sframes_t written;
|
||||
|
||||
frames = snd_pcm_bytes_to_frames(pcm, bytes);
|
||||
while
|
||||
( /* Try to write, recover if error, try again if recovery successful. */
|
||||
(written = snd_pcm_writei(pcm, buf, frames)) < 0
|
||||
&& snd_pcm_recover(pcm, (int)written, 0) == 0
|
||||
)
|
||||
{
|
||||
debug2("recovered from alsa issue %i while trying to write %lu frames", (int)written, (unsigned long)frames);
|
||||
}
|
||||
if(written < 0)
|
||||
{
|
||||
error1("Fatal problem with alsa output, error %i.", (int)written);
|
||||
return -1;
|
||||
}
|
||||
else return snd_pcm_frames_to_bytes(pcm, written);
|
||||
}
|
||||
|
||||
static void flush_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
|
||||
/* is this the optimal solution? - we should figure out what we really whant from this function */
|
||||
|
||||
debug("alsa drop");
|
||||
snd_pcm_drop(pcm);
|
||||
debug("alsa prepare");
|
||||
snd_pcm_prepare(pcm);
|
||||
debug("alsa flush done");
|
||||
}
|
||||
|
||||
static void drain_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
debug1("drain_alsa with %p", ao->userptr);
|
||||
snd_pcm_drain(pcm);
|
||||
}
|
||||
|
||||
static int close_alsa(out123_handle *ao)
|
||||
{
|
||||
snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
|
||||
debug1("close_alsa with %p", ao->userptr);
|
||||
if(pcm != NULL) /* be really generous for being called without any device opening */
|
||||
{
|
||||
ao->userptr = NULL; /* Should alsa do this or the module wrapper? */
|
||||
return snd_pcm_close(pcm);
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static int init_alsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_alsa;
|
||||
ao->flush = flush_alsa;
|
||||
ao->drain = drain_alsa;
|
||||
ao->write = write_alsa;
|
||||
ao->get_formats = get_formats_alsa;
|
||||
ao->close = close_alsa;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "alsa",
|
||||
/* description */ "Output audio using Advanced Linux Sound Architecture (ALSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_alsa,
|
||||
};
|
||||
|
||||
117
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/arts.c
vendored
Normal file
117
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/arts.c
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
arts: audio output via aRts Sound Daemon
|
||||
|
||||
copyright 2007-8 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
initially written by Stefan Lenselink (Stefan@lenselink.org)
|
||||
*/
|
||||
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <artsc.h>
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
arts_stream_t arse; /* That's short for ARts StrEam;-) */
|
||||
} mpg123_arts_t;
|
||||
|
||||
static int open_arts(out123_handle *ao)
|
||||
{
|
||||
short bits = 0;
|
||||
if(!ao) return -1;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
}
|
||||
/* Trial and error revealed these two formats to work with aRts. */
|
||||
if(ao->format == MPG123_ENC_SIGNED_16) bits = 16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8) bits = 8;
|
||||
else return -1;
|
||||
|
||||
/* Initialize the aRts lib*/
|
||||
arts_init();
|
||||
/* Open a stream to the aRts server */
|
||||
((mpg123_arts_t*)ao->userptr)->arse = arts_play_stream( ao->rate, bits, ao->channels, "mpg123" );
|
||||
/* Yeah, black box and all... it's still a pointer that is NULL on error. */
|
||||
return (void*)((mpg123_arts_t*)ao->userptr)->arse == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
static int get_formats_arts(out123_handle *ao)
|
||||
{
|
||||
/* aRts runs not everything, but any rate. */
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8;
|
||||
}
|
||||
|
||||
static int write_arts(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
/* PIPE the PCM forward to the aRts Sound Daemon */
|
||||
return arts_write( ((mpg123_arts_t*)ao->userptr)->arse , buf, len);
|
||||
}
|
||||
|
||||
static int close_arts(out123_handle *ao)
|
||||
{
|
||||
/* Close the connection! */
|
||||
arts_close_stream( ((mpg123_arts_t*)ao->userptr)->arse );
|
||||
/* Free the memory allocated*/
|
||||
arts_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_arts(out123_handle *ao)
|
||||
{
|
||||
/* aRts doesn't have a flush statement! */
|
||||
}
|
||||
|
||||
static int deinit_arts(out123_handle* ao)
|
||||
{
|
||||
if(ao->userptr)
|
||||
{
|
||||
free(ao->userptr);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
arts_free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_arts(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
ao->userptr = malloc(sizeof(mpg123_arts_t));
|
||||
if(ao->userptr == NULL)
|
||||
{
|
||||
error("Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
/* clear it to have a consistent state */
|
||||
memset(ao->userptr, 0, sizeof(mpg123_arts_t));
|
||||
/* Set callbacks */
|
||||
ao->open = open_arts;
|
||||
ao->flush = flush_arts;
|
||||
ao->write = write_arts;
|
||||
ao->get_formats = get_formats_arts;
|
||||
ao->close = close_arts;
|
||||
ao->deinit = deinit_arts;
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "arts",
|
||||
/* description */ "Output audio using aRts Sound Daemon",
|
||||
/* revision */ "$Rev: $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_arts,
|
||||
};
|
||||
|
||||
|
||||
435
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/coreaudio.c
vendored
Normal file
435
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/coreaudio.c
vendored
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
coreaudio: audio output on MacOS X
|
||||
|
||||
copyright ?-2016 by the mpg123 project - free software under the terms of the GPL 2
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Guillaume Outters
|
||||
modified by Nicholas J Humfrey to use SFIFO code
|
||||
modified by Taihei Monma to use AudioUnit and AudioConverter APIs
|
||||
*/
|
||||
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
/* has been around since at least 10.4 */
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
/* Use AudioComponents API when compiling for >= 10.6, otherwise fall back to
|
||||
* Components Manager, which is deprecated since 10.8.
|
||||
* MAC_OS_X_VERSION_MIN_REQUIRED defaults to the host system version and can be
|
||||
* governed by MACOSX_DEPLOYMENT_TARGET environment variable and
|
||||
* -mmacosx-version-min= when running the compiler. */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 20000
|
||||
#define HAVE_AUDIOCOMPONENTS 1
|
||||
#endif
|
||||
|
||||
#if HAVE_AUDIOCOMPONENTS
|
||||
#define MPG123_AUDIOCOMPONENTDESCRIPTION AudioComponentDescription
|
||||
#define MPG123_AUDIOCOMPONENT AudioComponent
|
||||
#define MPG123_AUDIOCOMPONENTFINDNEXT AudioComponentFindNext
|
||||
/* Funky API twist: AudioUnit is actually typedef'd AudioComponentInstance */
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCENEW AudioComponentInstanceNew
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCEDISPOSE AudioComponentInstanceDispose
|
||||
#else
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#define MPG123_AUDIOCOMPONENTDESCRIPTION ComponentDescription
|
||||
#define MPG123_AUDIOCOMPONENT Component
|
||||
#define MPG123_AUDIOCOMPONENTFINDNEXT FindNextComponent
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCENEW OpenAComponent
|
||||
#define MPG123_AUDIOCOMPONENTINSTANCEDISPOSE CloseComponent
|
||||
#endif
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* Duration of the ring buffer in seconds.
|
||||
Is that all that there is to tunable latency?
|
||||
Size of 200 ms should be enough for a default value, rare is the
|
||||
hardware that actually allows such large buffers. */
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
|
||||
|
||||
typedef struct mpg123_coreaudio
|
||||
{
|
||||
AudioConverterRef converter;
|
||||
AudioUnit outputUnit;
|
||||
int open;
|
||||
char play;
|
||||
int channels;
|
||||
int bps;
|
||||
int play_done;
|
||||
int decode_done;
|
||||
|
||||
/* Convertion buffer */
|
||||
unsigned char * buffer;
|
||||
size_t buffer_size;
|
||||
|
||||
/* Ring buffer */
|
||||
sfifo_t fifo;
|
||||
|
||||
} mpg123_coreaudio_t;
|
||||
|
||||
|
||||
|
||||
static OSStatus playProc(AudioConverterRef inAudioConverter,
|
||||
UInt32 *ioNumberDataPackets,
|
||||
AudioBufferList *outOutputData,
|
||||
AudioStreamPacketDescription **outDataPacketDescription,
|
||||
void* inClientData)
|
||||
{
|
||||
out123_handle *ao = (out123_handle*)inClientData;
|
||||
mpg123_coreaudio_t *ca = (mpg123_coreaudio_t *)ao->userptr;
|
||||
long n;
|
||||
|
||||
/* This is not actually a loop. See the early break. */
|
||||
for(n = 0; n < outOutputData->mNumberBuffers; n++)
|
||||
{
|
||||
unsigned int wanted = *ioNumberDataPackets * ca->channels * ca->bps;
|
||||
unsigned char *dest;
|
||||
unsigned int read;
|
||||
int avail;
|
||||
|
||||
/* Any buffer count > 1 would wreck havoc with this code. */
|
||||
if(n > 0)
|
||||
break;
|
||||
|
||||
if(ca->buffer_size < wanted) {
|
||||
debug1("Allocating %d byte sample conversion buffer", wanted);
|
||||
ca->buffer = realloc( ca->buffer, wanted);
|
||||
ca->buffer_size = wanted;
|
||||
}
|
||||
dest = ca->buffer;
|
||||
if(!dest)
|
||||
return -1;
|
||||
|
||||
/* Only play if we have data left */
|
||||
while((avail=sfifo_used( &ca->fifo )) < wanted && !ca->decode_done)
|
||||
{
|
||||
int ms = (wanted-avail)/ao->framesize*1000/ao->rate;
|
||||
debug3("waiting for more input, %d ms missing (%i < %u)"
|
||||
, ms, avail, wanted);
|
||||
usleep(ms*100); /* Wait for 1/10th of the missing duration. Might want to adjust. */
|
||||
}
|
||||
if(avail > wanted)
|
||||
avail = wanted;
|
||||
else if(ca->decode_done)
|
||||
ca->play_done = 1;
|
||||
|
||||
/* Read audio from FIFO to CoreAudio's buffer */
|
||||
read = sfifo_read(&ca->fifo, dest, avail);
|
||||
|
||||
if(read!=avail)
|
||||
warning2("Error reading from the ring buffer (avail=%u, read=%u).\n", avail, read);
|
||||
|
||||
outOutputData->mBuffers[n].mDataByteSize = read;
|
||||
outOutputData->mBuffers[n].mData = dest;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static OSStatus convertProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
|
||||
UInt32 inNumFrames, AudioBufferList *ioData)
|
||||
{
|
||||
AudioStreamPacketDescription* outPacketDescription = NULL;
|
||||
out123_handle *ao = (out123_handle*)inRefCon;
|
||||
mpg123_coreaudio_t *ca = (mpg123_coreaudio_t *)ao->userptr;
|
||||
OSStatus err= noErr;
|
||||
|
||||
err = AudioConverterFillComplexBuffer(ca->converter, playProc, inRefCon, &inNumFrames, ioData, outPacketDescription);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int open_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
UInt32 size;
|
||||
MPG123_AUDIOCOMPONENTDESCRIPTION desc;
|
||||
MPG123_AUDIOCOMPONENT comp;
|
||||
AudioStreamBasicDescription inFormat;
|
||||
AudioStreamBasicDescription outFormat;
|
||||
AURenderCallbackStruct renderCallback;
|
||||
Boolean outWritable;
|
||||
|
||||
/* Initialize our environment */
|
||||
ca->play = 0;
|
||||
ca->buffer = NULL;
|
||||
ca->buffer_size = 0;
|
||||
ca->play_done = 0;
|
||||
ca->decode_done = 0;
|
||||
|
||||
/* Get the default audio output unit */
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
#if TARGET_OS_IPHONE
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
#else
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
#endif
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
comp = MPG123_AUDIOCOMPONENTFINDNEXT(NULL, &desc);
|
||||
if(comp == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioComponentFindNext failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(MPG123_AUDIOCOMPONENTINSTANCENEW(comp, &(ca->outputUnit)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioComponentInstanceNew failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if(AudioUnitInitialize(ca->outputUnit))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitInitialize failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Specify the output PCM format */
|
||||
AudioUnitGetPropertyInfo(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &size, &outWritable);
|
||||
if(AudioUnitGetProperty(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outFormat, &size))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitGetProperty(kAudioUnitProperty_StreamFormat) failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if(AudioUnitSetProperty(ca->outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outFormat, size))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Specify the input PCM format */
|
||||
ca->channels = ao->channels;
|
||||
inFormat.mSampleRate = ao->rate;
|
||||
inFormat.mChannelsPerFrame = ao->channels;
|
||||
inFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
#ifdef _BIG_ENDIAN
|
||||
inFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
|
||||
#else
|
||||
inFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||
#endif
|
||||
|
||||
switch(ao->format)
|
||||
{
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 2;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 1;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ca->bps = 1;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
ca->bps = 4;
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
inFormat.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
|
||||
ca->bps = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
inFormat.mBitsPerChannel = ca->bps << 3;
|
||||
inFormat.mBytesPerPacket = ca->bps*inFormat.mChannelsPerFrame;
|
||||
inFormat.mFramesPerPacket = 1;
|
||||
inFormat.mBytesPerFrame = ca->bps*inFormat.mChannelsPerFrame;
|
||||
|
||||
/* Add our callback - but don't start it yet */
|
||||
memset(&renderCallback, 0, sizeof(AURenderCallbackStruct));
|
||||
renderCallback.inputProc = convertProc;
|
||||
renderCallback.inputProcRefCon = ao;
|
||||
if(AudioUnitSetProperty(ca->outputUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(AURenderCallbackStruct)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioUnitSetProperty(kAudioUnitProperty_SetRenderCallback) failed");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Open an audio I/O stream and create converter */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
int ringbuffer_len;
|
||||
|
||||
if(AudioConverterNew(&inFormat, &outFormat, &(ca->converter)))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterNew failed");
|
||||
return(-1);
|
||||
}
|
||||
if(ao->channels == 1) {
|
||||
SInt32 channelMap[2] = { 0, 0 };
|
||||
if(AudioConverterSetProperty(ca->converter, kAudioConverterChannelMap, sizeof(channelMap), channelMap))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterSetProperty(kAudioConverterChannelMap) failed");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
ringbuffer_len = ao->rate * FIFO_DURATION * ca->bps * ao->channels;
|
||||
debug2( "Allocating %d byte ring-buffer (%f seconds)", ringbuffer_len, (float)FIFO_DURATION);
|
||||
sfifo_init( &ca->fifo, ringbuffer_len );
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int get_formats_coreaudio(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_SIGNED_8|MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_32|MPG123_ENC_FLOAT_32;
|
||||
}
|
||||
|
||||
static int write_coreaudio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(&ca->fifo);
|
||||
block -= block % ao->framesize;
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(&ca->fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Start playback now that we have something to play */
|
||||
if(!ca->play && (sfifo_used(&ca->fifo) > (sfifo_size(&ca->fifo)/2)))
|
||||
{
|
||||
if(AudioOutputUnitStart(ca->outputUnit))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioOutputUnitStart failed");
|
||||
return(-1);
|
||||
}
|
||||
ca->play = 1;
|
||||
}
|
||||
}
|
||||
/* If there is no room, then sleep for a bit, but not too long. */
|
||||
if(len_remain)
|
||||
usleep( (0.1*FIFO_DURATION) * 1000000 );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
|
||||
if (ca) {
|
||||
ca->decode_done = 1;
|
||||
while(!ca->play_done && ca->play)
|
||||
usleep((0.1*FIFO_DURATION)*1000000);
|
||||
/* No matter the error code, we want to close it (by brute force if necessary) */
|
||||
AudioOutputUnitStop(ca->outputUnit);
|
||||
AudioUnitUninitialize(ca->outputUnit);
|
||||
MPG123_AUDIOCOMPONENTINSTANCEDISPOSE(ca->outputUnit);
|
||||
AudioConverterDispose(ca->converter);
|
||||
|
||||
/* Free the ring buffer */
|
||||
sfifo_close( &ca->fifo );
|
||||
|
||||
/* Free the conversion buffer */
|
||||
if (ca->buffer) {
|
||||
free( ca->buffer );
|
||||
ca->buffer = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_coreaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_coreaudio_t* ca = (mpg123_coreaudio_t*)ao->userptr;
|
||||
|
||||
/* Flush AudioConverter's buffer */
|
||||
if(AudioConverterReset(ca->converter))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AudioConverterReset failed");
|
||||
}
|
||||
|
||||
/* Empty out the ring buffer */
|
||||
sfifo_flush( &ca->fifo );
|
||||
}
|
||||
|
||||
static int deinit_coreaudio(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_coreaudio(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_coreaudio;
|
||||
ao->flush = flush_coreaudio;
|
||||
ao->write = write_coreaudio;
|
||||
ao->get_formats = get_formats_coreaudio;
|
||||
ao->close = close_coreaudio;
|
||||
ao->deinit = deinit_coreaudio;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_coreaudio_t ) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_coreaudio_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_coreaudio_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "coreaudio",
|
||||
/* description */ "Output audio using Mac OS X's CoreAudio.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_coreaudio,
|
||||
};
|
||||
|
||||
|
||||
84
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/dummy.c
vendored
Normal file
84
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/dummy.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
dummy: dummy audio output
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int open_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("open_dummy()");
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("get_formats_dummy()");
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static int write_dummy(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
debug("write_dummy()");
|
||||
return len;
|
||||
}
|
||||
|
||||
static void flush_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("flush_dummy()");
|
||||
}
|
||||
|
||||
static int close_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("close_dummy()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_dummy(out123_handle *ao)
|
||||
{
|
||||
debug("deinit_dummy()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_dummy(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
debug("init_dummy()");
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_dummy;
|
||||
ao->flush = flush_dummy;
|
||||
ao->write = write_dummy;
|
||||
ao->get_formats = get_formats_dummy;
|
||||
ao->close = close_dummy;
|
||||
ao->deinit = deinit_dummy;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "dummy",
|
||||
/* description */ "Dummy audio output - does not output audio.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_dummy,
|
||||
};
|
||||
|
||||
169
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/esd.c
vendored
Normal file
169
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/esd.c
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
esd: audio output for ESounD (highly untested nowadays (?))
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Eric B. Mitchell ("esd port" should be this file...)
|
||||
*/
|
||||
|
||||
/* First the common header, including config.h
|
||||
...this is important for stuff like _FILE_OFFSET_BITS */
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <esd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <stropts.h>
|
||||
#include <sys/conf.h>
|
||||
#endif
|
||||
#ifdef NETBSD
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
#include "debug.h"
|
||||
|
||||
static unsigned esd_rate = 0, esd_format = 0, esd_channels = 0;
|
||||
|
||||
|
||||
static int open_esound(out123_handle *ao)
|
||||
{
|
||||
esd_format_t format = ESD_STREAM | ESD_PLAY;
|
||||
|
||||
if (!esd_rate)
|
||||
{
|
||||
int esd;
|
||||
esd_server_info_t *info;
|
||||
esd_format_t fmt;
|
||||
|
||||
if ((esd = esd_open_sound(NULL)) >= 0)
|
||||
{
|
||||
info = esd_get_server_info(esd);
|
||||
esd_rate = info->rate;
|
||||
fmt = info->format;
|
||||
esd_free_server_info(info);
|
||||
esd_close(esd);
|
||||
}
|
||||
else
|
||||
{
|
||||
esd_rate = esd_audio_rate;
|
||||
fmt = esd_audio_format;
|
||||
}
|
||||
esd_format = MPG123_ENC_UNSIGNED_8;
|
||||
|
||||
if ((fmt & ESD_MASK_BITS) == ESD_BITS16)
|
||||
esd_format |= MPG123_ENC_SIGNED_16;
|
||||
esd_channels = fmt & ESD_MASK_CHAN;
|
||||
}
|
||||
|
||||
if (ao->format == -1)
|
||||
ao->format = esd_format;
|
||||
else if (!(ao->format & esd_format))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported audio format: %d\n", ao->format);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (ao->format & MPG123_ENC_SIGNED_16)
|
||||
format |= ESD_BITS16;
|
||||
else if (ao->format & MPG123_ENC_UNSIGNED_8)
|
||||
format |= ESD_BITS8;
|
||||
else assert(0);
|
||||
|
||||
if (ao->channels == -1) ao->channels = 2;
|
||||
else if (ao->channels <= 0 || ao->channels > esd_channels)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported no of channels: %d\n", ao->channels);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (ao->channels == 1)
|
||||
format |= ESD_MONO;
|
||||
else if (ao->channels == 2)
|
||||
format |= ESD_STEREO;
|
||||
else assert(0);
|
||||
|
||||
if (ao->rate == -1) ao->rate = esd_rate;
|
||||
else if (ao->rate > esd_rate)
|
||||
return -1;
|
||||
|
||||
ao->fn = esd_play_stream_fallback(format, ao->rate, ao->device, "mpg123");
|
||||
return (ao->fn);
|
||||
}
|
||||
|
||||
static int get_formats_esound (out123_handle *ao)
|
||||
{
|
||||
if (0 < ao->channels && ao->channels <= esd_channels
|
||||
&& 0 < ao->rate && ao->rate <= esd_rate)
|
||||
{
|
||||
return esd_format;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_esound(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_esound(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SOLARIS
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
ioctl (ao->fn, I_FLUSH, FLUSHRW);
|
||||
}
|
||||
#else
|
||||
#ifdef NETBSD
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
ioctl (ao->fn, AUDIO_FLUSH, 0);
|
||||
}
|
||||
#else
|
||||
/* Dunno what to do on Linux and Cygwin, but the func must be at least defined! */
|
||||
static void flush_esound (out123_handle *ao)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static int init_esound(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_esound;
|
||||
ao->flush = flush_esound;
|
||||
ao->write = write_esound;
|
||||
ao->get_formats = get_formats_esound;
|
||||
ao->close = close_esound;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "esd",
|
||||
/* description */ "Output audio using ESounD (The Enlightened Sound Daemon).",
|
||||
/* revision */ "$Rev: 3915 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_esound,
|
||||
};
|
||||
184
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/hp.c
vendored
Normal file
184
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/hp.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
hp: audio output for HP-UX
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Michael Hipp
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/audio.h>
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
if(ao->rate >= 0) {
|
||||
return ioctl(ao->fn,AUDIO_SET_SAMPLE_RATE,ao->rate);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
if(ao->channels<0) return 0;
|
||||
return ioctl(ao->fn,AUDIO_SET_CHANNELS,ao->channels);
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
int fmt;
|
||||
|
||||
switch(ao->format) {
|
||||
case -1:
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmt = MPG123_ENC_LINEAR16BIT;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
error("unsigned 8 bit linear not supported");
|
||||
return -1;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
error("signed 8 bit linear not supported");
|
||||
return -1;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
fmt = MPG123_ENC_ALAW;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmt = MPG123_ENC_ULAW;
|
||||
break;
|
||||
}
|
||||
return ioctl(ao->fn,AUDIO_SET_DATA_FORMAT,fmt);
|
||||
}
|
||||
|
||||
static int get_formats(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = set_format(ai);
|
||||
if(ret >= 0)
|
||||
ret = set_channels_hp(ai);
|
||||
if(ret >= 0)
|
||||
ret = set_rate_hp(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int open_hp(out123_handle *ao)
|
||||
{
|
||||
struct audio_describe ades;
|
||||
struct audio_gain again;
|
||||
int i,audio;
|
||||
|
||||
ao->fn = open("/dev/audio",O_RDWR);
|
||||
|
||||
if(ao->fn < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
ioctl(ao->fn,AUDIO_DESCRIBE,&ades);
|
||||
|
||||
if(ao->gain != -1)
|
||||
{
|
||||
if(ao->gain > ades.max_transmit_gain)
|
||||
{
|
||||
error("your gainvalue was to high -> set to maximum.");
|
||||
ao->gain = ades.max_transmit_gain;
|
||||
}
|
||||
if(ao->gain < ades.min_transmit_gain)
|
||||
{
|
||||
error("your gainvalue was to low -> set to minimum.");
|
||||
ao->gain = ades.min_transmit_gain;
|
||||
}
|
||||
again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
|
||||
ioctl(ao->fn,AUDIO_GET_GAINS,&again);
|
||||
again.cgain[0].transmit_gain = ao->gain;
|
||||
again.cgain[1].transmit_gain = ao->gain;
|
||||
again.channel_mask = AUDIO_CHANNEL_0 | AUDIO_CHANNEL_1;
|
||||
ioctl(ao->fn,AUDIO_SET_GAINS,&again);
|
||||
}
|
||||
|
||||
if(ao->flags != -1)
|
||||
{
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_SPEAKER);
|
||||
else if(ao->flags & OUT123_HEADPHONES)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_HEADPHONE);
|
||||
else if(ao->flags & OUT123_LINE_OUT)
|
||||
ioctl(ao->fn,AUDIO_SET_OUTPUT,OUT123_LINE);
|
||||
}
|
||||
|
||||
if(ao->rate == -1)
|
||||
ao->rate = 44100;
|
||||
|
||||
for(i=0;i<ades.nrates;i++)
|
||||
{
|
||||
if(ao->rate == ades.sample_rate[i])
|
||||
break;
|
||||
}
|
||||
if(i == ades.nrates)
|
||||
{
|
||||
error1("Can't set sample-rate to %ld.\n",ao->rate);
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if(reset_parameters(ai) < 0)
|
||||
return -1;
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int write_hp(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_hp(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_hp(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int init_hp(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_hp;
|
||||
ao->flush = flush_hp;
|
||||
ao->write = write_hp;
|
||||
ao->get_formats = get_formats_hp;
|
||||
ao->close = close_hp;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "hp",
|
||||
/* description */ "Output audio HP-UX",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_hp,
|
||||
};
|
||||
618
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/jack.c
vendored
Normal file
618
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/jack.c
vendored
Normal file
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
jack: audio output via JACK Audio Connection Kit
|
||||
|
||||
copyright 2006-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J. Humfrey
|
||||
|
||||
I reworked the processing logic. Only one ringbuffer, deinterleaving in the
|
||||
processing callback. A semaphore to avoid using usleep() for waiting. Up
|
||||
to 99 channels. Only float input (ensures that libmpg123 selects f32
|
||||
encoding). This is still a hack to shoehorn the JACK API into our model.
|
||||
|
||||
Damn. I'm wary of he semaphore. I'm sure I constructed a deadlock there.
|
||||
There's always a deadlock. --ThOr
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <jack/ringbuffer.h>
|
||||
/* Using some pthread to provide synchronization between process callback
|
||||
and writer part. The JACK API is not meant for this. Libpthread is
|
||||
pulled in as libjack dependency anyway. */
|
||||
#include <semaphore.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct {
|
||||
int alive;
|
||||
sem_t sem; /* semaphore to avoid busy waiting */
|
||||
int channels;
|
||||
int encoding;
|
||||
int framesize;
|
||||
jack_default_audio_sample_t **ports_buf;
|
||||
jack_port_t **ports;
|
||||
jack_ringbuffer_t *rb;
|
||||
size_t rb_size; /* in bytes */
|
||||
jack_client_t *client;
|
||||
char *procbuf;
|
||||
size_t procbuf_frames; /* in PCM frames */
|
||||
} jack_handle_t, *jack_handle_ptr;
|
||||
|
||||
static jack_handle_t* alloc_jack_handle(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle=NULL;
|
||||
int i;
|
||||
|
||||
handle = malloc(sizeof(jack_handle_t));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
handle->channels = ao->channels;
|
||||
handle->encoding = ao->format;
|
||||
handle->framesize = ao->framesize;
|
||||
handle->rb = NULL;
|
||||
handle->ports_buf = malloc( sizeof(jack_default_audio_sample_t*)
|
||||
* ao->channels );
|
||||
handle->ports = malloc(sizeof(jack_port_t*)*ao->channels);
|
||||
if(!handle->ports_buf || !handle->ports)
|
||||
{
|
||||
if(handle->ports_buf)
|
||||
free(handle->ports_buf);
|
||||
if(handle->ports)
|
||||
free(handle->ports);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<ao->channels; ++i)
|
||||
{
|
||||
handle->ports_buf[i] = NULL;
|
||||
handle->ports[i] = NULL;
|
||||
}
|
||||
if(sem_init(&handle->sem, 0, 0))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Semaphore init failed.");
|
||||
free(handle->ports_buf);
|
||||
free(handle->ports);
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
handle->alive = 0;
|
||||
handle->client = NULL;
|
||||
handle->procbuf = NULL;
|
||||
handle->rb_size = 0;
|
||||
handle->procbuf_frames = 0;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
static void free_jack_handle( jack_handle_t* handle )
|
||||
{
|
||||
int i;
|
||||
|
||||
if(handle->ports)
|
||||
{
|
||||
if(handle->client)
|
||||
for(i=0; i<handle->channels; i++)
|
||||
{
|
||||
/* Close the port for channel*/
|
||||
if(handle->ports[i])
|
||||
jack_port_unregister(handle->client, handle->ports[i]);
|
||||
}
|
||||
free(handle->ports);
|
||||
}
|
||||
if(handle->ports_buf)
|
||||
free(handle->ports_buf);
|
||||
/* Free up the ring buffer for channel*/
|
||||
if(handle->rb)
|
||||
jack_ringbuffer_free(handle->rb);
|
||||
if (handle->client)
|
||||
jack_client_close(handle->client);
|
||||
if (handle->procbuf)
|
||||
free(handle->procbuf);
|
||||
sem_destroy(&handle->sem);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
|
||||
static int process_callback( jack_nframes_t nframes, void *arg )
|
||||
{
|
||||
int c;
|
||||
jack_handle_t* handle = (jack_handle_t*)arg;
|
||||
size_t to_read = nframes;
|
||||
|
||||
for(c=0; c<handle->channels; ++c)
|
||||
handle->ports_buf[c] =
|
||||
jack_port_get_buffer(handle->ports[c], nframes);
|
||||
|
||||
/* One ringbuffer to rule them all, getting interleaved data piecewise
|
||||
and appending to non-interleaved buffers. */
|
||||
while(to_read)
|
||||
{
|
||||
/* Need to read into temporary storage, then deinterleave to JACK
|
||||
buffers. */
|
||||
size_t got_piece;
|
||||
size_t avail_piece;
|
||||
size_t piece = to_read > handle->procbuf_frames
|
||||
? handle->procbuf_frames
|
||||
: to_read;
|
||||
/* Ensure we get only full PCM frames by checking available byte count
|
||||
and reducing expectation. */
|
||||
avail_piece = jack_ringbuffer_read_space(handle->rb)/handle->framesize;
|
||||
got_piece = jack_ringbuffer_read( handle->rb
|
||||
, handle->procbuf, (avail_piece > piece ? piece : avail_piece)
|
||||
* handle->framesize ) / handle->framesize;
|
||||
debug2( "fetched %"SIZE_P" frames from ringbuffer (wanted %"SIZE_P")"
|
||||
, (size_p)got_piece, (size_p)piece );
|
||||
/* If this is the last piece, fill up, not time to wait. */
|
||||
if(to_read > piece)
|
||||
piece = got_piece; /* We got further loop cycle(s) to get the rest. */
|
||||
else
|
||||
{
|
||||
if(piece > got_piece)
|
||||
{
|
||||
debug("filling up with zeros");
|
||||
bzero( handle->procbuf+got_piece*handle->framesize
|
||||
, (piece-got_piece)*handle->framesize );
|
||||
}
|
||||
}
|
||||
/* Now extract the pieces for the channels. */
|
||||
for (c=0; c < handle->channels; ++c)
|
||||
{
|
||||
size_t n;
|
||||
jack_default_audio_sample_t *dst = handle->ports_buf[c];
|
||||
if(handle->encoding == MPG123_ENC_FLOAT_32)
|
||||
{
|
||||
float* src = (float*)handle->procbuf;
|
||||
for(n=0; n<piece; ++n)
|
||||
*(dst++) = src[(n*handle->channels)+c];
|
||||
}
|
||||
else /* MPG123_ENC_FLOAT_64 */
|
||||
{
|
||||
double* src = (double*)handle->procbuf;
|
||||
for(n=0; n<piece; ++n)
|
||||
*(dst++) = src[(n*handle->channels)+c];
|
||||
}
|
||||
/* Store output buffer offset. */
|
||||
handle->ports_buf[c] = dst;
|
||||
}
|
||||
/* Give the writer a hint about the time passed. */
|
||||
sem_post(&handle->sem);
|
||||
to_read -= piece;
|
||||
}
|
||||
/* Success*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is triggered on server shutdown and very much necessary to avoid
|
||||
out123 hanging on the processor semaphore. */
|
||||
static void shutdown_callback(void *arg)
|
||||
{
|
||||
jack_handle_t* handle = (jack_handle_t*)arg;
|
||||
handle->alive = 0;
|
||||
sem_post(&handle->sem);
|
||||
debug("shutdown_callback()");
|
||||
}
|
||||
|
||||
/* connect to jack ports named in the NULL-terminated wishlist */
|
||||
static int real_connect_jack_ports(out123_handle *ao
|
||||
, jack_handle_t* handle, const char** wishlist)
|
||||
{
|
||||
const char **wish = wishlist;
|
||||
int ch, err;
|
||||
int ch_wrap = 0, wish_wrap = 0;
|
||||
|
||||
if(!wish)
|
||||
return 0;
|
||||
if(wish != NULL && *wish == NULL)
|
||||
return 1; /* success, nothing connected as wanted */
|
||||
ch=0;
|
||||
/* Connect things as long as there are sources or sinks left. */
|
||||
while(!wish_wrap || !ch_wrap)
|
||||
{
|
||||
const char* in = jack_port_name(handle->ports[ch]);
|
||||
|
||||
if((err = jack_connect(handle->client, in, *wish)) != 0 && err != EEXIST)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error4( "connect_jack_ports(): failed to jack_connect() ch%i (%s) to %s: %d"
|
||||
, ch, in ? in : "<nil>", *wish, err );
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
Increment channel and wishlist, both possibly wrapping around, to
|
||||
ensure we connected all channels to some output port and provided
|
||||
some input to all ports in the wishlist. Both cases of less channels
|
||||
than output ports (splitting) and more channels than output ports
|
||||
(downmix) are sensible.
|
||||
*/
|
||||
if(++ch == handle->channels)
|
||||
{
|
||||
ch = 0;
|
||||
++ch_wrap;
|
||||
}
|
||||
if(!*(++wish))
|
||||
{
|
||||
wish = wishlist;
|
||||
++wish_wrap;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* crude way of automatically connecting up jack ports */
|
||||
/* 0 on error */
|
||||
static int autoconnect_jack_ports(out123_handle *ao, jack_handle_t* handle)
|
||||
{
|
||||
const char **all_ports;
|
||||
unsigned int ch=0;
|
||||
int err,i;
|
||||
|
||||
/* Get a list of all the jack ports*/
|
||||
all_ports = jack_get_ports (handle->client, NULL, NULL, JackPortIsInput);
|
||||
if(!all_ports)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("connect_jack_ports(): jack_get_ports() returned NULL.");
|
||||
return 0;
|
||||
}
|
||||
/* Step through each port name*/
|
||||
for (i = 0; all_ports[i]; ++i)
|
||||
{
|
||||
const char* in = jack_port_name( handle->ports[ch] );
|
||||
const char* out = all_ports[i];
|
||||
|
||||
if ((err = jack_connect(handle->client, in, out)) != 0 && err != EEXIST)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("connect_jack_ports(): failed to jack_connect() ports: %d",err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Found enough ports ?*/
|
||||
if (++ch >= handle->channels) break;
|
||||
}
|
||||
jack_free(all_ports);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int connect_jack_ports(out123_handle *ao
|
||||
, jack_handle_t* handle)
|
||||
{
|
||||
debug1("connect_jack_ports with dev=%s", ao->device ? ao->device : "<nil>");
|
||||
if(ao->device==NULL || strcmp(ao->device, "auto")==0)
|
||||
return autoconnect_jack_ports(ao, handle);
|
||||
else
|
||||
{
|
||||
/* Parse device for a set of ports, comma separated. */
|
||||
const char** wishlist; /* Channels and end marker. */
|
||||
int wish_channels = 1; /* Numper of entries in wishlist. */
|
||||
char *devcopy, *chr;
|
||||
int ret;
|
||||
int c;
|
||||
size_t len;
|
||||
len = strlen(ao->device);
|
||||
/* We connect as many JACK ports as desired, possibly duplicating. */
|
||||
for(chr=ao->device; *chr; ++chr)
|
||||
if(*chr == ',')
|
||||
++wish_channels;
|
||||
debug1("wish_channels: %i", wish_channels);
|
||||
wishlist = malloc(sizeof(char*)*(wish_channels+1));
|
||||
devcopy = compat_strdup(ao->device);
|
||||
if(devcopy == NULL || wishlist == NULL)
|
||||
{
|
||||
if(devcopy)
|
||||
free(devcopy);
|
||||
if(wishlist)
|
||||
free(wishlist);
|
||||
if(!AOQUIET)
|
||||
error("OOM");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(c=0;c<=wish_channels;++c)
|
||||
wishlist[c] = NULL;
|
||||
if(len && strcmp(devcopy, "none"))
|
||||
{
|
||||
size_t i=0;
|
||||
wishlist[0] = devcopy;
|
||||
for(c=0;c<wish_channels;++c)
|
||||
{
|
||||
while(devcopy[i] != 0 && devcopy[i] != ',') ++i;
|
||||
debug2("devcopy[%"SIZE_P"]=%i", i, devcopy[i]);
|
||||
if(devcopy[i] == ',')
|
||||
{
|
||||
/* Terminate previous port name, assign next one. */
|
||||
devcopy[i++] = 0;
|
||||
debug2("terminaled wish %i: %s", c, wishlist[c]);
|
||||
if(c+1 < wish_channels)
|
||||
wishlist[c+1] = devcopy+i;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(wishlist[0] == NULL && !AOQUIET)
|
||||
warning("Not connecting up jack ports as requested.");
|
||||
|
||||
ret = real_connect_jack_ports(ao, handle, wishlist);
|
||||
free(devcopy);
|
||||
free(wishlist);
|
||||
return ret;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void drain_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
debug("drain_jack().");
|
||||
|
||||
do errno = 0;
|
||||
while(sem_trywait(&handle->sem) == 0 || errno == EINTR);
|
||||
/* For some reason, a single byte is reserved by JACK?! */
|
||||
while( handle && handle->alive && handle->rb
|
||||
&& jack_ringbuffer_write_space(handle->rb)+1 < handle->rb_size )
|
||||
{
|
||||
debug2( "JACK close wait %"SIZE_P" < %"SIZE_P"\n"
|
||||
, (size_p)jack_ringbuffer_write_space(handle->rb)
|
||||
, (size_p)handle->rb_size );
|
||||
sem_wait(&handle->sem);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
debug("close_jack().");
|
||||
/* Close and shutdown*/
|
||||
if(handle)
|
||||
{
|
||||
free_jack_handle(handle);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle=NULL;
|
||||
jack_options_t jopt = JackNullOption|JackNoStartServer;
|
||||
jack_status_t jstat = 0;
|
||||
unsigned int i;
|
||||
char *realname;
|
||||
|
||||
debug("jack open");
|
||||
if(!ao)
|
||||
return -1;
|
||||
|
||||
/* Return if already open*/
|
||||
if(ao->userptr)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("audio device is already open.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The initial open lets me choose the settings. */
|
||||
if (ao->format==-1)
|
||||
{
|
||||
ao->format = MPG123_ENC_FLOAT_32;
|
||||
ao->channels = 2;
|
||||
/* Really need a framesize defined for callback. */
|
||||
ao->framesize = 2*4;
|
||||
}
|
||||
else if(!(ao->format & MPG123_ENC_FLOAT))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("JACK only wants float!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create some storage for ourselves*/
|
||||
if((handle = alloc_jack_handle(ao)) == NULL)
|
||||
return -1;
|
||||
ao->userptr = (void*)handle;
|
||||
|
||||
/* Register with Jack*/
|
||||
if((handle->client = jack_client_open(ao->name, jopt, &jstat)) == 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to open jack client: 0x%x", jstat);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
realname = jack_get_client_name(handle->client);
|
||||
/* Display the unique client name allocated to us */
|
||||
if(AOVERBOSE(1))
|
||||
fprintf( stderr, "Registered as JACK client %s.\n"
|
||||
, realname ? realname : "<nil>" );
|
||||
|
||||
/* Just make sure. */
|
||||
ao->rate = jack_get_sample_rate(handle->client);
|
||||
|
||||
/* Check the sample rate is correct*/
|
||||
if (jack_get_sample_rate( handle->client ) != (jack_nframes_t)ao->rate)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("JACK Sample Rate is different to sample rate of file.");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register ports with Jack*/
|
||||
if(handle->channels > 0 && handle->channels < 100)
|
||||
{
|
||||
for(i=0;i<handle->channels;++i)
|
||||
{
|
||||
char numbuf[3]; /* two digits, zero byte */
|
||||
sprintf(numbuf, "%d", i+1);
|
||||
if( !(handle->ports[i] = jack_port_register( handle->client
|
||||
, numbuf, JACK_DEFAULT_AUDIO_TYPE
|
||||
, JackPortIsOutput, 0 )) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Cannot register JACK output port '%s'.", numbuf);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("excessive number of output channels (%d).", handle->channels);
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Use device_buffer parameter for ring buffer, but ensure that two
|
||||
JACK buffers fit in there. We do not support that buffer increasing
|
||||
later on. */
|
||||
handle->rb_size = (size_t)( ao->device_buffer
|
||||
* jack_get_sample_rate(handle->client)
|
||||
+ 0.5 ); /* PCM frames */
|
||||
handle->procbuf_frames = jack_get_buffer_size(handle->client);
|
||||
if(handle->rb_size < 2*handle->procbuf_frames)
|
||||
handle->rb_size = 2*handle->procbuf_frames;
|
||||
debug1("JACK ringbuffer for %"SIZE_P" PCM frames", (size_p)handle->rb_size);
|
||||
/* Convert to bytes. */
|
||||
handle->rb_size *= handle->framesize;
|
||||
handle->rb = jack_ringbuffer_create(handle->rb_size);
|
||||
handle->procbuf = malloc(handle->procbuf_frames*handle->framesize);
|
||||
if(!handle->rb || !handle->procbuf)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to allocate buffers");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the callbacks*/
|
||||
jack_set_process_callback(handle->client, process_callback, (void*)handle);
|
||||
jack_on_shutdown(handle->client, shutdown_callback, (void*)handle);
|
||||
handle->alive = 1;
|
||||
/* Activate client*/
|
||||
if(jack_activate(handle->client))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Can't activate client.");
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect up the portsm, return */
|
||||
if(!connect_jack_ports(ao, handle))
|
||||
{
|
||||
/* deregistering of ports will not work but should just fail, then,
|
||||
and let the rest clean up */
|
||||
close_jack(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("Jack open successful.\n");
|
||||
ao->realname = compat_strdup(realname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Jack prefers floats, I actually assume it does _only_ float/double
|
||||
(as it is nowadays)! */
|
||||
static int get_formats_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
|
||||
if(jack_get_sample_rate(handle->client) != (jack_nframes_t)ao->rate)
|
||||
return 0;
|
||||
else
|
||||
return MPG123_ENC_FLOAT_32|MPG123_ENC_FLOAT_64;
|
||||
}
|
||||
|
||||
static int write_jack(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
size_t bytes_left;
|
||||
unsigned int strike = 0;
|
||||
|
||||
bytes_left = len;
|
||||
while(bytes_left && handle->alive)
|
||||
{
|
||||
size_t piece;
|
||||
|
||||
debug("writing to ringbuffer");
|
||||
/* No help: piece1 = jack_ringbuffer_write_space(handle->rb); */
|
||||
piece = jack_ringbuffer_write(handle->rb, (char*)buf, bytes_left);
|
||||
debug1("wrote %"SIZE_P" B", (size_p)piece);
|
||||
buf += piece;
|
||||
bytes_left -= piece;
|
||||
/* Allow nothing being written some times, but not too often.
|
||||
Don't know how often in a row that would be supposed to happen. */
|
||||
if(!piece)
|
||||
{
|
||||
if(++strike > 100)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Cannot write to ringbuffer.");
|
||||
break;
|
||||
}
|
||||
/* Avoid busy waiting and semaphore accumulation:
|
||||
Wait once on the semaphore, then clear it. We count on it being
|
||||
posted by the process callback and we are going to push new data
|
||||
so that that one gets the chance. */
|
||||
sem_wait(&handle->sem);
|
||||
do errno = 0;
|
||||
while(sem_trywait(&handle->sem) == 0 || errno == EINTR);
|
||||
}
|
||||
else
|
||||
strike = 0;
|
||||
}
|
||||
|
||||
return len-bytes_left;
|
||||
}
|
||||
|
||||
static void flush_jack(out123_handle *ao)
|
||||
{
|
||||
jack_handle_t *handle = (jack_handle_t*)ao->userptr;
|
||||
/* Reset the ring buffers*/
|
||||
jack_ringbuffer_reset(handle->rb);
|
||||
}
|
||||
|
||||
static int init_jack(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL)
|
||||
return -1;
|
||||
/* Set callbacks */
|
||||
ao->open = open_jack;
|
||||
ao->flush = flush_jack;
|
||||
ao->drain = drain_jack;
|
||||
ao->write = write_jack;
|
||||
ao->get_formats = get_formats_jack;
|
||||
ao->close = close_jack;
|
||||
ao->propflags |= OUT123_PROP_PERSISTENT;
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "jack",
|
||||
/* description */ "Output audio using JACK (JACK Audio Connection Kit).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_jack
|
||||
};
|
||||
199
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/mint.c
vendored
Normal file
199
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/mint.c
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
mint: audio output for MINT
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Petr Stehlik
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
/* derived from LINUX, VOXWARE and SUN for MiNT Audio Device by Petr Stehlik */
|
||||
#include <fcntl.h>
|
||||
#include <ioctl.h>
|
||||
#include <audios.h>
|
||||
#include "debug.h"
|
||||
|
||||
/* Globals */
|
||||
extern int outburst;
|
||||
int real_rate_printed = 0;
|
||||
|
||||
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
int ret,dsp_rate;
|
||||
|
||||
if(!ai || ao->fn < 0 || ao->rate < 0)
|
||||
return -1;
|
||||
|
||||
dsp_rate = ao->rate;
|
||||
ret = ioctl(ao->fn,AIOCSSPEED, (void *)dsp_rate);
|
||||
ret = ioctl(ao->fn,AIOCGSPEED,&dsp_rate);
|
||||
if(ret < 0) return ret;
|
||||
ao->rate = dsp_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
int dsp_rate = ao->rate;
|
||||
|
||||
if(ao->rate >= 0) {
|
||||
int ret, real_rate;
|
||||
ret = ioctl(ao->fn, AIOCSSPEED, (void *)dsp_rate);
|
||||
if (ret >= 0 && !real_rate_printed) {
|
||||
ioctl(ao->fn,AIOCGSPEED,&real_rate);
|
||||
if (real_rate != dsp_rate) {
|
||||
fprintf(stderr, "Replay rate: %d Hz\n", real_rate);
|
||||
real_rate_printed = 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
int chan = ao->channels;
|
||||
|
||||
if(ao->channels < 1) return 0;
|
||||
|
||||
return ioctl(ao->fn, AIOCSCHAN, (void *)chan);
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
int fmts;
|
||||
|
||||
if(ao->format == -1)
|
||||
return 0;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmts = AFMT_S16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
fmts = AFMT_U8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
fmts = AFMT_S8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmts = AFMT_ULAW;
|
||||
break;
|
||||
}
|
||||
|
||||
return ioctl(ao->fn, AIOCSFMT, (void *)fmts);
|
||||
}
|
||||
|
||||
static int reset_parameters(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = ioctl(ao->fn,AIOCRESET,NULL);
|
||||
if(ret >= 0) ret = set_format(ai);
|
||||
if(ret >= 0) ret = set_channels(ai);
|
||||
if(ret >= 0) ret = set_rate(ai);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int open_mint(out123_handle *ao)
|
||||
{
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!ai) return -1;
|
||||
if(!dev)
|
||||
dev = "/dev/audio";
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0)
|
||||
{
|
||||
error1("Can't open %s!",dev);
|
||||
return -1;
|
||||
}
|
||||
ioctl(ao->fn, AIOCGBLKSIZE, &outburst);
|
||||
if(outburst > MAXOUTBURST)
|
||||
outburst = MAXOUTBURST;
|
||||
if(audio_reset_parameters(ai) < 0) {
|
||||
close(ao->fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
static int get_formats_mint(out123_handle *ao)
|
||||
{
|
||||
int ret = 0;
|
||||
int fmts;
|
||||
|
||||
if(ioctl(ao->fn,AIOCGFMTS,&fmts) < 0)
|
||||
return -1;
|
||||
|
||||
if(fmts & AFMT_ULAW)
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
if(fmts & AFMT_S16)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(fmts & AFMT_U8)
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
if(fmts & AFMT_S8)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_mint(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_mint(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_mint(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_mint(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_mint;
|
||||
ao->flush = flush_mint;
|
||||
ao->write = write_mint;
|
||||
ao->get_formats = get_formats_mint;
|
||||
ao->close = close_mint;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "mint",
|
||||
/* description */ "Audio output for MINT.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_mint,
|
||||
};
|
||||
|
||||
|
||||
345
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/nas.c
vendored
Normal file
345
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/nas.c
vendored
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
nas: audio output via NAS
|
||||
|
||||
copyright ?-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Martin Denn
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <audio/audiolib.h>
|
||||
#include <audio/soundlib.h>
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AuServer *aud;
|
||||
AuFlowID flow;
|
||||
AuDeviceAttributes *da;
|
||||
int numDevices;
|
||||
char *buf;
|
||||
AuUint32 buf_size;
|
||||
AuUint32 buf_cnt;
|
||||
AuBool data_sent;
|
||||
AuBool finished;
|
||||
} InfoRec, *InfoPtr;
|
||||
|
||||
/* seconds */
|
||||
#define NAS_SOUND_PORT_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 5)
|
||||
#define NAS_SOUND_LOW_WATER_MARK 25 /* percent */
|
||||
#define NAS_MAX_FORMAT 10 /* currently, there are 7 supported formats */
|
||||
|
||||
|
||||
/* FIXME: stick this inside userptr inside out123_handle instead */
|
||||
static InfoRec info;
|
||||
|
||||
/* NAS specific routines */
|
||||
|
||||
static void nas_sendData(AuServer *aud, InfoPtr i, AuUint32 numBytes)
|
||||
{
|
||||
if (numBytes < i->buf_cnt) {
|
||||
AuWriteElement(aud, i->flow, 0, numBytes, i->buf, AuFalse, NULL);
|
||||
memmove(i->buf, i->buf + numBytes, i->buf_cnt - numBytes);
|
||||
i->buf_cnt = i->buf_cnt - numBytes;
|
||||
}
|
||||
else {
|
||||
AuWriteElement(aud, i->flow, 0, i->buf_cnt, i->buf,
|
||||
(numBytes > i->buf_cnt), NULL);
|
||||
i->buf_cnt = 0;
|
||||
}
|
||||
i->data_sent = AuTrue;
|
||||
}
|
||||
|
||||
static AuBool nas_eventHandler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *handler)
|
||||
{
|
||||
InfoPtr i = (InfoPtr) handler->data;
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case AuEventTypeMonitorNotify:
|
||||
i->finished = AuTrue;
|
||||
break;
|
||||
case AuEventTypeElementNotify:
|
||||
{
|
||||
AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
|
||||
|
||||
switch (event->kind)
|
||||
{
|
||||
case AuElementNotifyKindLowWater:
|
||||
nas_sendData(aud, i, event->num_bytes);
|
||||
break;
|
||||
case AuElementNotifyKindState:
|
||||
switch (event->cur_state)
|
||||
{
|
||||
case AuStatePause:
|
||||
if (event->reason != AuReasonUser)
|
||||
nas_sendData(aud, i, event->num_bytes);
|
||||
break;
|
||||
case AuStateStop:
|
||||
i->finished = AuTrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return AuTrue;
|
||||
}
|
||||
|
||||
/* 0 on error */
|
||||
static int nas_createFlow(out123_handle *ao)
|
||||
{
|
||||
AuDeviceID device = AuNone;
|
||||
AuElement elements[2];
|
||||
unsigned char format;
|
||||
AuUint32 buf_samples;
|
||||
int i;
|
||||
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
if (((char) *(short *)"x")=='x') /* ugly, but painless */
|
||||
format = AuFormatLinearSigned16LSB; /* little endian */
|
||||
else
|
||||
format = AuFormatLinearSigned16MSB; /* big endian */
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
format = AuFormatLinearUnsigned8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
format = AuFormatLinearSigned8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
format = AuFormatULAW8;
|
||||
break;
|
||||
}
|
||||
/* look for an output device */
|
||||
for (i = 0; i < AuServerNumDevices(info.aud); i++)
|
||||
if (((AuDeviceKind(AuServerDevice(info.aud, i)) ==
|
||||
AuComponentKindPhysicalOutput) &&
|
||||
AuDeviceNumTracks(AuServerDevice(info.aud, i))
|
||||
== ao->channels )) {
|
||||
device = AuDeviceIdentifier(AuServerDevice(info.aud, i));
|
||||
break;
|
||||
}
|
||||
if (device == AuNone) {
|
||||
if(!AOQUIET)
|
||||
error1( "Couldn't find an output device providing %d channels."
|
||||
, ao->channels );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set gain */
|
||||
if(ao->gain >= 0) {
|
||||
info.da = AuGetDeviceAttributes(info.aud, device, NULL);
|
||||
if ((info.da)!=NULL) {
|
||||
AuDeviceGain(info.da) = AuFixedPointFromSum(ao->gain, 0);
|
||||
AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da),
|
||||
AuCompDeviceGainMask, info.da, NULL);
|
||||
}
|
||||
else if(!AOQUIET)
|
||||
error("audio/gain: setable Volume/PCM-Level not supported");
|
||||
}
|
||||
|
||||
if (!(info.flow = AuCreateFlow(info.aud, NULL))) {
|
||||
if(!AOQUIET)
|
||||
error("Couldn't create flow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf_samples = ao->rate * NAS_SOUND_PORT_DURATION;
|
||||
|
||||
AuMakeElementImportClient(&elements[0], /* element */
|
||||
(unsigned short) ao->rate,
|
||||
/* rate */
|
||||
format, /* format */
|
||||
ao->channels, /* channels */
|
||||
AuTrue, /* ??? */
|
||||
buf_samples, /* max samples */
|
||||
(AuUint32) (buf_samples / 100
|
||||
* NAS_SOUND_LOW_WATER_MARK),
|
||||
/* low water mark */
|
||||
0, /* num actions */
|
||||
NULL); /* actions */
|
||||
AuMakeElementExportDevice(&elements[1], /* element */
|
||||
0, /* input */
|
||||
device, /* device */
|
||||
(unsigned short) ao->rate,
|
||||
/* rate */
|
||||
AuUnlimitedSamples, /* num samples */
|
||||
0, /* num actions */
|
||||
NULL); /* actions */
|
||||
AuSetElements(info.aud, /* Au server */
|
||||
info.flow, /* flow ID */
|
||||
AuTrue, /* clocked */
|
||||
2, /* num elements */
|
||||
elements, /* elements */
|
||||
NULL); /* return status */
|
||||
|
||||
AuRegisterEventHandler(info.aud, /* Au server */
|
||||
AuEventHandlerIDMask, /* value mask */
|
||||
0, /* type */
|
||||
info.flow, /* id */
|
||||
nas_eventHandler, /* callback */
|
||||
(AuPointer) &info); /* data */
|
||||
|
||||
info.buf_size = buf_samples * ao->channels * AuSizeofFormat(format);
|
||||
info.buf = (char *) malloc(info.buf_size);
|
||||
if (info.buf == NULL) {
|
||||
if(!AOQUIET)
|
||||
error1("Unable to allocate input/output buffer of size %ld",
|
||||
(long)info.buf_size);
|
||||
return 0;
|
||||
}
|
||||
info.buf_cnt = 0;
|
||||
info.data_sent = AuFalse;
|
||||
info.finished = AuFalse;
|
||||
|
||||
AuStartFlow(info.aud, /* Au server */
|
||||
info.flow, /* id */
|
||||
NULL); /* status */
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
|
||||
static void flush_nas(out123_handle *ao)
|
||||
{
|
||||
AuEvent ev;
|
||||
|
||||
while ((!info.data_sent) && (!info.finished)) {
|
||||
AuNextEvent(info.aud, AuTrue, &ev);
|
||||
AuDispatchEvent(info.aud, &ev);
|
||||
}
|
||||
info.data_sent = AuFalse;
|
||||
}
|
||||
|
||||
|
||||
/* returning -1 on error, 0 on success... */
|
||||
static int open_nas(out123_handle *ao)
|
||||
{
|
||||
if(!ao) return -1;
|
||||
|
||||
if (!(info.aud = AuOpenServer(ao->device, 0, NULL, 0, NULL, NULL)))
|
||||
{
|
||||
if (ao->device==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("could not open default NAS server");
|
||||
} else
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("could not open NAS server %s\n", ao->device);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
info.buf_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_nas(out123_handle *ao)
|
||||
{
|
||||
int i, j, k, ret;
|
||||
|
||||
ret=0;
|
||||
j = AuServerNumFormats(info.aud);
|
||||
for (i=0; i<j; i++) {
|
||||
k=AuServerFormat(info.aud,i);
|
||||
switch (k)
|
||||
{
|
||||
case AuFormatULAW8:
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
break;
|
||||
case AuFormatLinearUnsigned8:
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
break;
|
||||
case AuFormatLinearSigned8:
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
break;
|
||||
case AuFormatLinearSigned16LSB:
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_nas(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
int buf_cnt = 0;
|
||||
|
||||
if (info.buf_size == 0)
|
||||
if(!nas_createFlow(ao)) return -1;
|
||||
|
||||
while ((info.buf_cnt + (len - buf_cnt)) > info.buf_size) {
|
||||
memcpy(info.buf + info.buf_cnt,
|
||||
buf + buf_cnt,
|
||||
(info.buf_size - info.buf_cnt));
|
||||
buf_cnt += (info.buf_size - info.buf_cnt);
|
||||
info.buf_cnt += (info.buf_size - info.buf_cnt);
|
||||
flush_nas(ao);
|
||||
}
|
||||
memcpy(info.buf + info.buf_cnt,
|
||||
buf + buf_cnt,
|
||||
(len - buf_cnt));
|
||||
info.buf_cnt += (len - buf_cnt);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_nas(out123_handle *ao)
|
||||
{
|
||||
if (info.aud == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.buf_size == 0) {
|
||||
/* Au server opened, but not yet initialized */
|
||||
AuCloseServer(info.aud);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!info.finished) {
|
||||
flush_nas(ao);
|
||||
}
|
||||
AuCloseServer(info.aud);
|
||||
free(info.buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int init_nas(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_nas;
|
||||
ao->flush = flush_nas;
|
||||
ao->write = write_nas;
|
||||
ao->get_formats = get_formats_nas;
|
||||
ao->close = close_nas;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "nas",
|
||||
/* description */ "Output audio using NAS (Network Audio System)",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_nas,
|
||||
};
|
||||
|
||||
|
||||
201
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/openal.c
vendored
Normal file
201
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/openal.c
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
openal.c: audio output on OpenAL
|
||||
|
||||
copyright 1995-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Taihei Monma
|
||||
*/
|
||||
|
||||
/* Need usleep(). */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#ifdef OPENAL_SUBDIR_OPENAL
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
#elif defined(OPENAL_SUBDIR_AL)
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#else
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define NUM_BUFFERS 16
|
||||
|
||||
#ifndef AL_FORMAT_MONO_FLOAT32
|
||||
#define AL_FORMAT_MONO_FLOAT32 0x10010
|
||||
#endif
|
||||
#ifndef AL_FORMAT_STEREO_FLOAT32
|
||||
#define AL_FORMAT_STEREO_FLOAT32 0x10011
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ALCdevice *device;
|
||||
ALCcontext *context;
|
||||
ALuint source, buffer;
|
||||
ALenum format;
|
||||
ALsizei rate;
|
||||
} mpg123_openal_t;
|
||||
|
||||
|
||||
static int open_openal(out123_handle *ao)
|
||||
{
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
al->device = alcOpenDevice(NULL);
|
||||
al->context = alcCreateContext(al->device, NULL);
|
||||
alcMakeContextCurrent(al->context);
|
||||
alGenSources(1, &al->source);
|
||||
|
||||
al->rate = ao->rate;
|
||||
if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 2) al->format = AL_FORMAT_STEREO16;
|
||||
else if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 1) al->format = AL_FORMAT_MONO16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 2) al->format = AL_FORMAT_STEREO8;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 1) al->format = AL_FORMAT_MONO8;
|
||||
else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 2) al->format = AL_FORMAT_STEREO_FLOAT32;
|
||||
else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 1) al->format = AL_FORMAT_MONO_FLOAT32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_openal(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8|((alIsExtensionPresent((ALubyte*)"AL_EXT_float32") == AL_TRUE) ? MPG123_ENC_FLOAT_32 : 0);
|
||||
}
|
||||
|
||||
static int write_openal(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
ALint state, n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
alGetSourcei(al->source, AL_BUFFERS_QUEUED, &n);
|
||||
if(n < NUM_BUFFERS)
|
||||
{
|
||||
alGenBuffers(1, &al->buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
alGetSourcei(al->source, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(al->source);
|
||||
}
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n == 0)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
}
|
||||
|
||||
alBufferData(al->buffer, al->format, buf, len, al->rate);
|
||||
alSourceQueueBuffers(al->source, 1, &al->buffer);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_openal(out123_handle *ao)
|
||||
{
|
||||
ALint state, n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
if (al)
|
||||
{
|
||||
/* wait until all buffers are consumed */
|
||||
while(alGetSourcei(al->source, AL_SOURCE_STATE, &state), state == AL_PLAYING)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
/* free all processed buffers */
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
alDeleteBuffers(1, &al->buffer);
|
||||
}
|
||||
alDeleteSources(1, &al->source);
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(al->context);
|
||||
alcCloseDevice(al->device);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_openal(out123_handle *ao)
|
||||
{
|
||||
ALint n;
|
||||
mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
|
||||
|
||||
if (al)
|
||||
{
|
||||
/* stop playing and flush all buffers */
|
||||
alSourceStop(al->source);
|
||||
while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(al->source, 1, &al->buffer);
|
||||
alDeleteBuffers(1, &al->buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int deinit_openal(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if(ao->userptr)
|
||||
{
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_openal(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_openal;
|
||||
ao->flush = flush_openal;
|
||||
ao->write = write_openal;
|
||||
ao->get_formats = get_formats_openal;
|
||||
ao->close = close_openal;
|
||||
ao->deinit = deinit_openal;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_openal_t ) );
|
||||
if(ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_openal_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_openal_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "openal",
|
||||
/* description */ "Output audio using OpenAL.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_openal,
|
||||
};
|
||||
|
||||
|
||||
664
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/os2.c
vendored
Normal file
664
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/os2.c
vendored
Normal file
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
os2: OS/2 RealTime DART Engine
|
||||
|
||||
copyright 1998-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Samuel Audet
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#define INCL_OS2MM
|
||||
#define INCL_DOS
|
||||
#define INCL_VIO
|
||||
#define INCL_KBD
|
||||
#include <os2.h>
|
||||
#include <os2me.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* complementary audio parameters */
|
||||
int numbuffers = 5; /* total audio buffers, _bare_ minimum = 4 (cuz of prio boost check) */
|
||||
int audiobufsize = 4884;
|
||||
int lockdevice = FALSE;
|
||||
USHORT volume = 100;
|
||||
char *boostprio = NULL;
|
||||
char *normalprio = NULL;
|
||||
unsigned char boostclass = 3, normalclass = 2;
|
||||
signed char boostdelta = 0, normaldelta = 31;
|
||||
unsigned char mmerror[160] = {0};
|
||||
int playingframe;
|
||||
|
||||
/* audio buffers */
|
||||
static ULONG ulMCIBuffers;
|
||||
|
||||
static MCI_AMP_OPEN_PARMS maop = {0};
|
||||
static MCI_MIXSETUP_PARMS mmp = {0};
|
||||
static MCI_BUFFER_PARMS mbp = {0};
|
||||
static MCI_GENERIC_PARMS mgp = {0};
|
||||
static MCI_SET_PARMS msp = {0};
|
||||
static MCI_STATUS_PARMS mstatp = {0};
|
||||
static MCI_MIX_BUFFER *MixBuffers = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MCI_MIX_BUFFER *NextBuffer;
|
||||
int frameNum;
|
||||
} BUFFERINFO;
|
||||
|
||||
BUFFERINFO *bufferinfo = NULL;
|
||||
|
||||
|
||||
static HEV dataplayed = 0;
|
||||
static ULONG resetcount;
|
||||
static BOOL paused = FALSE;
|
||||
|
||||
static MCI_MIX_BUFFER *tobefilled, *playingbuffer = NULL, playedbuffer;
|
||||
static void *pBufferplayed;
|
||||
|
||||
static BOOL nomoredata,nobuffermode,justflushed;
|
||||
|
||||
static TIB *mainthread; /* thread info to set thread priority */
|
||||
|
||||
ULONG keyboardtid;
|
||||
|
||||
|
||||
static LONG APIENTRY DARTEvent(ULONG ulStatus, MCI_MIX_BUFFER *PlayedBuffer, ULONG ulFlags)
|
||||
{
|
||||
switch(ulFlags)
|
||||
{
|
||||
case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: /* error occur in device */
|
||||
|
||||
if ( ulStatus == ERROR_DEVICE_UNDERRUN)
|
||||
/* Write buffers to rekick off the amp mixer. */
|
||||
mmp.pmixWrite( mmp.ulMixHandle, MixBuffers, ulMCIBuffers );
|
||||
break;
|
||||
|
||||
case MIX_WRITE_COMPLETE: /* for playback */
|
||||
|
||||
playingbuffer = ((BUFFERINFO *) PlayedBuffer->ulUserParm)->NextBuffer;
|
||||
|
||||
/* the next three lines are only useful to audio_playing_samples() */
|
||||
playedbuffer = *PlayedBuffer;
|
||||
playedbuffer.pBuffer = pBufferplayed;
|
||||
memcpy(playedbuffer.pBuffer, PlayedBuffer->pBuffer, PlayedBuffer->ulBufferLength);
|
||||
|
||||
/* just too bad, the decoder fell behind... here we just keep the
|
||||
buffer to be filled in front of the playing one so that when the
|
||||
decoder kicks back in, we'll hear it in at the right time */
|
||||
if(tobefilled == playingbuffer)
|
||||
{
|
||||
tobefilled = ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer;
|
||||
nomoredata = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
playingframe = ((BUFFERINFO *) playingbuffer->ulUserParm)->frameNum;
|
||||
|
||||
/* if we're about to be short of decoder's data
|
||||
(2nd ahead buffer not filled), let's boost its priority! */
|
||||
if(tobefilled == ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
|
||||
DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
}
|
||||
|
||||
/* empty the played buffer in case it doesn't get filled back */
|
||||
memset(PlayedBuffer->pBuffer,0,PlayedBuffer->ulBufferLength);
|
||||
|
||||
DosPostEventSem(dataplayed);
|
||||
|
||||
mmp.pmixWrite( mmp.ulMixHandle, PlayedBuffer, 1 );
|
||||
break;
|
||||
|
||||
} /* end switch */
|
||||
|
||||
return( TRUE );
|
||||
|
||||
} /* end DARTEvent */
|
||||
|
||||
|
||||
static void MciError(ULONG ulError)
|
||||
{
|
||||
unsigned char buffer[128];
|
||||
ULONG rc;
|
||||
|
||||
rc = mciGetErrorString(ulError, buffer, sizeof(buffer));
|
||||
|
||||
if (rc == MCIERR_SUCCESS)
|
||||
sprintf(mmerror,"MCI Error %d: %s",ULONG_LOWD(ulError),buffer);
|
||||
else
|
||||
sprintf(mmerror,"MCI Error %d: Cannot query error message.",ULONG_LOWD(rc));
|
||||
|
||||
error1("%s",mmerror);
|
||||
}
|
||||
|
||||
|
||||
static int set_volume(out123_handle *ao, USHORT setvolume)
|
||||
{
|
||||
if(setvolume > 100) setvolume = 100;
|
||||
volume = setvolume; /* useful when device is closed and reopened */
|
||||
|
||||
if(maop.usDeviceID)
|
||||
{
|
||||
memset(&msp,0,sizeof(msp));
|
||||
msp.ulAudio = MCI_SET_AUDIO_ALL;
|
||||
msp.ulLevel = setvolume;
|
||||
|
||||
mciSendCommand(maop.usDeviceID, MCI_SET,
|
||||
MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
|
||||
&msp, 0);
|
||||
}
|
||||
return setvolume;
|
||||
}
|
||||
|
||||
|
||||
int open_os2(out123_handle *ao)
|
||||
{
|
||||
ULONG rc,i;
|
||||
char *temp;
|
||||
ULONG openflags;
|
||||
PPIB ppib;
|
||||
USHORT bits;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(maop.usDeviceID) return (maop.usDeviceID);
|
||||
|
||||
if(!ao) return -1;
|
||||
|
||||
if(!dev) dev = "0";
|
||||
|
||||
if(ao->rate < 0) ao->rate = 44100;
|
||||
if(ao->channels < 0) ao->channels = 2;
|
||||
if(ao->format < 0) ao->format = MPG123_ENC_SIGNED_16;
|
||||
|
||||
if(ao->format == MPG123_ENC_SIGNED_16)
|
||||
bits = 16;
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8)
|
||||
bits = 8;
|
||||
else return -1;
|
||||
|
||||
/* open the mixer device */
|
||||
memset (&maop, 0, sizeof(maop));
|
||||
maop.usDeviceID = 0;
|
||||
maop.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, atoi(dev));
|
||||
|
||||
openflags = MCI_WAIT | MCI_OPEN_TYPE_ID;
|
||||
if(!lockdevice) openflags |= MCI_OPEN_SHAREABLE;
|
||||
|
||||
rc = mciSendCommand(0, MCI_OPEN, openflags, &maop, 0);
|
||||
|
||||
if (ULONG_LOWD(rc) != MCIERR_SUCCESS)
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* volume in ao->gain ?? */
|
||||
|
||||
/* Set the MCI_MIXSETUP_PARMS data structure to match the audio stream. */
|
||||
|
||||
memset(&mmp, 0, sizeof(mmp));
|
||||
|
||||
mmp.ulBitsPerSample = bits;
|
||||
mmp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmp.ulSamplesPerSec = ao->rate;
|
||||
mmp.ulChannels = ao->channels;
|
||||
|
||||
/* Setup the mixer for playback of wave data */
|
||||
mmp.ulFormatMode = MCI_PLAY;
|
||||
mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
|
||||
mmp.pmixEvent = DARTEvent;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_INIT,
|
||||
&mmp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
volume = set_volume(ao,volume);
|
||||
|
||||
/* Set up the BufferParms data structure and allocate
|
||||
* device buffers from the Amp-Mixer */
|
||||
|
||||
memset(&mbp, 0, sizeof(mbp));
|
||||
free(MixBuffers);
|
||||
free(bufferinfo);
|
||||
if(numbuffers < 5) numbuffers = 5;
|
||||
if(numbuffers > 200) numbuffers = 200;
|
||||
MixBuffers = calloc(numbuffers, sizeof(*MixBuffers));
|
||||
bufferinfo = calloc(numbuffers, sizeof(*bufferinfo));
|
||||
|
||||
ulMCIBuffers = numbuffers;
|
||||
mbp.ulNumBuffers = ulMCIBuffers;
|
||||
/* mbp.ulBufferSize = mmp.ulBufferSize; */
|
||||
/* I don't like this... they must be smaller than 64KB or else the
|
||||
engine needs major rewrite */
|
||||
mbp.ulBufferSize = audiobufsize;
|
||||
mbp.pBufList = MixBuffers;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_BUFFER,
|
||||
MCI_WAIT | MCI_ALLOCATE_MEMORY,
|
||||
(PVOID) &mbp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
pBufferplayed = playedbuffer.pBuffer = calloc(1,audiobufsize);
|
||||
|
||||
ulMCIBuffers = mbp.ulNumBuffers; /* never know! */
|
||||
|
||||
/* Fill all device buffers with zeros and set linked list */
|
||||
|
||||
for(i = 0; i < ulMCIBuffers; i++)
|
||||
{
|
||||
MixBuffers[i].ulFlags = 0;
|
||||
MixBuffers[i].ulBufferLength = mbp.ulBufferSize;
|
||||
memset(MixBuffers[i].pBuffer, 0, MixBuffers[i].ulBufferLength);
|
||||
|
||||
MixBuffers[i].ulUserParm = (ULONG) &bufferinfo[i];
|
||||
bufferinfo[i].NextBuffer = &MixBuffers[i+1];
|
||||
}
|
||||
|
||||
bufferinfo[i-1].NextBuffer = &MixBuffers[0];
|
||||
|
||||
/* Create a semaphore to know when data has been played by the DART thread */
|
||||
DosCreateEventSem(NULL,&dataplayed,0,FALSE);
|
||||
|
||||
playingbuffer = &MixBuffers[0];
|
||||
tobefilled = &MixBuffers[1];
|
||||
playingframe = 0;
|
||||
nomoredata = TRUE;
|
||||
nobuffermode = FALSE;
|
||||
justflushed = FALSE;
|
||||
|
||||
if(boostprio)
|
||||
{
|
||||
temp = alloca(strlen(boostprio)+1);
|
||||
strcpy(temp,boostprio);
|
||||
|
||||
boostdelta = atoi(temp+1);
|
||||
*(temp+1) = 0;
|
||||
boostclass = atoi(temp);
|
||||
}
|
||||
if(boostclass > 4) boostdelta = 3;
|
||||
if(boostdelta > 31) boostdelta = 31;
|
||||
if(boostdelta < -31) boostdelta = -31;
|
||||
|
||||
|
||||
if(normalprio)
|
||||
{
|
||||
temp = alloca(strlen(normalprio)+1);
|
||||
strcpy(temp,normalprio);
|
||||
|
||||
normaldelta = atoi(temp+1);
|
||||
*(temp+1) = 0;
|
||||
normalclass = atoi(temp);
|
||||
}
|
||||
if(normalclass > 4) normaldelta = 3;
|
||||
if(normaldelta > 31) normaldelta = 31;
|
||||
if(normaldelta < -31) normaldelta = -31;
|
||||
|
||||
|
||||
DosGetInfoBlocks(&mainthread,&ppib); /* ppib not needed, but makes some DOSCALLS.DLL crash */
|
||||
DosSetPriority(PRTYS_THREAD,boostclass,boostdelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
|
||||
/* Write buffers to kick off the amp mixer. see DARTEvent() */
|
||||
rc = mmp.pmixWrite( mmp.ulMixHandle,
|
||||
MixBuffers,
|
||||
ulMCIBuffers );
|
||||
|
||||
return maop.usDeviceID;
|
||||
}
|
||||
|
||||
|
||||
static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
/* if we're too quick, let's wait */
|
||||
if(nobuffermode)
|
||||
{
|
||||
MCI_MIX_BUFFER *temp = playingbuffer;
|
||||
|
||||
while(
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) &&
|
||||
(tobefilled != (temp = ((BUFFERINFO *) temp->ulUserParm)->NextBuffer)) )
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
temp = playingbuffer;
|
||||
}
|
||||
|
||||
} else {
|
||||
while(tobefilled == playingbuffer)
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (justflushed) {
|
||||
justflushed = FALSE;
|
||||
} else {
|
||||
nomoredata = FALSE;
|
||||
|
||||
memcpy(tobefilled->pBuffer, buf, len);
|
||||
tobefilled->ulBufferLength = len;
|
||||
// ((BUFFERINFO *) tobefilled->ulUserParm)->frameNum = fr->frameNum;
|
||||
|
||||
/* if we're out of the water (3rd ahead buffer filled),
|
||||
let's reduce our priority */
|
||||
if(tobefilled == ( (BUFFERINFO *) ( (BUFFERINFO *) ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer->ulUserParm)->NextBuffer)
|
||||
DosSetPriority(PRTYS_THREAD,normalclass,normaldelta,mainthread->tib_ptib2->tib2_ultid);
|
||||
|
||||
tobefilled = ((BUFFERINFO *) tobefilled->ulUserParm)->NextBuffer;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int write_os2(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
if(len > audiobufsize || !playingbuffer) return -1;
|
||||
|
||||
if(mmp.ulBitsPerSample == 16)
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
else if(mmp.ulBitsPerSample == 8)
|
||||
ao->format = MPG123_ENC_UNSIGNED_8;
|
||||
else return -1;
|
||||
|
||||
ao->rate = mmp.ulSamplesPerSec;
|
||||
ao->channels = mmp.ulChannels;
|
||||
|
||||
if(buf && len)
|
||||
{
|
||||
ULONG rc;
|
||||
int upto;
|
||||
|
||||
mstatp.ulItem = MCI_STATUS_POSITION;
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_STATUS,
|
||||
MCI_STATUS_ITEM | MCI_WAIT,
|
||||
&mstatp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
maop.usDeviceID = 0;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* this is hypocrite...
|
||||
DART returns the value in ulReturn instead of ulValue,
|
||||
also it returns in milliseconds and not MMTIME... arg */
|
||||
|
||||
upto = (mstatp.ulReturn-playedbuffer.ulTime) * mmp.ulSamplesPerSec / 1000;
|
||||
upto *= mmp.ulChannels * (mmp.ulBitsPerSample>>3);
|
||||
|
||||
/* if a timing problem occurs, let's at least not crash */
|
||||
if(upto > playingbuffer->ulBufferLength)
|
||||
upto = playingbuffer->ulBufferLength;
|
||||
|
||||
if(len < upto) {
|
||||
memcpy(buf,(char *) (playingbuffer->pBuffer)+upto-len, len);
|
||||
} else {
|
||||
memcpy(buf,(char *) playedbuffer.pBuffer+playedbuffer.ulBufferLength-(len-upto),len-upto);
|
||||
memcpy(buf+(len-upto),playingbuffer->pBuffer,upto);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
static int audio_nobuffermode(out123_handle *ao, int setnobuffermode)
|
||||
{
|
||||
nobuffermode = setnobuffermode;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int audio_trash_buffers(out123_handle *ao)
|
||||
{
|
||||
int i;
|
||||
|
||||
justflushed = TRUE;
|
||||
|
||||
// Fill all device buffers with zeros
|
||||
for(i = 0; i < ulMCIBuffers; i++)
|
||||
memset(MixBuffers[i].pBuffer, 0, MixBuffers[i].ulBufferLength);
|
||||
|
||||
tobefilled = ((BUFFERINFO *) playingbuffer->ulUserParm)->NextBuffer;
|
||||
nomoredata = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
*/
|
||||
|
||||
static int close_os2(out123_handle *ao)
|
||||
{
|
||||
ULONG rc;
|
||||
|
||||
if(!maop.usDeviceID)
|
||||
return 0;
|
||||
|
||||
while(!nomoredata)
|
||||
{
|
||||
DosResetEventSem(dataplayed,&resetcount);
|
||||
DosWaitEventSem(dataplayed, -1);
|
||||
}
|
||||
|
||||
playingbuffer = NULL;
|
||||
|
||||
DosCloseEventSem(dataplayed);
|
||||
dataplayed = 0;
|
||||
|
||||
free(pBufferplayed);
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
|
||||
&mbp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
free(bufferinfo);
|
||||
free(MixBuffers);
|
||||
bufferinfo = NULL;
|
||||
MixBuffers = NULL;
|
||||
|
||||
memset(&mbp, 0, sizeof(mbp));
|
||||
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_CLOSE,
|
||||
MCI_WAIT ,
|
||||
&mgp,
|
||||
0 );
|
||||
|
||||
if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
|
||||
{
|
||||
MciError(rc);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
memset(&maop, 0, sizeof(maop));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get formats for specific channel/rate parameters
|
||||
*/
|
||||
int get_formats_os2(out123_handle *ao)
|
||||
{
|
||||
int fmts = 0;
|
||||
ULONG rc;
|
||||
MCI_MIXSETUP_PARMS mmptemp = {0};
|
||||
|
||||
mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
|
||||
mmp.pmixEvent = DARTEvent;
|
||||
|
||||
mmptemp.ulFormatMode = MCI_PLAY;
|
||||
mmptemp.ulSamplesPerSec = ao->rate;
|
||||
mmptemp.ulChannels = ao->channels;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmptemp.ulBitsPerSample = 16;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_SIGNED_16;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_UNSIGNED_8;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_ALAW;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_ALAW_8;
|
||||
|
||||
mmptemp.ulFormatTag = MCI_WAVE_FORMAT_MULAW;
|
||||
mmptemp.ulBitsPerSample = 8;
|
||||
rc = mciSendCommand( maop.usDeviceID,
|
||||
MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
|
||||
&mmptemp,
|
||||
0 );
|
||||
|
||||
if((ULONG_LOWD(rc) == MCIERR_SUCCESS) && (rc != 0x4000)) /* undocumented */
|
||||
fmts = fmts | MPG123_ENC_ULAW_8;
|
||||
|
||||
return fmts;
|
||||
}
|
||||
|
||||
static int get_devices_os2(char *info, int deviceid)
|
||||
{
|
||||
char buffer[128];
|
||||
MCI_SYSINFO_PARMS mip;
|
||||
|
||||
if(deviceid && info)
|
||||
{
|
||||
MCI_SYSINFO_LOGDEVICE mid;
|
||||
|
||||
mip.pszReturn = buffer;
|
||||
mip.ulRetSize = sizeof(buffer);
|
||||
mip.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
mip.ulNumber = deviceid;
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
mip.ulItem = MCI_SYSINFO_QUERY_DRIVER;
|
||||
mip.pSysInfoParm = ∣
|
||||
strcpy(mid.szInstallName,buffer);
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_ITEM,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
strcpy(info,mid.szProductInfo);
|
||||
return deviceid;
|
||||
|
||||
} else {
|
||||
int number;
|
||||
|
||||
mip.pszReturn = buffer;
|
||||
mip.ulRetSize = sizeof(buffer);
|
||||
mip.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
|
||||
mciSendCommand(0,
|
||||
MCI_SYSINFO,
|
||||
MCI_WAIT | MCI_SYSINFO_QUANTITY,
|
||||
&mip,
|
||||
0);
|
||||
|
||||
number = atoi(mip.pszReturn);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void flush_os2(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int init_os2(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_os2;
|
||||
ao->flush = flush_os2;
|
||||
ao->write = write_os2;
|
||||
ao->get_formats = get_formats_os2;
|
||||
ao->close = close_os2;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "os2",
|
||||
/* description */ "Audio output for OS2.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_os2,
|
||||
};
|
||||
|
||||
|
||||
321
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/oss.c
vendored
Normal file
321
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/oss.c
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
oss: audio output via Open Sound System
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Michael Hipp
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_LINUX_SOUNDCARD_H
|
||||
#include <linux/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOUNDCARD_H
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MACHINE_SOUNDCARD_H
|
||||
#include <machine/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifndef AFMT_S16_NE
|
||||
# ifdef OSS_BIG_ENDIAN
|
||||
# define AFMT_S16_NE AFMT_S16_BE
|
||||
# else
|
||||
# define AFMT_S16_NE AFMT_S16_LE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef AFMT_U16_NE
|
||||
# ifdef OSS_BIG_ENDIAN
|
||||
# define AFMT_U16_NE AFMT_U16_BE
|
||||
# else
|
||||
# define AFMT_U16_NE AFMT_U16_LE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
struct oss_stuff
|
||||
{
|
||||
int fragment; /* size of one fragment */
|
||||
int nfrag; /* number of fragments */
|
||||
};
|
||||
|
||||
static int rate_best_match_oss(out123_handle *ao)
|
||||
{
|
||||
int ret,dsp_rate;
|
||||
|
||||
if(!ao || ao->fn < 0 || ao->rate < 0) return -1;
|
||||
dsp_rate = ao->rate;
|
||||
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SPEED,&dsp_rate);
|
||||
if(ret < 0) return ret;
|
||||
ao->rate = dsp_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate_oss(out123_handle *ao)
|
||||
{
|
||||
int dsp_rate;
|
||||
int ret = 0;
|
||||
|
||||
if(ao->rate >= 0) {
|
||||
dsp_rate = ao->rate;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SPEED,&dsp_rate);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_channels_oss(out123_handle *ao)
|
||||
{
|
||||
int chan = ao->channels - 1;
|
||||
int ret;
|
||||
|
||||
if(ao->channels < 0) return 0;
|
||||
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_STEREO, &chan);
|
||||
if(chan != (ao->channels-1)) return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_format_oss(out123_handle *ao)
|
||||
{
|
||||
int fmts;
|
||||
int sf,ret;
|
||||
|
||||
if(ao->format == -1) return 0;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
fmts = AFMT_S16_NE;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
fmts = AFMT_U8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
fmts = AFMT_S8;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
fmts = AFMT_MU_LAW;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
fmts = AFMT_A_LAW;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
fmts = AFMT_U16_NE;
|
||||
break;
|
||||
}
|
||||
|
||||
sf = fmts;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_SETFMT, &fmts);
|
||||
if(sf != fmts) return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int reset_parameters_oss(out123_handle *ao)
|
||||
{
|
||||
int ret;
|
||||
ret = ioctl(ao->fn, SNDCTL_DSP_RESET, NULL);
|
||||
if(ret < 0 && !AOQUIET) error("Can't reset audio!");
|
||||
ret = set_format_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
ret = set_channels_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
ret = set_rate_oss(ao);
|
||||
if (ret == -1) goto err;
|
||||
|
||||
/* Careful here. As per OSS v1.1, the next ioctl() commits the format
|
||||
* set above, so we must issue SNDCTL_DSP_RESET before we're allowed to
|
||||
* change it again. [dk]
|
||||
*/
|
||||
|
||||
/* FIXME: this needs re-enabled (but not using global variables this time):
|
||||
if (ioctl(ao->fn, SNDCTL_DSP_GETBLKSIZE, &outburst) == -1 ||
|
||||
outburst > MAXOUTBURST)
|
||||
outburst = MAXOUTBURST;
|
||||
*/
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int open_oss(out123_handle *ao)
|
||||
{
|
||||
char usingdefdev = 0;
|
||||
const char *dev;
|
||||
|
||||
if(!ao) return -1;
|
||||
|
||||
dev = ao->device;
|
||||
if(!dev) {
|
||||
dev = "/dev/dsp";
|
||||
usingdefdev = 1;
|
||||
}
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
|
||||
if(ao->fn < 0)
|
||||
{
|
||||
if(usingdefdev) {
|
||||
dev = "/dev/sound/dsp";
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if(ao->fn < 0) {
|
||||
if(!AOQUIET) error("Can't open default sound device!");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if(!AOQUIET) error1("Can't open %s!",dev);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(reset_parameters_oss(ao) < 0) {
|
||||
close(ao->fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ao->gain >= 0) {
|
||||
int e,mask;
|
||||
e = ioctl(ao->fn , SOUND_MIXER_READ_DEVMASK ,&mask);
|
||||
if(e < 0) {
|
||||
if(!AOQUIET) error("audio/gain: Can't get audio device features list.");
|
||||
}
|
||||
else if(mask & SOUND_MASK_PCM) {
|
||||
int gain = (ao->gain<<8)|(ao->gain);
|
||||
e = ioctl(ao->fn, SOUND_MIXER_WRITE_PCM , &gain);
|
||||
}
|
||||
else if(!(mask & SOUND_MASK_VOLUME)) {
|
||||
if(!AOQUIET) error1("audio/gain: setable Volume/PCM-Level not supported by your audio device: %#04x",mask);
|
||||
}
|
||||
else {
|
||||
int gain = (ao->gain<<8)|(ao->gain);
|
||||
e = ioctl(ao->fn, SOUND_MIXER_WRITE_VOLUME , &gain);
|
||||
}
|
||||
}
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* get formats for specific channel/rate parameters
|
||||
*/
|
||||
static int get_formats_oss(out123_handle *ao)
|
||||
{
|
||||
int fmt = 0;
|
||||
int r = ao->rate;
|
||||
int c = ao->channels;
|
||||
int i;
|
||||
|
||||
static int fmts[] = {
|
||||
MPG123_ENC_ULAW_8 , MPG123_ENC_SIGNED_16 ,
|
||||
MPG123_ENC_UNSIGNED_8 , MPG123_ENC_SIGNED_8 ,
|
||||
MPG123_ENC_UNSIGNED_16 , MPG123_ENC_ALAW_8
|
||||
};
|
||||
|
||||
/* Reset is required before we're allowed to set the new formats. [dk] */
|
||||
ioctl(ao->fn, SNDCTL_DSP_RESET, NULL);
|
||||
|
||||
for(i=0;i<6;i++) {
|
||||
ao->format = fmts[i];
|
||||
if(set_format_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
ao->channels = c;
|
||||
if(set_channels_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
ao->rate = r;
|
||||
if(rate_best_match_oss(ao) < 0) {
|
||||
continue;
|
||||
}
|
||||
if( (ao->rate*100 > r*(100-AUDIO_RATE_TOLERANCE)) && (ao->rate*100 < r*(100+AUDIO_RATE_TOLERANCE)) ) {
|
||||
fmt |= fmts[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
if(ioctl(ao->fn,SNDCTL_DSP_GETFMTS,&fmts) < 0) {
|
||||
if(!AOQUIET) error("Failed to get SNDCTL_DSP_GETFMTS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(fmts & AFMT_MU_LAW)
|
||||
ret |= MPG123_ENC_ULAW_8;
|
||||
if(fmts & AFMT_S16_NE)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(fmts & AFMT_U8)
|
||||
ret |= MPG123_ENC_UNSIGNED_8;
|
||||
if(fmts & AFMT_S8)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
if(fmts & AFMT_U16_NE)
|
||||
ret |= MPG123_ENC_UNSIGNED_16;
|
||||
if(fmts & AFMT_A_LAW)
|
||||
ret |= MPG123_ENC_ALAW_8;
|
||||
#endif
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
static int write_oss(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_oss(out123_handle *ao)
|
||||
{
|
||||
close(ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_oss(out123_handle *ao)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int init_oss(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_oss;
|
||||
ao->flush = flush_oss;
|
||||
ao->write = write_oss;
|
||||
ao->get_formats = get_formats_oss;
|
||||
ao->close = close_oss;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "oss",
|
||||
/* description */ "Output audio using OSS",
|
||||
/* revision */ "$Rev: 4021 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_oss,
|
||||
};
|
||||
|
||||
|
||||
330
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/portaudio.c
vendored
Normal file
330
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/portaudio.c
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
portaudio: audio output via PortAudio cross-platform audio API
|
||||
|
||||
copyright 2006-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
/* Need usleep(). */
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#include "out123_int.h"
|
||||
#include <math.h>
|
||||
#include <portaudio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define SAMPLE_SIZE (2)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.5f)
|
||||
|
||||
|
||||
typedef struct {
|
||||
PaStream *stream;
|
||||
sfifo_t fifo;
|
||||
int finished;
|
||||
} mpg123_portaudio_t;
|
||||
|
||||
#ifdef PORTAUDIO18
|
||||
#define PaTime PaTimestamp
|
||||
#define Pa_IsStreamActive Pa_StreamActive
|
||||
#endif
|
||||
|
||||
/* Some busy waiting. Proper stuff like semaphores might add
|
||||
dependencies (POSIX) that the platform does not know. */
|
||||
static void ms_sleep(int milliseconds)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
usleep(milliseconds*1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PORTAUDIO18
|
||||
static int paCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTime outTime, void *userData )
|
||||
#else
|
||||
static int paCallback(
|
||||
const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
const PaStreamCallbackTimeInfo* timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData )
|
||||
#endif
|
||||
{
|
||||
out123_handle *ao = userData;
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
unsigned long bytes = framesPerBuffer * SAMPLE_SIZE * ao->channels;
|
||||
int bytes_avail;
|
||||
int bytes_read;
|
||||
|
||||
while((bytes_avail=sfifo_used(&pa->fifo))<bytes && !pa->finished)
|
||||
{
|
||||
int ms = (bytes-bytes_avail)/ao->framesize*1000/ao->rate;
|
||||
debug3("waiting for more input, %d ms missing (%i < %lu)"
|
||||
, ms, bytes_avail, bytes);
|
||||
ms_sleep(ms/10);
|
||||
}
|
||||
if(bytes_avail > bytes)
|
||||
bytes_avail = bytes;
|
||||
bytes_read = sfifo_read(&pa->fifo, outputBuffer, bytes_avail);
|
||||
if(bytes_read != bytes_avail)
|
||||
warning2("Error reading from the FIFO (wanted=%d, bytes_read=%d).\n"
|
||||
, bytes_avail, bytes_read);
|
||||
if(bytes_read < 0)
|
||||
bytes_read = 0;
|
||||
/* Ensure that any remaining space is filled with zero bytes. */
|
||||
if(bytes_read >= 0 && bytes_read < bytes)
|
||||
memset((char*)outputBuffer+bytes_read, 0, bytes-bytes_read);
|
||||
|
||||
debug1("callback successfully passed along %i B", bytes_read);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
|
||||
pa->finished = 0;
|
||||
/* Open an audio I/O stream. */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
|
||||
err = Pa_OpenDefaultStream(
|
||||
&pa->stream,
|
||||
0, /* no input channels */
|
||||
ao->channels, /* number of output channels */
|
||||
paInt16, /* signed 16-bit samples */
|
||||
ao->rate, /* sample rate */
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
#ifdef PORTAUDIO18
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
#endif
|
||||
paCallback, /* no callback - use blocking IO */
|
||||
ao );
|
||||
|
||||
if( err != paNoError ) {
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to open PortAudio default stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
sfifo_init( &pa->fifo, ao->rate * FIFO_DURATION * SAMPLE_SIZE *ao->channels );
|
||||
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_portaudio(out123_handle *ao)
|
||||
{
|
||||
/* Only implemented Signed 16-bit audio for now */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
|
||||
static int write_portaudio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(&pa->fifo);
|
||||
block -= block % ao->framesize;
|
||||
debug1("space for writing: %i", block);
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(&pa->fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Start stream if not ative and 50 % full.*/
|
||||
if(sfifo_used(&pa->fifo) > (sfifo_size(&pa->fifo)/2))
|
||||
{
|
||||
pa->finished = 0;
|
||||
err = Pa_IsStreamActive( pa->stream );
|
||||
if (err == 0) {
|
||||
err = Pa_StartStream( pa->stream );
|
||||
if( err != paNoError ) {
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to start PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1; /* triggering exit here is not good, better handle that somehow... */
|
||||
}
|
||||
else
|
||||
debug("started stream");
|
||||
} else if (err < 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to check state of PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
debug("stream already active");
|
||||
}
|
||||
}
|
||||
if(len_remain)
|
||||
{
|
||||
debug1("Still need to write %d bytes, sleeping a bit.", len_remain);
|
||||
ms_sleep(0.1*FIFO_DURATION*1000);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
PaError err;
|
||||
int stuff;
|
||||
|
||||
debug1("close_portaudio with %d", sfifo_used(&pa->fifo));
|
||||
pa->finished = 1;
|
||||
/* Wait at least until the FIFO is empty. */
|
||||
while((stuff = sfifo_used(&pa->fifo))>0)
|
||||
{
|
||||
int ms = stuff/ao->framesize*1000/ao->rate;
|
||||
debug1("still stuff for about %i ms there", ms);
|
||||
ms_sleep(ms/2);
|
||||
}
|
||||
|
||||
if (pa->stream) {
|
||||
/* stop the stream if it is active */
|
||||
if (Pa_IsStreamActive( pa->stream ) == 1) {
|
||||
err = Pa_StopStream( pa->stream );
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to stop PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* and then close the stream */
|
||||
err = Pa_CloseStream( pa->stream );
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to close PortAudio stream: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
pa->stream = NULL;
|
||||
}
|
||||
|
||||
/* and free memory used by fifo */
|
||||
sfifo_close( &pa->fifo );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void flush_portaudio(out123_handle *ao)
|
||||
{
|
||||
mpg123_portaudio_t *pa = (mpg123_portaudio_t*)ao->userptr;
|
||||
/*PaError err;*/
|
||||
|
||||
/* throw away contents of FIFO */
|
||||
sfifo_flush( &pa->fifo );
|
||||
|
||||
/* and empty out PortAudio buffers */
|
||||
/*err = */
|
||||
Pa_AbortStream( pa->stream );
|
||||
}
|
||||
|
||||
|
||||
static int deinit_portaudio(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Shut down PortAudio */
|
||||
Pa_Terminate();
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_portaudio(out123_handle* ao)
|
||||
{
|
||||
int err = paNoError;
|
||||
mpg123_portaudio_t *handle;
|
||||
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_portaudio;
|
||||
ao->flush = flush_portaudio;
|
||||
ao->write = write_portaudio;
|
||||
ao->get_formats = get_formats_portaudio;
|
||||
ao->close = close_portaudio;
|
||||
ao->deinit = deinit_portaudio;
|
||||
|
||||
/* Initialise PortAudio */
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1( "Failed to initialise PortAudio: %s"
|
||||
, Pa_GetErrorText(err) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory for handle */
|
||||
ao->userptr = handle = malloc( sizeof(mpg123_portaudio_t) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error( "Failed to allocated memory for driver structure" );
|
||||
return -1;
|
||||
}
|
||||
handle->finished = 0;
|
||||
handle->stream = NULL;
|
||||
memset(&handle->fifo, 0, sizeof(sfifo_t));
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "portaudio",
|
||||
/* description */ "Output audio using PortAudio",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_portaudio,
|
||||
};
|
||||
|
||||
194
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/pulse.c
vendored
Normal file
194
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/pulse.c
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
pulse: audio output using PulseAudio server
|
||||
|
||||
copyright 2006-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int open_pulse(out123_handle *ao)
|
||||
{
|
||||
int err;
|
||||
pa_simple* pas = NULL;
|
||||
pa_sample_spec ss;
|
||||
/* Check if already open ? */
|
||||
if (ao->userptr) {
|
||||
if(!AOQUIET)
|
||||
error("Pulse audio output is already open.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open an audio I/O stream. */
|
||||
/* When they are < 0, I shall set some default. */
|
||||
if(ao->rate < 0 || ao->format < 0 || ao->channels < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
/* Fill out pulse audio's data structure */
|
||||
ss.channels = ao->channels;
|
||||
ss.rate = ao->rate;
|
||||
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S16BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S16LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_24:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S24BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S24LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_S32BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_S32LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ss.format=PA_SAMPLE_FLOAT32BE;
|
||||
#else
|
||||
ss.format=PA_SAMPLE_FLOAT32LE;
|
||||
#endif
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ss.format=PA_SAMPLE_ALAW;
|
||||
break;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ss.format=PA_SAMPLE_ULAW;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ss.format=PA_SAMPLE_U8;
|
||||
break;
|
||||
default:
|
||||
if(!AOQUIET)
|
||||
error1("Unsupported audio format: 0x%x", ao->format);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Perform the open */
|
||||
pas = pa_simple_new(
|
||||
NULL, /* Use the default server */
|
||||
ao->name, /* Our application's name */
|
||||
PA_STREAM_PLAYBACK,
|
||||
ao->device, /* Use the default device if NULL */
|
||||
"via out123", /* Description of our stream */
|
||||
&ss, /* Our sample format */
|
||||
NULL, /* Use default channel map */
|
||||
NULL, /* Use default buffering attributes */
|
||||
&err /* Error result code */
|
||||
);
|
||||
|
||||
if(pas == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to open pulse audio output: %s", pa_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store the pointer */
|
||||
ao->userptr = (void*)pas;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_pulse(out123_handle *ao)
|
||||
{
|
||||
/* Only implemented Signed 16-bit audio for now */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
|
||||
static int write_pulse(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
pa_simple *pas = (pa_simple*)ao->userptr;
|
||||
int ret, err;
|
||||
/* Doesn't return number of bytes but just success or not. */
|
||||
ret = pa_simple_write( pas, buf, len, &err );
|
||||
if(ret<0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to write audio: %s", pa_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
return len; /* If successful, everything has been written. */
|
||||
}
|
||||
|
||||
static int close_pulse(out123_handle *ao)
|
||||
{
|
||||
pa_simple *pas = (pa_simple*)ao->userptr;
|
||||
|
||||
if (pas) {
|
||||
int err; /* Do we really want to handle errors here? End is the end. */
|
||||
pa_simple_drain(pas, &err);
|
||||
pa_simple_free(pas);
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_pulse(out123_handle *ao)
|
||||
{
|
||||
pa_simple *pas = (pa_simple*)ao->userptr;
|
||||
|
||||
if (pas) {
|
||||
int err;
|
||||
pa_simple_flush( pas, &err );
|
||||
if(err && !AOQUIET)
|
||||
error1("Failed to flush audio: %s", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int init_pulse(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_pulse;
|
||||
ao->flush = flush_pulse;
|
||||
ao->write = write_pulse;
|
||||
ao->get_formats = get_formats_pulse;
|
||||
ao->close = close_pulse;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "pulse",
|
||||
/* description */ "Output audio using PulseAudio Server",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_pulse,
|
||||
};
|
||||
|
||||
272
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/qsa.c
vendored
Normal file
272
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/qsa.c
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
qsa: sound output with QNX Sound Architecture 0.5.2 API
|
||||
|
||||
copyright 2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
written by Mike Gorchak <mike.gorchak.qnx@gmail.com>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct _qsa_mp_map
|
||||
{
|
||||
uint32_t qsa_format;
|
||||
int mp_format;
|
||||
} qsa_mp_map_t;
|
||||
|
||||
/* in order best format first */
|
||||
qsa_mp_map_t format_map[]=
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
{SND_PCM_SFMT_FLOAT64_BE, MPG123_ENC_FLOAT_64 },
|
||||
{SND_PCM_SFMT_FLOAT_BE, MPG123_ENC_FLOAT_32 },
|
||||
{SND_PCM_SFMT_S32_BE, MPG123_ENC_SIGNED_32 },
|
||||
{SND_PCM_SFMT_U32_BE, MPG123_ENC_UNSIGNED_32 },
|
||||
{SND_PCM_SFMT_S24_BE, MPG123_ENC_SIGNED_24 },
|
||||
{SND_PCM_SFMT_U24_BE, MPG123_ENC_UNSIGNED_24 },
|
||||
{SND_PCM_SFMT_S16_BE, MPG123_ENC_SIGNED_16 },
|
||||
{SND_PCM_SFMT_U16_BE, MPG123_ENC_UNSIGNED_16 },
|
||||
#else
|
||||
{SND_PCM_SFMT_FLOAT64_LE, MPG123_ENC_FLOAT_64 },
|
||||
{SND_PCM_SFMT_FLOAT_LE, MPG123_ENC_FLOAT_32 },
|
||||
{SND_PCM_SFMT_S32_LE, MPG123_ENC_SIGNED_32 },
|
||||
{SND_PCM_SFMT_U32_LE, MPG123_ENC_UNSIGNED_32 },
|
||||
{SND_PCM_SFMT_S24_LE, MPG123_ENC_SIGNED_24 },
|
||||
{SND_PCM_SFMT_U24_LE, MPG123_ENC_UNSIGNED_24 },
|
||||
{SND_PCM_SFMT_S16_LE, MPG123_ENC_SIGNED_16 },
|
||||
{SND_PCM_SFMT_U16_LE, MPG123_ENC_UNSIGNED_16 },
|
||||
#endif
|
||||
{SND_PCM_SFMT_U8, MPG123_ENC_UNSIGNED_8 },
|
||||
{SND_PCM_SFMT_S8, MPG123_ENC_SIGNED_8 },
|
||||
{SND_PCM_SFMT_A_LAW, MPG123_ENC_ALAW_8 },
|
||||
{SND_PCM_SFMT_MU_LAW, MPG123_ENC_ULAW_8 },
|
||||
{0, 0 },
|
||||
};
|
||||
|
||||
typedef struct _qsa_internal
|
||||
{
|
||||
int cardno;
|
||||
int deviceno;
|
||||
snd_pcm_t* audio_handle;
|
||||
snd_pcm_channel_params_t cpars;
|
||||
} qsa_internal_t;
|
||||
|
||||
static int open_qsa(out123_handle* ao)
|
||||
{
|
||||
int status;
|
||||
int cardno;
|
||||
int deviceno;
|
||||
int it;
|
||||
snd_pcm_t* audio_handle;
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
ao->userptr=NULL;
|
||||
|
||||
status=snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, SND_PCM_OPEN_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status=snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
userptr=calloc(1, sizeof(qsa_internal_t));
|
||||
if (userptr==NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ao->userptr=userptr;
|
||||
userptr->audio_handle=audio_handle;
|
||||
userptr->cardno=cardno;
|
||||
userptr->deviceno=deviceno;
|
||||
|
||||
memset(&userptr->cpars, 0, sizeof(userptr->cpars));
|
||||
|
||||
userptr->cpars.channel=SND_PCM_CHANNEL_PLAYBACK;
|
||||
userptr->cpars.mode=SND_PCM_MODE_BLOCK;
|
||||
userptr->cpars.start_mode=SND_PCM_START_DATA;
|
||||
userptr->cpars.stop_mode=SND_PCM_STOP_STOP;
|
||||
userptr->cpars.format.format=0;
|
||||
it=0;
|
||||
do {
|
||||
if ((format_map[it].qsa_format==0) && (format_map[it].mp_format==0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ao->format==format_map[it].mp_format)
|
||||
{
|
||||
userptr->cpars.format.format=format_map[it].qsa_format;
|
||||
break;
|
||||
}
|
||||
it++;
|
||||
} while(1);
|
||||
userptr->cpars.format.interleave=1;
|
||||
userptr->cpars.format.rate=ao->rate;
|
||||
userptr->cpars.format.voices=ao->channels;
|
||||
userptr->cpars.buf.block.frag_size=4096;
|
||||
userptr->cpars.buf.block.frags_min=8;
|
||||
userptr->cpars.buf.block.frags_max=16;
|
||||
|
||||
if ((ao->channels!=-1) && (ao->rate!=-1))
|
||||
{
|
||||
status=snd_pcm_plugin_params(userptr->audio_handle, &userptr->cpars);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status=snd_pcm_plugin_prepare(userptr->audio_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int get_formats_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
int status;
|
||||
int it=0;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
userptr->cpars.format.rate=ao->rate;
|
||||
userptr->cpars.format.voices=ao->channels;
|
||||
it=0;
|
||||
do {
|
||||
if ((format_map[it].qsa_format==0) && (format_map[it].mp_format==0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
userptr->cpars.format.format=format_map[it].qsa_format;
|
||||
status=snd_pcm_plugin_params(userptr->audio_handle, &userptr->cpars);
|
||||
if (status<0)
|
||||
{
|
||||
it++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return format_map[it].mp_format;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_qsa(out123_handle* ao, unsigned char* buf, int bytes)
|
||||
{
|
||||
int written;
|
||||
int status;
|
||||
snd_pcm_channel_status_t cstatus;
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
written=snd_pcm_plugin_write(userptr->audio_handle, buf, bytes);
|
||||
if (written!=bytes)
|
||||
{
|
||||
/* Check if samples playback got stuck somewhere in hardware or in */
|
||||
/* the audio device driver */
|
||||
if ((errno==EAGAIN) && (written==0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((errno==EINVAL) || (errno==EIO))
|
||||
{
|
||||
memset(&cstatus, 0, sizeof(cstatus));
|
||||
cstatus.channel=SND_PCM_CHANNEL_PLAYBACK;
|
||||
status=snd_pcm_plugin_status(userptr->audio_handle, &cstatus);
|
||||
if (status>0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
|
||||
(cstatus.status == SND_PCM_STATUS_READY))
|
||||
{
|
||||
status=snd_pcm_plugin_prepare(userptr->audio_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (status<0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
static void flush_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
snd_pcm_playback_flush(userptr->audio_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static int close_qsa(out123_handle* ao)
|
||||
{
|
||||
qsa_internal_t* userptr;
|
||||
|
||||
userptr=ao->userptr;
|
||||
if (userptr!=NULL);
|
||||
{
|
||||
snd_pcm_close(userptr->audio_handle);
|
||||
free(ao->userptr);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int deinit_qsa(out123_handle* ao)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int init_qsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_qsa;
|
||||
ao->flush = flush_qsa;
|
||||
ao->write = write_qsa;
|
||||
ao->get_formats = get_formats_qsa;
|
||||
ao->close = close_qsa;
|
||||
ao->deinit = deinit_qsa;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "qsa",
|
||||
/* description */ "Output audio using QNX Sound Architecture (QSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
/* init_output */ init_qsa,
|
||||
};
|
||||
302
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sdl.c
vendored
Normal file
302
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sdl.c
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
sdl: audio output via SDL cross-platform API
|
||||
|
||||
copyright 2006-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Nicholas J. Humfrey
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Including the sfifo code locally, to avoid module linkage issues. */
|
||||
#define SFIFO_STATIC
|
||||
#include "sfifo.c"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define SAMPLE_SIZE (2)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
/* Performance of SDL with ALSA is a bit of a mystery to me. Regardless
|
||||
of buffer size here, I just cannot avoid buffer underruns on my system.
|
||||
SDL always chooses 1024x2 periods, which seems to be just not quite
|
||||
enough on the Thinkpad:-/ Choosing 0.2 s as a plentiful default instead
|
||||
of 0.5 s which is just a lie. */
|
||||
#define FIFO_DURATION (ao->device_buffer > 0. ? ao->device_buffer : 0.2)
|
||||
#define BUFFER_SAMPLES ((FIFO_DURATION*ao->rate)/2)
|
||||
|
||||
struct handle
|
||||
{
|
||||
int finished; /* A flag for communicating end, one-way. */
|
||||
sfifo_t fifo;
|
||||
};
|
||||
|
||||
/* Some busy waiting. Proper stuff like semaphores might add
|
||||
dependencies (POSIX) that the platform does not know. */
|
||||
static void ms_sleep(int milliseconds)
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
usleep(milliseconds*1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The audio function callback takes the following parameters:
|
||||
stream: A pointer to the audio buffer to be filled
|
||||
len: The length (in bytes) of the audio buffer
|
||||
*/
|
||||
static void audio_callback_sdl(void *udata, Uint8 *stream, int len)
|
||||
{
|
||||
out123_handle *ao = (out123_handle*)udata;
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
int bytes_read;
|
||||
int bytes_avail;
|
||||
|
||||
/* Until the finished flag is set, we will wait for more.
|
||||
As the exact value does not matter and late detection of
|
||||
a change is kindof OK, I do not see a thread safety problem here. */
|
||||
while((bytes_avail = sfifo_used(fifo)) < len && !sh->finished)
|
||||
{
|
||||
int ms = (len-bytes_avail)/ao->framesize*1000/ao->rate;
|
||||
debug1("waiting for more input, %d ms missing", ms);
|
||||
ms_sleep(ms/10);
|
||||
}
|
||||
/* Read audio from FIFO to SDL's buffer */
|
||||
if(bytes_avail > len)
|
||||
bytes_avail = len;
|
||||
bytes_read = sfifo_read( fifo, stream, bytes_avail );
|
||||
if(bytes_read != bytes_avail)
|
||||
warning2("Error reading from the FIFO (wanted=%d, bytes_read=%d).\n"
|
||||
, bytes_avail, bytes_read);
|
||||
if(bytes_read < 0)
|
||||
bytes_read = 0;
|
||||
/* Ensure that any remaining space is filled with zero bytes. */
|
||||
if(bytes_read < len)
|
||||
memset(stream+bytes_read, 0, len-bytes_read);
|
||||
}
|
||||
|
||||
static int open_sdl(out123_handle *ao)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
|
||||
/* Open an audio I/O stream. */
|
||||
if (ao->rate > 0 && ao->channels >0 ) {
|
||||
size_t ringbuffer_len;
|
||||
SDL_AudioSpec wanted;
|
||||
|
||||
/* L16 uncompressed audio data, using 16-bit signed representation in twos
|
||||
complement notation - system endian-ness. */
|
||||
wanted.format = AUDIO_S16SYS;
|
||||
/* Seems reasonable to demand a buffer size related to the device
|
||||
buffer. */
|
||||
wanted.samples = BUFFER_SAMPLES;
|
||||
wanted.callback = audio_callback_sdl;
|
||||
wanted.userdata = ao;
|
||||
wanted.channels = ao->channels;
|
||||
wanted.freq = ao->rate;
|
||||
|
||||
sh->finished = 0;
|
||||
/* Open the audio device, forcing the desired format
|
||||
Actually, it is still subject to constraints by hardware.
|
||||
Need to have sample rate checked beforehand! SDL will
|
||||
happily play 22 kHz files with 44 kHz hardware rate!
|
||||
Same with channel count. No conversion. The manual is a bit
|
||||
misleading on that (only talking about sample format, I guess). */
|
||||
if ( SDL_OpenAudio(&wanted, NULL) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Couldn't open SDL audio: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise FIFO */
|
||||
ringbuffer_len = ao->rate * FIFO_DURATION * SAMPLE_SIZE *ao->channels;
|
||||
debug2( "Allocating %d byte ring-buffer (%f seconds)", (int)ringbuffer_len, (float)FIFO_DURATION);
|
||||
if (sfifo_init( fifo, ringbuffer_len ) && !AOQUIET)
|
||||
error1( "Failed to initialise FIFO of size %d bytes", (int)ringbuffer_len );
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_sdl(out123_handle *ao)
|
||||
{
|
||||
/* Got no better idea than to just take 16 bit and run with it */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
#if 0
|
||||
/*
|
||||
This code would "properly" test audio format support.
|
||||
But thing is, SDL will always say yes and amen to everything, but it takes
|
||||
an awful amount of time to get all the variants tested (about 2 seconds,
|
||||
for example). I have seen SDL builds that do proper format conversion
|
||||
behind your back, I have seen builds that do not. Every build seems to
|
||||
claim that it does, though. Just hope you're lucky and your SDL works.
|
||||
Otherwise, use a proper audio output API.
|
||||
*/
|
||||
SDL_AudioSpec wanted, got;
|
||||
|
||||
/* Only implemented Signed 16-bit audio for now.
|
||||
The SDL manual doesn't suggest more interesting formats
|
||||
like S24 or S32 anyway. */
|
||||
wanted.format = AUDIO_S16SYS;
|
||||
wanted.samples = BUFFER_SAMPLES;
|
||||
wanted.callback = audio_callback_sdl;
|
||||
wanted.userdata = ao;
|
||||
wanted.channels = ao->channels;
|
||||
wanted.freq = ao->rate;
|
||||
|
||||
if(SDL_OpenAudio(&wanted, &got)) return 0;
|
||||
SDL_CloseAudio();
|
||||
fprintf(stderr, "wanted rate: %li got rate %li\n", (long)wanted.freq, (long)got.freq);
|
||||
return (got.freq == ao->rate && got.channels == ao->channels)
|
||||
? MPG123_ENC_SIGNED_16
|
||||
: 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int write_sdl(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
int len_remain = len;
|
||||
|
||||
/* Some busy waiting, but feed what is possible. */
|
||||
while(len_remain) /* Note: input len is multiple of framesize! */
|
||||
{
|
||||
int block = sfifo_space(fifo);
|
||||
block -= block % ao->framesize;
|
||||
if(block > len_remain)
|
||||
block = len_remain;
|
||||
if(block)
|
||||
{
|
||||
sfifo_write(fifo, buf, block);
|
||||
len_remain -= block;
|
||||
buf += block;
|
||||
/* Unpause once the buffer is 50% full */
|
||||
if (sfifo_used(fifo) > (sfifo_size(fifo)/2) )
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
if(len_remain)
|
||||
{
|
||||
debug1("Still need to write %d bytes, sleeping a bit.", len_remain);
|
||||
ms_sleep(0.1*FIFO_DURATION*1000);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int close_sdl(out123_handle *ao)
|
||||
{
|
||||
int stuff;
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
sfifo_t *fifo = &sh->fifo;
|
||||
|
||||
debug1("close_sdl with %d", sfifo_used(fifo));
|
||||
sh->finished = 1;
|
||||
/* Wait at least until SDL emptied the FIFO. */
|
||||
while((stuff = sfifo_used(fifo))>0)
|
||||
{
|
||||
int ms = stuff/ao->framesize*1000/ao->rate;
|
||||
debug1("still stuff for about %i ms there", ms);
|
||||
ms_sleep(ms/2);
|
||||
}
|
||||
|
||||
SDL_CloseAudio();
|
||||
|
||||
/* Free up the memory used by the FIFO */
|
||||
sfifo_close( fifo );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sdl(out123_handle *ao)
|
||||
{
|
||||
struct handle *sh = (struct handle*)ao->userptr;
|
||||
|
||||
SDL_PauseAudio(1);
|
||||
sfifo_flush(&sh->fifo);
|
||||
}
|
||||
|
||||
/* You can only rely on that being called after successful init_sdl()!
|
||||
And sdl_close() should be called before to free the sfifo. */
|
||||
static int deinit_sdl(out123_handle* ao)
|
||||
{
|
||||
/* Free up memory */
|
||||
if (ao->userptr) {
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Shut down SDL */
|
||||
SDL_Quit();
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remember: If this returns failure, no additional cleanup happens.
|
||||
Resources must be freed here. */
|
||||
static int init_sdl(out123_handle* ao)
|
||||
{
|
||||
struct handle *sh;
|
||||
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sdl;
|
||||
ao->flush = flush_sdl;
|
||||
ao->write = write_sdl;
|
||||
ao->get_formats = get_formats_sdl;
|
||||
ao->close = close_sdl;
|
||||
ao->deinit = deinit_sdl;
|
||||
|
||||
/* Initialise SDL */
|
||||
if (SDL_Init( SDL_INIT_AUDIO ) )
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("Failed to initialise SDL: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
/* Allocate memory _after_ checking that SDL is available, so we do not
|
||||
have to free after failure. */
|
||||
ao->userptr = sh = malloc( sizeof(struct handle) );
|
||||
if (ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error( "Failed to allocated memory for FIFO structure" );
|
||||
return -1;
|
||||
}
|
||||
sh->finished = 0;
|
||||
/* Not exactly necessary; only for somewhat safe sdl_close after a fake
|
||||
sdl_open(). */
|
||||
memset( &sh->fifo, 0, sizeof(sfifo_t) );
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sdl",
|
||||
/* description */ "Output audio using SDL (Simple DirectMedia Layer).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sdl,
|
||||
};
|
||||
269
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sgi.c
vendored
Normal file
269
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sgi.c
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
sgi: audio output on SGI boxen
|
||||
|
||||
copyright ?-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written (as it seems) by Thomas Woerner
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <fcntl.h>
|
||||
#include <dmedia/audio.h>
|
||||
#include "errno.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int set_rate(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
int dev = alGetDevice(config);
|
||||
ALpv params[1];
|
||||
|
||||
/* Make sure the device is OK */
|
||||
if(dev < 0)
|
||||
{
|
||||
error1("set_rate: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
if(ao->rate > 0)
|
||||
{
|
||||
params[0].param = AL_RATE;
|
||||
params[0].value.ll = alDoubleToFixed((double)ao->rate);
|
||||
if(alSetParams(dev, params, 1) < 0)
|
||||
{
|
||||
error1("set_rate: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_channels(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(ao->channels == 2)
|
||||
ret = alSetChannels(config, AL_STEREO);
|
||||
else
|
||||
ret = alSetChannels(config, AL_MONO);
|
||||
|
||||
if(ret < 0)
|
||||
{
|
||||
error1("set_channels : %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao, ALconfig config)
|
||||
{
|
||||
if(ao->format == MPG123_ENC_FLOAT_32)
|
||||
{
|
||||
if(alSetSampFmt(config, AL_SAMPFMT_FLOAT) < 0)
|
||||
{
|
||||
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(alSetSampFmt(config, AL_SAMPFMT_TWOSCOMP) < 0)
|
||||
{
|
||||
error1("SetSampFmt: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
if(alSetWidth(config, AL_SAMPLE_16) < 0)
|
||||
{
|
||||
error1("SetWidth: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_sgi(out123_handle *ao)
|
||||
{
|
||||
int current_dev;
|
||||
ALport port = NULL;
|
||||
ALconfig config = alNewConfig();
|
||||
|
||||
ao->userptr = NULL;
|
||||
|
||||
/* Test for correct completion */
|
||||
if(config == 0)
|
||||
{
|
||||
error1("open_sgi: %s", alGetErrorString(oserror()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup output device to specified device name. If there is no device name
|
||||
specified in ao structure, use the default for output */
|
||||
if((ao->device) != NULL)
|
||||
{
|
||||
current_dev = alGetResourceByName(AL_SYSTEM, ao->device, AL_OUTPUT_DEVICE_TYPE);
|
||||
|
||||
debug2("Dev: %s %i", ao->device, current_dev);
|
||||
|
||||
if(!current_dev)
|
||||
{
|
||||
int i, numOut;
|
||||
char devname[32];
|
||||
ALpv pv[1];
|
||||
ALvalue *alvalues;
|
||||
|
||||
error2("Invalid audio resource: %s (%s)", ao->device, alGetErrorString(oserror()));
|
||||
|
||||
if((numOut= alQueryValues(AL_SYSTEM,AL_DEFAULT_OUTPUT,0,0,0,0))>=0)
|
||||
fprintf(stderr, "There are %d output devices on this system.\n", numOut);
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Can't find output devices. alQueryValues failed: %s\n", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
alvalues = malloc(sizeof(ALvalue) * numOut);
|
||||
i = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, alvalues, numOut, pv, 0);
|
||||
if(i == -1)
|
||||
error1("alQueryValues: %s", alGetErrorString(oserror()));
|
||||
else
|
||||
{
|
||||
for(i=0; i < numOut; i++)
|
||||
{
|
||||
pv[0].param = AL_NAME;
|
||||
pv[0].value.ptr = devname;
|
||||
pv[0].sizeIn = 32;
|
||||
alGetParams(alvalues[i].i, pv, 1);
|
||||
|
||||
fprintf(stderr, "%i: %s\n", i, devname);
|
||||
}
|
||||
}
|
||||
free(alvalues);
|
||||
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
if(alSetDevice(config, current_dev) < 0)
|
||||
{
|
||||
error1("open: alSetDevice : %s",alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
} else
|
||||
current_dev = AL_DEFAULT_OUTPUT;
|
||||
|
||||
/* Set the device */
|
||||
if(alSetDevice(config, current_dev) < 0)
|
||||
{
|
||||
error1("open_sgi: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
/* Set port parameters */
|
||||
|
||||
if(alSetQueueSize(config, 131069) < 0)
|
||||
{
|
||||
error1("open_sgi: setting audio buffer failed: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
if( set_format(ao, config) < 0
|
||||
|| set_rate(ao, config) < 0
|
||||
|| set_channels(ao, config) < 0 )
|
||||
goto open_sgi_bad;
|
||||
|
||||
/* Open the audio port */
|
||||
port = alOpenPort("mpg123-VSC", "w", config);
|
||||
if(port == NULL)
|
||||
{
|
||||
error1("Unable to open audio channel: %s", alGetErrorString(oserror()));
|
||||
goto open_sgi_bad;
|
||||
}
|
||||
|
||||
ao->userptr = (void*)port;
|
||||
|
||||
alFreeConfig(config);
|
||||
return 1;
|
||||
|
||||
open_sgi_bad:
|
||||
/* clean up and return error */
|
||||
alFreeConfig(config);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_sgi(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_FLOAT_32;
|
||||
}
|
||||
|
||||
|
||||
static int write_sgi(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
int length = len;
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(ao->channels == 2) length >>= 2;
|
||||
else length >>= 1;
|
||||
|
||||
if(ao->format == MPG123_ENC_FLOAT_32) length >>=1;
|
||||
|
||||
/* Not much error checking ... */
|
||||
alWriteFrames(port, buf, length);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int close_sgi(out123_handle *ao)
|
||||
{
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(port)
|
||||
{
|
||||
/* play all remaining samples */
|
||||
while(alGetFilled(port) > 0) sginap(1);
|
||||
|
||||
alClosePort(port);
|
||||
ao->userptr=NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sgi(out123_handle *ao)
|
||||
{
|
||||
ALport port = (ALport)ao->userptr;
|
||||
|
||||
if(port) alDiscardFrames(port, alGetFilled(port));
|
||||
}
|
||||
|
||||
static int init_sgi(out123_handle* ao)
|
||||
{
|
||||
if(ao == NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sgi;
|
||||
ao->flush = flush_sgi;
|
||||
ao->write = write_sgi;
|
||||
ao->get_formats = get_formats_sgi;
|
||||
ao->close = close_sgi;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info =
|
||||
{
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sgi",
|
||||
/* description */ "Audio output for SGI.",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sgi,
|
||||
};
|
||||
161
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sndio.c
vendored
Normal file
161
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sndio.c
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* sndio: sndio audio output
|
||||
*
|
||||
* Copyright (c) 2008 Christian Weisgerber <naddy@openbsd.org>,
|
||||
* Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#include <sndio.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int open_sndio(out123_handle *ao)
|
||||
{
|
||||
struct sio_hdl *hdl;
|
||||
struct sio_par par;
|
||||
|
||||
hdl = sio_open(ao->device /* NULL is fine */, SIO_PLAY, 0);
|
||||
if (hdl == NULL)
|
||||
return -1;
|
||||
|
||||
sio_initpar(&par);
|
||||
par.rate = ao->rate;
|
||||
par.pchan = ao->channels;
|
||||
par.le = SIO_LE_NATIVE;
|
||||
switch(ao->format) {
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
par.sig = 1;
|
||||
par.bits = 32;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_32:
|
||||
par.sig = 0;
|
||||
par.bits = 32;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
case -1: /* query mode */
|
||||
par.sig = 1;
|
||||
par.bits = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_16:
|
||||
par.sig = 0;
|
||||
par.bits = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
par.sig = 0;
|
||||
par.bits = 8;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
par.sig = 1;
|
||||
par.bits = 8;
|
||||
break;
|
||||
default:
|
||||
if (!AOQUIET)
|
||||
error1("open_sndio: invalid sample format %d",
|
||||
ao->format);
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) ||
|
||||
!sio_start(hdl)) {
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
if ((par.bits != 8 && par.bits != 16 && par.bits != 32) ||
|
||||
par.le != SIO_LE_NATIVE) {
|
||||
sio_close(hdl);
|
||||
return -1;
|
||||
}
|
||||
ao->rate = par.rate;
|
||||
ao->channels = par.pchan;
|
||||
switch (par.bits) {
|
||||
case 8:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_8 :
|
||||
MPG123_ENC_UNSIGNED_8;
|
||||
break;
|
||||
case 16:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_16 :
|
||||
MPG123_ENC_UNSIGNED_16;
|
||||
break;
|
||||
case 32:
|
||||
ao->format = par.sig ? MPG123_ENC_SIGNED_32 :
|
||||
MPG123_ENC_UNSIGNED_32;
|
||||
break;
|
||||
}
|
||||
ao->userptr = hdl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_formats_sndio(out123_handle *ao)
|
||||
{
|
||||
return (MPG123_ENC_SIGNED_32|MPG123_ENC_UNSIGNED_32|
|
||||
MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_16|
|
||||
MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_8);
|
||||
}
|
||||
|
||||
static int write_sndio(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct sio_hdl *hdl = (struct sio_hdl *)ao->userptr;
|
||||
int count;
|
||||
|
||||
count = (int)sio_write(hdl, buf, len);
|
||||
if (count == 0 && sio_eof(hdl))
|
||||
return -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
static void flush_sndio(out123_handle *ao)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int close_sndio(out123_handle *ao)
|
||||
{
|
||||
struct sio_hdl *hdl = (struct sio_hdl *)ao->userptr;
|
||||
|
||||
sio_close(hdl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_sndio(out123_handle* ao)
|
||||
{
|
||||
if (ao == NULL)
|
||||
return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sndio;
|
||||
ao->flush = flush_sndio; /* required */
|
||||
ao->write = write_sndio;
|
||||
ao->get_formats = get_formats_sndio;
|
||||
ao->close = close_sndio;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sndio",
|
||||
/* description */ "Output audio using sndio library",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sndio,
|
||||
};
|
||||
283
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sun.c
vendored
Normal file
283
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/sun.c
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
sun: audio output for Sun systems
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Michael Hipp
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SUN_AUDIOIO_H
|
||||
#include <sun/audioio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_AUDIOIO_H
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_AUDIO_H
|
||||
#include <sys/audio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASM_AUDIOIO_H
|
||||
#include <asm/audioio.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include "debug.h"
|
||||
|
||||
static void set_format_helper(out123_handle *ao, audio_info_t *ainfo)
|
||||
{
|
||||
|
||||
switch(ao->format) {
|
||||
case -1:
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
default:
|
||||
#ifndef AUDIO_ENCODING_LINEAR /* not supported */
|
||||
#define AUDIO_ENCODING_LINEAR 3
|
||||
#endif
|
||||
ainfo->play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
ainfo->play.precision = 16;
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
ainfo->play.encoding = AUDIO_ENCODING_LINEAR8;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
#endif
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
if(!AOQUIET)
|
||||
error("Linear signed 8 bit not supported!");
|
||||
return;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
ainfo->play.encoding = AUDIO_ENCODING_ULAW;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
case MPG123_ENC_ALAW_8:
|
||||
ainfo->play.encoding = AUDIO_ENCODING_ALAW;
|
||||
ainfo->play.precision = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int reset_parameters_sun(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
if(ao->rate != -1) ainfo.play.sample_rate = ao->rate;
|
||||
|
||||
if(ao->channels >= 0) ainfo.play.channels = ao->channels;
|
||||
|
||||
set_format_helper(ao,&ainfo);
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rate_best_match(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) < 0) {
|
||||
ao->rate = 0;
|
||||
return 0;
|
||||
}
|
||||
if(ioctl(ao->fn, AUDIO_GETINFO, &ainfo) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ao->rate = ainfo.play.sample_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rate(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
if(ao->rate != -1) {
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int set_channels(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.channels = ao->channels;
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_format(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
set_format_helper(ao,&ainfo);
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_sun(out123_handle *ao)
|
||||
{
|
||||
audio_info_t ainfo;
|
||||
const char *dev = ao->device;
|
||||
|
||||
if(!dev) {
|
||||
if(getenv("AUDIODEV")) {
|
||||
dev = getenv("AUDIODEV");
|
||||
} else {
|
||||
dev = "/dev/audio";
|
||||
}
|
||||
}
|
||||
|
||||
ao->fn = open(dev,O_WRONLY);
|
||||
if(ao->fn < 0) return ao->fn;
|
||||
|
||||
#if defined(SUNOS) && defined(AUDIO_GETDEV)
|
||||
{
|
||||
int type;
|
||||
if(ioctl(ao->fn, AUDIO_GETDEV, &type) == -1) return -1;
|
||||
if(type == AUDIO_DEV_UNKNOWN || type == AUDIO_DEV_AMD)
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
{
|
||||
struct audio_device ad;
|
||||
if(ioctl(ao->fn, AUDIO_GETDEV, &ad) == -1)
|
||||
return -1;
|
||||
if(!strstr(ad.name,"dbri") && !strstr(ad.name,"CS4231"))
|
||||
warning1("Unknown sound system %s. But we try it.",ad.name);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(reset_parameters_sun(ao) < 0) return -1;
|
||||
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
|
||||
if(ao->flags > 0)
|
||||
ainfo.play.port = 0;
|
||||
if(ao->flags & OUT123_INTERNAL_SPEAKER)
|
||||
ainfo.play.port |= AUDIO_SPEAKER;
|
||||
if(ao->flags & OUT123_HEADPHONES)
|
||||
ainfo.play.port |= AUDIO_HEADPHONE;
|
||||
#ifdef AUDIO_LINE_OUT
|
||||
if(ao->flags & OUT123_LINE_OUT)
|
||||
ainfo.play.port |= AUDIO_LINE_OUT;
|
||||
#endif
|
||||
|
||||
if(ao->gain != -1)
|
||||
ainfo.play.gain = ao->gain;
|
||||
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) == -1)
|
||||
return -1;
|
||||
|
||||
return ao->fn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int get_formats_sun(out123_handle *ao)
|
||||
{
|
||||
static int tab[][3] = {
|
||||
{ AUDIO_ENCODING_ULAW , 8, MPG123_ENC_ULAW_8 } ,
|
||||
{ AUDIO_ENCODING_ALAW , 8, MPG123_ENC_ALAW_8 } ,
|
||||
{ AUDIO_ENCODING_LINEAR , 16, MPG123_ENC_SIGNED_16 } ,
|
||||
#if 0
|
||||
#if defined(SOLARIS) || defined(SPARCLINUX)
|
||||
{ AUDIO_ENCODING_LINEAR8 , 8, MPG123_ENC_UNSIGNED_8 } ,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
audio_info_t ainfo;
|
||||
int i,fmts=0;
|
||||
|
||||
for(i=0;i<sizeof(tab)/sizeof(tab[0]);i++) {
|
||||
AUDIO_INITINFO(&ainfo);
|
||||
ainfo.play.encoding = tab[i][0];
|
||||
ainfo.play.precision = tab[i][1];
|
||||
#if 1
|
||||
ainfo.play.sample_rate = ao->rate;
|
||||
ainfo.play.channels = ao->channels;
|
||||
#endif
|
||||
if(ioctl(ao->fn, AUDIO_SETINFO, &ainfo) >= 0) {
|
||||
fmts |= tab[i][2];
|
||||
}
|
||||
}
|
||||
return fmts;
|
||||
}
|
||||
|
||||
static int write_sun(out123_handle *ao,unsigned char *buf,int len)
|
||||
{
|
||||
return write(ao->fn,buf,len);
|
||||
}
|
||||
|
||||
static int close_sun(out123_handle *ao)
|
||||
{
|
||||
close (ao->fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flush_sun(out123_handle *ao)
|
||||
{
|
||||
/*ioctl (ao->fn, I_FLUSH, FLUSHRW);*/
|
||||
}
|
||||
|
||||
|
||||
static int init_sun(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_sun;
|
||||
ao->flush = flush_sun;
|
||||
ao->write = write_sun;
|
||||
ao->get_formats = get_formats_sun;
|
||||
ao->close = close_sun;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "sun",
|
||||
/* description */ "Audio output for Sun Audio.",
|
||||
/* revision */ "$Rev: 3915 $",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_sun,
|
||||
};
|
||||
|
||||
|
||||
213
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/tinyalsa.c
vendored
Normal file
213
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/tinyalsa.c
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
tinyalsa: sound output with TINY Advanced Linux Sound Architecture
|
||||
|
||||
copyright 2006-8 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
initially written by Jarno Lehtinen <lehtinen@sci.fi>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include <tinyalsa/asoundlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct pcm *pcm;
|
||||
struct pcm_params *params;
|
||||
struct pcm_config config;
|
||||
|
||||
unsigned int device;
|
||||
unsigned int card;
|
||||
} mpg123_tinyalsa_t;
|
||||
|
||||
|
||||
static int initialize_device(out123_handle *ao)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
ta->config.channels = ao->channels;
|
||||
ta->config.rate = ao->rate;
|
||||
ta->config.period_size = 1024;
|
||||
ta->config.period_count = 4;
|
||||
ta->config.format = PCM_FORMAT_S16_LE;
|
||||
ta->config.start_threshold = 0;
|
||||
ta->config.stop_threshold = 0;
|
||||
ta->config.silence_threshold = 0;
|
||||
|
||||
ta->pcm = pcm_open(ta->card, ta->device, PCM_OUT, &ta->config);
|
||||
if (!ta->pcm || !pcm_is_ready(ta->pcm))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error3( "(open) Unable to open card %u PCM device %u (%s)\n"
|
||||
, ta->card, ta->device, pcm_get_error(ta->pcm) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int open_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("open_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ao->format != -1)
|
||||
{
|
||||
/* we're going to play: initalize sample format */
|
||||
return initialize_device(ao);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* query mode; sample format will be set for each query */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_formats_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("get_formats_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if ( ao->rate >= pcm_params_get_min(ta->params, PCM_PARAM_RATE) && ao->rate <= pcm_params_get_max(ta->params, PCM_PARAM_RATE) && ao->channels >= pcm_params_get_min(ta->params, PCM_PARAM_CHANNELS) && ao->channels <= pcm_params_get_max(ta->params, PCM_PARAM_CHANNELS) )
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int write_tinyalsa(out123_handle *ao, unsigned char *buf, int bytes)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ta->pcm)
|
||||
{
|
||||
if(pcm_write(ta->pcm, buf, bytes))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Error playing sample\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
static void flush_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("flush_tinyalsa()");
|
||||
}
|
||||
|
||||
|
||||
static int close_tinyalsa(out123_handle *ao)
|
||||
{
|
||||
debug("close_tinyalsa()");
|
||||
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
if (ta->pcm)
|
||||
{
|
||||
pcm_close(ta->pcm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int deinit_tinyalsa(out123_handle* ao)
|
||||
{
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
/* Free up card/device parameters */
|
||||
pcm_params_free(ta->params);
|
||||
|
||||
/* Free up memory */
|
||||
if(ao->userptr)
|
||||
{
|
||||
free( ao->userptr );
|
||||
ao->userptr = NULL;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_tinyalsa(out123_handle* ao)
|
||||
{
|
||||
if (ao==NULL) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_tinyalsa;
|
||||
ao->flush = flush_tinyalsa;
|
||||
ao->write = write_tinyalsa;
|
||||
ao->get_formats = get_formats_tinyalsa;
|
||||
ao->close = close_tinyalsa;
|
||||
ao->deinit = deinit_tinyalsa;
|
||||
|
||||
/* Allocate memory for data structure */
|
||||
ao->userptr = malloc( sizeof( mpg123_tinyalsa_t ) );
|
||||
if(ao->userptr==NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("failed to malloc memory for 'mpg123_tinyalsa_t'");
|
||||
return -1;
|
||||
}
|
||||
memset( ao->userptr, 0, sizeof(mpg123_tinyalsa_t) );
|
||||
|
||||
/* Set card and device */
|
||||
mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
|
||||
|
||||
ta->card = 0;
|
||||
ta->device = 0;
|
||||
|
||||
if (ao->device)
|
||||
{
|
||||
char *ptr = ao->device;
|
||||
ta->card = (unsigned int)strtol(ptr, &ptr, 10);
|
||||
if (strlen(ptr) > 0)
|
||||
{
|
||||
ta->device = (unsigned int)strtol(++ptr, &ptr, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get card/device parameters */
|
||||
ta->params = pcm_params_get(ta->card, ta->device, PCM_OUT);
|
||||
if (ta->params == NULL)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error2( "(params) Unable to open card %u PCM device %u.\n"
|
||||
, ta->card, ta->device );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "tinyalsa",
|
||||
/* description */ "Output audio using TINY Advanced Linux Sound Architecture (TINYALSA).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_tinyalsa,
|
||||
};
|
||||
|
||||
305
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32.c
vendored
Normal file
305
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32.c
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
win32: audio output for Windows 32bit
|
||||
|
||||
copyright ?-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
initially written (as it seems) by Tony Million
|
||||
rewrite of basic functionality for callback-less and properly ringbuffered operation by ravenexp
|
||||
Closing buffer playback fixed by David Wohlferd <limegreensocks (*) yahoo dod com>
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include <windows.h>
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
Buffer size and number of buffers in the playback ring
|
||||
NOTE: This particular num/size combination performs best under heavy
|
||||
loads for my system, however this may not be true for any hardware/OS out there.
|
||||
Generally, BUFFER_SIZE < 8k || NUM_BUFFERS > 16 || NUM_BUFFERS < 4 are not recommended.
|
||||
*/
|
||||
#define BUFFER_SIZE 0x10000
|
||||
#define NUM_BUFFERS 8 /* total 512k roughly 2.5 sec of CD quality sound */
|
||||
|
||||
static void wait_for_buffer(WAVEHDR* hdr, HANDLE hEvent);
|
||||
static void drain_win32(out123_handle *ao);
|
||||
|
||||
/* Buffer ring queue state */
|
||||
struct queue_state
|
||||
{
|
||||
WAVEHDR buffer_headers[NUM_BUFFERS];
|
||||
/* The next buffer to be filled and put in playback */
|
||||
int next_buffer;
|
||||
/* Buffer playback completion event */
|
||||
HANDLE play_done_event;
|
||||
HWAVEOUT waveout;
|
||||
};
|
||||
|
||||
static int open_win32(out123_handle *ao)
|
||||
{
|
||||
struct queue_state* state;
|
||||
int i;
|
||||
MMRESULT res;
|
||||
WAVEFORMATEX out_fmt;
|
||||
UINT dev_id;
|
||||
|
||||
if(!ao) return -1;
|
||||
if(ao->rate == -1) return 0;
|
||||
|
||||
/* Allocate queue state struct for this device */
|
||||
state = calloc(1, sizeof(struct queue_state));
|
||||
if(!state) return -1;
|
||||
|
||||
ao->userptr = state;
|
||||
|
||||
state->play_done_event = CreateEvent(0,FALSE,FALSE,0);
|
||||
if(state->play_done_event == INVALID_HANDLE_VALUE) return -1;
|
||||
|
||||
/* FIXME: real device enumeration by capabilities? */
|
||||
dev_id = WAVE_MAPPER; /* probably does the same thing */
|
||||
/* FIXME: support for smth besides MPG123_ENC_SIGNED_16? */
|
||||
out_fmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
out_fmt.wBitsPerSample = 16;
|
||||
out_fmt.nChannels = ao->channels;
|
||||
out_fmt.nSamplesPerSec = ao->rate;
|
||||
out_fmt.nBlockAlign = out_fmt.nChannels*out_fmt.wBitsPerSample/8;
|
||||
out_fmt.nAvgBytesPerSec = out_fmt.nBlockAlign*out_fmt.nSamplesPerSec;
|
||||
out_fmt.cbSize = 0;
|
||||
|
||||
res = waveOutOpen(&state->waveout, dev_id, &out_fmt,
|
||||
(DWORD_PTR)state->play_done_event, 0, CALLBACK_EVENT);
|
||||
|
||||
switch(res)
|
||||
{
|
||||
case MMSYSERR_NOERROR:
|
||||
break;
|
||||
case MMSYSERR_ALLOCATED:
|
||||
ereturn(-1, "Audio output device is already allocated.");
|
||||
case MMSYSERR_NODRIVER:
|
||||
ereturn(-1, "No device driver is present.");
|
||||
case MMSYSERR_NOMEM:
|
||||
ereturn(-1, "Unable to allocate or lock memory.");
|
||||
case WAVERR_BADFORMAT:
|
||||
ereturn(-1, "Unsupported waveform-audio format.");
|
||||
default:
|
||||
ereturn(-1, "Unable to open wave output device.");
|
||||
}
|
||||
|
||||
/* Reset event from the "device open" message */
|
||||
ResetEvent(state->play_done_event);
|
||||
/* Allocate playback buffers */
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
if(!(state->buffer_headers[i].lpData = (LPSTR)malloc(BUFFER_SIZE)))
|
||||
{
|
||||
ereturn(-1, "Out of memory for playback buffers.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Tell waveOutPrepareHeader the maximum value of dwBufferLength
|
||||
we will ever send */
|
||||
state->buffer_headers[i].dwBufferLength = BUFFER_SIZE;
|
||||
state->buffer_headers[i].dwFlags = 0;
|
||||
res = waveOutPrepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR));
|
||||
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device (prepare).");
|
||||
|
||||
/* set the current size of the buffer to 0 */
|
||||
state->buffer_headers[i].dwBufferLength = 0;
|
||||
|
||||
/* set flags to unprepared - must reset this to WHDR_PREPARED before calling write */
|
||||
state->buffer_headers[i].dwFlags = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_for_buffer(WAVEHDR* hdr, HANDLE hEvent)
|
||||
{
|
||||
/* At this point there are several possible states:
|
||||
1) Empty or partial buffer (unqueued) - dwFlags == 0
|
||||
2) Buffer queued or being played - dwFlags == WHDR_PREPARED | WHDR_INQUEUE
|
||||
3) Buffer unqueued and finished being played - dwFlags == WHDR_PREPARED | WHDR_DONE
|
||||
4) Buffer removed from queue, but not yet marked as done - dwFlags == WHDR_PREPARED
|
||||
*/
|
||||
|
||||
/* Check buffer header and wait if it's being played. */
|
||||
if (hdr->dwFlags & WHDR_PREPARED)
|
||||
{
|
||||
while(!(hdr->dwFlags & WHDR_DONE))
|
||||
{
|
||||
/*debug1("waiting for buffer %i...", state->next_buffer);*/
|
||||
/* Waits for *a* buffer to finish. May not be the one we
|
||||
want, so check again */
|
||||
WaitForSingleObject(hEvent, INFINITE);
|
||||
}
|
||||
hdr->dwFlags = 0;
|
||||
hdr->dwBufferLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_formats_win32(out123_handle *ao)
|
||||
{
|
||||
/* FIXME: support for smth besides MPG123_ENC_SIGNED_16? */
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
}
|
||||
|
||||
/* Stores audio data to the fixed size buffers and pushes them into the playback queue.
|
||||
I have one grief with that: The last piece of a track may not reach the output,
|
||||
only full buffers sent... But we don't get smooth audio otherwise. */
|
||||
static int write_win32(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct queue_state* state;
|
||||
MMRESULT res;
|
||||
WAVEHDR* hdr;
|
||||
|
||||
int rest_len; /* Input data bytes left for next recursion. */
|
||||
int bufill; /* Bytes we stuff into buffer now. */
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
if(!buf || len <= 0) return 0;
|
||||
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
|
||||
wait_for_buffer(hdr, state->play_done_event);
|
||||
|
||||
/* Now see how much we want to stuff in and then stuff it in. */
|
||||
bufill = BUFFER_SIZE - hdr->dwBufferLength;
|
||||
if(len < bufill) bufill = len;
|
||||
|
||||
rest_len = len - bufill;
|
||||
memcpy(hdr->lpData + hdr->dwBufferLength, buf, bufill);
|
||||
hdr->dwBufferLength += bufill;
|
||||
if(hdr->dwBufferLength == BUFFER_SIZE)
|
||||
{ /* Send the buffer out when it's full. */
|
||||
hdr->dwFlags |= WHDR_PREPARED;
|
||||
|
||||
res = waveOutWrite(state->waveout, hdr, sizeof(WAVEHDR));
|
||||
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device.");
|
||||
|
||||
/* Cycle to the next buffer in the ring queue */
|
||||
state->next_buffer = (state->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
/* I'd like to propagate error codes or something... but there are no catchable surprises left.
|
||||
Anyhow: Here is the recursion that makes ravenexp happy;-) */
|
||||
if(rest_len && write_win32(ao, buf + bufill, rest_len) < 0) /* Write the rest. */
|
||||
return -1;
|
||||
else
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Flush means abort any pending playback */
|
||||
static void flush_win32(out123_handle *ao)
|
||||
{
|
||||
struct queue_state* state;
|
||||
WAVEHDR* hdr;
|
||||
|
||||
if(!ao || !ao->userptr) return;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* Cancel any buffers in queue. Ignore errors since we are void and
|
||||
can't return them anyway */
|
||||
waveOutReset(state->waveout);
|
||||
|
||||
/* Discard any partial buffer */
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
|
||||
/* If WHDR_PREPARED is not set, this is (potentially) a partial buffer */
|
||||
if (!(hdr->dwFlags & WHDR_PREPARED))
|
||||
hdr->dwBufferLength = 0;
|
||||
|
||||
/* Finish processing the buffers */
|
||||
drain_win32(ao);
|
||||
}
|
||||
|
||||
/* output final buffer (if any) */
|
||||
static void write_final_buffer(struct queue_state *state)
|
||||
{
|
||||
WAVEHDR* hdr;
|
||||
hdr = &state->buffer_headers[state->next_buffer];
|
||||
if((!(hdr->dwFlags & WHDR_PREPARED)) && (hdr->dwBufferLength != 0))
|
||||
{
|
||||
hdr->dwFlags |= WHDR_PREPARED;
|
||||
/* ignore any errors */
|
||||
waveOutWrite(state->waveout, hdr, sizeof(WAVEHDR));
|
||||
|
||||
/* Cycle to the next buffer in the ring queue */
|
||||
state->next_buffer = (state->next_buffer + 1) % NUM_BUFFERS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: I tried to fix this stuff without testing.
|
||||
There were some obvious errors in the code.
|
||||
Someone run this on a win32 machine! -- ThOr */
|
||||
static void drain_win32(out123_handle *ao)
|
||||
{
|
||||
int i, z;
|
||||
struct queue_state* state;
|
||||
|
||||
if(!ao || !ao->userptr) return;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* output final buffer (if any) */
|
||||
write_final_buffer(state);
|
||||
|
||||
/* I _think_ I understood how this should work. -- ThOr */
|
||||
z = state->next_buffer;
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
{
|
||||
wait_for_buffer(&state->buffer_headers[z], state->play_done_event);
|
||||
z = (z + 1) % NUM_BUFFERS;
|
||||
}
|
||||
}
|
||||
|
||||
static int close_win32(out123_handle *ao)
|
||||
{
|
||||
int i;
|
||||
struct queue_state* state;
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
state = (struct queue_state*)ao->userptr;
|
||||
|
||||
/* wait for all active buffers to complete */
|
||||
drain_win32(ao);
|
||||
CloseHandle(state->play_done_event);
|
||||
|
||||
for(i = 0; i < NUM_BUFFERS; i++)
|
||||
{
|
||||
state->buffer_headers[i].dwFlags |= WHDR_PREPARED;
|
||||
waveOutUnprepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR));
|
||||
free(state->buffer_headers[i].lpData);
|
||||
}
|
||||
|
||||
waveOutClose(state->waveout);
|
||||
free(ao->userptr);
|
||||
ao->userptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_win32(out123_handle* ao)
|
||||
{
|
||||
if(!ao) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_win32;
|
||||
ao->flush = flush_win32;
|
||||
ao->write = write_win32;
|
||||
ao->get_formats = get_formats_win32;
|
||||
ao->close = close_win32;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "win32",
|
||||
/* description */ "Audio output for Windows (winmm).",
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_win32,
|
||||
};
|
||||
497
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32_wasapi.c
vendored
Normal file
497
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/modules/win32_wasapi.c
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
win32_wasapi: audio output for Windows wasapi exclusive mode audio
|
||||
|
||||
copyright ?-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
|
||||
based on win32.c
|
||||
*/
|
||||
#define _WIN32_WINNT 0x601
|
||||
#define COBJMACROS 1
|
||||
#include "out123_int.h"
|
||||
#include <initguid.h>
|
||||
#include <audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <avrt.h>
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
/* When compiling C code with MSVC it is only possible to declare, but not
|
||||
define the WASAPI interface GUIDs using MS headers. So we define them
|
||||
ourselves. */
|
||||
|
||||
#ifndef GUID_SECT
|
||||
#define GUID_SECT
|
||||
#endif
|
||||
|
||||
#define __DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define __DEFINE_IID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const IID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define __DEFINE_CLSID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const CLSID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
#define MPG123_DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
__DEFINE_CLSID(mpg123_CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
#define MPG123_DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
__DEFINE_IID(mpg123_IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
// "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"
|
||||
MPG123_DEFINE_IID(IAudioClient, 1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2);
|
||||
// "A95664D2-9614-4F35-A746-DE8DB63617E6"
|
||||
MPG123_DEFINE_IID(IMMDeviceEnumerator, a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6);
|
||||
// "BCDE0395-E52F-467C-8E3D-C4579291692E"
|
||||
MPG123_DEFINE_CLSID(IMMDeviceEnumerator, bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e);
|
||||
// "F294ACFC-3146-4483-A7BF-ADDCA7C260E2"
|
||||
MPG123_DEFINE_IID(IAudioRenderClient, f294acfc, 3146, 4483, a7, bf, ad, dc, a7, c2, 60, e2);
|
||||
#else
|
||||
#define mpg123_IID_IAudioClient IID_IAudioClient
|
||||
#define mpg123_IID_IMMDeviceEnumerator IID_IMMDeviceEnumerator
|
||||
#define mpg123_CLSID_IMMDeviceEnumerator CLSID_MMDeviceEnumerator
|
||||
#define mpg123_IID_IAudioRenderClient IID_IAudioRenderClient
|
||||
#endif
|
||||
|
||||
/* Push mode does not work right yet, noisy audio, probably something to do with timing and buffers */
|
||||
#define WASAPI_EVENT_MODE 1
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
#define Init_Flag AUDCLNT_STREAMFLAGS_EVENTCALLBACK
|
||||
#define MOD_STRING "Experimental Audio output for Windows (wasapi event mode)."
|
||||
#define BUFFER_TIME 20000000.0
|
||||
#else
|
||||
#define Init_Flag 0
|
||||
#define MOD_STRING "Experimental Audio output for Windows (wasapi push mode)."
|
||||
#define BUFFER_TIME 640000000.0
|
||||
#endif
|
||||
|
||||
static int init_win32(out123_handle* ao);
|
||||
static void flush_win32(out123_handle *ao);
|
||||
/*
|
||||
Module information data structure
|
||||
*/
|
||||
mpg123_module_t mpg123_output_module_info = {
|
||||
/* api_version */ MPG123_MODULE_API_VERSION,
|
||||
/* name */ "win32_wasapi",
|
||||
/* description */ MOD_STRING,
|
||||
/* revision */ "$Rev:$",
|
||||
/* handle */ NULL,
|
||||
|
||||
/* init_output */ init_win32,
|
||||
};
|
||||
|
||||
// REFERENCE_TIME time units per second and per millisecond
|
||||
#define REFTIMES_PER_SEC 10000000
|
||||
#define REFTIMES_PER_MILLISEC 10000
|
||||
|
||||
#define EXIT_ON_ERROR(hres) \
|
||||
if (FAILED(hres)) { goto Exit; }
|
||||
#define SAFE_RELEASE(punk) \
|
||||
if ((punk) != NULL) \
|
||||
{ (punk)->Release(); (punk) = NULL; }
|
||||
|
||||
/* todo: move into handle struct */
|
||||
typedef struct _wasapi_state_struct {
|
||||
IMMDeviceEnumerator *pEnumerator;
|
||||
IMMDevice *pDevice;
|
||||
IAudioClient *pAudioClient;
|
||||
IAudioRenderClient *pRenderClient;
|
||||
BYTE *pData;
|
||||
UINT32 bufferFrameCount;
|
||||
REFERENCE_TIME hnsRequestedDuration;
|
||||
HANDLE hEvent;
|
||||
HANDLE hTask;
|
||||
size_t pData_off;
|
||||
DWORD taskIndex;
|
||||
char is_playing;
|
||||
DWORD framesize;
|
||||
} wasapi_state_struct;
|
||||
|
||||
/* setup endpoints */
|
||||
static int open_win32(out123_handle *ao){
|
||||
HRESULT hr = 0;
|
||||
wasapi_state_struct *state;
|
||||
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || ao->userptr) return -1; /* userptr should really be null */
|
||||
state = calloc(sizeof(*state),1);
|
||||
if(!state) return -1;
|
||||
state->hnsRequestedDuration = REFTIMES_PER_SEC;
|
||||
ao->userptr = (void *)state;
|
||||
|
||||
CoInitialize(NULL);
|
||||
hr = CoCreateInstance(&mpg123_CLSID_IMMDeviceEnumerator,NULL,CLSCTX_ALL, &mpg123_IID_IMMDeviceEnumerator,(void**)&state->pEnumerator);
|
||||
debug("CoCreateInstance");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(state->pEnumerator,eRender, eConsole, &state->pDevice);
|
||||
debug("IMMDeviceEnumerator_GetDefaultAudioEndpoint");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
hr = IMMDeviceActivator_Activate(state->pDevice,
|
||||
&mpg123_IID_IAudioClient, CLSCTX_ALL,
|
||||
NULL, (void**)&state->pAudioClient);
|
||||
debug("IMMDeviceActivator_Activate");
|
||||
EXIT_ON_ERROR(hr)
|
||||
|
||||
return 0;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
typedef struct tWAVEFORMATEX {
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
WORD wBitsPerSample;
|
||||
WORD cbSize;
|
||||
|
||||
} WAVEFORMATEX;
|
||||
*/
|
||||
|
||||
static int formats_generator(const out123_handle * const ao, const int waveformat, WAVEFORMATEX *const format){
|
||||
DWORD bytes_per_sample = 0;
|
||||
WORD tag = WAVE_FORMAT_PCM;
|
||||
debug1("%s",__FUNCTION__);
|
||||
int ret = waveformat;
|
||||
switch(waveformat){
|
||||
case MPG123_ENC_SIGNED_8:
|
||||
bytes_per_sample = 1;
|
||||
break;
|
||||
case MPG123_ENC_FLOAT_32:
|
||||
tag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
case MPG123_ENC_SIGNED_32:
|
||||
bytes_per_sample = 4;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
bytes_per_sample = 2;
|
||||
break;
|
||||
case MPG123_ENC_SIGNED_24:
|
||||
bytes_per_sample = 3;
|
||||
break;
|
||||
default:
|
||||
debug1("uh oh unknown %d",waveformat);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
format->wFormatTag = tag;
|
||||
format->nChannels = ao->channels;
|
||||
format->nSamplesPerSec = ao->rate;
|
||||
format->nAvgBytesPerSec = ao->channels * bytes_per_sample * ao->rate;
|
||||
format->nBlockAlign = ao->channels * bytes_per_sample;
|
||||
format->wBitsPerSample = bytes_per_sample * 8;
|
||||
format->cbSize = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check supported formats */
|
||||
static int get_formats_win32(out123_handle *ao){
|
||||
/* PLEASE check with write_init and write_win32 buffer size calculation in case it is able to support something other than 16bit */
|
||||
HRESULT hr;
|
||||
int ret = 0;
|
||||
debug1("%s",__FUNCTION__);
|
||||
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
debug2("channels %d, rate %ld",ao->channels, ao->rate);
|
||||
|
||||
WAVEFORMATEX wf;
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_8){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_8,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_8;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_8 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_16){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_16,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_16;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_16 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_32){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_32,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_32;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_32 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_FLOAT_32){
|
||||
formats_generator(ao,MPG123_ENC_FLOAT_32,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_FLOAT_32;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_FLOAT_32 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_SIGNED_24){
|
||||
formats_generator(ao,MPG123_ENC_SIGNED_24,&wf);
|
||||
if((hr = IAudioClient_IsFormatSupported(state->pAudioClient,AUDCLNT_SHAREMODE_EXCLUSIVE, &wf, NULL)) == S_OK)
|
||||
ret |= MPG123_ENC_SIGNED_24;
|
||||
if(hr == AUDCLNT_E_UNSUPPORTED_FORMAT) debug1("MPG123_ENC_SIGNED_24 %ld not supported", ao->rate);
|
||||
}
|
||||
|
||||
return ret; /* afaik only 16bit 44.1kHz/48kHz has been known to work */
|
||||
}
|
||||
|
||||
/* setup with agreed on format, for now only MPG123_ENC_SIGNED_16 */
|
||||
static int write_init(out123_handle *ao){
|
||||
HRESULT hr;
|
||||
double offset = 0.5;
|
||||
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
|
||||
WAVEFORMATEX s16;
|
||||
formats_generator(ao,ao->format,&s16);
|
||||
state->framesize = s16.nBlockAlign;
|
||||
debug1("block size %ld", state->framesize);
|
||||
/* cargo cult code */
|
||||
hr = IAudioClient_GetDevicePeriod(state->pAudioClient,NULL, &state->hnsRequestedDuration);
|
||||
debug("IAudioClient_GetDevicePeriod OK");
|
||||
reinit:
|
||||
hr = IAudioClient_Initialize(state->pAudioClient,
|
||||
AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
Init_Flag,
|
||||
state->hnsRequestedDuration,
|
||||
state->hnsRequestedDuration,
|
||||
&s16,
|
||||
NULL);
|
||||
debug("IAudioClient_Initialize OK");
|
||||
/* something about buffer sizes on Win7, fixme might loop forever */
|
||||
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED){
|
||||
if (offset > 10.0) goto Exit; /* is 10 enough to break out of the loop?*/
|
||||
debug("AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED");
|
||||
IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
/* double buffered */
|
||||
state->hnsRequestedDuration = (REFERENCE_TIME)((BUFFER_TIME / s16.nSamplesPerSec * state->bufferFrameCount) + offset);
|
||||
offset += 0.5;
|
||||
IAudioClient_Release(state->pAudioClient);
|
||||
state->pAudioClient = NULL;
|
||||
hr = IMMDeviceActivator_Activate(state->pDevice,
|
||||
&mpg123_IID_IAudioClient, CLSCTX_ALL,
|
||||
NULL, (void**)&state->pAudioClient);
|
||||
debug("IMMDeviceActivator_Activate");
|
||||
goto reinit;
|
||||
}
|
||||
EXIT_ON_ERROR(hr)
|
||||
EXIT_ON_ERROR(hr)
|
||||
hr = IAudioClient_GetService(state->pAudioClient,
|
||||
&mpg123_IID_IAudioRenderClient,
|
||||
(void**)&state->pRenderClient);
|
||||
debug("IAudioClient_GetService OK");
|
||||
EXIT_ON_ERROR(hr)
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
state->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
debug("CreateEvent OK");
|
||||
if(!state->hEvent) goto Exit;
|
||||
hr = IAudioClient_SetEventHandle(state->pAudioClient,state->hEvent);
|
||||
EXIT_ON_ERROR(hr);
|
||||
#endif
|
||||
hr = IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
debug("IAudioClient_GetBufferSize OK");
|
||||
EXIT_ON_ERROR(hr)
|
||||
return 0;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Set play mode if unset, also raise thread priority */
|
||||
static HRESULT play_init(out123_handle *ao){
|
||||
HRESULT hr = S_OK;
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
if(!state->is_playing){
|
||||
debug1("%s",__FUNCTION__);
|
||||
state->hTask = AvSetMmThreadCharacteristicsW(L"Pro Audio", &state->taskIndex);
|
||||
hr = IAudioClient_Start(state->pAudioClient);
|
||||
state->is_playing = 1;
|
||||
debug("IAudioClient_Start");
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
return hr;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* copy audio into IAudioRenderClient provided buffer */
|
||||
static int write_win32(out123_handle *ao, unsigned char *buf, int len){
|
||||
HRESULT hr;
|
||||
size_t to_copy = 0;
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
if(!len) return 0;
|
||||
if(!state->pRenderClient) write_init(ao);
|
||||
size_t frames_in = len/state->framesize; /* Frames in buf, is framesize even correct? */
|
||||
debug("mode entered");
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
/* Event mode WASAPI */
|
||||
DWORD retval = -1;
|
||||
int flag = 0; /* Silence flag */
|
||||
feed_again:
|
||||
if(!state->pData){
|
||||
/* Acquire buffer */
|
||||
hr = IAudioRenderClient_GetBuffer(state->pRenderClient,state->bufferFrameCount, &state->pData);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
if(frames_in){ /* Did we get half a frame?? non-zero len smaller than framesize? */
|
||||
/* We must put in exactly the amount of frames specified by IAudioRenderClient_GetBuffer */
|
||||
while(state->pData_off < state->bufferFrameCount){
|
||||
to_copy = state->bufferFrameCount - state->pData_off;
|
||||
debug3("pData_off %I64d, bufferFrameCount %d, to_copy %I64d", state->pData_off, state->bufferFrameCount, to_copy);
|
||||
if(to_copy > frames_in){
|
||||
/* buf can fit in provided buffer space */
|
||||
debug1("all buffers copied, %I64d", frames_in);
|
||||
memcpy(state->pData+state->pData_off*state->framesize,buf,state->framesize*(frames_in));
|
||||
state->pData_off += frames_in;
|
||||
frames_in = 0;
|
||||
break;
|
||||
} else {
|
||||
/* buf too big, needs spliting */
|
||||
debug1("partial buffers %I64d", to_copy);
|
||||
memcpy(state->pData+state->pData_off*state->framesize,buf,state->framesize*(to_copy));
|
||||
state->pData_off += to_copy;
|
||||
buf+=(to_copy*state->framesize);
|
||||
frames_in -= to_copy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* In case we ever get half a frame, is it possible? */
|
||||
flag = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
}
|
||||
debug2("Copied %I64d, left %I64d", state->pData_off, frames_in);
|
||||
if(state->pData_off == state->bufferFrameCount) {
|
||||
/* Tell IAudioRenderClient that buffer is filled and released */
|
||||
hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient,state->pData_off, flag);
|
||||
state->pData_off = 0;
|
||||
state->pData = NULL;
|
||||
debug("IAudioRenderClient_ReleaseBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
if(!state->is_playing){
|
||||
hr = play_init(ao);
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
/* wait for next pull event */
|
||||
retval = WaitForSingleObject(state->hEvent, 2000);
|
||||
if (retval != WAIT_OBJECT_0){
|
||||
/* Event handle timed out after a 2-second wait, something went very wrong */
|
||||
IAudioClient_Stop(state->pAudioClient);
|
||||
hr = ERROR_TIMEOUT;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
if(frames_in > 0)
|
||||
goto feed_again;
|
||||
#else /* PUSH mode code */
|
||||
UINT32 numFramesAvailable, numFramesPadding;
|
||||
debug1("block size %ld", state->framesize);
|
||||
feed_again:
|
||||
/* How much buffer do we get to use? */
|
||||
hr = IAudioClient_GetBufferSize(state->pAudioClient,&state->bufferFrameCount);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
hr = IAudioClient_GetCurrentPadding(state->pAudioClient,&numFramesPadding);
|
||||
debug("IAudioClient_GetCurrentPadding");
|
||||
EXIT_ON_ERROR(hr)
|
||||
/* How much buffer is writable at the moment? */
|
||||
numFramesAvailable = state->bufferFrameCount - numFramesPadding;
|
||||
debug3("numFramesAvailable %d, bufferFrameCount %d, numFramesPadding %d", numFramesAvailable, state->bufferFrameCount, numFramesPadding);
|
||||
if(numFramesAvailable > frames_in){
|
||||
/* can fit all frames now */
|
||||
state->pData_off = 0;
|
||||
to_copy = frames_in;
|
||||
} else {
|
||||
/* copy whatever that fits in the buffer */
|
||||
state->pData_off = frames_in - numFramesAvailable;
|
||||
to_copy = numFramesAvailable;
|
||||
}
|
||||
/* Acquire buffer */
|
||||
hr = IAudioRenderClient_GetBuffer(state->pRenderClient,to_copy,&state->pData);
|
||||
debug("IAudioRenderClient_GetBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
memcpy(state->pData,buf+state->pData_off * state->framesize,to_copy*state->framesize);
|
||||
/* Release buffer */
|
||||
hr = IAudioRenderClient_ReleaseBuffer(state->pRenderClient,to_copy, 0);
|
||||
debug("IAudioRenderClient_ReleaseBuffer");
|
||||
EXIT_ON_ERROR(hr)
|
||||
if(!state->is_playing){
|
||||
hr = play_init(ao);
|
||||
EXIT_ON_ERROR(hr)
|
||||
}
|
||||
frames_in -= to_copy;
|
||||
/* Wait sometime for buffer to empty? */
|
||||
DWORD sleeptime = (DWORD)(state->hnsRequestedDuration/REFTIMES_PER_MILLISEC/ao->rate);
|
||||
debug1("Sleeping %ld msec", sleeptime);
|
||||
Sleep(sleeptime);
|
||||
if (frames_in)
|
||||
goto feed_again;
|
||||
#endif
|
||||
return len;
|
||||
Exit:
|
||||
debug2("%s failed with %lx", __FUNCTION__, hr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void flush_win32(out123_handle *ao){
|
||||
/* Wait for the last buffer to play before stopping. */
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
HRESULT hr;
|
||||
if(!state->pAudioClient) return;
|
||||
state->pData = NULL;
|
||||
hr = IAudioClient_Stop(state->pAudioClient);
|
||||
EXIT_ON_ERROR(hr)
|
||||
IAudioClient_Reset(state->pAudioClient);
|
||||
EXIT_ON_ERROR(hr)
|
||||
return;
|
||||
Exit:
|
||||
debug2("%s IAudioClient_Stop with %lx", __FUNCTION__, hr);
|
||||
}
|
||||
|
||||
static int close_win32(out123_handle *ao)
|
||||
{
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao || !ao->userptr) return -1;
|
||||
wasapi_state_struct *state = (wasapi_state_struct *) ao->userptr;
|
||||
#ifdef WASAPI_EVENT_MODE
|
||||
if(state->pData){
|
||||
/* Play all in buffer before closing */
|
||||
debug("Flushing remaining buffers");
|
||||
IAudioRenderClient_ReleaseBuffer(state->pRenderClient,state->bufferFrameCount, 0);
|
||||
WaitForSingleObject(state->hEvent, 2000);
|
||||
state->pData = NULL;
|
||||
}
|
||||
#endif
|
||||
if(state->pAudioClient) IAudioClient_Stop(state->pAudioClient);
|
||||
if(state->pRenderClient) IAudioRenderClient_Release(state->pRenderClient);
|
||||
if(state->pAudioClient) IAudioClient_Release(state->pAudioClient);
|
||||
if(state->hTask) AvRevertMmThreadCharacteristics(state->hTask);
|
||||
if(state->pEnumerator) IMMDeviceEnumerator_Release(state->pEnumerator);
|
||||
if(state->pDevice) IMMDevice_Release(state->pDevice);
|
||||
CoUninitialize();
|
||||
free(state);
|
||||
ao->userptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_win32(out123_handle* ao){
|
||||
debug1("%s",__FUNCTION__);
|
||||
if(!ao) return -1;
|
||||
|
||||
/* Set callbacks */
|
||||
ao->open = open_win32;
|
||||
ao->flush = flush_win32;
|
||||
ao->write = write_win32;
|
||||
ao->get_formats = get_formats_win32;
|
||||
ao->close = close_win32;
|
||||
ao->userptr = NULL;
|
||||
|
||||
/* Success */
|
||||
return 0;
|
||||
}
|
||||
588
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/out123.h.in
vendored
Normal file
588
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/out123.h.in
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
out123: audio output interface
|
||||
|
||||
copyright 1995-2016 by the mpg123 project,
|
||||
free software under the terms of the LGPL 2.1
|
||||
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written as audio.h by Michael Hipp, reworked into out123 API
|
||||
by Thomas Orgis
|
||||
*/
|
||||
|
||||
#ifndef _OUT123_H_
|
||||
#define _OUT123_H_
|
||||
|
||||
/** \file out123.h The header file for the libout123 audio output facility. */
|
||||
|
||||
/* We only need size_t definition. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Common audio encoding specification, including a macro for getting
|
||||
* size of encodined samples in bytes. Said macro is still hardcoded
|
||||
* into out123_encsize(). Relying on this one may help an old program
|
||||
* know sizes of encodings added to fmt123.h later on.
|
||||
* If you don't care, just use the macro.
|
||||
*/
|
||||
#include <fmt123.h>
|
||||
|
||||
/** A macro to check at compile time which set of API functions to expect.
|
||||
* This should be incremented at least each time a new symbol is added
|
||||
* to the header.
|
||||
*/
|
||||
#define OUT123_API_VERSION @OUTAPI_VERSION@
|
||||
|
||||
#ifndef MPG123_EXPORT
|
||||
/** Defines needed for MS Visual Studio(tm) DLL builds.
|
||||
* Every public function must be prefixed with MPG123_EXPORT. When building
|
||||
* the DLL ensure to define BUILD_MPG123_DLL. This makes the function accessible
|
||||
* for clients and includes it in the import library which is created together
|
||||
* with the DLL. When consuming the DLL ensure to define LINK_MPG123_DLL which
|
||||
* imports the functions from the DLL.
|
||||
*/
|
||||
#ifdef BUILD_MPG123_DLL
|
||||
/* The dll exports. */
|
||||
#define MPG123_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#ifdef LINK_MPG123_DLL
|
||||
/* The exe imports. */
|
||||
#define MPG123_EXPORT __declspec(dllimport)
|
||||
#else
|
||||
/* Nothing on normal/UNIX builds */
|
||||
#define MPG123_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup out123_api out123 library API
|
||||
* This is out123, a library focused on continuous playback of audio streams
|
||||
* via various platform-specific output methods. It glosses over details of
|
||||
* the native APIs to give an interface close to simply writing data to a
|
||||
* file. There might be the option to tune details like buffer (period) sizes
|
||||
* and the number of them on the device side in future, but the focus of the
|
||||
* library is to ease the use case of just getting that raw audio data out
|
||||
* there, without interruptions.
|
||||
*
|
||||
* The basic idea is to create a handle with out123_new() and open a certain
|
||||
* output device (using a certain driver module, possibly build-time defaults)
|
||||
* with out123_open(). Now, you can query the output device for supported
|
||||
* encodings for given rate and channel count with out123_get_encodings() and
|
||||
* decide what to use for actually starting playback with out123_start().
|
||||
*
|
||||
* Then, you just need to provide (interleaved pcm) data for playback with
|
||||
* out123_play(), which will block when the device's buffers are full. You get
|
||||
* your timing from that (instead of callbacks). If your program does the
|
||||
* production of the audio data just a little bit faster than the playback,
|
||||
* causing out123_play() to block ever so briefly, you're fine.
|
||||
*
|
||||
* You stop playback with out123_stop(), or just close the device and driver
|
||||
* via out123_close(), or even just decide to drop it all and do out123_del()
|
||||
* right away when you're done.
|
||||
*
|
||||
* There are other functions for specific needs, but the basic idea should be
|
||||
* covered by the above.
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Opaque structure for the libout123 handle. */
|
||||
struct out123_struct;
|
||||
/** Typedef shortcut as preferrend name for the handle type. */
|
||||
typedef struct out123_struct out123_handle;
|
||||
|
||||
/** Enumeration of codes for the parameters that it is possible to set/get. */
|
||||
enum out123_parms
|
||||
{
|
||||
OUT123_FLAGS = 1 /**< integer, various flags, see enum out123_flags */
|
||||
, OUT123_PRELOAD /**< float, fraction of buffer to fill before playback */
|
||||
, OUT123_GAIN /**< integer, output device gain (module-specific) */
|
||||
, OUT123_VERBOSE /**< integer, verbosity to stderr, >= 0 */
|
||||
, OUT123_DEVICEBUFFER /**<
|
||||
* float, length of device buffer in seconds;
|
||||
* This might be ignored, might have only a loose relation to actual
|
||||
* buffer sizes and latency, depending on output driver. Try to tune
|
||||
* this before opening a device if you want to influcence latency or reduce
|
||||
* dropouts. Value <= 0 uses some default, usually favouring stable playback
|
||||
* over low latency. Values above 0.5 are probably too much.
|
||||
*/
|
||||
, OUT123_PROPFLAGS /**< integer, query driver/device property flags (r/o) */
|
||||
, OUT123_NAME /**< string, name of this instance (NULL restores default);
|
||||
* The value returned by out123_getparam() might be different if the audio
|
||||
* backend changed it (to be unique among clients, p.ex.).
|
||||
* TODO: The name provided here is used as prefix in diagnostic messages. */
|
||||
, OUT123_BINDIR /**< string, path to a program binary directory to use
|
||||
* as starting point in the search for the output module directory
|
||||
* (e.g. ../lib/mpg123 or ./plugins). The environment variable MPG123_MODDIR
|
||||
* is always tried first and the in-built installation path last.
|
||||
*/
|
||||
};
|
||||
|
||||
/** Flags to tune out123 behaviour */
|
||||
enum out123_flags
|
||||
{
|
||||
OUT123_HEADPHONES = 0x01 /**< output to headphones (if supported) */
|
||||
, OUT123_INTERNAL_SPEAKER = 0x02 /**< output to speaker (if supported) */
|
||||
, OUT123_LINE_OUT = 0x04 /**< output to line out (if supported) */
|
||||
, OUT123_QUIET = 0x08 /**< no printouts to standard error */
|
||||
, OUT123_KEEP_PLAYING = 0x10 /**<
|
||||
* When this is set (default), playback continues in a loop when the device
|
||||
* does not consume all given data at once. This happens when encountering
|
||||
* signals (like SIGSTOP, SIGCONT) that cause interruption of the underlying
|
||||
* functions.
|
||||
* Note that this flag is meaningless when the optional buffer is employed,
|
||||
* There, your program will always block until the buffer completely took
|
||||
* over the data given to it via out123_play(), unless a communication error
|
||||
* arises.
|
||||
*/
|
||||
};
|
||||
|
||||
/** Read-only output driver/device property flags (OUT123_PROPFLAGS). */
|
||||
enum out123_propflags
|
||||
{
|
||||
OUT123_PROP_LIVE = 0x01 /**< This is a live output, meaning that
|
||||
* special care might be needed for pauses in playback (p.ex. stream
|
||||
* of silence instead of interruption), as opposed to files on disk.
|
||||
*/
|
||||
, OUT123_PROP_PERSISTENT = 0x02 /**< This (live) output does not need
|
||||
* special care for pauses (continues with silence itself),
|
||||
* out123_pause() does nothing to the device.
|
||||
*/
|
||||
};
|
||||
|
||||
/** Create a new output handle.
|
||||
* This only allocates and initializes memory, so the only possible
|
||||
* error condition is running out of memory.
|
||||
* \return pointer to new handle or NULL on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
out123_handle *out123_new(void);
|
||||
|
||||
/** Delete output handle.
|
||||
* This implies out123_close().
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_del(out123_handle *ao);
|
||||
|
||||
/** Error code enumeration
|
||||
* API calls return a useful (positve) value or zero (OUT123_OK) on simple
|
||||
* success. A negative value (-1 == OUT123_ERR) usually indicates that some
|
||||
* error occured. Which one, that can be queried using out123_errcode()
|
||||
* and friends.
|
||||
*/
|
||||
enum out123_error
|
||||
{
|
||||
OUT123_ERR = -1 /**< generic alias for verbosity, always == -1 */
|
||||
, OUT123_OK = 0 /**< just a name for zero, not going to change */
|
||||
, OUT123_DOOM /**< dazzled, out of memory */
|
||||
, OUT123_BAD_DRIVER_NAME /**< bad driver name given */
|
||||
, OUT123_BAD_DRIVER /**< unspecified issue loading a driver */
|
||||
, OUT123_NO_DRIVER /**< no driver loaded */
|
||||
, OUT123_NOT_LIVE /**< no active audio device */
|
||||
, OUT123_DEV_PLAY /**< some device playback error */
|
||||
, OUT123_DEV_OPEN /**< error opening device */
|
||||
, OUT123_BUFFER_ERROR /**<
|
||||
* Some (really unexpected) error in buffer infrastructure.
|
||||
*/
|
||||
, OUT123_MODULE_ERROR /**< basic failure in module loading */
|
||||
, OUT123_ARG_ERROR /**< some bad function arguments supplied */
|
||||
, OUT123_BAD_PARAM /**< unknown parameter code */
|
||||
, OUT123_SET_RO_PARAM /**< attempt to set read-only parameter */
|
||||
, OUT123_BAD_HANDLE /**< bad handle pointer (NULL, usually) */
|
||||
, OUT123_ERRCOUNT /**< placeholder for shaping arrays */
|
||||
};
|
||||
|
||||
/** Get string representation of last encountered error in the
|
||||
* context of given handle.
|
||||
* \param ao handle
|
||||
* \return error string
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
const char* out123_strerror(out123_handle *ao);
|
||||
|
||||
/** Get the plain errcode intead of a string.
|
||||
* Note that this used to return OUT123_ERR instead of
|
||||
* OUT123_BAD_HANDLE in case of ao==NULL before mpg123-1.23.5 .
|
||||
* \param ao handle
|
||||
* \return error code recorded in handle or OUT123_BAD_HANDLE
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_errcode(out123_handle *ao);
|
||||
|
||||
/** Return the error string for a given error code.
|
||||
* \param errcode the integer error code
|
||||
* \return error string
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
const char* out123_plain_strerror(int errcode);
|
||||
|
||||
/** Set a desired output buffer size.
|
||||
* This starts a separate process that handles the audio output, decoupling
|
||||
* the latter from the main process with a memory buffer and saving you the
|
||||
* burden to ensure sparing CPU cycles for actual playback.
|
||||
* This is for applicatons that prefer continuous playback over small latency.
|
||||
* In other words: The kind of applications that out123 is designed for.
|
||||
* This routine always kills off any currently active audio output module /
|
||||
* device, even if you just disable the buffer when there is no buffer.
|
||||
*
|
||||
* Keep this in mind for memory-constrainted systems: Activating the
|
||||
* buffer causes a fork of the calling process, doubling the virtual memory
|
||||
* use. Depending on your operating system kernel's behaviour regarding
|
||||
* memory overcommit, it might be wise to call out123_set_buffer() very
|
||||
* early in your program before allocating lots of memory.
|
||||
*
|
||||
* There _might_ be a change to threads in future, but for now this is
|
||||
* classic fork with shared memory, working without any threading library.
|
||||
* If your platform or build does not support that, you will always get an
|
||||
* error on trying to set up a non-zero buffer (but the API call will be
|
||||
* present).
|
||||
*
|
||||
* Also, if you do intend to use this from a multithreaded program, think
|
||||
* twice and make sure that your setup is happy with forking full-blown
|
||||
* processes off threaded programs. Probably you are better off spawning a
|
||||
* buffer thread yourself.
|
||||
*
|
||||
* \param ao handle
|
||||
* \param buffer_bytes size (bytes) of a memory buffer for decoded audio,
|
||||
* a value of zero disables the buffer.
|
||||
* \return 0 on success, OUT123_ERR on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_set_buffer(out123_handle *ao, size_t buffer_bytes);
|
||||
|
||||
/** Set a specific parameter, for a specific out123_handle, using a parameter
|
||||
* code chosen from the out123_parms enumeration, to the specified value.
|
||||
* The parameters usually only change what happens on next out123_open, not
|
||||
* incfluencing running operation.
|
||||
* \param ao handle
|
||||
* \param code parameter code
|
||||
* \param value input value for integer parameters
|
||||
* \param fvalue input value for floating point parameters
|
||||
* \param svalue input value for string parameters (contens are copied)
|
||||
* \return 0 on success, OUT123_ERR on error.
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_param( out123_handle *ao, enum out123_parms code
|
||||
, long value, double fvalue, const char *svalue );
|
||||
#define out123_param_int(ao, code, value) \
|
||||
out123_param((ao), (code), (value), 0., NULL)
|
||||
#define out123_param_float(ao, code, value) \
|
||||
out123_param((ao), (code), 0, (value), NULL)
|
||||
#define out123_param_string(ao, code, value) \
|
||||
out123_param((ao), (code), 0, 0., (value))
|
||||
|
||||
/** Get a specific parameter, for a specific out123_handle, using a parameter
|
||||
* code chosen from the out123_parms enumeration, to the specified value.
|
||||
* \param ao handle
|
||||
* \param code parameter code
|
||||
* \param ret_value output address for integer parameters
|
||||
* \param ret_fvalue output address for floating point parameters
|
||||
* \param ret_svalue output address for string parameters (pointer to
|
||||
* internal memory, so no messing around, please)
|
||||
* \return 0 on success, OUT123_ERR on error (bad parameter name or bad handle).
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_getparam( out123_handle *ao, enum out123_parms code
|
||||
, long *ret_value, double *ret_fvalue, char* *ret_svalue );
|
||||
#define out123_getparam_int(ao, code, value) \
|
||||
out123_getparam((ao), (code), (value), NULL, NULL)
|
||||
#define out123_getparam_float(ao, code, value) \
|
||||
out123_getparam((ao), (code), NULL, (value), NULL)
|
||||
#define out123_getparam_string(ao, code, value) \
|
||||
out123_getparam((ao), (code), NULL, NULL, (value))
|
||||
|
||||
/** Copy parameters from another out123_handle.
|
||||
* \param ao handle
|
||||
* \param from_ao the handle to copy parameters from
|
||||
* \return 0 in success, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_param_from(out123_handle *ao, out123_handle* from_ao);
|
||||
|
||||
/** Get list of driver modules reachable in system in C argv-style format.
|
||||
* The client is responsible for freeing the memory of both the individual
|
||||
* strings and the lists themselves.
|
||||
* A module that is not loadable because of missing libraries is simply
|
||||
* skipped. You will get stderr messages about that unless OUT123_QUIET was
|
||||
* was set, though. Failure to open the module directory is a serious error,
|
||||
* resulting in negative return value.
|
||||
* \param ao handle
|
||||
* \param names address for storing list of names
|
||||
* \param descr address for storing list of descriptions
|
||||
* \return number of drivers found, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_drivers(out123_handle *ao, char ***names, char ***descr);
|
||||
|
||||
/** Open an output device with a certain driver
|
||||
* Note: Opening means that the driver code is loaded and the desired
|
||||
* device name recorded, possibly tested for availability or tentatively
|
||||
* opened. After out123_open(), you can ask for supported encodings
|
||||
* and then really open the device for playback with out123_start().
|
||||
* \param ao handle
|
||||
* \param driver (comma-separated list of) output driver name(s to try),
|
||||
* NULL for default (stdout for file-based drivers)
|
||||
* \param device device name to open, NULL for default
|
||||
* \return 0 on success, -1 on error.
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_open(out123_handle *ao, const char* driver, const char* device);
|
||||
|
||||
/** Give info about currently loaded driver and device
|
||||
* Any of the return addresses can be NULL if you are not interested in
|
||||
* everything. You get pointers to internal storage. They are valid
|
||||
* as long as the driver/device combination is opened.
|
||||
* The device may be NULL indicating some unnamed default.
|
||||
* TODO: Make the driver modules return names for such defaults.
|
||||
* \param ao handle
|
||||
* \param driver return address for driver name
|
||||
* \param device return address for device name
|
||||
* \return 0 on success, -1 on error (i.e. no driver loaded)
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_driver_info(out123_handle *ao, char **driver, char **device);
|
||||
|
||||
/** Close the current output device and driver.
|
||||
* This implies out123_drain() to ensure no data is lost.
|
||||
* With a buffer, that might cause considerable delay during
|
||||
* which your main application is blocked waiting.
|
||||
* Call out123_drop() beforehand if you want to end things
|
||||
* quickly.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_close(out123_handle *ao);
|
||||
|
||||
/** Get supported audio encodings for given rate and channel count,
|
||||
* for the currently openend audio device.
|
||||
* TODO: Reopening the underlying audio device for each query
|
||||
* is dumb, at least when dealing with JACK. It takes
|
||||
* a long time and is just a waste. Reconsider that.
|
||||
* Make sure that all output modules are fine with it, though!
|
||||
* Usually, a wider range of rates is supported, but the number
|
||||
* of sample encodings is limited, as is the number of channels.
|
||||
* So you can call this with some standard rate and hope that the
|
||||
* returned encodings work also for others, with the tested channel
|
||||
* count.
|
||||
* The return value of -1 on some encountered error conveniently also
|
||||
* does not match any defined format (only 15 bits used for encodings,
|
||||
* so this would even work with 16 bit integers).
|
||||
* This implies out123_stop() to enter query mode.
|
||||
* \param ao handle
|
||||
* \param rate sampling rate
|
||||
* \param channels number of channels
|
||||
* \return supported encodings combined with bitwise or, to be checked
|
||||
* against your favourite bitmask, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_encodings(out123_handle *ao, long rate, int channels);
|
||||
|
||||
/** Return the size (in bytes) of one mono sample of the named encoding.
|
||||
* \param encoding The encoding value to analyze.
|
||||
* \return positive size of encoding in bytes, 0 on invalid encoding. */
|
||||
MPG123_EXPORT int out123_encsize(int encoding);
|
||||
|
||||
/** Get list of supported formats for currently opened audio device.
|
||||
* Given a list of sampling rates and minimal/maximal channel count,
|
||||
* this quickly checks what formats are supported with these
|
||||
* constraints. The first entry is always reserved for a default
|
||||
* format for the output device. If there is no such default,
|
||||
* all values of the format are -1.
|
||||
* For each requested combination of rate and channels, a format entry is
|
||||
* created, possible with encoding value 0 to indicate that this combination
|
||||
* has been tested and rejected. So, when there is no basic error, the
|
||||
* number of returned format entries should be
|
||||
* (ratecount*(maxchannels-minchannels+1)+1)
|
||||
* . But instead of forcing you to guess, this will be allocated by
|
||||
* successful run.
|
||||
* For the first entry, the encoding member is supposed to be a definite
|
||||
* encoding, for the others it is a bitwise combination of all possible
|
||||
* encodings.
|
||||
* This function is more efficient than many calls to out123_encodings().
|
||||
* \param ao handle
|
||||
* \param rates pointer to an array of sampling rates, may be NULL for none
|
||||
* \param ratecount number of provided sampling rates
|
||||
* \param minchannels minimal channel count
|
||||
* \param maxchannels maximal channel count
|
||||
* \param fmtlist return address for array of supported formats
|
||||
* the encoding field of each entry is a combination of all
|
||||
* supported encodings at this rate and channel count;
|
||||
* Memory shall be freed by user.
|
||||
* \return number of returned format enries, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_formats( out123_handle *ao, const long *rates, int ratecount
|
||||
, int minchannels, int maxchannels
|
||||
, struct mpg123_fmt **fmtlist );
|
||||
|
||||
/** Get list of encodings known to the library.
|
||||
* You are responsible for freeing the allocated array.
|
||||
* \param enclist return address for allocated array of encoding codes
|
||||
* \return number of encodings, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_enc_list(int **enclist);
|
||||
|
||||
/** Find encoding code by name.
|
||||
* \param name short or long name to find encoding code for
|
||||
* \return encoding if found (enum mpg123_enc_enum), else 0
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_enc_byname(const char *name);
|
||||
|
||||
/** Get name of encoding.
|
||||
* \param encoding code (enum mpg123_enc_enum)
|
||||
* \return short name for valid encodings, NULL otherwise
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
const char* out123_enc_name(int encoding);
|
||||
|
||||
/** Get long name of encoding.
|
||||
* \param encoding code (enum mpg123_enc_enum)
|
||||
* \return long name for valid encodings, NULL otherwise
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
const char* out123_enc_longname(int encoding);
|
||||
|
||||
/** Start playback with a certain output format
|
||||
* It might be a good idea to have audio data handy to feed after this
|
||||
* returns with success.
|
||||
* Rationale for not taking a pointer to struct mpg123_fmt: This would
|
||||
* always force you to deal with that type and needlessly enlarge the
|
||||
* shortest possible program.
|
||||
* \param ao handle
|
||||
* \param encoding sample encoding (values matching libmpg123 API)
|
||||
* \param channels number of channels (1 or 2, usually)
|
||||
* \param rate sampling rate
|
||||
* \return 0 on success, negative on error (bad format, usually)
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_start( out123_handle *ao
|
||||
, long rate, int channels, int encoding );
|
||||
|
||||
/** Pause playback
|
||||
* Interrupt playback, holding any data in the optional buffer.
|
||||
*
|
||||
* This closes the audio device if it is a live sink, ready to be re-opened
|
||||
* by out123_continue() or out123_play() with the existing parameters.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_pause(out123_handle *ao);
|
||||
|
||||
/** Continue playback
|
||||
* The counterpart to out123_pause(). Announce to the driver that playback
|
||||
* shall continue.
|
||||
*
|
||||
* Playback might not resume immediately if the optional buffer is configured
|
||||
* to wait for a minimum fill and close to being empty. You can force playback
|
||||
* of the last scrap with out123_drain(), or just by feeding more data with
|
||||
* out123_play(), which will trigger out123_continue() for you, too.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_continue(out123_handle *ao);
|
||||
|
||||
/** Stop playback.
|
||||
* This waits for pending audio data to drain to the speakers.
|
||||
* You might want to call out123_drop() before stopping if you want
|
||||
* to end things right away.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_stop(out123_handle *ao);
|
||||
|
||||
/** Hand over data for playback and wait in case audio device is busy.
|
||||
* This survives non-fatal signals like SIGSTOP/SIGCONT and keeps on
|
||||
* playing until the buffer is done with if the flag
|
||||
* OUT123_KEEP_PLAYING ist set (default). So, per default, if
|
||||
* you provided a byte count divisible by the PCM frame size, it is an
|
||||
* error when less bytes than given are played.
|
||||
* To be sure if an error occured, check out123_errcode().
|
||||
* Also note that it is no accident that the buffer parameter is not marked
|
||||
* as constant. Some output drivers might need to do things like swap
|
||||
* byte order. This is done in-place instead of wasting memory on yet
|
||||
* another copy.
|
||||
* \param ao handle
|
||||
* \param buffer pointer to raw audio data to be played
|
||||
* \param bytes number of bytes to read from the buffer
|
||||
* \return number of bytes played (might be less than given, even zero)
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
size_t out123_play( out123_handle *ao
|
||||
, void *buffer, size_t bytes );
|
||||
|
||||
/** Drop any buffered data, making next provided data play right away.
|
||||
* This does not imply an actual pause in playback.
|
||||
* You are expected to play something, unless you called out123_pause().
|
||||
* Feel free to call out123_stop() afterwards instead for a quicker
|
||||
* exit than the implied out123_drain().
|
||||
* For live sinks, this may include dropping data from their buffers.
|
||||
* For others (files), this only concerns data in the optional buffer.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_drop(out123_handle *ao);
|
||||
|
||||
/** Drain the output, waiting until all data went to the hardware.
|
||||
* This does imply out123_continue() before and out123_pause()
|
||||
* after draining.
|
||||
* This might involve only the optional buffer process, or the
|
||||
* buffers on the audio driver side, too.
|
||||
* \param ao handle
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_drain(out123_handle *ao);
|
||||
|
||||
/** Drain the output, but only partially up to the given number of
|
||||
* bytes. This gives you the opportunity to do something while
|
||||
* the optional buffer is writing remaining data instead of having
|
||||
* one atomic API call for it all.
|
||||
*
|
||||
* It is wholly expected that the return value of out123_buffered()
|
||||
* before and after calling this has a bigger difference than the
|
||||
* provided limit, as the buffer is writing all the time in the
|
||||
* background.
|
||||
*
|
||||
* This is just a plain out123_drain() if the optional buffer is not
|
||||
* in use. Also triggers out123_continue(), but only out123_pause()
|
||||
* if there is no buffered data anymore.
|
||||
* \param ao handle
|
||||
* \param bytes limit of buffered bytes to drain
|
||||
* \return number of bytes drained from buffer
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
void out123_ndrain(out123_handle *ao, size_t bytes);
|
||||
|
||||
/** Get an indication of how many bytes reside in the optional buffer.
|
||||
* This might get extended to tell the number of bytes queued up in the
|
||||
* audio backend, too.
|
||||
* \param ao handle
|
||||
* \return number of bytes in out123 library buffer
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
size_t out123_buffered(out123_handle *ao);
|
||||
|
||||
/** Extract currently used audio format from handle.
|
||||
* matching mpg123_getformat().
|
||||
* Given return addresses may be NULL to indicate no interest.
|
||||
* \param ao handle
|
||||
* \param rate address for sample rate
|
||||
* \param channels address for channel count
|
||||
* \param encoding address for encoding
|
||||
* \param framesize size of a full PCM frame (for convenience)
|
||||
* \return 0 on success, -1 on error
|
||||
*/
|
||||
MPG123_EXPORT
|
||||
int out123_getformat( out123_handle *ao
|
||||
, long *rate, int *channels, int *encoding, int *framesize );
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
115
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/out123_int.h
vendored
Normal file
115
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/out123_int.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
out123_int: internal header for libout123
|
||||
|
||||
copyright ?-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Michael Hipp (some traces left)
|
||||
*/
|
||||
|
||||
#ifndef _MPG123_OUT123_INT_H_
|
||||
#define _MPG123_OUT123_INT_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "intsym.h"
|
||||
#include "abi_align.h"
|
||||
#include "compat.h"
|
||||
#include "out123.h"
|
||||
#include "module.h"
|
||||
|
||||
#ifndef NOXFERMEM
|
||||
#include "xfermem.h"
|
||||
#endif
|
||||
|
||||
/* 3% rate tolerance */
|
||||
#define AUDIO_RATE_TOLERANCE 3
|
||||
|
||||
/* Keep those internally? To the outside, it's just a selection of
|
||||
driver modules. */
|
||||
enum {
|
||||
DECODE_TEST, /* "test" */
|
||||
DECODE_AUDIO, /* gone */
|
||||
DECODE_FILE, /* "raw" */
|
||||
DECODE_BUFFER, /* internal use only, if at all */
|
||||
DECODE_WAV, /* wav */
|
||||
DECODE_AU, /* au */
|
||||
DECODE_CDR, /* cdr */
|
||||
DECODE_AUDIOFILE /* internal use only, if at all */
|
||||
};
|
||||
|
||||
/* Playback states mostly for the buffer process.
|
||||
Maybe also used in main program. */
|
||||
enum playstate
|
||||
{
|
||||
play_dead = 0 /* nothing playing, nothing loaded */
|
||||
, play_stopped /* driver present, but no device configured/opened */
|
||||
/* The ordering is used, state > play_stopped means some device is opened. */
|
||||
, play_paused /* paused, ready to continue, device still active */
|
||||
, play_live /* playing right now */
|
||||
};
|
||||
|
||||
struct out123_struct
|
||||
{
|
||||
enum out123_error errcode;
|
||||
#ifndef NOXFERMEM
|
||||
/* If buffer_pid >= 0, there is a separate buffer process actually
|
||||
handling everything, this instance here is then only a proxy. */
|
||||
int buffer_pid;
|
||||
int buffer_fd[2];
|
||||
txfermem *buffermem;
|
||||
#endif
|
||||
|
||||
int fn; /* filenumber */
|
||||
void *userptr; /* driver specific pointer */
|
||||
|
||||
/* Callbacks */
|
||||
int (*open)(out123_handle *);
|
||||
int (*get_formats)(out123_handle *);
|
||||
int (*write)(out123_handle *, unsigned char *,int);
|
||||
void (*flush)(out123_handle *); /* flush == drop != drain */
|
||||
void (*drain)(out123_handle *);
|
||||
int (*close)(out123_handle *);
|
||||
int (*deinit)(out123_handle *);
|
||||
|
||||
/* the loaded that has set the above */
|
||||
mpg123_module_t *module;
|
||||
|
||||
char *name; /* optional name of this instance */
|
||||
char *realname; /* name possibly changed by backend */
|
||||
char *driver; /* driver (module) name */
|
||||
char *device; /* device name */
|
||||
int flags; /* some bits; namely headphone/speaker/line */
|
||||
long rate; /* sample rate */
|
||||
long gain; /* output gain */
|
||||
int channels; /* number of channels */
|
||||
int format; /* encoding (TODO: rename this to "encoding"!) */
|
||||
int framesize; /* Output needs data in chunks of framesize bytes. */
|
||||
enum playstate state; /* ... */
|
||||
int auxflags; /* For now just one: quiet mode (for probing). */
|
||||
int propflags; /* Property flags, set by driver. */
|
||||
double preload; /* buffer fraction to preload before play */
|
||||
int verbose; /* verbosity to stderr */
|
||||
double device_buffer; /* device buffer in seconds */
|
||||
char *bindir; /* OUT123_BINDIR */
|
||||
/* TODO int intflag; ... is it really useful/necessary from the outside? */
|
||||
};
|
||||
|
||||
/* Lazy. */
|
||||
#define AOQUIET ((ao->auxflags | ao->flags) & OUT123_QUIET)
|
||||
#define AOVERBOSE(v) (!AOQUIET && ao->verbose >= (v))
|
||||
#define GOOD_WRITEVAL(fd, val) (unintr_write(fd, &(val), sizeof((val))) == sizeof((val)))
|
||||
#define GOOD_WRITEBUF(fd, addr, n) (unintr_write(fd, (addr), (n)) == (n))
|
||||
#define GOOD_READVAL(fd, val) (unintr_read(fd, &(val), sizeof((val))) == sizeof((val)))
|
||||
#define GOOD_READBUF(fd, addr, n) (unintr_read(fd, (addr), (n)) == (n))
|
||||
|
||||
struct audio_format_name {
|
||||
int val;
|
||||
char *name;
|
||||
char *sname;
|
||||
};
|
||||
|
||||
int write_parameters(out123_handle *ao, int fd);
|
||||
int read_parameters(out123_handle *ao
|
||||
, int fd, byte *prebuf, int *preoff, int presize);
|
||||
|
||||
#endif
|
||||
|
||||
149
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/sfifo.c
vendored
Normal file
149
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/sfifo.c
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
SFIFO 1.3 Simple portable lock-free FIFO
|
||||
|
||||
(c) 2000-2002, David Olofson - free software under the terms of the LGPL 2.1
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------
|
||||
TODO:
|
||||
* Is there a way to avoid losing one byte of buffer
|
||||
space to avoid extra variables or locking?
|
||||
|
||||
* Test more compilers and environments.
|
||||
-----------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sfifo.h"
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* Alloc buffer, init FIFO etc...
|
||||
*/
|
||||
SFIFO_SCOPE int sfifo_init(sfifo_t *f, int size)
|
||||
{
|
||||
memset(f, 0, sizeof(sfifo_t));
|
||||
|
||||
if(size > SFIFO_MAX_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Set sufficient power-of-2 size.
|
||||
*
|
||||
* No, there's no bug. If you need
|
||||
* room for N bytes, the buffer must
|
||||
* be at least N+1 bytes. (The fifo
|
||||
* can't tell 'empty' from 'full'
|
||||
* without unsafe index manipulations
|
||||
* otherwise.)
|
||||
*/
|
||||
f->size = 1;
|
||||
for(; f->size <= size; f->size <<= 1)
|
||||
;
|
||||
|
||||
/* Get buffer */
|
||||
if( 0 == (f->buffer = (void *)malloc(f->size)) )
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dealloc buffer etc...
|
||||
*/
|
||||
SFIFO_SCOPE void sfifo_close(sfifo_t *f)
|
||||
{
|
||||
if(f->buffer) {
|
||||
free(f->buffer);
|
||||
f->buffer = NULL; /* Prevent double free */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty FIFO buffer
|
||||
*/
|
||||
SFIFO_SCOPE void sfifo_flush(sfifo_t *f)
|
||||
{
|
||||
debug("sfifo_flush()");
|
||||
/* Reset positions */
|
||||
f->readpos = 0;
|
||||
f->writepos = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write bytes to a FIFO
|
||||
* Return number of bytes written, or an error code
|
||||
*/
|
||||
SFIFO_SCOPE int sfifo_write(sfifo_t *f, const void *_buf, int len)
|
||||
{
|
||||
int total;
|
||||
int i;
|
||||
const char *buf = (const char *)_buf;
|
||||
|
||||
if(!f->buffer)
|
||||
return -ENODEV; /* No buffer! */
|
||||
|
||||
/* total = len = min(space, len) */
|
||||
total = sfifo_space(f);
|
||||
debug1("sfifo_space() = %d",total);
|
||||
if(len > total)
|
||||
len = total;
|
||||
else
|
||||
total = len;
|
||||
debug1("sfifo_write() = %d", total);
|
||||
|
||||
i = f->writepos;
|
||||
if(i + len > f->size)
|
||||
{
|
||||
memcpy(f->buffer + i, buf, f->size - i);
|
||||
buf += f->size - i;
|
||||
len -= f->size - i;
|
||||
i = 0;
|
||||
}
|
||||
memcpy(f->buffer + i, buf, len);
|
||||
f->writepos = i + len;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read bytes from a FIFO
|
||||
* Return number of bytes read, or an error code
|
||||
*/
|
||||
SFIFO_SCOPE int sfifo_read(sfifo_t *f, void *_buf, int len)
|
||||
{
|
||||
int total;
|
||||
int i;
|
||||
char *buf = (char *)_buf;
|
||||
|
||||
if(!f->buffer)
|
||||
return -ENODEV; /* No buffer! */
|
||||
|
||||
/* total = len = min(used, len) */
|
||||
total = sfifo_used(f);
|
||||
debug1("sfifo_used() = %d",total);
|
||||
if(len > total)
|
||||
len = total;
|
||||
else
|
||||
total = len;
|
||||
debug1("sfifo_read() = %d", total);
|
||||
|
||||
i = f->readpos;
|
||||
if(i + len > f->size)
|
||||
{
|
||||
memcpy(buf, f->buffer + i, f->size - i);
|
||||
buf += f->size - i;
|
||||
len -= f->size - i;
|
||||
i = 0;
|
||||
}
|
||||
memcpy(buf, f->buffer + i, len);
|
||||
f->readpos = i + len;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
95
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/sfifo.h
vendored
Normal file
95
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/sfifo.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
SFIFO 1.3 Simple portable lock-free FIFO
|
||||
|
||||
(c) 2000-2002, David Olofson - free software under the terms of the LGPL 2.1
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Platform support:
|
||||
* gcc / Linux / x86: Works
|
||||
* gcc / Linux / x86 kernel: Works
|
||||
* gcc / FreeBSD / x86: Works
|
||||
* gcc / NetBSD / x86: Works
|
||||
* gcc / Mac OS X / PPC: Works
|
||||
* gcc / Win32 / x86: Works
|
||||
* Borland C++ / DOS / x86RM: Works
|
||||
* Borland C++ / Win32 / x86PM16: Untested
|
||||
* ? / Various Un*ces / ?: Untested
|
||||
* ? / Mac OS / PPC: Untested
|
||||
* gcc / BeOS / x86: Untested
|
||||
* gcc / BeOS / PPC: Untested
|
||||
* ? / ? / Alpha: Untested
|
||||
*
|
||||
* 1.2: Max buffer size halved, to avoid problems with
|
||||
* the sign bit...
|
||||
*
|
||||
* 1.3: Critical buffer allocation bug fixed! For certain
|
||||
* requested buffer sizes, older version would
|
||||
* allocate a buffer of insufficient size, which
|
||||
* would result in memory thrashing. (Amazing that
|
||||
* I've manage to use this to the extent I have
|
||||
* without running into this... *heh*)
|
||||
*/
|
||||
|
||||
#ifndef _SFIFO_H_
|
||||
#define _SFIFO_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* Defining SFIFO_STATIC and then including the sfifo.c will result in local code. */
|
||||
#ifdef SFIFO_STATIC
|
||||
#define SFIFO_SCOPE static
|
||||
#else
|
||||
#define SFIFO_SCOPE
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------
|
||||
"Private" stuff
|
||||
------------------------------------------------*/
|
||||
/*
|
||||
* Porting note:
|
||||
* Reads and writes of a variable of this type in memory
|
||||
* must be *atomic*! 'int' is *not* atomic on all platforms.
|
||||
* A safe type should be used, and sfifo should limit the
|
||||
* maximum buffer size accordingly.
|
||||
*/
|
||||
typedef int sfifo_atomic_t;
|
||||
#ifdef __TURBOC__
|
||||
# define SFIFO_MAX_BUFFER_SIZE 0x7fff
|
||||
#else /* Kludge: Assume 32 bit platform */
|
||||
# define SFIFO_MAX_BUFFER_SIZE 0x7fffffff
|
||||
#endif
|
||||
|
||||
typedef struct sfifo_t
|
||||
{
|
||||
char *buffer;
|
||||
int size; /* Number of bytes */
|
||||
sfifo_atomic_t readpos; /* Read position */
|
||||
sfifo_atomic_t writepos; /* Write position */
|
||||
} sfifo_t;
|
||||
|
||||
#define SFIFO_SIZEMASK(x) ((x)->size - 1)
|
||||
|
||||
|
||||
/*------------------------------------------------
|
||||
API
|
||||
------------------------------------------------*/
|
||||
SFIFO_SCOPE int sfifo_init(sfifo_t *f, int size);
|
||||
SFIFO_SCOPE void sfifo_close(sfifo_t *f);
|
||||
SFIFO_SCOPE void sfifo_flush(sfifo_t *f);
|
||||
SFIFO_SCOPE int sfifo_write(sfifo_t *f, const void *buf, int len);
|
||||
SFIFO_SCOPE int sfifo_read(sfifo_t *f, void *buf, int len);
|
||||
#define sfifo_used(x) (((x)->writepos - (x)->readpos) & SFIFO_SIZEMASK(x))
|
||||
#define sfifo_space(x) ((x)->size - 1 - sfifo_used(x))
|
||||
#define sfifo_size(x) ((x)->size - 1)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
51
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/stringlists.c
vendored
Normal file
51
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/stringlists.c
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
stringlists: creation of paired string lists for one-time consumption
|
||||
|
||||
copyright 2015 by the mpg123 project
|
||||
free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
|
||||
Thomas did not want to introduce a list type complete with management
|
||||
functions just for returning driver module lists.
|
||||
*/
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
/* Construction helper for paired string lists.
|
||||
Returns 0 on success. */
|
||||
int stringlists_add( char ***alist, char ***blist
|
||||
, const char *atext, const char *btext, int *count)
|
||||
{
|
||||
char *atextcopy = NULL;
|
||||
char *btextcopy = NULL;
|
||||
char **morealist = NULL;
|
||||
char **moreblist = NULL;
|
||||
|
||||
/* If one of these succeeded, the old memory is gone, so always overwrite
|
||||
the old pointer, worst case is wasted but not leaked memory in an
|
||||
out-of-memory situation. */
|
||||
if((morealist = safe_realloc(*alist, sizeof(char*)*(*count+1))))
|
||||
*alist = morealist;
|
||||
if((moreblist = safe_realloc(*blist, sizeof(char*)*(*count+1))))
|
||||
*blist = moreblist;
|
||||
if(!morealist || !moreblist)
|
||||
return -1;
|
||||
|
||||
if(
|
||||
(atextcopy = compat_strdup(atext))
|
||||
&& (btextcopy = compat_strdup(btext))
|
||||
)
|
||||
{
|
||||
(*alist)[*count] = atextcopy;
|
||||
(*blist)[*count] = btextcopy;
|
||||
++*count;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(atextcopy);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
16
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/stringlists.h
vendored
Normal file
16
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/stringlists.h
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
stringlists: creation of paired string lists for one-time consumption
|
||||
|
||||
copyright 2015 by the mpg123 project
|
||||
free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
*/
|
||||
|
||||
#ifndef MPG123_H_STRINGLISTS
|
||||
#define MPG123_H_STRINGLISTS
|
||||
|
||||
int stringlists_add( char ***alist, char ***blist
|
||||
, const char *atext, const char *btext, int *count);
|
||||
|
||||
#endif
|
||||
756
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wav.c
vendored
Normal file
756
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wav.c
vendored
Normal file
@@ -0,0 +1,756 @@
|
||||
/*
|
||||
wav.c: write wav/au/cdr files (and headerless raw
|
||||
|
||||
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Samuel Audet
|
||||
|
||||
Geez, why are WAV RIFF headers are so secret? I got something together,
|
||||
but wow... anyway, I hope someone will find this useful.
|
||||
- Samuel Audet
|
||||
|
||||
minor simplifications and ugly AU/CDR format stuff by MH
|
||||
|
||||
It's not a very clean code ... Fix this!
|
||||
|
||||
ThOr: The usage of stdio streams means we loose control over what data is actually written. On a full disk, fwrite() happily suceeds for ages, only a fflush fails.
|
||||
Now: Do we want to fflush() after every write? That defeats the purpose of buffered I/O. So, switching to good old write() is an option (kernel doing disk buffering anyway).
|
||||
|
||||
ThOr: Again reworked things for libout123, with non-static state.
|
||||
This set of builtin "modules" is what we can use in automated tests
|
||||
of libout123. Code still not very nice, but I tried to keep modification
|
||||
of what stood the test of time minimal. One still can add a module to
|
||||
libout123 that uses sndfile and similar libraries for more choice on writing
|
||||
output files.
|
||||
*/
|
||||
|
||||
#include "out123_int.h"
|
||||
#include "wav.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include "debug.h"
|
||||
|
||||
/* Create the two WAV headers. */
|
||||
|
||||
#define WAVE_FORMAT 1
|
||||
#define RIFF_NAME riff_template
|
||||
#define RIFF_STRUCT_NAME riff
|
||||
#include "wavhead.h"
|
||||
|
||||
#undef WAVE_FORMAT
|
||||
#undef RIFF_NAME
|
||||
#undef RIFF_STRUCT_NAME
|
||||
#define WAVE_FORMAT 3
|
||||
#define RIFF_NAME riff_float_template
|
||||
#define RIFF_STRUCT_NAME riff_float
|
||||
#define FLOATOUT
|
||||
#include "wavhead.h"
|
||||
|
||||
/* AU header struct... */
|
||||
|
||||
struct auhead {
|
||||
byte magic[4];
|
||||
byte headlen[4];
|
||||
byte datalen[4];
|
||||
byte encoding[4];
|
||||
byte rate[4];
|
||||
byte channels[4];
|
||||
byte dummy[8];
|
||||
} const auhead_template = {
|
||||
{ 0x2e,0x73,0x6e,0x64 } , { 0x00,0x00,0x00,0x20 } ,
|
||||
{ 0xff,0xff,0xff,0xff } , { 0,0,0,0 } , { 0,0,0,0 } , { 0,0,0,0 } ,
|
||||
{ 0,0,0,0,0,0,0,0 }};
|
||||
|
||||
struct wavdata
|
||||
{
|
||||
FILE *wavfp;
|
||||
long datalen;
|
||||
int flipendian;
|
||||
int bytes_per_sample;
|
||||
int floatwav; /* If we write a floating point WAV file. */
|
||||
/*
|
||||
Open routines only prepare a header, stored here and written on first
|
||||
actual data write. If no data is written at all, proper files will
|
||||
still get a header via the update at closing; non-seekable streams will
|
||||
just have no no header if there is no data.
|
||||
*/
|
||||
void *the_header;
|
||||
size_t the_header_size;
|
||||
};
|
||||
|
||||
static struct wavdata* wavdata_new(void)
|
||||
{
|
||||
struct wavdata *wdat = malloc(sizeof(struct wavdata));
|
||||
if(wdat)
|
||||
{
|
||||
wdat->wavfp = NULL;
|
||||
wdat->datalen = 0;
|
||||
wdat->flipendian = 0;
|
||||
wdat->bytes_per_sample = -1;
|
||||
wdat->floatwav = 0;
|
||||
wdat->the_header = NULL;
|
||||
wdat->the_header_size = 0;
|
||||
}
|
||||
return wdat;
|
||||
}
|
||||
|
||||
static void wavdata_del(struct wavdata *wdat)
|
||||
{
|
||||
if(!wdat) return;
|
||||
if(wdat->wavfp && wdat->wavfp != stdout)
|
||||
compat_fclose(wdat->wavfp);
|
||||
if(wdat->the_header)
|
||||
free(wdat->the_header);
|
||||
free(wdat);
|
||||
}
|
||||
|
||||
/* Pointer types are for pussies;-) */
|
||||
static void* wavhead_new(void const *template, size_t size)
|
||||
{
|
||||
void *header = malloc(size);
|
||||
if(header)
|
||||
memcpy(header, template, size);
|
||||
return header;
|
||||
}
|
||||
|
||||
/* Convertfunctions: */
|
||||
/* always little endian */
|
||||
|
||||
static void long2littleendian(long inval,byte *outval,int b)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<b;i++) {
|
||||
outval[i] = (inval>>(i*8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* always big endian */
|
||||
static void long2bigendian(long inval,byte *outval,int b)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<b;i++) {
|
||||
outval[i] = (inval>>((b-i-1)*8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static long from_little(byte *inval, int b)
|
||||
{
|
||||
long ret = 0;
|
||||
int i;
|
||||
for(i=0;i<b;++i) ret += ((long)inval[i])<<(i*8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int testEndian(void)
|
||||
{
|
||||
long i,a=0,b=0,c=0;
|
||||
int ret = 0;
|
||||
|
||||
for(i=0;i<sizeof(long);i++) {
|
||||
((byte *)&a)[i] = i;
|
||||
b<<=8;
|
||||
b |= i;
|
||||
c |= i << (i*8);
|
||||
}
|
||||
if(a == b)
|
||||
ret = 1;
|
||||
else if(a != c) {
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return: 0 is good, -1 is bad */
|
||||
static int open_file(struct wavdata *wdat, char *filename)
|
||||
{
|
||||
debug2("open_file(%p, %s)", (void*)wdat, filename ? filename : "<nil>");
|
||||
if(!wdat)
|
||||
return -1;
|
||||
#if defined(HAVE_SETUID) && defined(HAVE_GETUID)
|
||||
/* TODO: get rid of that and settle that you rather not install mpg123
|
||||
setuid-root. Why should you?
|
||||
In case this program is setuid, create files owned by original user. */
|
||||
setuid(getuid());
|
||||
#endif
|
||||
if(!filename || !strcmp("-",filename) || !strcmp("", filename))
|
||||
{
|
||||
wdat->wavfp = stdout;
|
||||
#ifdef WIN32
|
||||
_setmode(STDOUT_FILENO, _O_BINARY);
|
||||
#endif
|
||||
/* If stdout is redirected to a file, seeks suddenly can work.
|
||||
Doing one here to ensure that such a file has the same output
|
||||
it had when opening directly as such. */
|
||||
fseek(wdat->wavfp, 0L, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wdat->wavfp = compat_fopen(filename, "wb");
|
||||
if(!wdat->wavfp)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* return: 0 is good, -1 is bad
|
||||
Works for any partial state of setup, especially should not complain if
|
||||
ao->userptr == NULL. */
|
||||
static int close_file(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
int ret = 0;
|
||||
|
||||
if(wdat->wavfp != NULL && wdat->wavfp != stdout)
|
||||
{
|
||||
if(compat_fclose(wdat->wavfp))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("problem closing the audio file, probably because of flushing to disk: %s\n", strerror(errno));
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always cleanup here. */
|
||||
wdat->wavfp = NULL;
|
||||
wavdata_del(wdat);
|
||||
ao->userptr = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return: 0 is good, -1 is bad */
|
||||
static int write_header(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
|
||||
if(!wdat)
|
||||
return 0;
|
||||
|
||||
if(
|
||||
wdat->the_header_size > 0
|
||||
&& (
|
||||
fwrite(wdat->the_header, wdat->the_header_size, 1, wdat->wavfp) != 1
|
||||
|| fflush(wdat->wavfp)
|
||||
)
|
||||
)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("cannot write header: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int au_open(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = NULL;
|
||||
struct auhead *auhead = NULL;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ao->format & MPG123_ENC_FLOAT)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("AU file support for float values not there yet");
|
||||
goto au_open_bad;
|
||||
}
|
||||
|
||||
if(
|
||||
!(wdat = wavdata_new())
|
||||
|| !(auhead = wavhead_new(&auhead_template, sizeof(auhead_template)))
|
||||
)
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto au_open_bad;
|
||||
}
|
||||
|
||||
wdat->the_header = auhead;
|
||||
wdat->the_header_size = sizeof(*auhead);
|
||||
|
||||
wdat->flipendian = 0;
|
||||
|
||||
switch(ao->format)
|
||||
{
|
||||
case MPG123_ENC_SIGNED_16:
|
||||
{
|
||||
int endiantest = testEndian();
|
||||
if(endiantest == -1)
|
||||
goto au_open_bad;
|
||||
wdat->flipendian = !endiantest; /* big end */
|
||||
long2bigendian(3,auhead->encoding,sizeof(auhead->encoding));
|
||||
}
|
||||
break;
|
||||
case MPG123_ENC_UNSIGNED_8:
|
||||
ao->format = MPG123_ENC_ULAW_8;
|
||||
case MPG123_ENC_ULAW_8:
|
||||
long2bigendian(1,auhead->encoding,sizeof(auhead->encoding));
|
||||
break;
|
||||
default:
|
||||
if(!AOQUIET)
|
||||
error("AU output is only a hack. This audio mode isn't supported yet.");
|
||||
goto au_open_bad;
|
||||
}
|
||||
|
||||
long2bigendian(0xffffffff,auhead->datalen,sizeof(auhead->datalen));
|
||||
long2bigendian(ao->rate,auhead->rate,sizeof(auhead->rate));
|
||||
long2bigendian(ao->channels,auhead->channels,sizeof(auhead->channels));
|
||||
|
||||
if(open_file(wdat, ao->device) < 0)
|
||||
goto au_open_bad;
|
||||
|
||||
wdat->datalen = 0;
|
||||
|
||||
ao->userptr = wdat;
|
||||
return 0;
|
||||
|
||||
au_open_bad:
|
||||
if(auhead)
|
||||
free(auhead);
|
||||
if(wdat)
|
||||
{
|
||||
wdat->the_header = NULL;
|
||||
wavdata_del(wdat);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cdr_open(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = NULL;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(
|
||||
ao->format != MPG123_ENC_SIGNED_16
|
||||
|| ao->rate != 44100
|
||||
|| ao->channels != 2
|
||||
)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Oops .. not forced to 16 bit, 44 kHz, stereo?");
|
||||
goto cdr_open_bad;
|
||||
}
|
||||
|
||||
if(!(wdat = wavdata_new()))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto cdr_open_bad;
|
||||
}
|
||||
|
||||
wdat->flipendian = !testEndian(); /* big end */
|
||||
|
||||
if(open_file(wdat, ao->device) < 0)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("cannot open file for writing");
|
||||
goto cdr_open_bad;
|
||||
}
|
||||
|
||||
ao->userptr = wdat;
|
||||
return 0;
|
||||
cdr_open_bad:
|
||||
if(wdat)
|
||||
wavdata_del(wdat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* RAW files are headerless WAVs where the format does not matter. */
|
||||
int raw_open(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(wdat = wavdata_new()))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto raw_open_bad;
|
||||
}
|
||||
|
||||
if(open_file(wdat, ao->device) < 0)
|
||||
goto raw_open_bad;
|
||||
|
||||
ao->userptr = wdat;
|
||||
return 1;
|
||||
raw_open_bad:
|
||||
if(wdat)
|
||||
wavdata_del(wdat);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int wav_open(out123_handle *ao)
|
||||
{
|
||||
int bps;
|
||||
struct wavdata *wdat = NULL;
|
||||
struct riff *inthead = NULL;
|
||||
struct riff_float *floathead = NULL;
|
||||
|
||||
if(ao->format < 0)
|
||||
{
|
||||
ao->rate = 44100;
|
||||
ao->channels = 2;
|
||||
ao->format = MPG123_ENC_SIGNED_16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(wdat = wavdata_new()))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto wav_open_bad;
|
||||
}
|
||||
|
||||
wdat->floatwav = (ao->format & MPG123_ENC_FLOAT);
|
||||
if(wdat->floatwav)
|
||||
{
|
||||
if(!(floathead = wavhead_new( &riff_float_template
|
||||
, sizeof(riff_float_template)) ))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto wav_open_bad;
|
||||
}
|
||||
wdat->the_header = floathead;
|
||||
wdat->the_header_size = sizeof(*floathead);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(inthead = wavhead_new( &riff_template
|
||||
, sizeof(riff_template)) ))
|
||||
{
|
||||
ao->errcode = OUT123_DOOM;
|
||||
goto wav_open_bad;
|
||||
}
|
||||
wdat->the_header = inthead;
|
||||
wdat->the_header_size = sizeof(*inthead);
|
||||
|
||||
/* standard MS PCM, and its format specific is BitsPerSample */
|
||||
long2littleendian(1, inthead->WAVE.fmt.FormatTag
|
||||
, sizeof(inthead->WAVE.fmt.FormatTag));
|
||||
}
|
||||
|
||||
if(ao->format == MPG123_ENC_FLOAT_32)
|
||||
{
|
||||
long2littleendian(3, floathead->WAVE.fmt.FormatTag
|
||||
, sizeof(floathead->WAVE.fmt.FormatTag));
|
||||
long2littleendian(bps=32, floathead->WAVE.fmt.BitsPerSample
|
||||
, sizeof(floathead->WAVE.fmt.BitsPerSample));
|
||||
wdat->flipendian = testEndian();
|
||||
}
|
||||
else if(ao->format == MPG123_ENC_SIGNED_32)
|
||||
{
|
||||
long2littleendian(bps=32, inthead->WAVE.fmt.BitsPerSample
|
||||
, sizeof(inthead->WAVE.fmt.BitsPerSample));
|
||||
wdat->flipendian = testEndian();
|
||||
}
|
||||
else if(ao->format == MPG123_ENC_SIGNED_24)
|
||||
{
|
||||
long2littleendian(bps=24, inthead->WAVE.fmt.BitsPerSample
|
||||
, sizeof(inthead->WAVE.fmt.BitsPerSample));
|
||||
wdat->flipendian = testEndian();
|
||||
}
|
||||
else if(ao->format == MPG123_ENC_SIGNED_16)
|
||||
{
|
||||
long2littleendian(bps=16, inthead->WAVE.fmt.BitsPerSample
|
||||
, sizeof(inthead->WAVE.fmt.BitsPerSample));
|
||||
wdat->flipendian = testEndian();
|
||||
}
|
||||
else if(ao->format == MPG123_ENC_UNSIGNED_8)
|
||||
long2littleendian(bps=8, inthead->WAVE.fmt.BitsPerSample
|
||||
, sizeof(inthead->WAVE.fmt.BitsPerSample));
|
||||
else
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Format not supported.");
|
||||
goto wav_open_bad;
|
||||
}
|
||||
|
||||
if(wdat->floatwav)
|
||||
{
|
||||
long2littleendian(ao->channels, floathead->WAVE.fmt.Channels
|
||||
, sizeof(floathead->WAVE.fmt.Channels));
|
||||
long2littleendian(ao->rate, floathead->WAVE.fmt.SamplesPerSec
|
||||
, sizeof(floathead->WAVE.fmt.SamplesPerSec));
|
||||
long2littleendian( (int)(ao->channels * ao->rate * bps)>>3
|
||||
, floathead->WAVE.fmt.AvgBytesPerSec
|
||||
, sizeof(floathead->WAVE.fmt.AvgBytesPerSec) );
|
||||
long2littleendian( (int)(ao->channels * bps)>>3
|
||||
, floathead->WAVE.fmt.BlockAlign
|
||||
, sizeof(floathead->WAVE.fmt.BlockAlign) );
|
||||
}
|
||||
else
|
||||
{
|
||||
long2littleendian(ao->channels, inthead->WAVE.fmt.Channels
|
||||
, sizeof(inthead->WAVE.fmt.Channels));
|
||||
long2littleendian(ao->rate, inthead->WAVE.fmt.SamplesPerSec
|
||||
, sizeof(inthead->WAVE.fmt.SamplesPerSec));
|
||||
long2littleendian( (int)(ao->channels * ao->rate * bps)>>3
|
||||
, inthead->WAVE.fmt.AvgBytesPerSec
|
||||
,sizeof(inthead->WAVE.fmt.AvgBytesPerSec) );
|
||||
long2littleendian( (int)(ao->channels * bps)>>3
|
||||
, inthead->WAVE.fmt.BlockAlign
|
||||
, sizeof(inthead->WAVE.fmt.BlockAlign) );
|
||||
}
|
||||
|
||||
if(open_file(wdat, ao->device) < 0)
|
||||
goto wav_open_bad;
|
||||
|
||||
if(wdat->floatwav)
|
||||
{
|
||||
long2littleendian(wdat->datalen, floathead->WAVE.data.datalen
|
||||
, sizeof(floathead->WAVE.data.datalen));
|
||||
long2littleendian(wdat->datalen+sizeof(floathead->WAVE)
|
||||
, floathead->WAVElen, sizeof(floathead->WAVElen));
|
||||
}
|
||||
else
|
||||
{
|
||||
long2littleendian(wdat->datalen, inthead->WAVE.data.datalen
|
||||
, sizeof(inthead->WAVE.data.datalen));
|
||||
long2littleendian( wdat->datalen+sizeof(inthead->WAVE)
|
||||
, inthead->WAVElen
|
||||
, sizeof(inthead->WAVElen) );
|
||||
}
|
||||
|
||||
wdat->bytes_per_sample = bps>>3;
|
||||
|
||||
ao->userptr = wdat;
|
||||
return 0;
|
||||
|
||||
wav_open_bad:
|
||||
if(inthead)
|
||||
free(inthead);
|
||||
if(floathead)
|
||||
free(floathead);
|
||||
if(wdat)
|
||||
{
|
||||
wdat->the_header = NULL;
|
||||
wavdata_del(wdat);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int wav_write(out123_handle *ao, unsigned char *buf, int len)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
int temp;
|
||||
int i;
|
||||
|
||||
if(!wdat || !wdat->wavfp)
|
||||
return 0; /* Really? Zero? */
|
||||
|
||||
if(wdat->datalen == 0 && write_header(ao) < 0)
|
||||
return -1;
|
||||
|
||||
/* Endianess conversion. Not fancy / optimized. */
|
||||
if(wdat->flipendian)
|
||||
{
|
||||
if(wdat->bytes_per_sample == 4) /* 32 bit */
|
||||
{
|
||||
if(len & 3)
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error("Number of bytes no multiple of 4 (32bit)!");
|
||||
return -1;
|
||||
}
|
||||
for(i=0;i<len;i+=4)
|
||||
{
|
||||
int j;
|
||||
unsigned char tmp[4];
|
||||
for(j = 0; j<=3; ++j) tmp[j] = buf[i+j];
|
||||
for(j = 0; j<=3; ++j) buf[i+j] = tmp[3-j];
|
||||
}
|
||||
}
|
||||
else /* 16 bit */
|
||||
{
|
||||
if(len & 1)
|
||||
{
|
||||
error("Odd number of bytes!");
|
||||
return -1;
|
||||
}
|
||||
for(i=0;i<len;i+=2)
|
||||
{
|
||||
unsigned char tmp;
|
||||
tmp = buf[i+0];
|
||||
buf[i+0] = buf[i+1];
|
||||
buf[i+1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp = fwrite(buf, 1, len, wdat->wavfp);
|
||||
if(temp <= 0) return temp;
|
||||
/* That would kill it of early when running out of disk space. */
|
||||
#if 0
|
||||
if(fflush(wdat->wavfp))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("flushing failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
wdat->datalen += temp;
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
int wav_close(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
|
||||
if(!wdat) /* Special case: Opened only for format query. */
|
||||
return 0;
|
||||
|
||||
if(!wdat || !wdat->wavfp)
|
||||
return -1;
|
||||
|
||||
/* flush before seeking to catch out-of-disk explicitly at least at the end */
|
||||
if(fflush(wdat->wavfp))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("cannot flush WAV stream: %s", strerror(errno));
|
||||
return close_file(ao);
|
||||
}
|
||||
if(fseek(wdat->wavfp, 0L, SEEK_SET) >= 0)
|
||||
{
|
||||
if(wdat->floatwav)
|
||||
{
|
||||
struct riff_float *floathead = wdat->the_header;
|
||||
long2littleendian(wdat->datalen
|
||||
, floathead->WAVE.data.datalen
|
||||
, sizeof(floathead->WAVE.data.datalen));
|
||||
long2littleendian(wdat->datalen+sizeof(floathead->WAVE)
|
||||
, floathead->WAVElen
|
||||
, sizeof(floathead->WAVElen));
|
||||
long2littleendian( wdat->datalen
|
||||
/ (
|
||||
from_little(floathead->WAVE.fmt.Channels,2)
|
||||
* from_little(floathead->WAVE.fmt.BitsPerSample,2)/8
|
||||
)
|
||||
, floathead->WAVE.fact.samplelen
|
||||
, sizeof(floathead->WAVE.fact.samplelen) );
|
||||
}
|
||||
else
|
||||
{
|
||||
struct riff *inthead = wdat->the_header;
|
||||
long2littleendian(wdat->datalen, inthead->WAVE.data.datalen
|
||||
, sizeof(inthead->WAVE.data.datalen));
|
||||
long2littleendian(wdat->datalen+sizeof(inthead->WAVE), inthead->WAVElen
|
||||
, sizeof(inthead->WAVElen));
|
||||
}
|
||||
/* Always (over)writing the header here; also for stdout, when
|
||||
fseek worked, this overwrite works. */
|
||||
write_header(ao);
|
||||
}
|
||||
else if(!AOQUIET)
|
||||
warning("Cannot rewind WAV file. File-format isn't fully conform now.");
|
||||
|
||||
return close_file(ao);
|
||||
}
|
||||
|
||||
int au_close(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
|
||||
if(!wdat) /* Special case: Opened only for format query. */
|
||||
return 0;
|
||||
|
||||
if(!wdat->wavfp)
|
||||
return -1;
|
||||
|
||||
/* flush before seeking to catch out-of-disk explicitly at least at the end */
|
||||
if(fflush(wdat->wavfp))
|
||||
{
|
||||
if(!AOQUIET)
|
||||
error1("cannot flush WAV stream: %s", strerror(errno));
|
||||
return close_file(ao);
|
||||
}
|
||||
if(fseek(wdat->wavfp, 0L, SEEK_SET) >= 0)
|
||||
{
|
||||
struct auhead *auhead = wdat->the_header;
|
||||
long2bigendian(wdat->datalen, auhead->datalen, sizeof(auhead->datalen));
|
||||
/* Always (over)writing the header here; also for stdout, when
|
||||
fseek worked, this overwrite works. */
|
||||
write_header(ao);
|
||||
}
|
||||
else if(!AOQUIET)
|
||||
warning("Cannot rewind AU file. File-format isn't fully conform now.");
|
||||
|
||||
return close_file(ao);
|
||||
}
|
||||
|
||||
/* CDR data also uses that. */
|
||||
int raw_close(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
|
||||
if(!wdat) /* Special case: Opened only for format query. */
|
||||
return 0;
|
||||
|
||||
if(!wdat->wavfp)
|
||||
return -1;
|
||||
|
||||
return close_file(ao);
|
||||
}
|
||||
|
||||
/* Some trivial functions to interface with out123's module architecture. */
|
||||
|
||||
int cdr_formats(out123_handle *ao)
|
||||
{
|
||||
if(ao->rate == 44100 && ao->channels == 2)
|
||||
return MPG123_ENC_SIGNED_16;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int au_formats(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8|MPG123_ENC_ULAW_8;
|
||||
}
|
||||
|
||||
int raw_formats(out123_handle *ao)
|
||||
{
|
||||
return MPG123_ENC_ANY;
|
||||
}
|
||||
|
||||
int wav_formats(out123_handle *ao)
|
||||
{
|
||||
return
|
||||
MPG123_ENC_SIGNED_16
|
||||
| MPG123_ENC_UNSIGNED_8
|
||||
| MPG123_ENC_FLOAT_32
|
||||
| MPG123_ENC_SIGNED_24
|
||||
| MPG123_ENC_SIGNED_32;
|
||||
}
|
||||
|
||||
/* Draining is flushing to disk. Words do suck at times.
|
||||
One could call fsync(), too, but to be safe, that would need to
|
||||
be called on the directory, too. Also, apps randomly calling
|
||||
fsync() can cause annoying issues in a system. */
|
||||
void wav_drain(out123_handle *ao)
|
||||
{
|
||||
struct wavdata *wdat = ao->userptr;
|
||||
|
||||
if(!wdat)
|
||||
return;
|
||||
|
||||
if(fflush(wdat->wavfp) && !AOQUIET)
|
||||
error1("flushing failed: %s\n", strerror(errno));
|
||||
}
|
||||
33
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wav.h
vendored
Normal file
33
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wav.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
wav.c: write wav/au/cdr files (and headerless raw)
|
||||
|
||||
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially extracted of out123_int.h, formerly audio.h, by Thomas Orgis
|
||||
*/
|
||||
|
||||
#ifndef _MPG123_WAV_H_
|
||||
#define _MPG123_WAV_H_
|
||||
|
||||
/* Could get away without any header, as only pointers declared. */
|
||||
#include "out123.h"
|
||||
|
||||
/* Interfaces from wav.c, variants of file writing, to be combined into
|
||||
fake modules by the main library code. */
|
||||
|
||||
int au_open(out123_handle *);
|
||||
int cdr_open(out123_handle *);
|
||||
int raw_open(out123_handle *);
|
||||
int wav_open(out123_handle *);
|
||||
int wav_write(out123_handle *, unsigned char *buf, int len);
|
||||
int wav_close(out123_handle *);
|
||||
int au_close(out123_handle *);
|
||||
int raw_close(out123_handle *);
|
||||
int cdr_formats(out123_handle *);
|
||||
int au_formats(out123_handle *);
|
||||
int raw_formats(out123_handle *);
|
||||
int wav_formats(out123_handle *);
|
||||
void wav_drain(out123_handle *);
|
||||
|
||||
#endif
|
||||
|
||||
68
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wavhead.h
vendored
Normal file
68
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/wavhead.h
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
wavhead.h: wav file header, to be included twice for integer and float wavs
|
||||
|
||||
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Samuel Audet
|
||||
*/
|
||||
|
||||
struct RIFF_STRUCT_NAME
|
||||
{
|
||||
byte riffheader[4];
|
||||
byte WAVElen[4]; /* should this include riffheader or not? */
|
||||
struct
|
||||
{
|
||||
byte WAVEID[4];
|
||||
byte fmtheader[4];
|
||||
byte fmtlen[4];
|
||||
struct
|
||||
{
|
||||
byte FormatTag[2];
|
||||
byte Channels[2];
|
||||
byte SamplesPerSec[4];
|
||||
byte AvgBytesPerSec[4];
|
||||
byte BlockAlign[2];
|
||||
byte BitsPerSample[2]; /* format specific for PCM */
|
||||
#ifdef FLOATOUT
|
||||
byte cbSize[2];
|
||||
#endif
|
||||
} fmt;
|
||||
#ifdef FLOATOUT
|
||||
byte factheader[4];
|
||||
byte factlen[4];
|
||||
struct
|
||||
{
|
||||
byte samplelen[4];
|
||||
} fact;
|
||||
#endif
|
||||
struct
|
||||
{
|
||||
byte dataheader[4];
|
||||
byte datalen[4];
|
||||
/* from here you insert your PCM data */
|
||||
} data;
|
||||
} WAVE;
|
||||
} const RIFF_NAME =
|
||||
{
|
||||
{ 'R','I','F','F' } ,
|
||||
{ sizeof(RIFF_NAME.WAVE),0,0,0 } ,
|
||||
{
|
||||
{ 'W','A','V','E' },
|
||||
{ 'f','m','t',' ' },
|
||||
{ sizeof(RIFF_NAME.WAVE.fmt),0,0,0 } ,
|
||||
{
|
||||
{WAVE_FORMAT,0} , {0,0},{0,0,0,0},{0,0,0,0},{0,0},{0,0}
|
||||
#ifdef FLOATOUT
|
||||
,{0,0}
|
||||
#endif
|
||||
} ,
|
||||
#ifdef FLOATOUT
|
||||
{ 'f','a','c','t' },
|
||||
{ sizeof(RIFF_NAME.WAVE.fact),0,0,0 },
|
||||
{
|
||||
{0,0,0,0} /* to be filled later, like datalen and wavelen */
|
||||
},
|
||||
#endif
|
||||
{ { 'd','a','t','a' } , {0,0,0,0} }
|
||||
}
|
||||
};
|
||||
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/xfermem.c
vendored
Normal file
304
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/xfermem.c
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
xfermem: unidirectional fast pipe
|
||||
|
||||
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Oliver Fromme
|
||||
old timestamp: Sun Apr 6 02:26:26 MET DST 1997
|
||||
|
||||
See xfermem.h for documentation/description.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "compat.h"
|
||||
#include "xfermem.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef HAVE_MMAP
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#if defined (HAVE_MMAP) && defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
|
||||
void xfermem_init (txfermem **xf, size_t bufsize, size_t msize, size_t skipbuf)
|
||||
{
|
||||
size_t regsize = bufsize + msize + skipbuf + sizeof(txfermem);
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
# ifdef MAP_ANON
|
||||
if ((*xf = (txfermem *) mmap(0, regsize, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_SHARED, -1, 0)) == (txfermem *) -1) {
|
||||
perror ("mmap()");
|
||||
exit (1);
|
||||
}
|
||||
# else
|
||||
int devzero;
|
||||
if ((devzero = open("/dev/zero", O_RDWR, 0)) == -1) {
|
||||
perror ("open(/dev/zero)");
|
||||
exit (1);
|
||||
}
|
||||
if ((*xf = (txfermem *) mmap(0, regsize, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, devzero, 0)) == (txfermem *) -1) {
|
||||
perror ("mmap()");
|
||||
exit (1);
|
||||
}
|
||||
close (devzero);
|
||||
# endif
|
||||
#else
|
||||
struct shmid_ds shmemds;
|
||||
int shmemid;
|
||||
if ((shmemid = shmget(IPC_PRIVATE, regsize, IPC_CREAT | 0600)) == -1) {
|
||||
perror ("shmget()");
|
||||
exit (1);
|
||||
}
|
||||
if ((*xf = (txfermem *) shmat(shmemid, 0, 0)) == (txfermem *) -1) {
|
||||
perror ("shmat()");
|
||||
shmctl (shmemid, IPC_RMID, &shmemds);
|
||||
exit (1);
|
||||
}
|
||||
if (shmctl(shmemid, IPC_RMID, &shmemds) == -1) {
|
||||
perror ("shmctl()");
|
||||
xfermem_done (*xf);
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, (*xf)->fd) < 0) {
|
||||
perror ("socketpair()");
|
||||
xfermem_done (*xf);
|
||||
exit (1);
|
||||
}
|
||||
(*xf)->freeindex = (*xf)->readindex = 0;
|
||||
(*xf)->data = ((char *) *xf) + sizeof(txfermem) + msize;
|
||||
(*xf)->metadata = ((char *) *xf) + sizeof(txfermem);
|
||||
(*xf)->size = bufsize;
|
||||
(*xf)->metasize = msize + skipbuf;
|
||||
}
|
||||
|
||||
void xfermem_done (txfermem *xf)
|
||||
{
|
||||
if(!xf)
|
||||
return;
|
||||
#ifdef HAVE_MMAP
|
||||
/* Here was a cast to (caddr_t) ... why? Was this needed for SunOS?
|
||||
Casting to (void*) should silence compilers in case of funny
|
||||
prototype for munmap(). */
|
||||
munmap ( (void*)xf, xf->size + xf->metasize + sizeof(txfermem));
|
||||
#else
|
||||
if (shmdt((void *) xf) == -1) {
|
||||
perror ("shmdt()");
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void xfermem_init_writer (txfermem *xf)
|
||||
{
|
||||
if(xf)
|
||||
close (xf->fd[XF_READER]);
|
||||
debug1("xfermem writer fd=%i", xf->fd[XF_WRITER]);
|
||||
}
|
||||
|
||||
void xfermem_init_reader (txfermem *xf)
|
||||
{
|
||||
if(xf)
|
||||
close (xf->fd[XF_WRITER]);
|
||||
debug1("xfermem reader fd=%i", xf->fd[XF_READER]);
|
||||
}
|
||||
|
||||
size_t xfermem_get_freespace (txfermem *xf)
|
||||
{
|
||||
size_t freeindex, readindex;
|
||||
|
||||
if(!xf)
|
||||
return 0;
|
||||
|
||||
if ((freeindex = xf->freeindex) < 0
|
||||
|| (readindex = xf->readindex) < 0)
|
||||
return (0);
|
||||
if (readindex > freeindex)
|
||||
return ((readindex - freeindex) - 1);
|
||||
else
|
||||
return ((xf->size - (freeindex - readindex)) - 1);
|
||||
}
|
||||
|
||||
size_t xfermem_get_usedspace (txfermem *xf)
|
||||
{
|
||||
size_t freeindex, readindex;
|
||||
|
||||
if(!xf)
|
||||
return 0;
|
||||
|
||||
if ((freeindex = xf->freeindex) < 0
|
||||
|| (readindex = xf->readindex) < 0)
|
||||
return (0);
|
||||
if (freeindex >= readindex)
|
||||
return (freeindex - readindex);
|
||||
else
|
||||
return (xf->size - (readindex - freeindex));
|
||||
}
|
||||
|
||||
static int xfermem_getcmd_raw (int fd, int block, byte *cmds, int count)
|
||||
{
|
||||
fd_set selfds;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
struct timeval selto = {0, 0};
|
||||
|
||||
FD_ZERO (&selfds);
|
||||
FD_SET (fd, &selfds);
|
||||
#ifdef HPUX
|
||||
switch (select(FD_SETSIZE, (int *) &selfds, NULL, NULL, block ? NULL : &selto))
|
||||
#else
|
||||
switch (select(FD_SETSIZE, &selfds, NULL, NULL, block ? NULL : &selto))
|
||||
#endif
|
||||
{
|
||||
case 0:
|
||||
if (!block)
|
||||
return (0);
|
||||
continue;
|
||||
case -1:
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return (-2);
|
||||
case 1:
|
||||
if (FD_ISSET(fd, &selfds))
|
||||
switch((ret=read(fd, cmds, count)))
|
||||
{
|
||||
case 0: /* EOF */
|
||||
return (-1);
|
||||
case -1:
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return (-3);
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
else /* ?!? */
|
||||
return (-5);
|
||||
default: /* ?!? */
|
||||
return (-6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Verbose variant for debugging communication. */
|
||||
int xfermem_getcmd(int fd, int block)
|
||||
{
|
||||
byte cmd;
|
||||
int res = xfermem_getcmd_raw(fd, block, &cmd, 1);
|
||||
debug3("xfermem_getcmd(%i, %i) = %i", fd, block, res == 1 ? cmd : res);
|
||||
return res == 1 ? cmd : res;
|
||||
}
|
||||
|
||||
int xfermem_getcmds(int fd, int block, byte *cmds, int count)
|
||||
{
|
||||
int res = xfermem_getcmd_raw(fd, block, cmds, count);
|
||||
debug5("xfermem_getcmds(%i, %i, %p, %i) = %i"
|
||||
, fd, block, (void*)cmds, count
|
||||
, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int xfermem_putcmd (int fd, byte cmd)
|
||||
{
|
||||
for (;;) {
|
||||
switch (write(fd, &cmd, 1)) {
|
||||
case 1:
|
||||
debug2("xfermem_putcmd(%i, %i) = 1", fd, cmd);
|
||||
return (1);
|
||||
case -1:
|
||||
if (errno != EINTR)
|
||||
{
|
||||
debug3("xfermem_putcmd(%i, %i) = -1 (%s)"
|
||||
, fd, cmd, strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
There is a basic assumetry between reader and writer:
|
||||
The reader does work in periodic pieces and can be relied upon to
|
||||
eventually answer a call. It is important that it does not block
|
||||
for a significant duration unless it has really nothing to do.
|
||||
|
||||
The writer is more undefined in its behaviour, it is controlled by
|
||||
external agents. You cannot rely on it answering synchronization
|
||||
requests in a timely manner. But on the other hand, it can be left
|
||||
hanging for a while. The critical side is that of the reader.
|
||||
|
||||
Because of that, it is only sensible to provide a voluntary
|
||||
xfermem_writer_block() here. The reader does not need such a function.
|
||||
Only if it has nothing else to do, it will simply block on
|
||||
xfermem_getcmd(), and the writer promises to xfermem_putcmd() when
|
||||
something happens.
|
||||
|
||||
The writer always sends a wakeup command to the reader since the latter
|
||||
could be in the process of putting itself to sleep right now, without
|
||||
a flag indicating so being set yet.
|
||||
|
||||
The reader periodically reads from its file descriptor so that it does
|
||||
not get clogged up with pending messages. It will only (and always) send
|
||||
a wakeup call in response to a received command.
|
||||
*/
|
||||
|
||||
/* Wait a bit to get a sign of life from the reader.
|
||||
Returns -1 if even that did not work. */
|
||||
int xfermem_writer_block(txfermem *xf)
|
||||
{
|
||||
int myfd = xf->fd[XF_WRITER];
|
||||
int result;
|
||||
|
||||
xfermem_putcmd(myfd, XF_CMD_PING);
|
||||
result = xfermem_getcmd(myfd, TRUE);
|
||||
/* Only a pong to my ping is the expected good answer.
|
||||
Everything else is a problem to be communicated. */
|
||||
return (result == XF_CMD_PONG) ? 0 : result;
|
||||
}
|
||||
|
||||
/* Return: 0 on success, -1 on communication error, > 0 for
|
||||
error on buffer side, some special return code from buffer to be
|
||||
evaluated. */
|
||||
int xfermem_write(txfermem *xf, void *buffer, size_t bytes)
|
||||
{
|
||||
if(buffer == NULL || bytes < 1) return 0;
|
||||
|
||||
/* You weren't so braindead not allocating enough space at all, right? */
|
||||
while (xfermem_get_freespace(xf) < bytes)
|
||||
{
|
||||
int cmd = xfermem_writer_block(xf);
|
||||
if(cmd) /* Non-successful wait. */
|
||||
return cmd;
|
||||
}
|
||||
/* Now we have enough space. copy the memory, possibly with the wrap. */
|
||||
if(xf->size - xf->freeindex >= bytes)
|
||||
{ /* one block of free memory */
|
||||
memcpy(xf->data+xf->freeindex, buffer, bytes);
|
||||
}
|
||||
else
|
||||
{ /* two blocks */
|
||||
size_t endblock = xf->size - xf->freeindex;
|
||||
memcpy(xf->data+xf->freeindex, buffer, endblock);
|
||||
memcpy(xf->data, (char*)buffer + endblock, bytes-endblock);
|
||||
}
|
||||
/* Advance the free space pointer, including the wrap. */
|
||||
xf->freeindex = (xf->freeindex + bytes) % xf->size;
|
||||
/* Always notify the buffer process. */
|
||||
debug("write waking");
|
||||
return xfermem_putcmd(xf->fd[XF_WRITER], XF_CMD_DATA) < 0
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
86
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/xfermem.h
vendored
Normal file
86
libsdl2_mixer/external/mpg123-1.25.6/src/libout123/xfermem.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
xfermem: unidirectional fast pipe
|
||||
|
||||
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Oliver Fromme
|
||||
old timestamp: Sat Mar 29 04:41:34 MET 1997
|
||||
|
||||
This is a stand-alone module which implements a unidirectional,
|
||||
fast pipe using mmap(). Its primary use is to transfer large
|
||||
amounts of data from a parent process to its child process,
|
||||
with a buffer in between which decouples blocking conditions
|
||||
on both sides. Control information is transferred between the
|
||||
processes through a socketpair. See xftest.c for an example on
|
||||
how to use this module.
|
||||
|
||||
note: xftest not there anymore
|
||||
*/
|
||||
|
||||
#ifndef _XFERMEM_H_
|
||||
#define _XFERMEM_H_
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
typedef struct {
|
||||
size_t freeindex; /* [W] next free index */
|
||||
size_t readindex; /* [R] next index to read */
|
||||
int fd[2];
|
||||
char *data;
|
||||
char *metadata;
|
||||
size_t size;
|
||||
size_t metasize;
|
||||
} txfermem;
|
||||
/*
|
||||
* [W] -- May be written to by the writing process only!
|
||||
* [R] -- May be written to by the reading process only!
|
||||
* All other entries are initialized once.
|
||||
*/
|
||||
|
||||
void xfermem_init (txfermem **xf, size_t bufsize, size_t msize, size_t skipbuf);
|
||||
void xfermem_init_writer (txfermem *xf);
|
||||
void xfermem_init_reader (txfermem *xf);
|
||||
|
||||
size_t xfermem_get_freespace (txfermem *xf);
|
||||
size_t xfermem_get_usedspace (txfermem *xf);
|
||||
|
||||
/* Unless otherwise noted, each command demands a reponse if issued from the
|
||||
writer. The reader does not expect responses, only orders. */
|
||||
enum xf_cmd_code
|
||||
{
|
||||
XF_CMD_PING = 1 /**< Wake up and give a response, not changing any state. */
|
||||
, XF_CMD_PONG /**< The response to a ping. */
|
||||
, XF_CMD_DATA /**< Re-check the amount of data available without response. */
|
||||
, XF_CMD_TERMINATE /**< Stop operation. */
|
||||
, XF_CMD_DROP /**< Drop current buffer contents. */
|
||||
, XF_CMD_DRAIN /**< Consume current buffer contents now. */
|
||||
, XF_CMD_PAUSE /**< Pause operation, wait for next command. */
|
||||
, XF_CMD_CONTINUE /**< Continue operation. */
|
||||
, XF_CMD_IGNLOW /**< Ignore situation with low buffer fill. */
|
||||
, XF_CMD_OK /**< Response from reader: Operation succeeded. */
|
||||
, XF_CMD_ERROR /**< Response from reader: Operation failed. */
|
||||
, XF_CMD_CUSTOM1 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM2 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM3 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM4 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM5 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM6 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM7 /**< Some custom command to be filled with meaning. */
|
||||
, XF_CMD_CUSTOM8 /**< Some custom command to be filled with meaning. */
|
||||
};
|
||||
|
||||
#define XF_WRITER 0
|
||||
#define XF_READER 1
|
||||
int xfermem_getcmd(int fd, int block);
|
||||
int xfermem_getcmds(int fd, int block, byte* cmds, int count);
|
||||
int xfermem_putcmd(int fd, byte cmd);
|
||||
int xfermem_writer_block(txfermem *xf);
|
||||
/* returns TRUE for being interrupted */
|
||||
int xfermem_write(txfermem *xf, void *buffer, size_t bytes);
|
||||
|
||||
void xfermem_done (txfermem *xf);
|
||||
#define xfermem_done_writer xfermem_init_reader
|
||||
#define xfermem_done_reader xfermem_init_writer
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user