Commit b6f744a9 authored by Michael Smith's avatar Michael Smith
Browse files

ALSA input module from Jason Chu <jchu@uvic.ca>

svn path=/trunk/ices/; revision=4171
parent 96104680
......@@ -85,6 +85,16 @@ if test "$have_sun_audio" = yes; then
SUN_CFLAGS="-DHAVE_SUN_AUDIO"
fi
dnl Check for ALSA audio
AC_CHECK_HEADER(alsa/asoundlib.h, have_alsa=yes, have_alsa=no)
AM_CONDITIONAL(HAVE_ALSA,test "$have_alsa" = yes)
if test "$have_alsa" = yes; then
ALSA_CFLAGS="-DHAVE_ALSA"
ALSA_LIBS="-lasound"
fi
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
......@@ -131,6 +141,8 @@ dnl Make substitutions
AC_SUBST(OSS_CFLAGS)
AC_SUBST(SUN_CFLAGS)
AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)
AC_SUBST(SOCKET_LIBS)
AC_SUBST(XML_LIBS)
AC_SUBST(SHOUT_LIBS)
......
......@@ -16,25 +16,29 @@ sunsources = im_sun.c
endif
if HAVE_ALSA
alsaheaders = im_alsa.h
alsasources = im_alsa.c
endif
SUBDIRS = avl thread net log timing
bin_PROGRAMS = ices
noinst_HEADERS = config.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h $(ossheaders) $(sunheaders) event.h stream_shared.h metadata.h audio.h resample.h
ices_SOURCES = input.c config.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c $(osssources) $(sunsources) stream_shared.c savefile.c metadata.c stream_rewrite.c playlist_script.c audio.c resample.c
noinst_HEADERS = config.h input.h inputmodule.h im_playlist.h signals.h stream.h reencode.h encode.h playlist_basic.h logging.h im_stdinpcm.h $(ossheaders) $(sunheaders) $(alsaheaders) event.h stream_shared.h metadata.h audio.h resample.h
ices_SOURCES = input.c config.c stream.c ices.c signals.c im_playlist.c reencode.c encode.c playlist_basic.c im_stdinpcm.c $(osssources) $(sunsources) $(alsaheaders) stream_shared.c savefile.c metadata.c stream_rewrite.c playlist_script.c audio.c resample.c
ices_LDADD = net/libicenet.la thread/libicethread.la log/libicelog.la\
avl/libiceavl.la timing/libicetiming.la
LIBS = @LIBS@ -lpthread @SOCKET_LIBS@ @XML_LIBS@ @OGG_LIBS@ @VORBIS_LIBS@\
@VORBISENC_LIBS@ @SHOUT_LIBS@
@VORBISENC_LIBS@ @SHOUT_LIBS@ @ALSA_LIBS@
CFLAGS = @CFLAGS@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ @SHOUT_CFLAGS@
INCLUDES = -Inet -Ithread -Iavl -Ilog -Itiming $(OSS_CFLAGS) $(SUN_CFLAGS)
# SCCS stuff (for BitKeeper)
GET = true
INCLUDES = -Inet -Ithread -Iavl -Ilog -Itiming $(OSS_CFLAGS) $(SUN_CFLAGS) $(ALSA_CFLAGS)
debug:
$(MAKE) all CFLAGS="@DEBUG@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ @SHOUT_CFLAGS@"
......
/* im_alsa.c
* - Raw PCM input from ALSA devices
*
* $Id: im_alsa.c,v 1.1 2002/12/29 10:28:30 msmith Exp $
*
* by Jason Chu <jchu@uvic.ca>, based
* on im_oss.c which is...
* Copyright (c) 2001 Michael Smith <msmith@labyrinth.net.au>
*
* This program is distributed under the terms of the GNU General
* Public License, version 2. You may use, modify, and redistribute
* it under the terms of this license. A copy should be included
* with this source.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <ogg/ogg.h>
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include "thread.h"
#include "config.h"
#include "stream.h"
#include "metadata.h"
#include "inputmodule.h"
#include "im_alsa.h"
#define MODULE "input-alsa/"
#include "logging.h"
#define BUFSIZE 8192
static void close_module(input_module_t *mod)
{
if(mod)
{
if(mod->internal)
{
im_alsa_state *s = mod->internal;
if(s->fd != NULL)
snd_pcm_close(s->fd);
thread_mutex_destroy(&s->metadatalock);
free(s);
}
free(mod);
}
}
static int event_handler(input_module_t *mod, enum event_type ev, void *param)
{
im_alsa_state *s = mod->internal;
switch(ev)
{
case EVENT_SHUTDOWN:
close_module(mod);
break;
case EVENT_NEXTTRACK:
s->newtrack = 1;
break;
case EVENT_METADATAUPDATE:
thread_mutex_lock(&s->metadatalock);
if(s->metadata)
{
char **md = s->metadata;
while(*md)
free(*md++);
free(s->metadata);
}
s->metadata = (char **)param;
s->newtrack = 1;
thread_mutex_unlock(&s->metadatalock);
break;
default:
LOG_WARN1("Unhandled event %d", ev);
return -1;
}
return 0;
}
static void metadata_update(void *self, vorbis_comment *vc)
{
im_alsa_state *s = self;
char **md;
thread_mutex_lock(&s->metadatalock);
md = s->metadata;
if(md)
{
while(*md)
vorbis_comment_add(vc, *md++);
}
thread_mutex_unlock(&s->metadatalock);
}
/* Core streaming function for this module
* This is what actually produces the data which gets streamed.
*
* returns: >0 Number of bytes read
* 0 Non-fatal error.
* <0 Fatal error.
*/
static int alsa_read(void *self, ref_buffer *rb)
{
int result;
im_alsa_state *s = self;
rb->buf = malloc(BUFSIZE*2*s->channels);
if(!rb->buf)
return -1;
result = snd_pcm_readi(s->fd, rb->buf, BUFSIZE>>2);
rb->len = result*4;
rb->aux_data = s->rate*s->channels*2;
if(s->newtrack)
{
rb->critical = 1;
s->newtrack = 0;
}
if (result == -EPIPE)
{
snd_pcm_prepare(s->fd);
return 0;
}
else if (result == -EBADFD)
{
LOG_ERROR0("Bad descriptor passed to snd_pcm_readi");
free(rb->buf);
return -1;
}
return rb->len;
}
input_module_t *alsa_open_module(module_param_t *params)
{
input_module_t *mod = calloc(1, sizeof(input_module_t));
im_alsa_state *s;
module_param_t *current;
char *device = "plughw:0,0"; /* default device */
int format = AFMT_S16_LE;
int channels, rate;
int use_metadata = 1; /* Default to on */
snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
snd_pcm_hw_params_t *hwparams;
int err;
mod->type = ICES_INPUT_PCM;
mod->subtype = INPUT_PCM_LE_16;
mod->getdata = alsa_read;
mod->handle_event = event_handler;
mod->metadata_update = metadata_update;
mod->internal = calloc(1, sizeof(im_alsa_state));
s = mod->internal;
s->fd = NULL; /* Set it to something invalid, for now */
s->rate = 44100; /* Defaults */
s->channels = 2;
thread_mutex_create(&s->metadatalock);
current = params;
while(current)
{
if(!strcmp(current->name, "rate"))
s->rate = atoi(current->value);
else if(!strcmp(current->name, "channels"))
s->channels = atoi(current->value);
else if(!strcmp(current->name, "device"))
device = current->value;
else if(!strcmp(current->name, "metadata"))
use_metadata = atoi(current->value);
else if(!strcmp(current->name, "metadatafilename"))
ices_config->metadata_filename = current->value;
else
LOG_WARN1("Unknown parameter %s for alsa module", current->name);
current = current->next;
}
snd_pcm_hw_params_alloca(&hwparams);
if ((err = snd_pcm_open(&s->fd, device, stream, 0)) < 0)
{
LOG_ERROR2("Failed to open audio device %s: %s", device, snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params_any(s->fd, hwparams)) < 0)
{
LOG_ERROR1("Failed to initialize hwparams: %s", snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params_set_access(s->fd, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
LOG_ERROR1("Error setting access: %s", snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params_set_format(s->fd, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
{
LOG_ERROR1("Couldn't set sample format to SND_PCM_FORMAT_S16_LE: %s", snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params_set_rate_near(s->fd, hwparams, s->rate, 0)) < 0)
{
LOG_ERROR1("Error setting rate: %s", snd_strerror(err));
goto fail;
}
s->rate = snd_pcm_hw_params_get_rate(hwparams, 0);
if ((err = snd_pcm_hw_params_set_channels(s->fd, hwparams, s->channels)) < 0)
{
LOG_ERROR1("Error setting channels: %s", snd_strerror(err));
goto fail;
}
s->channels = snd_pcm_hw_params_get_channels(hwparams);
if ((err = snd_pcm_hw_params_set_periods(s->fd, hwparams, 2, 0)) < 0)
{
LOG_ERROR1("Error setting periods: %s", snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params_set_buffer_size_near(s->fd, hwparams, (BUFSIZE * 2)>>2)) < 0)
{
LOG_ERROR1("Error setting buffersize: %s", snd_strerror(err));
goto fail;
}
if ((err = snd_pcm_hw_params(s->fd, hwparams)) < 0)
{
LOG_ERROR1("Error setting HW params: %s", snd_strerror(err));
goto fail;
}
/* We're done, and we didn't fail! */
LOG_INFO3("Opened audio device %s at %d channel(s), %d Hz",
device, s->channels, s->rate);
if(use_metadata)
{
if(ices_config->metadata_filename)
thread_create("im_alsa-metadata", metadata_thread_signal, mod, 1);
else
thread_create("im_alsa-metadata", metadata_thread_stdin, mod, 1);
LOG_INFO0("Started metadata update thread");
}
return mod;
fail:
close_module(mod); /* safe, this checks for valid contents */
return NULL;
}
/* im_alsa.h
* - read pcm data from oss devices
*
* $Id: im_alsa.h,v 1.1 2002/12/29 10:28:30 msmith Exp $
*
* by Jason Chu <jchu@uvic.ca>, based
* on im_oss.c which is...
* Copyright (c) 2001 Michael Smith <msmith@labyrinth.net.au>
*
* This program is distributed under the terms of the GNU General
* Public License, version 2. You may use, modify, and redistribute
* it under the terms of this license. A copy should be included
* with this source.
*/
#ifndef __IM_ALSA_H__
#define __IM_ALSA_H__
#include <alsa/asoundlib.h>
#include "inputmodule.h"
#include "thread.h"
#include <ogg/ogg.h>
typedef struct
{
int rate;
int channels;
snd_pcm_t *fd;
char **metadata;
int newtrack;
mutex_t metadatalock;
} im_alsa_state;
input_module_t *alsa_open_module(module_param_t *params);
#endif /* __IM_ALSA */
......@@ -2,7 +2,7 @@
* - Main producer control loop. Fetches data from input modules, and controls
* submission of these to the instance threads. Timing control happens here.
*
* $Id: input.c,v 1.18 2002/11/22 13:01:34 msmith Exp $
* $Id: input.c,v 1.19 2002/12/29 10:28:30 msmith Exp $
*
* Copyright (c) 2001 Michael Smith <msmith@labyrinth.net.au>
*
......@@ -40,6 +40,10 @@
#include "im_sun.h"
#endif
#ifdef HAVE_ALSA
#include "im_alsa.h"
#endif
#ifdef _WIN32
typedef __int64 int64_t
typedef unsigned __int64 uint64_t
......@@ -74,6 +78,9 @@ static module modules[] = {
#endif
#ifdef HAVE_SUN_AUDIO
{ "sun", sun_open_module},
#endif
#ifdef HAVE_ALSA
{ "alsa", alsa_open_module},
#endif
{NULL,NULL}
};
......
/* registry.h
* - Registry of input/output/processing modules.
*
* $Id: registry.h,v 1.2 2002/02/09 05:07:01 msmith Exp $
* $Id: registry.h,v 1.3 2002/12/29 10:28:30 msmith Exp $
*
* Copyright (c) 2001-2002 Michael Smith <msmith@labyrinth.net.au>
*
......@@ -25,6 +25,10 @@
#include "im_oss.h"
#endif
#ifdef HAVE_ALSA
#include "im_alsa.h"
#endif
/*
#ifdef HAVE_SUN_AUDIO
#include "im_sun.h"
......@@ -50,6 +54,9 @@ static module registered_modules[] = {
#endif
#ifdef HAVE_SUN_AUDIO
{ "sun", sun_open_module},
#endif
#ifdef HAVE_ALSA
{ "alsa", alsa_open_module},
#endif
{NULL,NULL}
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment