aout_qnx.c 9.58 KB
Newer Older
1
/*****************************************************************************
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
2
 * aout_qnx.c : QNX audio output 
3
 *****************************************************************************
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
4
 * Copyright (C) 2000, 2001 VideoLAN
5 6
 *
 * Authors: Henri Fallon <henri@videolan.org>
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
7
 *          Jon Lech Johansen <jon-vl@nanocrew.net>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * 
 * 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 <errno.h>                                                 /* ENOMEM */
#include <string.h>                                            /* strerror() */
#include <stdio.h>                                           /* "intf_msg.h" */
#include <stdlib.h>                            /* calloc(), malloc(), free() */

#include <sys/asoundlib.h>

Sam Hocevar's avatar
 
Sam Hocevar committed
34
#include <videolan/vlc.h>
35 36 37 38 39

#include "audio_output.h"                                   /* aout_thread_t */

typedef struct aout_sys_s
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
40 41 42
    snd_pcm_t  * p_pcm_handle;
    int          i_card;
    int          i_device;
43 44 45 46 47 48 49
} aout_sys_t;

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int     aout_Open        ( aout_thread_t *p_aout );
static int     aout_SetFormat   ( aout_thread_t *p_aout );
Sam Hocevar's avatar
 
Sam Hocevar committed
50
static int     aout_GetBufInfo  ( aout_thread_t *p_aout, int i_buffer_info );
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
static void    aout_Play        ( aout_thread_t *p_aout,
                                  byte_t *buffer, int i_size );
static void    aout_Close       ( aout_thread_t *p_aout );

/*****************************************************************************
 * Functions exported as capabilities. They are declared as static so that
 * we don't pollute the namespace too much.
 *****************************************************************************/
void _M( aout_getfunctions )( function_list_t * p_function_list )
{
    p_function_list->functions.aout.pf_open = aout_Open;
    p_function_list->functions.aout.pf_setformat = aout_SetFormat;
    p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
    p_function_list->functions.aout.pf_play = aout_Play;
    p_function_list->functions.aout.pf_close = aout_Close;
}

/*****************************************************************************
 * aout_Open : creates a handle and opens an alsa device
 *****************************************************************************
 * This function opens an alsa device, through the alsa API
 *****************************************************************************/
static int aout_Open( aout_thread_t *p_aout )
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
75 76 77
    int i_ret;

    /* allocate structure */
78 79 80
    p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
    if( p_aout->p_sys == NULL )
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
81 82
        intf_ErrMsg( "aout error: unable to allocate memory (%s)",
                     strerror( ENOMEM ) );
83 84 85
        return( 1 );
    }

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
86 87 88 89 90
    /* open audio device */
    if( ( i_ret = snd_pcm_open_preferred( &p_aout->p_sys->p_pcm_handle,
                                          &p_aout->p_sys->i_card,
                                          &p_aout->p_sys->i_device,
                                          SND_PCM_OPEN_PLAYBACK ) ) < 0 )
91
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
92 93
        intf_ErrMsg( "aout error: unable to open audio device (%s)",
                      snd_strerror( i_ret ) );
Sam Hocevar's avatar
 
Sam Hocevar committed
94
        free( p_aout->p_sys );
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
95 96 97 98 99 100 101 102 103 104
        return( 1 );
    }

    /* disable mmap */
    if( ( i_ret = snd_pcm_plugin_set_disable( p_aout->p_sys->p_pcm_handle,
                                              PLUGIN_DISABLE_MMAP ) ) < 0 )
    {
        intf_ErrMsg( "aout error: unable to disable mmap (%s)",
                     snd_strerror( i_ret ) );
        aout_Close( p_aout );
Sam Hocevar's avatar
 
Sam Hocevar committed
105
        free( p_aout->p_sys );
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
106
        return( 1 );
107 108 109 110 111 112 113
    }

    return( 0 );
}


/*****************************************************************************
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
114
 * aout_SetFormat : set the audio output format 
115 116 117 118 119 120
 *****************************************************************************
 * This function prepares the device, sets the rate, format, the mode
 * ("play as soon as you have data"), and buffer information.
 *****************************************************************************/
static int aout_SetFormat( aout_thread_t *p_aout )
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
121
    int i_ret;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
122
    int i_bytes_per_sample;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
123 124 125 126 127 128 129 130 131
    snd_pcm_channel_info_t pi;
    snd_pcm_channel_params_t pp;

    memset( &pi, 0, sizeof(pi) );
    memset( &pp, 0, sizeof(pp) );

    pi.channel = SND_PCM_CHANNEL_PLAYBACK;
    if( ( i_ret = snd_pcm_plugin_info( p_aout->p_sys->p_pcm_handle,
                                       &pi ) ) < 0 )
132
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
133 134 135
        intf_ErrMsg( "aout error: unable to get plugin info (%s)",
                     snd_strerror( i_ret ) );
        return( 1 );
136
    }
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
137

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
138
    pp.mode       = SND_PCM_MODE_BLOCK;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
139
    pp.channel    = SND_PCM_CHANNEL_PLAYBACK;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
140
    pp.start_mode = SND_PCM_START_FULL;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
141 142
    pp.stop_mode  = SND_PCM_STOP_STOP;

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
143 144 145
    pp.buf.block.frags_max   = 1;
    pp.buf.block.frags_min   = 1;
    
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
146
    pp.format.interleave     = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
147
    pp.format.rate           = p_aout->i_rate;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
148 149 150
    pp.format.voices         = p_aout->i_channels;

    switch( p_aout->i_format )
151
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
152 153
        case AOUT_FMT_S16_LE:
            pp.format.format = SND_PCM_SFMT_S16_LE;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
154
            i_bytes_per_sample = 2;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
155 156 157 158
            break;

        default:
            pp.format.format = SND_PCM_SFMT_S16_BE;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
159
            i_bytes_per_sample = 2;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
160
            break;
161
    }
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
162

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
163
    pp.buf.block.frag_size =
Sam Hocevar's avatar
 
Sam Hocevar committed
164
        (((s64)p_aout->i_rate * AOUT_BUFFER_DURATION) / 1000000) *
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
165 166
        p_aout->i_channels * i_bytes_per_sample;

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
167 168 169
    /* set parameters */
    if( ( i_ret = snd_pcm_plugin_params( p_aout->p_sys->p_pcm_handle,
                                         &pp ) ) < 0 )
170 171
    {
        intf_ErrMsg( "aout error: unable to set parameters (%s)",
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
172 173
                     snd_strerror( i_ret ) );
        return( 1 );
174 175
    }

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
176 177 178
    /* prepare channel */
    if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
                                          SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
179 180
    {
        intf_ErrMsg( "aout error: unable to prepare channel (%s)",
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
181 182
                     snd_strerror( i_ret ) );
        return( 1 );
183 184 185 186 187 188 189 190 191 192 193 194 195
    }

    return( 0 );
}

/*****************************************************************************
 * aout_BufInfo: buffer status query
 *****************************************************************************
 * This function returns the number of used byte in the queue.
 * It also deals with errors : indeed if the device comes to run out
 * of data to play, it switches to the "underrun" status. It has to
 * be flushed and re-prepared
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
196
static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
197
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
198 199 200 201 202 203 204
    int i_ret;
    snd_pcm_channel_status_t status;

    /* get current pcm status */
    memset( &status, 0, sizeof(status) );
    if( ( i_ret = snd_pcm_plugin_status( p_aout->p_sys->p_pcm_handle,
                                         &status ) ) < 0 )
205
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
206 207
        intf_ErrMsg( "aout error: unable to get device status (%s)",
                     snd_strerror( i_ret ) );
208 209 210
        return( -1 );
    }

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
211 212
    /* check for underrun */
    switch( status.status )
213
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
214
        case SND_PCM_STATUS_READY:
215
        case SND_PCM_STATUS_UNDERRUN:
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
216 217
            if( ( i_ret = snd_pcm_plugin_prepare( p_aout->p_sys->p_pcm_handle,
                                          SND_PCM_CHANNEL_PLAYBACK ) ) < 0 )
218
            {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
219 220
                intf_ErrMsg( "aout error: unable to prepare channel (%s)",
                             snd_strerror( i_ret ) );
221 222
            }
            break;
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
223
    }
224

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
225
    return( status.count );
226 227 228 229 230 231 232 233 234
}

/*****************************************************************************
 * aout_Play : plays a sample
 *****************************************************************************
 * Plays a sample using the snd_pcm_write function from the alsa API
 *****************************************************************************/
static void aout_Play( aout_thread_t *p_aout, byte_t *buffer, int i_size )
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
235
    int i_ret;
236

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
237 238 239
    if( ( i_ret = snd_pcm_plugin_write( p_aout->p_sys->p_pcm_handle,
                                        (void *) buffer, 
                                        (size_t) i_size ) ) <= 0 )
240
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
241 242
        intf_ErrMsg( "aout error: unable to write data (%s)",
                     snd_strerror( i_ret ) );
243 244 245 246
    }
}

/*****************************************************************************
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
247
 * aout_Close : close the audio device
248 249 250
 *****************************************************************************/
static void aout_Close( aout_thread_t *p_aout )
{
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
251
    int i_ret;
252

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
253
    if( ( i_ret = snd_pcm_close( p_aout->p_sys->p_pcm_handle ) ) < 0 )
254
    {
Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
255 256
        intf_ErrMsg( "aout error: unable to close audio device (%s)",
                     snd_strerror( i_ret ) );
257 258
    }

Jon Lech Johansen's avatar
 
Jon Lech Johansen committed
259
    free( p_aout->p_sys );
260
}