10 changed files with 602 additions and 144 deletions
File diff suppressed because it is too large
@ -0,0 +1,108 @@ |
|||
/*****************************************************************************
|
|||
* dsp.c : OSS /dev/dsp plugin for vlc |
|||
***************************************************************************** |
|||
* Copyright (C) 2000 VideoLAN |
|||
* |
|||
* Authors: |
|||
* Henri Fallon <henri@videolan.org> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
#include "defs.h" |
|||
|
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/asoundlib.h> /* for alsa :) */ |
|||
#include <fcntl.h> |
|||
#include <stdlib.h> /* malloc(), free() */ |
|||
// #include <unistd.h> /* close() */
|
|||
|
|||
#include "config.h" |
|||
#include "common.h" /* boolean_t, byte_t */ |
|||
#include "threads.h" |
|||
#include "mtime.h" |
|||
#include "tests.h" |
|||
#include "plugins.h" |
|||
|
|||
#include "interface.h" |
|||
#include "audio_output.h" |
|||
#include "video.h" |
|||
#include "video_output.h" |
|||
|
|||
#include "main.h" |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* Exported prototypes |
|||
*****************************************************************************/ |
|||
static void aout_GetPlugin( p_aout_thread_t p_aout ); |
|||
|
|||
/* Audio output */ |
|||
int aout_AlsaOpen ( aout_thread_t *p_aout ); |
|||
int aout_AlsaReset ( aout_thread_t *p_aout ); |
|||
int aout_AlsaSetFormat ( aout_thread_t *p_aout ); |
|||
int aout_AlsaSetChannels ( aout_thread_t *p_aout ); |
|||
int aout_AlsaSetRate ( aout_thread_t *p_aout ); |
|||
long aout_AlsaGetBufInfo ( aout_thread_t *p_aout, long l_buffer_info ); |
|||
void aout_AlsaPlaySamples ( aout_thread_t *p_aout, byte_t *buffer, |
|||
int i_size ); |
|||
void aout_AlsaClose ( aout_thread_t *p_aout ); |
|||
|
|||
/*****************************************************************************
|
|||
* GetConfig: get the plugin structure and configuration |
|||
*****************************************************************************/ |
|||
plugin_info_t * GetConfig( void ) |
|||
{ |
|||
int i_fd; |
|||
plugin_info_t * p_info = (plugin_info_t *) malloc( sizeof(plugin_info_t) ); |
|||
|
|||
p_info->psz_name = "Alsa plugin"; |
|||
p_info->psz_version = VERSION; |
|||
p_info->psz_author = "the VideoLAN team <vlc@videolan.org>"; |
|||
|
|||
p_info->aout_GetPlugin = aout_GetPlugin; |
|||
p_info->vout_GetPlugin = NULL; |
|||
p_info->intf_GetPlugin = NULL; |
|||
p_info->yuv_GetPlugin = NULL; |
|||
|
|||
|
|||
/* TODO : test if alsa is available */ |
|||
p_info->i_score = 0x100; |
|||
|
|||
/* If this plugin was requested, score it higher */ |
|||
if( TestMethod( AOUT_METHOD_VAR, "alsa" ) ) |
|||
{ |
|||
p_info->i_score += 0x200; |
|||
} |
|||
|
|||
return( p_info ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* Following functions are only called through the p_info structure |
|||
*****************************************************************************/ |
|||
|
|||
static void aout_GetPlugin( p_aout_thread_t p_aout ) |
|||
{ |
|||
p_aout->p_sys_open = aout_AlsaOpen; |
|||
p_aout->p_sys_reset = aout_AlsaReset; |
|||
p_aout->p_sys_setformat = aout_AlsaSetFormat; |
|||
p_aout->p_sys_setchannels = aout_AlsaSetChannels; |
|||
p_aout->p_sys_setrate = aout_AlsaSetRate; |
|||
p_aout->p_sys_getbufinfo = aout_AlsaGetBufInfo; |
|||
p_aout->p_sys_playsamples = aout_AlsaPlaySamples; |
|||
p_aout->p_sys_close = aout_AlsaClose; |
|||
} |
|||
@ -0,0 +1,328 @@ |
|||
/*****************************************************************************
|
|||
* aout_alsa.c : Alsa functions library |
|||
***************************************************************************** |
|||
* Copyright (C) 2000 VideoLAN |
|||
* |
|||
* Authors: |
|||
* Henri Fallon <henri@videolan.org> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program 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 General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program; if not, write to the Free Software |
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. |
|||
*****************************************************************************/ |
|||
|
|||
/*****************************************************************************
|
|||
* Preamble |
|||
*****************************************************************************/ |
|||
|
|||
#include "defs.h" |
|||
|
|||
#include <errno.h> /* ENOMEM */ |
|||
#include <fcntl.h> /* open(), O_WRONLY */ |
|||
#include <sys/ioctl.h> /* ioctl() */ |
|||
#include <string.h> /* strerror() */ |
|||
#include <unistd.h> /* write(), close() */ |
|||
#include <stdio.h> /* "intf_msg.h" */ |
|||
#include <stdlib.h> /* calloc(), malloc(), free() */ |
|||
|
|||
#include <sys/asoundlib.h> |
|||
#include <linux/asound.h> |
|||
|
|||
#include "config.h" |
|||
#include "common.h" /* boolean_t, byte_t */ |
|||
#include "threads.h" |
|||
#include "mtime.h" |
|||
#include "plugins.h" |
|||
|
|||
#include "audio_output.h" /* aout_thread_t */ |
|||
|
|||
#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */ |
|||
#include "main.h" |
|||
|
|||
|
|||
|
|||
|
|||
typedef struct alsa_device_s |
|||
{ |
|||
int i_num; |
|||
} alsa_device_t; |
|||
|
|||
typedef struct alsa_card_s |
|||
{ |
|||
int i_num; |
|||
} alsa_card_t; |
|||
|
|||
/* here we store plugin dependant informations */ |
|||
|
|||
typedef struct aout_sys_s |
|||
{ |
|||
snd_pcm_t * p_alsa_handle; |
|||
alsa_device_t * p_alsa_device; |
|||
alsa_card_t * p_alsa_card; |
|||
snd_pcm_channel_params_t s_alsa_channel_params; |
|||
snd_pcm_format_t s_alsa_format; |
|||
} aout_sys_t; |
|||
|
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaOpen : creates a handle and opens an alsa device |
|||
*****************************************************************************/ |
|||
|
|||
int aout_AlsaOpen( aout_thread_t *p_aout ) |
|||
{ |
|||
|
|||
int i_open_returns; |
|||
|
|||
/* Allocate structures */ |
|||
p_aout->p_sys = malloc( sizeof( aout_sys_t ) ); |
|||
if( p_aout->p_sys == NULL ) |
|||
{ |
|||
intf_ErrMsg("error: %s\n", strerror(ENOMEM) ); |
|||
return( 1 ); |
|||
} |
|||
|
|||
p_aout->p_sys->p_alsa_device = malloc( sizeof( alsa_device_t) ); |
|||
p_aout->p_sys->p_alsa_card = malloc( sizeof( alsa_device_t ) ); |
|||
if( ( p_aout->p_sys->p_alsa_device == NULL ) || |
|||
( p_aout->p_sys->p_alsa_card == NULL ) ) |
|||
{ |
|||
intf_ErrMsg ( "error: %s\n", strerror(ENOMEM) ); |
|||
return ( 1 ); |
|||
} |
|||
|
|||
/* Initialize */ |
|||
p_aout->p_sys->p_alsa_device->i_num = 0; |
|||
p_aout->p_sys->p_alsa_card->i_num = 0; |
|||
/* FIXME : why not other format ? */ |
|||
p_aout->i_format = AOUT_FMT_S16_LE; |
|||
/* FIXME : why always 2 channels ?*/ |
|||
p_aout->i_channels = 2; |
|||
p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR, AOUT_RATE_DEFAULT ); |
|||
|
|||
/* Open device */ |
|||
if ( ( i_open_returns = snd_pcm_open( &(p_aout->p_sys->p_alsa_handle), |
|||
p_aout->p_sys->p_alsa_card->i_num, |
|||
p_aout->p_sys->p_alsa_device->i_num, |
|||
SND_PCM_OPEN_PLAYBACK ) ) ) |
|||
{ |
|||
intf_ErrMsg ( "could not open alsa device; error code : %i\n", |
|||
i_open_returns ); |
|||
return ( 1 ); |
|||
} |
|||
|
|||
return ( 0 ); |
|||
|
|||
intf_ErrMsg("Alsa device open \n\n"); |
|||
} |
|||
|
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaSetFormat : sets the alsa output format |
|||
*****************************************************************************/ |
|||
|
|||
int aout_AlsaSetFormat ( aout_thread_t *p_aout ) |
|||
{ |
|||
|
|||
int i_set_param_returns; |
|||
int i_prepare_playback_returns; |
|||
int i_playback_go_returns; |
|||
|
|||
/* Fill with zeros */ |
|||
memset(&p_aout->p_sys->s_alsa_channel_params,0, |
|||
sizeof(p_aout->p_sys->s_alsa_channel_params)); |
|||
|
|||
/* Fill the s_alsa_channel_params structure */ |
|||
|
|||
/* Tranfer mode and direction*/ |
|||
p_aout->p_sys->s_alsa_channel_params.channel = SND_PCM_CHANNEL_PLAYBACK ; |
|||
p_aout->p_sys->s_alsa_channel_params.mode = SND_PCM_MODE_STREAM; |
|||
|
|||
/* Format and rate */ |
|||
p_aout->p_sys->s_alsa_channel_params.format.interleave = 1; |
|||
if ( p_aout->i_format == AOUT_FMT_S16_LE ) |
|||
p_aout->p_sys->s_alsa_channel_params.format.format = |
|||
SND_PCM_SFMT_S16_LE; |
|||
else |
|||
p_aout->p_sys->s_alsa_channel_params.format.format = |
|||
SND_PCM_SFMT_S16_BE; |
|||
|
|||
p_aout->p_sys->s_alsa_channel_params.format.rate = p_aout->l_rate; |
|||
p_aout->p_sys->s_alsa_channel_params.format.voices = p_aout->i_channels ; |
|||
|
|||
/* When to start playing and when to stop */ |
|||
p_aout->p_sys->s_alsa_channel_params.start_mode = SND_PCM_START_DATA; |
|||
p_aout->p_sys->s_alsa_channel_params.stop_mode = SND_PCM_STOP_STOP; |
|||
|
|||
/* Buffer information . I have chosen the stream mode here
|
|||
* instead of the block mode. I don't know whether i'm wrong |
|||
* but it seemed more logical */ |
|||
p_aout->p_sys->s_alsa_channel_params.buf.stream.queue_size = 131072; |
|||
/* Fill with silence */ |
|||
p_aout->p_sys->s_alsa_channel_params.buf.stream.fill = SND_PCM_FILL_NONE ; |
|||
p_aout->p_sys->s_alsa_channel_params.buf.stream.max_fill = 0 ; |
|||
|
|||
/* Now we pass this to the driver */ |
|||
i_set_param_returns = snd_pcm_channel_params ( |
|||
p_aout->p_sys->p_alsa_handle, |
|||
&(p_aout->p_sys->s_alsa_channel_params) ); |
|||
|
|||
if ( i_set_param_returns ) |
|||
{ |
|||
intf_ErrMsg ( "ALSA_PLUGIN : Unable to set parameters; exit = %i\n", |
|||
i_set_param_returns ); |
|||
intf_ErrMsg( "This means : %s\n\n", |
|||
snd_strerror( i_set_param_returns ) ); |
|||
return ( 1 ); |
|||
} |
|||
|
|||
/* we shall now prepare the channel */ |
|||
i_prepare_playback_returns = |
|||
snd_pcm_playback_prepare ( p_aout->p_sys->p_alsa_handle ); |
|||
|
|||
if ( i_prepare_playback_returns ) |
|||
{ |
|||
intf_ErrMsg ( "ALSA_PLUGIN : Unable to prepare channel : exit = %i\n", |
|||
i_prepare_playback_returns ); |
|||
intf_ErrMsg( "This means : %s\n\n", |
|||
snd_strerror( i_set_param_returns ) ); |
|||
|
|||
return ( 1 ); |
|||
} |
|||
|
|||
/* then we may go */ |
|||
i_playback_go_returns = |
|||
snd_pcm_playback_go ( p_aout->p_sys->p_alsa_handle ); |
|||
if ( i_playback_go_returns ) |
|||
{ |
|||
intf_ErrMsg ( "ALSA_PLUGIN : Unable to prepare channel (bis) : |
|||
exit = %i\n", i_playback_go_returns ); |
|||
intf_ErrMsg( "This means : %s\n\n", |
|||
snd_strerror( i_set_param_returns ) ); |
|||
return ( 1 ); |
|||
} |
|||
return ( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaReset: resets the dsp |
|||
*****************************************************************************/ |
|||
int aout_AlsaReset ( aout_thread_t *p_aout ) |
|||
{ |
|||
/* TODO : put something in here, such as close and open again
|
|||
* or check status, drain, flush, .... */ |
|||
return ( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaSetChannels: sets mono, stereo and other modes |
|||
*****************************************************************************/ |
|||
int aout_AlsaSetChannels ( aout_thread_t *p_aout ) |
|||
{ |
|||
/* TODO : normally, nothing
|
|||
* everything should be done in the AlsaSetFormat, as far a I understand |
|||
* the alsa documentation |
|||
*/ |
|||
return ( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaSetRate: sets the audio output rate |
|||
***************************************************************************** |
|||
* As in the previous function, the rate is supposed to be set in the |
|||
* AlsaSetFormat function |
|||
*****************************************************************************/ |
|||
int aout_AlsaSetRate ( aout_thread_t *p_aout ) |
|||
{ |
|||
return ( 0 ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaGetBufInfo: buffer status query |
|||
*****************************************************************************/ |
|||
long aout_AlsaGetBufInfo ( aout_thread_t *p_aout, long l_buffer_limit ) |
|||
{ |
|||
snd_pcm_channel_status_t alsa_channel_status; |
|||
int i_alsa_get_status_returns; |
|||
|
|||
memset (&alsa_channel_status, 0, sizeof(alsa_channel_status)); |
|||
i_alsa_get_status_returns = snd_pcm_channel_status ( |
|||
p_aout->p_sys->p_alsa_handle, &alsa_channel_status ); |
|||
|
|||
if ( i_alsa_get_status_returns ) |
|||
{ |
|||
intf_ErrMsg ( "Error getting alsa buffer info; exit=%i\n", |
|||
i_alsa_get_status_returns ); |
|||
intf_ErrMsg ( "This means : %s \n\n", |
|||
snd_strerror ( i_alsa_get_status_returns ) ); |
|||
return ( 1 ); |
|||
} |
|||
|
|||
switch (alsa_channel_status.status) |
|||
{ |
|||
case SND_PCM_STATUS_NOTREADY : intf_ErrMsg("Status NOT READY \n \n"); |
|||
break; |
|||
case SND_PCM_STATUS_UNDERRUN : { |
|||
int i_drain_returns; |
|||
intf_ErrMsg( |
|||
"Status UNDERRUN ... draining \n \n"); |
|||
i_drain_returns = |
|||
snd_pcm_playback_prepare( |
|||
p_aout->p_sys->p_alsa_handle ); |
|||
if ( i_drain_returns ) |
|||
{ |
|||
intf_ErrMsg( |
|||
"Error : could not flush : %i\n", |
|||
i_drain_returns); |
|||
intf_ErrMsg( |
|||
"This means : %s\n", |
|||
snd_strerror(i_drain_returns)); |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
return ( alsa_channel_status.count ); |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaPlaySamples |
|||
*****************************************************************************/ |
|||
void aout_AlsaPlaySamples ( aout_thread_t *p_aout, byte_t *buffer, int i_size ) |
|||
{ |
|||
int i_write_returns; |
|||
|
|||
i_write_returns = (int) snd_pcm_write ( |
|||
p_aout->p_sys->p_alsa_handle, (void *)buffer, (size_t) i_size ); |
|||
|
|||
if ( i_write_returns <= 0 ) |
|||
{ |
|||
intf_ErrMsg ( "Error writing blocks; exit=%i\n", i_write_returns ); |
|||
intf_ErrMsg ( "This means : %s\n", snd_strerror( i_write_returns ) ); |
|||
} |
|||
} |
|||
|
|||
/*****************************************************************************
|
|||
* aout_AlsaClose : close the Alsa device |
|||
*****************************************************************************/ |
|||
void aout_AlsaClose ( aout_thread_t *p_aout ) |
|||
{ |
|||
int i_close_returns; |
|||
|
|||
i_close_returns = snd_pcm_close ( p_aout->p_sys->p_alsa_handle ); |
|||
|
|||
if ( i_close_returns ) |
|||
{ |
|||
intf_ErrMsg( "Error closing alsa device; exit=%i\n",i_close_returns ); |
|||
intf_ErrMsg( "This means : %s\n\n",snd_strerror( i_close_returns ) ); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue