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 frames;
|
bhaal22@643 | 32 | static int frame_bytes;
|
bhaal22@643 | 33 |
|
bhaal22@643 | 34 |
|
bhaal22@643 | 35 | struct lxdream_config_entry alsa_config[] = {
|
bhaal22@643 | 36 | {"device", CONFIG_TYPE_FILE, "default"},
|
bhaal22@643 | 37 | {NULL, CONFIG_TYPE_NONE}
|
bhaal22@643 | 38 | };
|
bhaal22@643 | 39 |
|
bhaal22@643 | 40 |
|
bhaal22@643 | 41 | gboolean audio_alsa_init( )
|
bhaal22@643 | 42 | {
|
bhaal22@643 | 43 | int err;
|
bhaal22@643 | 44 |
|
bhaal22@643 | 45 | return TRUE;
|
bhaal22@643 | 46 | }
|
bhaal22@643 | 47 |
|
bhaal22@643 | 48 |
|
bhaal22@643 | 49 | gboolean audio_alsa_set_format( uint32_t rate, uint32_t format )
|
bhaal22@643 | 50 | {
|
bhaal22@643 | 51 | int i;
|
bhaal22@643 | 52 | int err;
|
bhaal22@643 | 53 | snd_pcm_hw_params_t *hw_params;
|
bhaal22@643 | 54 | snd_pcm_sw_params_t *sw_params;
|
bhaal22@643 | 55 | snd_pcm_uframes_t frames;
|
bhaal22@643 | 56 | unsigned int resample = 1;
|
bhaal22@643 | 57 | unsigned int actualRate = rate;
|
bhaal22@643 | 58 | snd_pcm_uframes_t bufferSize;
|
bhaal22@643 | 59 | int dir;
|
bhaal22@643 | 60 |
|
bhaal22@643 | 61 |
|
bhaal22@643 | 62 | // Open the device we were told to open.
|
bhaal22@643 | 63 | err = snd_pcm_open( &_soundDevice, alsa_config[0].value,
|
bhaal22@643 | 64 | SND_PCM_STREAM_PLAYBACK, 0 );
|
bhaal22@643 | 65 |
|
bhaal22@643 | 66 | // Check for error on open.
|
bhaal22@643 | 67 | if ( err < 0 ) {
|
bhaal22@643 | 68 | ERROR( "Init: cannot open audio device %s (%s)\n",
|
bhaal22@643 | 69 | alsa_config[0].value, snd_strerror( err ) );
|
bhaal22@643 | 70 | return FALSE;
|
bhaal22@643 | 71 | } else {
|
bhaal22@643 | 72 | DEBUG( "Audio device opened successfully." );
|
bhaal22@643 | 73 | }
|
bhaal22@643 | 74 |
|
bhaal22@643 | 75 | frame_bytes = ( 2 * ( snd_pcm_format_width( SND_PCM_FORMAT_S16_LE ) / 8 ) );
|
bhaal22@643 | 76 |
|
bhaal22@643 | 77 |
|
bhaal22@643 | 78 | //snd_pcm_hw_params_alloca (&hw_params);
|
bhaal22@643 | 79 | // Allocate the hardware parameter structure.
|
bhaal22@643 | 80 | if ( ( err = snd_pcm_hw_params_malloc( &hw_params ) ) < 0 ) {
|
bhaal22@643 | 81 | ERROR( "Init: cannot allocate hardware parameter structure (%s)\n",
|
bhaal22@643 | 82 | snd_strerror( err ) );
|
bhaal22@643 | 83 | return FALSE;
|
bhaal22@643 | 84 | }
|
bhaal22@643 | 85 |
|
bhaal22@643 | 86 | if ( ( err = snd_pcm_hw_params_any( _soundDevice, hw_params ) ) < 0 ) {
|
bhaal22@643 | 87 | ERROR( "Init: cannot allocate hardware parameter structure (%s)\n",
|
bhaal22@643 | 88 | snd_strerror( err ) );
|
bhaal22@643 | 89 | return FALSE;
|
bhaal22@643 | 90 | }
|
bhaal22@643 | 91 | // Set access to RW interleaved.
|
bhaal22@643 | 92 | if ( ( err = snd_pcm_hw_params_set_access( _soundDevice, hw_params,
|
bhaal22@643 | 93 | SND_PCM_ACCESS_RW_INTERLEAVED ) )
|
bhaal22@643 | 94 | < 0 ) {
|
bhaal22@643 | 95 | ERROR( " Init: cannot set access type (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 96 | return FALSE;
|
bhaal22@643 | 97 | }
|
bhaal22@643 | 98 |
|
bhaal22@643 | 99 | if ( ( err = snd_pcm_hw_params_set_format( _soundDevice, hw_params,
|
bhaal22@643 | 100 | SND_PCM_FORMAT_S16_LE ) ) <
|
bhaal22@643 | 101 | 0 ) {
|
bhaal22@643 | 102 | ERROR( "Init: cannot set sample format (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 103 | return FALSE;
|
bhaal22@643 | 104 | }
|
bhaal22@643 | 105 |
|
bhaal22@643 | 106 | err = snd_pcm_hw_params_set_rate_near( _soundDevice, hw_params, &rate, 0 );
|
bhaal22@643 | 107 | if ( err < 0 ) {
|
bhaal22@643 | 108 | ERROR( "Init: Resampling setup failed for playback: %s\n",
|
bhaal22@643 | 109 | snd_strerror( err ) );
|
bhaal22@643 | 110 | return err;
|
bhaal22@643 | 111 | }
|
bhaal22@643 | 112 | // Set channels to stereo (2).
|
bhaal22@643 | 113 | err = snd_pcm_hw_params_set_channels( _soundDevice, hw_params, 2 );
|
bhaal22@643 | 114 | if ( err < 0 ) {
|
bhaal22@643 | 115 | ERROR( "Init: cannot set channel count (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 116 | return FALSE;
|
bhaal22@643 | 117 | }
|
bhaal22@643 | 118 |
|
bhaal22@643 | 119 | // frames = 4410;
|
bhaal22@643 | 120 | // snd_pcm_hw_params_set_period_size_near( _soundDevice, hw_params, &frames,
|
bhaal22@643 | 121 | // &dir );
|
bhaal22@643 | 122 |
|
bhaal22@643 | 123 | // Apply the hardware parameters that we've set.
|
bhaal22@643 | 124 | err = snd_pcm_hw_params( _soundDevice, hw_params );
|
bhaal22@643 | 125 | if ( err < 0 ) {
|
bhaal22@643 | 126 | DEBUG( "Init: cannot set parameters (%s)\n", snd_strerror( err ) );
|
bhaal22@643 | 127 | return FALSE;
|
bhaal22@643 | 128 | } else {
|
bhaal22@643 | 129 | DEBUG( "Audio device parameters have been set successfully." );
|
bhaal22@643 | 130 | }
|
bhaal22@643 | 131 |
|
bhaal22@643 | 132 | snd_pcm_hw_params_get_period_size( hw_params, &frames, &dir );
|
bhaal22@643 | 133 | DEBUG( "period size = %d\n", frames );
|
bhaal22@643 | 134 |
|
bhaal22@643 | 135 | // Get the buffer size.
|
bhaal22@643 | 136 | snd_pcm_hw_params_get_buffer_size( hw_params, &bufferSize );
|
bhaal22@643 | 137 | DEBUG("Buffer Size = %d\n", bufferSize);
|
bhaal22@643 | 138 |
|
bhaal22@643 | 139 | // If we were going to do more with our sound device we would want to store
|
bhaal22@643 | 140 | // the buffer size so we know how much data we will need to fill it with.
|
bhaal22@643 | 141 |
|
bhaal22@643 | 142 | //cout << "Init: Buffer size = " << bufferSize << " frames." << endl;
|
bhaal22@643 | 143 |
|
bhaal22@643 | 144 | // Display the bit size of samples.
|
bhaal22@643 | 145 | //cout << "Init: Significant bits for linear samples = " << snd_pcm_hw_params_get_sbits(hw_params) << endl;
|
bhaal22@643 | 146 |
|
bhaal22@643 | 147 | // Free the hardware parameters now that we're done with them.
|
bhaal22@643 | 148 | snd_pcm_hw_params_free( hw_params );
|
bhaal22@643 | 149 |
|
bhaal22@643 | 150 | // Set the start threshold to reduce inter-buffer gaps
|
bhaal22@643 | 151 | snd_pcm_sw_params_alloca( &sw_params );
|
bhaal22@643 | 152 | snd_pcm_sw_params_current( _soundDevice, sw_params );
|
bhaal22@643 | 153 | snd_pcm_sw_params_set_start_threshold( _soundDevice, sw_params, bufferSize/2 );
|
bhaal22@643 | 154 | err = snd_pcm_sw_params( _soundDevice, sw_params );
|
bhaal22@643 | 155 | if( err < 0 ) {
|
bhaal22@643 | 156 | ERROR("Unable to set sw params for alsa driver: %s\n", snd_strerror(err));
|
bhaal22@643 | 157 | return FALSE;
|
bhaal22@643 | 158 | }
|
bhaal22@643 | 159 |
|
bhaal22@643 | 160 | err = snd_pcm_prepare( _soundDevice );
|
bhaal22@643 | 161 | if ( err < 0 ) {
|
bhaal22@643 | 162 | ERROR( "Init: cannot prepare audio interface for use (%s)\n",
|
bhaal22@643 | 163 | snd_strerror( err ) );
|
bhaal22@643 | 164 | return FALSE;
|
bhaal22@643 | 165 | }
|
bhaal22@643 | 166 | return TRUE;
|
bhaal22@643 | 167 | }
|
bhaal22@643 | 168 |
|
bhaal22@643 | 169 | gboolean audio_alsa_process_buffer( audio_buffer_t buffer )
|
bhaal22@643 | 170 | {
|
bhaal22@643 | 171 | int err;
|
bhaal22@643 | 172 | int length;
|
bhaal22@643 | 173 |
|
bhaal22@643 | 174 |
|
bhaal22@643 | 175 | length = buffer->length / frame_bytes;
|
bhaal22@643 | 176 |
|
bhaal22@643 | 177 | err = snd_pcm_writei( _soundDevice, buffer->data, length );
|
bhaal22@643 | 178 | if( err == -EPIPE ) {
|
bhaal22@643 | 179 | snd_pcm_prepare( _soundDevice );
|
bhaal22@643 | 180 | } else if( err == -ESTRPIPE ) {
|
bhaal22@643 | 181 | snd_pcm_resume( _soundDevice );
|
bhaal22@643 | 182 | }
|
bhaal22@643 | 183 |
|
bhaal22@643 | 184 | return TRUE;
|
bhaal22@643 | 185 | }
|
bhaal22@643 | 186 |
|
bhaal22@643 | 187 |
|
bhaal22@643 | 188 | gboolean audio_alsa_close( )
|
bhaal22@643 | 189 | {
|
bhaal22@643 | 190 | int err;
|
bhaal22@643 | 191 |
|
bhaal22@643 | 192 | return TRUE;
|
bhaal22@643 | 193 | }
|
bhaal22@643 | 194 |
|
bhaal22@643 | 195 |
|
bhaal22@643 | 196 |
|
bhaal22@643 | 197 | struct audio_driver audio_alsa_driver = {
|
bhaal22@643 | 198 | "alsa",
|
bhaal22@643 | 199 | audio_alsa_init,
|
bhaal22@643 | 200 | audio_alsa_set_format,
|
bhaal22@643 | 201 | audio_alsa_process_buffer,
|
bhaal22@643 | 202 | audio_alsa_close
|
bhaal22@643 | 203 | };
|