bhaal22@643 | 1 | /**
|
bhaal22@643 | 2 | * $Id: audio_esd.c 602 2008-01-15 20:50:23Z nkeynes $
|
bhaal22@643 | 3 | *
|
bhaal22@643 | 4 | * The asla audio driver
|
bhaal22@643 | 5 | *
|
bhaal22@643 | 6 | * Copyright (c) 2008 Jonathan Muller
|
bhaal22@643 | 7 | *
|
bhaal22@643 | 8 | * This program is free software; you can redistribute it and/or modify
|
bhaal22@643 | 9 | * it under the terms of the GNU General Public License as published by
|
bhaal22@643 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
bhaal22@643 | 11 | * (at your option) any later version.
|
bhaal22@643 | 12 | *
|
bhaal22@643 | 13 | * This program is distributed in the hope that it will be useful,
|
bhaal22@643 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
bhaal22@643 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
bhaal22@643 | 16 | * GNU General Public License for more details.
|
bhaal22@643 | 17 | */
|
bhaal22@643 | 18 | #include <stdio.h>
|
bhaal22@643 | 19 | #include <unistd.h>
|
bhaal22@643 | 20 |
|
bhaal22@643 | 21 | /* Use the newer ALSA API */
|
bhaal22@643 | 22 | #define ALSA_PCM_NEW_HW_PARAMS_API
|
bhaal22@643 | 23 |
|
bhaal22@643 | 24 | #include <alsa/asoundlib.h>
|
bhaal22@643 | 25 | #include "config.h"
|
bhaal22@643 | 26 | #include "aica/audio.h"
|
bhaal22@643 | 27 | #include "dream.h"
|
bhaal22@643 | 28 |
|
bhaal22@643 | 29 |
|
bhaal22@643 | 30 | static snd_pcm_t *_soundDevice = NULL;
|
bhaal22@643 | 31 | static int frame_bytes;
|
bhaal22@643 | 32 |
|
bhaal22@643 | 33 |
|
bhaal22@643 | 34 | struct lxdream_config_entry alsa_config[] = {
|
bhaal22@643 | 35 | {"device", CONFIG_TYPE_FILE, "default"},
|
bhaal22@643 | 36 | {NULL, CONFIG_TYPE_NONE}
|
bhaal22@643 | 37 | };
|
bhaal22@643 | 38 |
|
bhaal22@643 | 39 |
|
bhaal22@643 | 40 | gboolean audio_alsa_init( )
|
bhaal22@643 | 41 | {
|
bhaal22@643 | 42 | int err;
|
bhaal22@643 | 43 | snd_pcm_hw_params_t *hw_params;
|
bhaal22@643 | 44 | snd_pcm_sw_params_t *sw_params;
|
bhaal22@643 | 45 | snd_pcm_uframes_t frames;
|
bhaal22@643 | 46 | snd_pcm_uframes_t bufferSize;
|
nkeynes@697 | 47 | int rate = DEFAULT_SAMPLE_RATE;
|
nkeynes@697 | 48 | int format = DEFAULT_SAMPLE_FORMAT;
|
bhaal22@643 | 49 | int dir;
|
bhaal22@643 | 50 |
|
bhaal22@643 | 51 |
|
bhaal22@643 | 52 | // Open the device we were told to open.
|
bhaal22@643 | 53 | err = snd_pcm_open( &_soundDevice, alsa_config[0].value,
|
bhaal22@643 | 54 | SND_PCM_STREAM_PLAYBACK, 0 );
|
bhaal22@643 | 55 |
|
bhaal22@643 | 56 | // Check for error on open.
|
bhaal22@643 | 57 | if ( err < 0 ) {
|
bhaal22@643 | 58 | ERROR( "Init: cannot open audio device %s (%s)\n",
|
bhaal22@643 | 59 | alsa_config[0].value, snd_strerror( err ) );
|
bhaal22@643 | 60 | return FALSE;
|
bhaal22@643 | 61 | } else {
|
bhaal22@643 | 62 | DEBUG( "Audio device opened successfully." );
|
bhaal22@643 | 63 | }
|
bhaal22@643 | 64 |
|
bhaal22@643 | 65 | frame_bytes = ( 2 * ( snd_pcm_format_width( SND_PCM_FORMAT_S16_LE ) / 8 ) );
|
bhaal22@643 | 66 |
|
bhaal22@643 | 67 |
|
bhaal22@643 | 68 | //snd_pcm_hw_params_alloca (&hw_params);
|
bhaal22@643 | 69 | // Allocate the hardware parameter structure.
|
bhaal22@643 | 70 | if ( ( err = snd_pcm_hw_params_malloc( &hw_params ) ) < 0 ) {
|
bhaal22@643 | 71 | ERROR( "Init: cannot allocate hardware parameter structure (%s)\n",
|
bhaal22@643 | 72 | snd_strerror( err ) );
|
bhaal22@643 | 73 | return FALSE;
|
bhaal22@643 | 74 | }
|
bhaal22@643 | 75 |
|
bhaal22@643 | 76 | if ( ( err = snd_pcm_hw_params_any( _soundDevice, hw_params ) ) < 0 ) {
|
bhaal22@643 | 77 | ERROR( "Init: cannot allocate hardware parameter structure (%s)\n",
|
bhaal22@643 | 78 | snd_strerror( err ) );
|
bhaal22@643 | 79 | return FALSE;
|
bhaal22@643 | 80 | }
|
bhaal22@643 | 81 | // Set access to RW interleaved.
|
bhaal22@643 | 82 | if ( ( err = snd_pcm_hw_params_set_access( _soundDevice, hw_params,
|
bhaal22@643 | 83 | SND_PCM_ACCESS_RW_INTERLEAVED ) )
|
bhaal22@643 | 84 | < 0 ) {
|
bhaal22@643 | 85 | ERROR( " Init: cannot set access type (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 86 | return FALSE;
|
bhaal22@643 | 87 | }
|
bhaal22@643 | 88 |
|
bhaal22@643 | 89 | if ( ( err = snd_pcm_hw_params_set_format( _soundDevice, hw_params,
|
bhaal22@643 | 90 | SND_PCM_FORMAT_S16_LE ) ) <
|
bhaal22@643 | 91 | 0 ) {
|
bhaal22@643 | 92 | ERROR( "Init: cannot set sample format (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 93 | return FALSE;
|
bhaal22@643 | 94 | }
|
bhaal22@643 | 95 |
|
bhaal22@643 | 96 | err = snd_pcm_hw_params_set_rate_near( _soundDevice, hw_params, &rate, 0 );
|
bhaal22@643 | 97 | if ( err < 0 ) {
|
bhaal22@643 | 98 | ERROR( "Init: Resampling setup failed for playback: %s\n",
|
bhaal22@643 | 99 | snd_strerror( err ) );
|
bhaal22@643 | 100 | return err;
|
bhaal22@643 | 101 | }
|
bhaal22@643 | 102 | // Set channels to stereo (2).
|
bhaal22@643 | 103 | err = snd_pcm_hw_params_set_channels( _soundDevice, hw_params, 2 );
|
bhaal22@643 | 104 | if ( err < 0 ) {
|
bhaal22@643 | 105 | ERROR( "Init: cannot set channel count (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 106 | return FALSE;
|
bhaal22@643 | 107 | }
|
bhaal22@643 | 108 |
|
bhaal22@643 | 109 | // frames = 4410;
|
bhaal22@643 | 110 | // snd_pcm_hw_params_set_period_size_near( _soundDevice, hw_params, &frames,
|
bhaal22@643 | 111 | // &dir );
|
bhaal22@643 | 112 |
|
bhaal22@643 | 113 | // Apply the hardware parameters that we've set.
|
bhaal22@643 | 114 | err = snd_pcm_hw_params( _soundDevice, hw_params );
|
bhaal22@643 | 115 | if ( err < 0 ) {
|
bhaal22@643 | 116 | DEBUG( "Init: cannot set parameters (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 117 | return FALSE;
|
bhaal22@643 | 118 | } else {
|
bhaal22@643 | 119 | DEBUG( "Audio device parameters have been set successfully." );
|
bhaal22@643 | 120 | }
|
bhaal22@643 | 121 |
|
bhaal22@643 | 122 | snd_pcm_hw_params_get_period_size( hw_params, &frames, &dir );
|
bhaal22@643 | 123 | DEBUG( "period size = %d\n", frames );
|
bhaal22@643 | 124 |
|
bhaal22@643 | 125 | // Get the buffer size.
|
bhaal22@643 | 126 | snd_pcm_hw_params_get_buffer_size( hw_params, &bufferSize );
|
bhaal22@643 | 127 | DEBUG("Buffer Size = %d\n", bufferSize);
|
bhaal22@643 | 128 |
|
bhaal22@643 | 129 | // If we were going to do more with our sound device we would want to store
|
bhaal22@643 | 130 | // the buffer size so we know how much data we will need to fill it with.
|
bhaal22@643 | 131 |
|
bhaal22@643 | 132 | //cout << "Init: Buffer size = " << bufferSize << " frames." << endl;
|
bhaal22@643 | 133 |
|
bhaal22@643 | 134 | // Display the bit size of samples.
|
bhaal22@643 | 135 | //cout << "Init: Significant bits for linear samples = " << snd_pcm_hw_params_get_sbits(hw_params) << endl;
|
bhaal22@643 | 136 |
|
bhaal22@643 | 137 | // Free the hardware parameters now that we're done with them.
|
bhaal22@643 | 138 | snd_pcm_hw_params_free( hw_params );
|
bhaal22@643 | 139 |
|
bhaal22@643 | 140 | // Set the start threshold to reduce inter-buffer gaps
|
bhaal22@643 | 141 | snd_pcm_sw_params_alloca( &sw_params );
|
bhaal22@643 | 142 | snd_pcm_sw_params_current( _soundDevice, sw_params );
|
bhaal22@643 | 143 | snd_pcm_sw_params_set_start_threshold( _soundDevice, sw_params, bufferSize/2 );
|
bhaal22@643 | 144 | err = snd_pcm_sw_params( _soundDevice, sw_params );
|
bhaal22@643 | 145 | if( err < 0 ) {
|
bhaal22@643 | 146 | ERROR("Unable to set sw params for alsa driver: %s\n", snd_strerror(err));
|
bhaal22@643 | 147 | return FALSE;
|
bhaal22@643 | 148 | }
|
bhaal22@643 | 149 |
|
bhaal22@643 | 150 | err = snd_pcm_prepare( _soundDevice );
|
bhaal22@643 | 151 | if ( err < 0 ) {
|
bhaal22@643 | 152 | ERROR( "Init: cannot prepare audio interface for use (%s)\n",
|
bhaal22@643 | 153 | snd_strerror( err ) );
|
bhaal22@643 | 154 | return FALSE;
|
bhaal22@643 | 155 | }
|
bhaal22@643 | 156 | return TRUE;
|
bhaal22@643 | 157 | }
|
bhaal22@643 | 158 |
|
bhaal22@643 | 159 | gboolean audio_alsa_process_buffer( audio_buffer_t buffer )
|
bhaal22@643 | 160 | {
|
bhaal22@643 | 161 | int err;
|
bhaal22@643 | 162 | int length;
|
bhaal22@643 | 163 |
|
bhaal22@643 | 164 |
|
bhaal22@643 | 165 | length = buffer->length / frame_bytes;
|
bhaal22@643 | 166 |
|
bhaal22@643 | 167 | err = snd_pcm_writei( _soundDevice, buffer->data, length );
|
bhaal22@643 | 168 | if( err == -EPIPE ) {
|
bhaal22@643 | 169 | snd_pcm_prepare( _soundDevice );
|
bhaal22@643 | 170 | } else if( err == -ESTRPIPE ) {
|
bhaal22@643 | 171 | snd_pcm_resume( _soundDevice );
|
bhaal22@643 | 172 | }
|
bhaal22@643 | 173 |
|
bhaal22@643 | 174 | return TRUE;
|
bhaal22@643 | 175 | }
|
bhaal22@643 | 176 |
|
bhaal22@643 | 177 |
|
nkeynes@697 | 178 | gboolean audio_alsa_shutdown( )
|
bhaal22@643 | 179 | {
|
bhaal22@643 | 180 | return TRUE;
|
bhaal22@643 | 181 | }
|
bhaal22@643 | 182 |
|
bhaal22@643 | 183 |
|
bhaal22@643 | 184 |
|
bhaal22@643 | 185 | struct audio_driver audio_alsa_driver = {
|
bhaal22@643 | 186 | "alsa",
|
nkeynes@700 | 187 | N_("Linux ALSA system driver"),
|
nkeynes@697 | 188 | DEFAULT_SAMPLE_RATE,
|
nkeynes@697 | 189 | DEFAULT_SAMPLE_FORMAT,
|
bhaal22@643 | 190 | audio_alsa_init,
|
nkeynes@697 | 191 | NULL,
|
bhaal22@643 | 192 | audio_alsa_process_buffer,
|
nkeynes@697 | 193 | NULL,
|
nkeynes@697 | 194 | audio_alsa_shutdown
|
bhaal22@643 | 195 | };
|