00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00031 #include "stdinc.h"
00032
00033 #include <alsa/asoundlib.h>
00034
00035 #include "audio_file.h"
00036 #include "audio_output.h"
00037 #include "config.h"
00038 #include "gui.h"
00039
00043 static snd_pcm_t *devhnd;
00047 static unsigned int channels = 0;
00051 static unsigned int srate = 0;
00052 #ifdef BUILD_VOLUME
00053
00056 static snd_mixer_t *mixhnd = NULL;
00060 static snd_mixer_elem_t *elem;
00061 #endif
00062
00066 static int
00067 audio_output_apply_hwparams(void)
00068 {
00069 snd_pcm_hw_params_t *devparam;
00070
00071 snd_pcm_hw_params_alloca(&devparam);
00072
00073
00074 if (snd_pcm_hw_params_any(devhnd, devparam) != 0)
00075 return (-1);
00076
00077
00078 if (snd_pcm_hw_params_set_access(devhnd, devparam,
00079 SND_PCM_ACCESS_RW_INTERLEAVED) != 0)
00080 return (-1);
00081
00082
00083 if (snd_pcm_hw_params_set_format(devhnd, devparam,
00084 SND_PCM_FORMAT_S16) != 0)
00085 return (-1);
00086
00087 if (snd_pcm_hw_params_set_rate_near(devhnd, devparam, &srate, NULL) != 0)
00088 return (-1);
00089
00090 if (snd_pcm_hw_params_set_channels(devhnd, devparam, channels) != 0)
00091 return (-1);
00092
00093
00094 snd_pcm_drain(devhnd);
00095
00096
00097 if (snd_pcm_hw_params(devhnd, devparam) != 0)
00098 return (-1);
00099
00100 return (0);
00101 }
00102
00103 #ifdef BUILD_VOLUME
00104
00108 static void
00109 audio_output_volume_open(void)
00110 {
00111 snd_mixer_selem_id_t *mixer;
00112
00113
00114 if (snd_mixer_open(&mixhnd, 0) != 0)
00115 return;
00116 if (snd_mixer_attach(mixhnd,
00117 config_getopt("audio.output.alsa.device")) != 0)
00118 goto bad;
00119 if (snd_mixer_selem_register(mixhnd, NULL, NULL) < 0)
00120 goto bad;
00121 if (snd_mixer_load(mixhnd) < 0)
00122 goto bad;
00123
00124
00125 snd_mixer_selem_id_alloca(&mixer);
00126 snd_mixer_selem_id_set_name(mixer, config_getopt("audio.output.alsa.mixer"));
00127
00128 elem = snd_mixer_find_selem(mixhnd, mixer);
00129 if (elem != NULL)
00130 return;
00131 bad:
00132 snd_mixer_close(mixhnd);
00133 mixhnd = NULL;
00134 }
00135 #endif
00136
00137 int
00138 audio_output_open(void)
00139 {
00140
00141 if (snd_pcm_open(&devhnd, config_getopt("audio.output.alsa.device"),
00142 SND_PCM_STREAM_PLAYBACK, 0) != 0)
00143 goto error;
00144
00145 #ifdef BUILD_VOLUME
00146 audio_output_volume_open();
00147 #endif
00148
00149 return (0);
00150 error:
00151 g_printerr("%s\n", _("Cannot open the audio device."));
00152 return (-1);
00153 }
00154
00155 int
00156 audio_output_play(struct audio_file *fd)
00157 {
00158 int16_t buf[8192];
00159 snd_pcm_sframes_t ret, len, done = 0;
00160
00161 if ((len = audio_file_read(fd, buf, sizeof buf / sizeof(int16_t))) == 0)
00162 return (-1);
00163
00164 if (fd->channels != channels || fd->srate != srate) {
00165
00166 channels = fd->channels;
00167 srate = fd->srate;
00168 if (audio_output_apply_hwparams() != 0) {
00169 gui_msgbar_warn(_("Sample rate or amount of channels not supported."));
00170
00171 srate = 0;
00172 return (-1);
00173 }
00174 }
00175
00176
00177 len /= fd->channels;
00178
00179
00180 while (done < len) {
00181 ret = snd_pcm_writei(devhnd, buf + (done * fd->channels), len - done);
00182 if (ret == -EPIPE) {
00183
00184 if (snd_pcm_prepare(devhnd) != 0)
00185 return (-1);
00186 continue;
00187 } else if (ret <= 0) {
00188
00189 return (-1);
00190 }
00191
00192 done += ret;
00193 }
00194
00195 return (0);
00196 }
00197
00198 void
00199 audio_output_close(void)
00200 {
00201 snd_pcm_close(devhnd);
00202 #ifdef BUILD_VOLUME
00203 if (mixhnd != NULL)
00204 snd_mixer_close(mixhnd);
00205 #endif
00206 }
00207
00208 #ifdef BUILD_VOLUME
00209
00213 static int
00214 audio_output_volume_adjust(int n)
00215 {
00216 int delta;
00217 long min, max;
00218 long right, left;
00219
00220 if (mixhnd == NULL)
00221 return (-1);
00222
00223
00224 snd_mixer_handle_events(mixhnd);
00225
00226
00227 if (snd_mixer_selem_get_playback_volume_range(elem, &min, &max) != 0)
00228 return (-1);
00229 if (min >= max)
00230 return (-1);
00231
00232
00233 delta = (n * (max - min)) / 100;
00234 if (delta == 0)
00235 delta = n > 0 ? 1 : -1;
00236
00237
00238 if (snd_mixer_selem_get_playback_volume(elem,
00239 SND_MIXER_SCHN_FRONT_LEFT, &left) != 0)
00240 return (-1);
00241 if (snd_mixer_selem_get_playback_volume(elem,
00242 SND_MIXER_SCHN_FRONT_RIGHT, &right) != 0)
00243 return (-1);
00244
00245 left = left + delta;
00246 left = CLAMP(left, min, max);
00247 right = right + delta;
00248 right = CLAMP(right, min, max);
00249
00250
00251 if (snd_mixer_selem_set_playback_volume(elem,
00252 SND_MIXER_SCHN_FRONT_LEFT, left) != 0)
00253 return (-1);
00254 if (snd_mixer_selem_set_playback_volume(elem,
00255 SND_MIXER_SCHN_FRONT_RIGHT, right) != 0)
00256 return (-1);
00257
00258
00259 return (((left + right) / 2 - min) * 100) / (max - min);
00260 }
00261
00262 int
00263 audio_output_volume_up(void)
00264 {
00265 return audio_output_volume_adjust(4);
00266 }
00267
00268 int
00269 audio_output_volume_down(void)
00270 {
00271 return audio_output_volume_adjust(-4);
00272 }
00273 #endif