You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
641 lines
18 KiB
641 lines
18 KiB
/*
|
|
The mediastreamer library aims at providing modular media processing and I/O
|
|
for linphone, but also for any telephony application.
|
|
Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "alsacard.h"
|
|
|
|
#ifdef HAVE_ALSA_ASOUNDLIB_H
|
|
|
|
static gchar *over_pcmdev=NULL;
|
|
|
|
#include "msossread.h"
|
|
#include "msosswrite.h"
|
|
|
|
#include <signal.h>
|
|
|
|
int __alsa_card_write(AlsaCard *obj,char *buf,int size);
|
|
|
|
int alsa_set_params(AlsaCard *obj, int rw, int bits, int stereo, int rate)
|
|
{
|
|
snd_pcm_hw_params_t *hwparams=NULL;
|
|
snd_pcm_sw_params_t *swparams=NULL;
|
|
snd_pcm_t *pcm_handle;
|
|
gint dir,exact_value;
|
|
gint channels;
|
|
gint fsize=0;
|
|
gint periods=8;
|
|
gint periodsize=256;
|
|
gint err;
|
|
int format;
|
|
|
|
if (rw) {
|
|
pcm_handle=obj->write_handle;
|
|
}
|
|
else pcm_handle=obj->read_handle;
|
|
|
|
/* Allocate the snd_pcm_hw_params_t structure on the stack. */
|
|
snd_pcm_hw_params_alloca(&hwparams);
|
|
|
|
/* Init hwparams with full configuration space */
|
|
if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
|
|
g_warning("alsa_set_params: Cannot configure this PCM device.\n");
|
|
return(-1);
|
|
}
|
|
|
|
if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
|
|
g_warning("alsa_set_params: Error setting access.\n");
|
|
return(-1);
|
|
}
|
|
/* Set sample format */
|
|
#ifdef WORDS_BIGENDIAN
|
|
format=SND_PCM_FORMAT_S16_BE;
|
|
#else
|
|
format=SND_PCM_FORMAT_S16_LE;
|
|
#endif
|
|
if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {
|
|
g_warning("alsa_set_params: Error setting format.\n");
|
|
return(-1);
|
|
}
|
|
/* Set number of channels */
|
|
if (stereo) channels=2;
|
|
else channels=1;
|
|
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {
|
|
g_warning("alsa_set_params: Error setting channels.\n");
|
|
return(-1);
|
|
}
|
|
/* Set sample rate. If the exact rate is not supported */
|
|
/* by the hardware, use nearest possible rate. */
|
|
exact_value=rate;
|
|
dir=0;
|
|
if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_value, &dir))<0){
|
|
g_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));
|
|
return -1;
|
|
}
|
|
if (dir != 0) {
|
|
g_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "
|
|
"==> Using %d Hz instead.\n", rate, exact_value);
|
|
}
|
|
/* choose greater period size when rate is high */
|
|
periodsize=periodsize*(rate/8000);
|
|
|
|
/* Set buffer size (in frames). The resulting latency is given by */
|
|
/* latency = periodsize * periods / (rate * bytes_per_frame) */
|
|
/*
|
|
fsize=periodsize * periods;
|
|
exact_value=fsize;
|
|
if ((err=snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,&exact_value)) < 0) {
|
|
g_warning("alsa_set_params: Error setting buffer size:%s",snd_strerror(err));
|
|
return(-1);
|
|
}
|
|
if (fsize!= exact_value) {
|
|
g_warning("alsa_set_params: The buffer size %d is not supported by your hardware.\n "
|
|
"==> Using %d instead.\n", fsize, exact_value);
|
|
}
|
|
*/
|
|
/* set period size */
|
|
exact_value=periodsize;
|
|
dir=0;
|
|
if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
|
|
g_warning("alsa_set_params: Error setting period size.\n");
|
|
return(-1);
|
|
}
|
|
if (dir != 0) {
|
|
g_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "
|
|
"==> Using %d instead.\n", periodsize, exact_value);
|
|
}
|
|
periodsize=exact_value;
|
|
/* Set number of periods. Periods used to be called fragments. */
|
|
exact_value=periods;
|
|
dir=0;
|
|
if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_value, &dir) < 0) {
|
|
g_warning("alsa_set_params: Error setting periods.\n");
|
|
return(-1);
|
|
}
|
|
if (dir != 0) {
|
|
g_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "
|
|
"==> Using %d instead.\n", periods, exact_value);
|
|
}
|
|
/* Apply HW parameter settings to */
|
|
/* PCM device and prepare device */
|
|
if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
|
|
g_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));
|
|
return(-1);
|
|
}
|
|
/*prepare sw params */
|
|
if (rw){
|
|
snd_pcm_sw_params_alloca(&swparams);
|
|
snd_pcm_sw_params_current(pcm_handle, swparams);
|
|
if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){
|
|
g_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));
|
|
return -1;
|
|
}
|
|
if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){
|
|
g_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));
|
|
return(-1);
|
|
}
|
|
}
|
|
obj->frame_size=channels*(bits/8);
|
|
SND_CARD(obj)->bsize=periodsize*obj->frame_size;
|
|
/* //SND_CARD(obj)->bsize=4096; */
|
|
obj->frames=periodsize;
|
|
g_message("alsa_set_params: blocksize=%i.",SND_CARD(obj)->bsize);
|
|
return SND_CARD(obj)->bsize;
|
|
}
|
|
|
|
int alsa_card_open_r(AlsaCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
int bsize;
|
|
int err;
|
|
snd_pcm_t *pcm_handle;
|
|
gchar *pcmdev;
|
|
if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
|
|
else pcmdev=obj->pcmdev;
|
|
|
|
if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {
|
|
g_warning("alsa_card_open_r: Error opening PCM device %s\n",obj->pcmdev );
|
|
return -1;
|
|
}
|
|
g_return_val_if_fail(pcm_handle!=NULL,-1);
|
|
obj->read_handle=pcm_handle;
|
|
if ((bsize=alsa_set_params(obj,0,bits,stereo,rate))<0){
|
|
snd_pcm_close(pcm_handle);
|
|
obj->read_handle=NULL;
|
|
return -1;
|
|
}
|
|
obj->readbuf=g_malloc0(bsize);
|
|
|
|
err=snd_pcm_start(obj->read_handle);
|
|
if (err<0){
|
|
g_warning("Cannot start read pcm: %s", snd_strerror(err));
|
|
}
|
|
obj->readpos=0;
|
|
SND_CARD(obj)->bsize=bsize;
|
|
SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
|
|
return 0;
|
|
}
|
|
|
|
int alsa_card_open_w(AlsaCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
int err,bsize;
|
|
snd_pcm_t *pcm_handle;
|
|
gchar *pcmdev;
|
|
if (over_pcmdev!=NULL) pcmdev=over_pcmdev;
|
|
else pcmdev=obj->pcmdev;
|
|
|
|
if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {
|
|
g_warning("alsa_card_open_w: Error opening PCM device %s\n", obj->pcmdev);
|
|
return -1;
|
|
}
|
|
obj->write_handle=pcm_handle;
|
|
if ((bsize=alsa_set_params(obj,1,bits,stereo,rate))<0){
|
|
snd_pcm_close(pcm_handle);
|
|
obj->write_handle=NULL;
|
|
return -1;
|
|
}
|
|
obj->writebuf=g_malloc0(bsize);
|
|
|
|
obj->writepos=0;
|
|
SND_CARD(obj)->bsize=bsize;
|
|
SND_CARD(obj)->flags|=SND_CARD_FLAGS_OPENED;
|
|
return 0;
|
|
}
|
|
|
|
|
|
void alsa_card_set_blocking_mode(AlsaCard *obj, gboolean yesno){
|
|
if (obj->read_handle!=NULL) snd_pcm_nonblock(obj->read_handle,!yesno);
|
|
if (obj->write_handle!=NULL) snd_pcm_nonblock(obj->write_handle,!yesno);
|
|
}
|
|
|
|
void alsa_card_close_r(AlsaCard *obj)
|
|
{
|
|
if (obj->read_handle!=NULL){
|
|
snd_pcm_close(obj->read_handle);
|
|
obj->read_handle=NULL;
|
|
g_free(obj->readbuf);
|
|
obj->readbuf=NULL;
|
|
}
|
|
}
|
|
|
|
void alsa_card_close_w(AlsaCard *obj)
|
|
{
|
|
if (obj->write_handle!=NULL){
|
|
snd_pcm_close(obj->write_handle);
|
|
obj->write_handle=NULL;
|
|
g_free(obj->writebuf);
|
|
obj->writebuf=NULL;
|
|
}
|
|
}
|
|
|
|
int alsa_card_probe(AlsaCard *obj,int bits,int stereo,int rate)
|
|
{
|
|
int ret;
|
|
ret=alsa_card_open_w(obj,bits,stereo,rate);
|
|
if (ret<0) return -1;
|
|
ret=SND_CARD(obj)->bsize;
|
|
alsa_card_close_w(obj);
|
|
return ret;
|
|
}
|
|
|
|
|
|
void alsa_card_destroy(AlsaCard *obj)
|
|
{
|
|
snd_card_uninit(SND_CARD(obj));
|
|
g_free(obj->pcmdev);
|
|
if (obj->readbuf!=0) g_free(obj->readbuf);
|
|
if (obj->writebuf!=0) g_free(obj->writebuf);
|
|
}
|
|
|
|
gboolean alsa_card_can_read(AlsaCard *obj)
|
|
{
|
|
int frames;
|
|
g_return_val_if_fail(obj->read_handle!=NULL,0);
|
|
if (obj->readpos!=0) return TRUE;
|
|
if ( frames=snd_pcm_avail_update(obj->read_handle)>=obj->frames) return 1;
|
|
/* //g_message("frames=%i",frames); */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int __alsa_card_read(AlsaCard *obj,char *buf,int bsize)
|
|
{
|
|
int err;
|
|
sigset_t set;
|
|
sigemptyset(&set);
|
|
sigaddset(&set,SIGALRM);
|
|
sigprocmask(SIG_BLOCK,&set,NULL);
|
|
err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
|
|
if (err<0) {
|
|
if (err!=-EPIPE){
|
|
g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
|
|
}
|
|
snd_pcm_prepare(obj->read_handle);
|
|
err=snd_pcm_readi(obj->read_handle,buf,bsize/obj->frame_size);
|
|
if (err<0) g_warning("alsa_card_read: snd_pcm_readi() failed:%s.",snd_strerror(err));
|
|
}
|
|
sigprocmask(SIG_UNBLOCK,&set,NULL);
|
|
return err*obj->frame_size;
|
|
}
|
|
|
|
int alsa_card_read(AlsaCard *obj,char *buf,int size)
|
|
{
|
|
int err;
|
|
gint bsize=SND_CARD(obj)->bsize;
|
|
g_return_val_if_fail(obj->read_handle!=NULL,-1);
|
|
if (size<bsize){
|
|
gint canread=MIN(bsize-obj->readpos,size);
|
|
|
|
if (obj->readpos==0){
|
|
err=__alsa_card_read(obj,obj->readbuf,bsize);
|
|
}
|
|
|
|
memcpy(buf,&obj->readbuf[obj->readpos],canread);
|
|
obj->readpos+=canread;
|
|
if (obj->readpos>=bsize) obj->readpos=0;
|
|
return canread;
|
|
}else{
|
|
err=__alsa_card_read(obj,buf,size);
|
|
return err;
|
|
}
|
|
|
|
}
|
|
|
|
int __alsa_card_write(AlsaCard *obj,char *buf,int size)
|
|
{
|
|
int err;
|
|
sigset_t set;
|
|
sigemptyset(&set);
|
|
sigaddset(&set,SIGALRM);
|
|
sigprocmask(SIG_BLOCK,&set,NULL);
|
|
if ((err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size))<0){
|
|
if (err!=-EPIPE){
|
|
g_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));
|
|
}
|
|
snd_pcm_prepare(obj->write_handle);
|
|
err=snd_pcm_writei(obj->write_handle,buf,size/obj->frame_size);
|
|
if (err<0) g_warning("alsa_card_write: Error writing sound buffer (size=%i):%s",size,snd_strerror(err));
|
|
|
|
}
|
|
sigprocmask(SIG_UNBLOCK,&set,NULL);
|
|
return err;
|
|
}
|
|
|
|
int alsa_card_write(AlsaCard *obj,char *buf,int size)
|
|
{
|
|
int err;
|
|
gint bsize=SND_CARD(obj)->bsize;
|
|
g_return_val_if_fail(obj->write_handle!=NULL,-1);
|
|
if (size<bsize){
|
|
gint canwrite;
|
|
|
|
canwrite=MIN(bsize-obj->writepos,size);
|
|
memcpy(&obj->writebuf[obj->writepos],buf,canwrite);
|
|
obj->writepos+=canwrite;
|
|
if (obj->writepos>=bsize){
|
|
err=__alsa_card_write(obj,obj->writebuf,bsize);
|
|
obj->writepos=0;
|
|
}
|
|
return canwrite;
|
|
}else{
|
|
return __alsa_card_write(obj,buf,bsize);
|
|
}
|
|
}
|
|
|
|
snd_mixer_t *alsa_mixer_open(AlsaCard *obj){
|
|
snd_mixer_t *mixer=NULL;
|
|
int err;
|
|
err=snd_mixer_open(&mixer,0);
|
|
if (err<0){
|
|
g_warning("Could not open alsa mixer: %s",snd_strerror(err));
|
|
return NULL;
|
|
}
|
|
if ((err = snd_mixer_attach (mixer, obj->mixdev)) < 0){
|
|
g_warning("Could not attach mixer to card: %s",snd_strerror(err));
|
|
snd_mixer_close(mixer);
|
|
return NULL;
|
|
}
|
|
if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){
|
|
g_warning("snd_mixer_selem_register: %s",snd_strerror(err));
|
|
snd_mixer_close(mixer);
|
|
return NULL;
|
|
}
|
|
if ((err = snd_mixer_load (mixer)) < 0){
|
|
g_warning("snd_mixer_load: %s",snd_strerror(err));
|
|
snd_mixer_close(mixer);
|
|
return NULL;
|
|
}
|
|
obj->mixer=mixer;
|
|
return mixer;
|
|
}
|
|
|
|
void alsa_mixer_close(AlsaCard *obj){
|
|
snd_mixer_close(obj->mixer);
|
|
obj->mixer=NULL;
|
|
}
|
|
|
|
typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;
|
|
|
|
static gint get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){
|
|
long value=0;
|
|
const char *elemname;
|
|
snd_mixer_elem_t *elem;
|
|
int err;
|
|
long sndMixerPMin;
|
|
long sndMixerPMax;
|
|
long newvol;
|
|
elem=snd_mixer_first_elem(mixer);
|
|
while (elem!=NULL){
|
|
elemname=snd_mixer_selem_get_name(elem);
|
|
/* //g_message("Found alsa mixer element %s.",elemname); */
|
|
if (strcmp(elemname,name)==0){
|
|
switch (action){
|
|
case CAPTURE:
|
|
if (snd_mixer_selem_has_capture_volume(elem)){
|
|
snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
|
|
err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);
|
|
newvol-=sndMixerPMin;
|
|
value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
|
|
if (err<0) g_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));
|
|
/* //else g_message("Succesfully get capture level for %s.",elemname); */
|
|
break;
|
|
}
|
|
break;
|
|
case PLAYBACK:
|
|
if (snd_mixer_selem_has_playback_volume(elem)){
|
|
snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
|
|
err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);
|
|
newvol-=sndMixerPMin;
|
|
value=(100*newvol)/(sndMixerPMax-sndMixerPMin);
|
|
if (err<0) g_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));
|
|
/* //else g_message("Succesfully get playback level for %s.",elemname); */
|
|
break;
|
|
}
|
|
break;
|
|
case CAPTURE_SWITCH:
|
|
|
|
break;
|
|
}
|
|
}
|
|
elem=snd_mixer_elem_next(elem);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
static void set_mixer_element(snd_mixer_t *mixer,const char *name, gint level,MixerAction action){
|
|
const char *elemname;
|
|
snd_mixer_elem_t *elem;
|
|
int tmp;
|
|
long sndMixerPMin;
|
|
long sndMixerPMax;
|
|
long newvol;
|
|
|
|
elem=snd_mixer_first_elem(mixer);
|
|
|
|
while (elem!=NULL){
|
|
elemname=snd_mixer_selem_get_name(elem);
|
|
/* //g_message("Found alsa mixer element %s.",elemname); */
|
|
if (strcmp(elemname,name)==0){
|
|
switch(action){
|
|
case CAPTURE:
|
|
if (snd_mixer_selem_has_capture_volume(elem)){
|
|
snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
|
|
newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
|
|
snd_mixer_selem_set_capture_volume_all(elem,newvol);
|
|
/* //g_message("Succesfully set capture level for %s.",elemname); */
|
|
return;
|
|
}
|
|
break;
|
|
case PLAYBACK:
|
|
if (snd_mixer_selem_has_playback_volume(elem)){
|
|
snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);
|
|
newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;
|
|
snd_mixer_selem_set_playback_volume_all(elem,newvol);
|
|
/* //g_message("Succesfully set playback level for %s.",elemname); */
|
|
return;
|
|
}
|
|
break;
|
|
case CAPTURE_SWITCH:
|
|
if (snd_mixer_selem_has_capture_switch(elem)){
|
|
snd_mixer_selem_set_capture_switch_all(elem,level);
|
|
/* //g_message("Succesfully set capture switch for %s.",elemname); */
|
|
}
|
|
break;
|
|
case PLAYBACK_SWITCH:
|
|
if (snd_mixer_selem_has_playback_switch(elem)){
|
|
snd_mixer_selem_set_playback_switch_all(elem,level);
|
|
/* //g_message("Succesfully set capture switch for %s.",elemname); */
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
elem=snd_mixer_elem_next(elem);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
void alsa_card_set_level(AlsaCard *obj,gint way,gint a)
|
|
{
|
|
snd_mixer_t *mixer;
|
|
mixer=alsa_mixer_open(obj);
|
|
if (mixer==NULL) return ;
|
|
switch(way){
|
|
case SND_CARD_LEVEL_GENERAL:
|
|
set_mixer_element(mixer,"Master",a,PLAYBACK);
|
|
break;
|
|
case SND_CARD_LEVEL_INPUT:
|
|
set_mixer_element(mixer,"Capture",a,CAPTURE);
|
|
break;
|
|
case SND_CARD_LEVEL_OUTPUT:
|
|
set_mixer_element(mixer,"PCM",a,PLAYBACK);
|
|
break;
|
|
default:
|
|
g_warning("oss_card_set_level: unsupported command.");
|
|
}
|
|
alsa_mixer_close(obj);
|
|
}
|
|
|
|
gint alsa_card_get_level(AlsaCard *obj,gint way)
|
|
{
|
|
snd_mixer_t *mixer;
|
|
gint value;
|
|
mixer=alsa_mixer_open(obj);
|
|
if (mixer==NULL) return 0;
|
|
switch(way){
|
|
case SND_CARD_LEVEL_GENERAL:
|
|
value=get_mixer_element(mixer,"Master",PLAYBACK);
|
|
break;
|
|
case SND_CARD_LEVEL_INPUT:
|
|
value=get_mixer_element(mixer,"Capture",CAPTURE);
|
|
break;
|
|
case SND_CARD_LEVEL_OUTPUT:
|
|
value=get_mixer_element(mixer,"PCM",PLAYBACK);
|
|
break;
|
|
default:
|
|
g_warning("oss_card_set_level: unsupported command.");
|
|
}
|
|
alsa_mixer_close(obj);
|
|
return value;
|
|
}
|
|
|
|
void alsa_card_set_source(AlsaCard *obj,int source)
|
|
{
|
|
snd_mixer_t *mixer;
|
|
mixer=alsa_mixer_open(obj);
|
|
if (mixer==NULL) return;
|
|
switch (source){
|
|
case 'm':
|
|
set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);
|
|
set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
|
|
break;
|
|
case 'l':
|
|
set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);
|
|
set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
MSFilter *alsa_card_create_read_filter(AlsaCard *card)
|
|
{
|
|
MSFilter *f=ms_oss_read_new();
|
|
ms_oss_read_set_device(MS_OSS_READ(f),SND_CARD(card)->index);
|
|
return f;
|
|
}
|
|
|
|
MSFilter *alsa_card_create_write_filter(AlsaCard *card)
|
|
{
|
|
MSFilter *f=ms_oss_write_new();
|
|
ms_oss_write_set_device(MS_OSS_WRITE(f),SND_CARD(card)->index);
|
|
return f;
|
|
}
|
|
|
|
|
|
SndCard * alsa_card_new(gint devid)
|
|
{
|
|
AlsaCard * obj;
|
|
SndCard *base;
|
|
int err;
|
|
gchar *name=NULL;
|
|
|
|
/* carefull: this is an alsalib call despite its name! */
|
|
err=snd_card_get_name(devid,&name);
|
|
if (err<0) {
|
|
return NULL;
|
|
}
|
|
obj= g_new0(AlsaCard,1);
|
|
base= SND_CARD(obj);
|
|
snd_card_init(base);
|
|
|
|
base->card_name=g_strdup_printf("%s (Advanced Linux Sound Architecture)",name);
|
|
base->_probe=(SndCardOpenFunc)alsa_card_probe;
|
|
base->_open_r=(SndCardOpenFunc)alsa_card_open_r;
|
|
base->_open_w=(SndCardOpenFunc)alsa_card_open_w;
|
|
base->_can_read=(SndCardPollFunc)alsa_card_can_read;
|
|
base->_set_blocking_mode=(SndCardSetBlockingModeFunc)alsa_card_set_blocking_mode;
|
|
base->_read=(SndCardIOFunc)alsa_card_read;
|
|
base->_write=(SndCardIOFunc)alsa_card_write;
|
|
base->_close_r=(SndCardCloseFunc)alsa_card_close_r;
|
|
base->_close_w=(SndCardCloseFunc)alsa_card_close_w;
|
|
base->_set_rec_source=(SndCardMixerSetRecSourceFunc)alsa_card_set_source;
|
|
base->_set_level=(SndCardMixerSetLevelFunc)alsa_card_set_level;
|
|
base->_get_level=(SndCardMixerGetLevelFunc)alsa_card_get_level;
|
|
base->_destroy=(SndCardDestroyFunc)alsa_card_destroy;
|
|
base->_create_read_filter=(SndCardCreateFilterFunc)alsa_card_create_read_filter;
|
|
base->_create_write_filter=(SndCardCreateFilterFunc)alsa_card_create_write_filter;
|
|
|
|
|
|
obj->pcmdev=g_strdup_printf("plughw:%i,0",devid);
|
|
obj->mixdev=g_strdup_printf("hw:%i",devid);
|
|
obj->readbuf=NULL;
|
|
obj->writebuf=NULL;
|
|
return base;
|
|
}
|
|
|
|
|
|
gint alsa_card_manager_init(SndCardManager *m, gint index)
|
|
{
|
|
gint devindex;
|
|
gint i;
|
|
gint found=0;
|
|
gchar *name=NULL;
|
|
for(devindex=0;index<MAX_SND_CARDS && devindex<MAX_SND_CARDS ;devindex++){
|
|
if (snd_card_get_name(devindex,&name)==0){
|
|
g_message("Found ALSA device: %s",name);
|
|
m->cards[index]=alsa_card_new(devindex);
|
|
m->cards[index]->index=index;
|
|
found++;
|
|
index++;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
void alsa_card_manager_set_default_pcm_device(const gchar *pcmdev){
|
|
if (over_pcmdev!=NULL){
|
|
g_free(over_pcmdev);
|
|
}
|
|
over_pcmdev=g_strdup(pcmdev);
|
|
}
|
|
|
|
#endif
|