]> git.sesse.net Git - vlc/blob - plugins/dsp/aout_dsp.c
* ./plugins/macosx/intf_vlc_wrapper.m: fix for non-ASCII filenames in the
[vlc] / plugins / dsp / aout_dsp.c
1 /*****************************************************************************
2  * aout_dsp.c : dsp functions library
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: aout_dsp.c,v 1.27 2002/04/23 14:16:20 sam Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /* TODO:
26  *
27  * - an aout_GetFormats() function
28  * - dsp inline/static
29  * - make this library portable (see mpg123)
30  *
31  */
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 #include <errno.h>                                                 /* ENOMEM */
37 #include <fcntl.h>                                       /* open(), O_WRONLY */
38 #include <sys/ioctl.h>                                            /* ioctl() */
39 #include <string.h>                                            /* strerror() */
40 #include <unistd.h>                                      /* write(), close() */
41 #include <stdio.h>                                           /* "intf_msg.h" */
42 #include <stdlib.h>                            /* calloc(), malloc(), free() */
43
44 #include <videolan/vlc.h>
45
46 /* SNDCTL_DSP_RESET, SNDCTL_DSP_SETFMT, SNDCTL_DSP_STEREO, SNDCTL_DSP_SPEED,
47  * SNDCTL_DSP_GETOSPACE */
48 #ifdef HAVE_SOUNDCARD_H
49 #   include <soundcard.h>
50 #elif defined( HAVE_SYS_SOUNDCARD_H )
51 #   include <sys/soundcard.h>
52 #elif defined( HAVE_MACHINE_SOUNDCARD_H )
53 #   include <machine/soundcard.h>
54 #endif
55
56 #include "audio_output.h"                                   /* aout_thread_t */
57
58 /*****************************************************************************
59  * aout_sys_t: dsp audio output method descriptor
60  *****************************************************************************
61  * This structure is part of the audio output thread descriptor.
62  * It describes the dsp specific properties of an audio device.
63  *****************************************************************************/
64 typedef struct aout_sys_s
65 {
66     audio_buf_info        audio_buf;
67
68     /* Path to the audio output device */
69     char *                psz_device;
70     int                   i_fd;
71
72 } aout_sys_t;
73
74 /*****************************************************************************
75  * Local prototypes.
76  *****************************************************************************/
77 static int     aout_Open        ( aout_thread_t *p_aout );
78 static int     aout_SetFormat   ( aout_thread_t *p_aout );
79 static int     aout_GetBufInfo  ( aout_thread_t *p_aout, int i_buffer_info );
80 static void    aout_Play        ( aout_thread_t *p_aout,
81                                   byte_t *buffer, int i_size );
82 static void    aout_Close       ( aout_thread_t *p_aout );
83
84 /*****************************************************************************
85  * Functions exported as capabilities. They are declared as static so that
86  * we don't pollute the namespace too much.
87  *****************************************************************************/
88 void _M( aout_getfunctions )( function_list_t * p_function_list )
89 {
90     p_function_list->functions.aout.pf_open = aout_Open;
91     p_function_list->functions.aout.pf_setformat = aout_SetFormat;
92     p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
93     p_function_list->functions.aout.pf_play = aout_Play;
94     p_function_list->functions.aout.pf_close = aout_Close;
95 }
96
97 /*****************************************************************************
98  * aout_Open: opens the audio device (the digital sound processor)
99  *****************************************************************************
100  * This function opens the dsp as a usual non-blocking write-only file, and
101  * modifies the p_aout->p_sys->i_fd with the file's descriptor.
102  *****************************************************************************/
103 static int aout_Open( aout_thread_t *p_aout )
104 {
105     /* Allocate structure */
106     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
107     if( p_aout->p_sys == NULL )
108     {
109         intf_ErrMsg("aout error: %s", strerror(ENOMEM) );
110         return( 1 );
111     }
112
113     /* Initialize some variables */
114     if( !(p_aout->p_sys->psz_device = config_GetPszVariable( "dspdev" )) )
115     {
116         intf_ErrMsg( "aout error: don't know which audio device to open" );
117         free( p_aout->p_sys );
118         return( -1 );
119     }
120
121     /* Open the sound device */
122     if( (p_aout->p_sys->i_fd = open( p_aout->p_sys->psz_device, O_WRONLY ))
123         < 0 )
124     {
125         intf_ErrMsg( "aout error: can't open audio device (%s)",
126                      p_aout->p_sys->psz_device );
127         free( p_aout->p_sys->psz_device );
128         free( p_aout->p_sys );
129         return( -1 );
130     }
131
132     return( 0 );
133 }
134
135 /*****************************************************************************
136  * aout_SetFormat: resets the dsp and sets its format
137  *****************************************************************************
138  * This functions resets the DSP device, tries to initialize the output
139  * format with the value contained in the dsp structure, and if this value
140  * could not be set, the default value returned by ioctl is set. It then
141  * does the same for the stereo mode, and for the output rate.
142  *****************************************************************************/
143 static int aout_SetFormat( aout_thread_t *p_aout )
144 {
145     int i_format;
146     int i_rate;
147     boolean_t b_stereo;
148
149     /* Reset the DSP device */
150     if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 )
151     {
152         intf_ErrMsg( "aout error: can't reset audio device (%s)",
153                      p_aout->p_sys->psz_device );
154         return( -1 );
155     }
156
157     /* Set the output format */
158     i_format = p_aout->i_format;
159     if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 )
160     {
161         intf_ErrMsg( "aout error: can't set audio output format (%i)",
162                      p_aout->i_format );
163         return( -1 );
164     }
165
166     if( i_format != p_aout->i_format )
167     {
168         intf_WarnMsg( 2, "aout warning: audio output format not supported (%i)"
169                       ,p_aout->i_format );
170         p_aout->i_format = i_format;
171     }
172
173     /* Set the number of channels */
174     b_stereo = ( p_aout->i_channels >= 2 );
175
176     if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_STEREO, &b_stereo ) < 0 )
177     {
178         intf_ErrMsg( "aout error: can't set number of audio channels (%i)",
179                      p_aout->i_channels );
180         return( -1 );
181     }
182
183     if( (1 + b_stereo) != p_aout->i_channels )
184     {
185         intf_WarnMsg( 2, "aout warning: %i audio channels not supported",
186                       p_aout->i_channels );
187         p_aout->i_channels = 1 + b_stereo;
188     }
189
190     /* Set the output rate */
191     i_rate = p_aout->i_rate;
192     if( ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 )
193     {
194         intf_ErrMsg( "aout error: can't set audio output rate (%i)",
195                      p_aout->i_rate );
196         return( -1 );
197     }
198
199     if( i_rate != p_aout->i_rate )
200     {
201         intf_WarnMsg( 1, "aout warning: audio output rate not supported (%li)",
202                       p_aout->i_rate );
203         p_aout->i_rate = i_rate;
204     }
205
206     return( 0 );
207 }
208
209 /*****************************************************************************
210  * aout_GetBufInfo: buffer status query
211  *****************************************************************************
212  * This function fills in the audio_buf_info structure :
213  * - returns : number of available fragments (not partially used ones)
214  * - int fragstotal : total number of fragments allocated
215  * - int fragsize : size of a fragment in bytes
216  * - int bytes : available space in bytes (includes partially used fragments)
217  * Note! 'bytes' could be more than fragments*fragsize
218  *****************************************************************************/
219 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
220 {
221     ioctl( p_aout->p_sys->i_fd, SNDCTL_DSP_GETOSPACE,
222            &p_aout->p_sys->audio_buf );
223
224     /* returns the allocated space in bytes */
225     return ( (p_aout->p_sys->audio_buf.fragstotal
226                  * p_aout->p_sys->audio_buf.fragsize)
227             - p_aout->p_sys->audio_buf.bytes );
228 }
229
230 /*****************************************************************************
231  * aout_Play: plays a sound samples buffer
232  *****************************************************************************
233  * This function writes a buffer of i_length bytes in the dsp
234  *****************************************************************************/
235 static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
236 {
237     if( p_aout->b_active )
238     {
239         int i_tmp;
240         i_tmp = write( p_aout->p_sys->i_fd, buffer, i_size );
241         if( i_tmp < 0 )
242             intf_ErrMsg("aout error: %s", strerror(ENOMEM) );
243
244     }
245 }
246
247 /*****************************************************************************
248  * aout_Close: closes the dsp audio device
249  *****************************************************************************/
250 static void aout_Close( aout_thread_t *p_aout )
251 {
252     close( p_aout->p_sys->i_fd );
253     free( p_aout->p_sys->psz_device );
254 }