annotate Output/alsa/audio.c @ 21:26e98cee788f trunk

[svn] I hate GCC4.
author nenolod
date Mon, 24 Oct 2005 20:15:55 -0700
parents cb178e5ad177
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1 /* XMMS - ALSA output plugin
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
2 * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
3 * Copyright (C) 1998-2003 Peter Alm, Mikael Alm, Olle Hallnas,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
4 * Thomas Nilsson and 4Front Technologies
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
5 * Copyright (C) 1999-2004 Haavard Kvaalen
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
6 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
7 * This program is free software; you can redistribute it and/or modify
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
8 * it under the terms of the GNU General Public License as published by
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
9 * the Free Software Foundation; either version 2 of the License, or
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
10 * (at your option) any later version.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
11 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
12 * This program is distributed in the hope that it will be useful,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
15 * GNU General Public License for more details.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
16 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
17 * You should have received a copy of the GNU General Public License
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
18 * along with this program; if not, write to the Free Software
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
20 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
21 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
22 * CHANGES
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
23 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
24 * 2005.01.05 Takashi Iwai <tiwai@suse.de>
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
25 * Impelemented the multi-threaded mode with an audio-thread.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
26 * Many fixes and cleanups.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
27 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
28
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
29 #include "alsa.h"
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
30 #include <ctype.h>
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
31 #include <glib.h>
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
32 #include <libaudacious/xconvert.h>
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
33
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
34 static snd_pcm_t *alsa_pcm = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
35
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
36 static snd_output_t *logs = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
37
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
38 static guint64 alsa_total_written = 0; /* input bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
39 static guint64 alsa_hw_written = 0; /* output bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
40 static gint output_time_offset = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
41
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
42 /* device buffer/period sizes in bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
43 static int hw_buffer_size, hw_period_size; /* in output bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
44 static int hw_buffer_size_in, hw_period_size_in; /* in input bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
45
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
46 /* Set/Get volume */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
47 static snd_mixer_elem_t *pcm_element = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
48 static snd_mixer_t *mixer = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
49
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
50 static gboolean mmap, going = FALSE, paused, multi_thread, mixer_start = TRUE;;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
51
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
52 static gboolean alsa_can_pause;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
53
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
54 static guint mixer_timeout;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
55
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
56 /* for audio thread */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
57 static GThread *audio_thread; /* audio loop thread */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
58 static int thread_buffer_size; /* size of intermediate buffer in bytes */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
59 static char *thread_buffer; /* audio intermediate buffer */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
60 static int rd_index, wr_index; /* current read/write position in int-buffer */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
61 static gboolean pause_request; /* pause status currently requested */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
62 static gint flush_request; /* flush status (time) currently requested */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
63
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
64 struct snd_format {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
65 unsigned int rate;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
66 unsigned int channels;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
67 snd_pcm_format_t format;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
68 AFormat xmms_format;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
69 int sample_bits;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
70 int bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
71 };
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
72
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
73 static struct snd_format *inputf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
74 static struct snd_format *effectf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
75 static struct snd_format *outputf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
76
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
77 static int alsa_setup(struct snd_format *f);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
78 static void alsa_mmap_audio(char *data, int length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
79 static void alsa_write_audio(char *data, int length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
80
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
81 static struct snd_format *snd_format_from_xmms(AFormat fmt, int rate,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
82 int channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
83
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
84 static struct xmms_convert_buffers *convertb;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
85
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
86 static convert_func_t alsa_convert_func;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
87 static convert_channel_func_t alsa_stereo_convert_func;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
88 static convert_freq_func_t alsa_frequency_convert_func;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
89
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
90 static const struct {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
91 AFormat xmms;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
92 snd_pcm_format_t alsa;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
93 } format_table[] = {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
94 {FMT_S16_LE, SND_PCM_FORMAT_S16_LE},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
95 {FMT_S16_BE, SND_PCM_FORMAT_S16_BE},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
96 {FMT_S16_NE, SND_PCM_FORMAT_S16},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
97 {FMT_U16_LE, SND_PCM_FORMAT_U16_LE},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
98 {FMT_U16_BE, SND_PCM_FORMAT_U16_BE},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
99 {FMT_U16_NE, SND_PCM_FORMAT_U16},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
100 {FMT_U8, SND_PCM_FORMAT_U8},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
101 {FMT_S8, SND_PCM_FORMAT_S8},
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
102 };
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
103
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
104
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
105 static void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
106 debug(char *str, ...)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
107 G_GNUC_PRINTF(1, 2);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
108
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
109 static void debug(char *str, ...)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
110 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
111 va_list args;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
112
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
113 if (alsa_cfg.debug) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
114 va_start(args, str);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
115 g_logv(NULL, G_LOG_LEVEL_MESSAGE, str, args);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
116 va_end(args);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
117 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
118 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
119
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
120 /*
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
121 * mixer stuff
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
122 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
123 static void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
124 parse_mixer_name(char *str, char **name, int *index)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
125 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
126 char *end;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
127
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
128 while (isspace(*str))
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
129 str++;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
130
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
131 if ((end = strchr(str, ',')) != NULL) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
132 *name = g_strndup(str, end - str);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
133 end++;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
134 *index = atoi(end);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
135 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
136 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
137 *name = g_strdup(str);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
138 *index = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
139 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
140 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
141
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
142 int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
143 alsa_get_mixer(snd_mixer_t ** mixer, int card)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
144 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
145 char *dev;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
146 int err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
147
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
148 debug("alsa_get_mixer");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
149
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
150 dev = g_strdup_printf("hw:%i", card);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
151
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
152 if ((err = snd_mixer_open(mixer, 0)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
153 g_warning("alsa_get_mixer(): Failed to open empty mixer: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
154 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
155 mixer = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
156 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
157 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
158 if ((err = snd_mixer_attach(*mixer, dev)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
159 g_warning("alsa_get_mixer(): Attaching to mixer %s failed: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
160 dev, snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
161 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
162 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
163 if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
164 g_warning("alsa_get_mixer(): Failed to register mixer: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
165 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
166 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
167 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
168 if ((err = snd_mixer_load(*mixer)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
169 g_warning("alsa_get_mixer(): Failed to load mixer: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
170 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
171 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
172 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
173
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
174 g_free(dev);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
175
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
176 return (*mixer != NULL);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
177 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
178
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
179
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
180 static snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, char *name, int index)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
181 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
182 snd_mixer_selem_id_t *selem_id;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
183 snd_mixer_elem_t *elem;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
184 snd_mixer_selem_id_alloca(&selem_id);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
185
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
186 if (index != -1)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
187 snd_mixer_selem_id_set_index(selem_id, index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
188 if (name != NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
189 snd_mixer_selem_id_set_name(selem_id, name);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
190
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
191 elem = snd_mixer_find_selem(mixer, selem_id);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
192
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
193 return elem;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
194 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
195
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
196 static int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
197 alsa_setup_mixer(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
198 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
199 char *name;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
200 long int a, b;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
201 long alsa_min_vol, alsa_max_vol;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
202 int err, index;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
203
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
204 debug("alsa_setup_mixer");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
205
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
206 if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
207 return err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
208
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
209 parse_mixer_name(alsa_cfg.mixer_device, &name, &index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
210
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
211 pcm_element = alsa_get_mixer_elem(mixer, name, index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
212
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
213 g_free(name);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
214
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
215 if (!pcm_element) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
216 g_warning("alsa_setup_mixer(): Failed to find mixer element: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
217 alsa_cfg.mixer_device);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
218 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
219 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
220
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
221 /*
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
222 * Work around a bug in alsa-lib up to 1.0.0rc2 where the
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
223 * new range don't take effect until the volume is changed.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
224 * This hack should be removed once we depend on Alsa 1.0.0.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
225 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
226 snd_mixer_selem_get_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
227 SND_MIXER_SCHN_FRONT_LEFT, &a);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
228 snd_mixer_selem_get_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
229 SND_MIXER_SCHN_FRONT_RIGHT, &b);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
230
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
231 snd_mixer_selem_get_playback_volume_range(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
232 &alsa_min_vol, &alsa_max_vol);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
233 snd_mixer_selem_set_playback_volume_range(pcm_element, 0, 100);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
234
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
235 if (alsa_max_vol == 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
236 pcm_element = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
237 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
238 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
239
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
240 if (!alsa_cfg.soft_volume)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
241 alsa_set_volume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
242
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
243 debug("alsa_setup_mixer: end");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
244
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
245 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
246 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
247
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
248 static int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
249 alsa_mixer_timeout(void *data)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
250 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
251 if (mixer) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
252 snd_mixer_close(mixer);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
253 mixer = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
254 pcm_element = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
255 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
256 mixer_timeout = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
257 mixer_start = TRUE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
258
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
259 g_message("alsa mixer timed out");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
260 return FALSE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
261 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
262
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
263
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
264 static void alsa_cleanup_mixer(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
265 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
266 pcm_element = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
267 if (mixer) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
268 snd_mixer_close(mixer);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
269 mixer = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
270 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
271 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
272
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
273
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
274 void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
275 alsa_get_volume(int *l, int *r)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
276 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
277 long ll = *l, lr = *r;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
278
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
279 if (mixer_start) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
280 alsa_setup_mixer();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
281 mixer_start = FALSE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
282 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
283
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
284 if (!pcm_element)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
285 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
286
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
287 snd_mixer_handle_events(mixer);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
288
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
289 if (alsa_cfg.soft_volume) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
290 *l = alsa_cfg.vol.left;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
291 *r = alsa_cfg.vol.right;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
292 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
293 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
294 snd_mixer_selem_get_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
295 SND_MIXER_SCHN_FRONT_LEFT, &ll);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
296 snd_mixer_selem_get_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
297 SND_MIXER_SCHN_FRONT_RIGHT, &lr);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
298 *l = ll;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
299 *r = lr;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
300 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
301 if (mixer_timeout)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
302 gtk_timeout_remove(mixer_timeout);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
303 mixer_timeout = gtk_timeout_add(5000, alsa_mixer_timeout, NULL);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
304 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
305
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
306
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
307 void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
308 alsa_set_volume(int l, int r)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
309 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
310 if (!pcm_element)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
311 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
312
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
313 if (alsa_cfg.soft_volume) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
314 alsa_cfg.vol.left = l;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
315 alsa_cfg.vol.right = r;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
316 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
317 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
318 snd_mixer_selem_set_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
319 SND_MIXER_SCHN_FRONT_LEFT, l);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
320 snd_mixer_selem_set_playback_volume(pcm_element,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
321 SND_MIXER_SCHN_FRONT_RIGHT, r);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
322 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
323 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
324
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
325 /*
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
326 * audio stuff
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
327 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
328
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
329 int alsa_playing(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
330 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
331 if (!going || paused || alsa_pcm == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
332 return FALSE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
333
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
334 return(snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
335 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
336
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
337
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
338 /* handle generic errors */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
339 static int alsa_handle_error(int err)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
340 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
341 switch (err) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
342 case -EPIPE: /* XRUN */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
343 if (alsa_cfg.debug) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
344 snd_pcm_status_t *alsa_status;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
345 snd_pcm_status_alloca(&alsa_status);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
346 if (snd_pcm_status(alsa_pcm, alsa_status) < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
347 g_warning("xrun_recover(): snd_pcm_status() failed");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
348 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
349 printf("Status:\n");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
350 snd_pcm_status_dump(alsa_status, logs);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
351 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
352 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
353 return snd_pcm_prepare(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
354
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
355 case -ESTRPIPE: /* suspend */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
356 while ((err = snd_pcm_resume(alsa_pcm)) == -EAGAIN)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
357 sleep(1); /* wait until suspend flag is released */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
358 if (err < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
359 g_warning("suspend_recover(): snd_pcm_resume() failed.");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
360 return snd_pcm_prepare(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
361 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
362 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
363 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
364
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
365 return err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
366 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
367
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
368 /* update and get the available space on h/w buffer (in frames) */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
369 static snd_pcm_sframes_t alsa_get_avail(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
370 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
371 snd_pcm_sframes_t ret;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
372
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
373 if (alsa_pcm == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
374 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
375
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
376 while ((ret = snd_pcm_avail_update(alsa_pcm)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
377 ret = alsa_handle_error(ret);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
378 if (ret < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
379 g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
380 snd_strerror(-ret));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
381 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
382 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
383 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
384 return ret;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
385 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
386
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
387 /* do pause operation */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
388 static void alsa_do_pause(gboolean p)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
389 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
390 if (paused == p)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
391 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
392
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
393 if (alsa_pcm) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
394 if (alsa_can_pause) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
395 snd_pcm_pause(alsa_pcm, p);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
396 } else if (p) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
397 snd_pcm_drop(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
398 snd_pcm_prepare(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
399 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
400 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
401 paused = p;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
402 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
403
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
404 void alsa_pause(short p)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
405 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
406 debug("alsa_pause");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
407 if (multi_thread)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
408 pause_request = p;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
409 else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
410 alsa_do_pause(p);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
411 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
412
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
413 /* close PCM and release associated resources */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
414 static void alsa_close_pcm(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
415 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
416 if (alsa_pcm) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
417 int err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
418 snd_pcm_drop(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
419 if ((err = snd_pcm_close(alsa_pcm)) < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
420 g_warning("alsa_pcm_close() failed: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
421 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
422 alsa_pcm = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
423 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
424 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
425
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
426 /* reopen ALSA PCM */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
427 static int alsa_reopen(struct snd_format *f)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
428 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
429 /* remember the current position */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
430 output_time_offset += (alsa_hw_written * 1000) / outputf->bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
431 alsa_hw_written = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
432
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
433 alsa_close_pcm();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
434
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
435 return alsa_setup(f);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
436 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
437
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
438 /* do flush (drop) operation */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
439 static void alsa_do_flush(int time)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
440 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
441 if (alsa_pcm) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
442 snd_pcm_drop(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
443 snd_pcm_prepare(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
444 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
445 /* correct the offset */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
446 output_time_offset = time;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
447 alsa_total_written = (guint64) time * inputf->bps / 1000;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
448 rd_index = wr_index = alsa_hw_written = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
449 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
450
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
451 void alsa_flush(int time)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
452 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
453 if (multi_thread) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
454 flush_request = time;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
455 while (flush_request != -1)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
456 xmms_usleep(10000);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
457 } else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
458 alsa_do_flush(time);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
459 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
460
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
461 void alsa_close(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
462 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
463 if (! going)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
464 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
465
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
466 debug("Closing device");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
467
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
468 going = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
469
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
470 if (multi_thread)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
471 g_thread_join(audio_thread);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
472 else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
473 alsa_close_pcm();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
474
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
475 alsa_cleanup_mixer();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
476
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
477 xmms_convert_buffers_destroy(convertb);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
478 convertb = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
479 g_free(inputf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
480 inputf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
481 g_free(effectf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
482 effectf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
483 g_free(outputf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
484 outputf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
485
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
486 alsa_save_config();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
487
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
488 if (alsa_cfg.debug)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
489 snd_output_close(logs);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
490 debug("Device closed");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
491 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
492
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
493 /* return the size of audio data filled in the audio thread buffer */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
494 static int get_thread_buffer_filled(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
495 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
496 if (wr_index >= rd_index)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
497 return wr_index - rd_index;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
498 return thread_buffer_size - (rd_index - wr_index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
499 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
500
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
501 /* get the free space on buffer */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
502 int alsa_free(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
503 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
504 int result = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
505 if (multi_thread)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
506 result = thread_buffer_size - get_thread_buffer_filled() - 1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
507 else if (! paused && alsa_pcm)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
508 result = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
509 return result;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
510 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
511
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
512
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
513 int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
514 alsa_get_output_time(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
515 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
516 snd_pcm_sframes_t delay;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
517 guint64 bytes = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
518
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
519 if (!going || alsa_pcm == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
520 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
521
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
522 if (!snd_pcm_delay(alsa_pcm, &delay)) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
523 bytes = snd_pcm_frames_to_bytes(alsa_pcm, delay);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
524 if (alsa_hw_written < bytes)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
525 bytes = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
526 else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
527 bytes = alsa_hw_written - bytes;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
528 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
529 return output_time_offset + (bytes * 1000) / outputf->bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
530 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
531
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
532 int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
533 alsa_get_written_time(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
534 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
535 if (!going)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
536 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
537 return (alsa_total_written * 1000) / inputf->bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
538 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
539
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
540 #define STEREO_ADJUST(type, type2, endian) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
541 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
542 type *ptr = data; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
543 for (i = 0; i < length; i += 4) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
544 { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
545 *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
546 alsa_cfg.vol.left / 100); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
547 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
548 *ptr = type2##_TO_##endian(type2##_FROM_##endian(*ptr) * \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
549 alsa_cfg.vol.right / 100); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
550 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
551 } \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
552 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
553
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
554 #define MONO_ADJUST(type, type2, endian) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
555 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
556 type *ptr = data; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
557 for (i = 0; i < length; i += 4) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
558 { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
559 *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
560 vol / 100); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
561 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
562 } \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
563 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
564
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
565 #define VOLUME_ADJUST(type, type2, endian) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
566 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
567 if (channels == 2) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
568 STEREO_ADJUST(type, type2, endian); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
569 else \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
570 MONO_ADJUST(type, type2, endian); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
571 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
572
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
573 #define STEREO_ADJUST8(type) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
574 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
575 type *ptr = data; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
576 for (i = 0; i < length; i += 2) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
577 { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
578 *ptr = *ptr * alsa_cfg.vol.left / 100; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
579 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
580 *ptr = *ptr * alsa_cfg.vol.right / 100; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
581 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
582 } \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
583 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
584
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
585 #define MONO_ADJUST8(type) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
586 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
587 type *ptr = data; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
588 for (i = 0; i < length; i += 4) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
589 { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
590 *ptr = *ptr * vol / 100; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
591 ptr++; \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
592 } \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
593 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
594
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
595 #define VOLUME_ADJUST8(type) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
596 do { \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
597 if (channels == 2) \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
598 STEREO_ADJUST8(type); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
599 else \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
600 MONO_ADJUST8(type); \
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
601 } while (0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
602
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
603
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
604 static void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
605 volume_adjust(void *data, int length, AFormat fmt, int channels)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
606 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
607 int i, vol;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
608
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
609 if ((alsa_cfg.vol.left == 100 && alsa_cfg.vol.right == 100) ||
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
610 (channels == 1 &&
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
611 (alsa_cfg.vol.left == 100 || alsa_cfg.vol.right == 100)))
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
612 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
613
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
614 vol = MAX(alsa_cfg.vol.left, alsa_cfg.vol.right);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
615
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
616 switch (fmt) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
617 case FMT_S16_LE:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
618 VOLUME_ADJUST(gint16, GINT16, LE);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
619 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
620 case FMT_U16_LE:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
621 VOLUME_ADJUST(guint16, GUINT16, LE);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
622 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
623 case FMT_S16_BE:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
624 VOLUME_ADJUST(gint16, GINT16, BE);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
625 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
626 case FMT_U16_BE:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
627 VOLUME_ADJUST(guint16, GUINT16, BE);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
628 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
629 case FMT_S8:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
630 VOLUME_ADJUST8(gint8);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
631 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
632 case FMT_U8:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
633 VOLUME_ADJUST8(guint8);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
634 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
635 default:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
636 g_warning("volume_adjust(): unhandled format: %d", fmt);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
637 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
638 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
639 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
640
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
641
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
642 /* transfer data to audio h/w; length is given in bytes
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
643 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
644 * data can be modified via effect plugin, rate conversion or
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
645 * software volume before passed to audio h/w
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
646 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
647 static void alsa_do_write(gpointer data, int length)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
648 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
649 EffectPlugin *ep = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
650 int new_freq;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
651 int new_chn;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
652 AFormat f;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
653
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
654 if (paused)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
655 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
656
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
657 new_freq = inputf->rate;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
658 new_chn = inputf->channels;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
659 f = inputf->xmms_format;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
660
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
661 if (effects_enabled() && (ep = get_current_effect_plugin()) &&
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
662 ep->query_format)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
663 ep->query_format(&f, &new_freq, &new_chn);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
664
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
665 if (f != effectf->xmms_format || new_freq != effectf->rate ||
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
666 new_chn != effectf->channels) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
667 debug("Changing audio format for effect plugin");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
668 g_free(effectf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
669 effectf = snd_format_from_xmms(f, new_freq, new_chn);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
670 if (alsa_reopen(effectf) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
671 /* fatal error... */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
672 alsa_close();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
673 return;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
674 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
675 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
676
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
677 if (ep) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
678 length = ep->mod_samples(&data, length,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
679 inputf->xmms_format,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
680 inputf->rate, inputf->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
681 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
682
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
683 if (alsa_convert_func != NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
684 length = alsa_convert_func(convertb, &data, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
685 if (alsa_stereo_convert_func != NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
686 length = alsa_stereo_convert_func(convertb, &data, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
687 if (alsa_frequency_convert_func != NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
688 length = alsa_frequency_convert_func(convertb, &data, length,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
689 effectf->rate, outputf->rate);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
690
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
691 if (alsa_cfg.soft_volume)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
692 volume_adjust(data, length, outputf->xmms_format, outputf->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
693
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
694 if (mmap)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
695 alsa_mmap_audio(data, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
696 else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
697 alsa_write_audio(data, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
698 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
699
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
700 /* write callback */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
701 void alsa_write(gpointer data, int length)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
702 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
703 if (multi_thread) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
704 int cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
705 char *src = (char *)data;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
706
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
707 alsa_total_written += length;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
708 while (length > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
709 int wr;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
710 cnt = MIN(length, thread_buffer_size - wr_index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
711 memcpy(thread_buffer + wr_index, src, cnt);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
712 wr = (wr_index + cnt) % thread_buffer_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
713 wr_index = wr;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
714 length -= cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
715 src += cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
716 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
717 } else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
718 alsa_do_write(data, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
719 alsa_total_written += length;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
720 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
721 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
722
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
723 /* transfer data to audio h/w via normal write */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
724 static void alsa_write_audio(char *data, int length)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
725 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
726 snd_pcm_sframes_t written_frames;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
727
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
728 while (length > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
729 int frames = snd_pcm_bytes_to_frames(alsa_pcm, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
730 written_frames = snd_pcm_writei(alsa_pcm, data, frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
731
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
732 if (written_frames > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
733 int written = snd_pcm_frames_to_bytes(alsa_pcm,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
734 written_frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
735 length -= written;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
736 data += written;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
737 alsa_hw_written += written;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
738 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
739 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
740 int err = alsa_handle_error((int)written_frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
741 if (err < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
742 g_warning("alsa_write_audio(): write error: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
743 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
744 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
745 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
746 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
747 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
748 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
749
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
750 /* transfer data to audio h/w via mmap
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
751 *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
752 * basically, it makes sense only in the single thread mode.
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
753 * also, don't expect too much efficiency over mmap...
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
754 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
755 static void
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
756 alsa_mmap_audio(char *data, int length)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
757 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
758 int cnt, err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
759 snd_pcm_uframes_t offset, frames;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
760 const snd_pcm_channel_area_t *chan_areas;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
761 snd_pcm_channel_area_t src_area;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
762 int ch, channels, sample_bits;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
763
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
764 if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_XRUN)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
765 alsa_handle_error(-EPIPE);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
766
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
767 /* need to call this before snd_pcm_mmap_begin() */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
768 alsa_get_avail();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
769
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
770 channels = outputf->channels;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
771 sample_bits = outputf->sample_bits;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
772 while (length > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
773 frames = snd_pcm_bytes_to_frames(alsa_pcm, length);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
774 if ((err = snd_pcm_mmap_begin(alsa_pcm, &chan_areas, &offset, &frames) < 0)) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
775 g_warning("alsa_mmap_audio(): snd_pcm_mmap_begin() " "failed: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
776 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
777 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
778 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
779
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
780 cnt = snd_pcm_frames_to_bytes(alsa_pcm, frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
781
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
782 src_area.addr = data;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
783 src_area.first = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
784 src_area.step = channels * sample_bits;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
785 for (ch = 0; ch < channels; ch++) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
786 snd_pcm_area_copy(&chan_areas[ch], offset,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
787 &src_area, 0, frames, outputf->format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
788 src_area.first += sample_bits;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
789 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
790
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
791 err = snd_pcm_mmap_commit(alsa_pcm, offset, frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
792 if (err < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
793 err = alsa_handle_error(err);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
794 if (err < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
795 g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit() "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
796 "failed: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
797 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
798 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
799 if (err != frames)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
800 g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
801 "returned %d, expected %d", err, (int)frames);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
802 data += cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
803 length -= cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
804 alsa_hw_written += cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
805 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
806 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
807
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
808 /* PCM isn't started automatically in the case of mmap mode, so
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
809 * we need to trigger manually
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
810 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
811 if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
812 if (alsa_hw_written >= hw_period_size)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
813 snd_pcm_start(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
814 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
815 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
816
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
817 /* transfer audio data from thread buffer to h/w */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
818 static void alsa_write_out_thread_data(void)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
819 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
820 gint length, cnt, avail;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
821 int err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
822
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
823 length = MIN(hw_period_size_in, get_thread_buffer_filled());
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
824 avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
825 length = MIN(length, avail);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
826 while (length > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
827 int rd;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
828 cnt = MIN(length, thread_buffer_size - rd_index);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
829 alsa_do_write(thread_buffer + rd_index, cnt);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
830 rd = (rd_index + cnt) % thread_buffer_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
831 rd_index = rd;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
832 length -= cnt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
833
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
834 if (length > 0 && snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
835 if ((err = snd_pcm_start(alsa_pcm)) < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
836 g_warning("alsa_mmap_audio(): snd_pcm_start() "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
837 "failed: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
838 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
839 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
840 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
841
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
842 /* audio thread loop */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
843 /* FIXME: proper lock? */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
844 static void *alsa_loop(void *arg)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
845 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
846 int npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
847 struct pollfd *pfds;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
848 unsigned short *revents;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
849
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
850 if (npfds <= 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
851 goto _error;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
852 pfds = alloca(sizeof(*pfds) * npfds);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
853 revents = alloca(sizeof(*revents) * npfds);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
854 while (going && alsa_pcm) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
855 if (! paused && get_thread_buffer_filled() > hw_period_size_in) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
856 snd_pcm_poll_descriptors(alsa_pcm, pfds, npfds);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
857 if (poll(pfds, npfds, 10) > 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
858 /* need to check revents. poll() with dmix returns
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
859 * a postive value even if no data is available
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
860 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
861 int i;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
862 snd_pcm_poll_descriptors_revents(alsa_pcm, pfds, npfds, revents);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
863 for (i = 0; i < npfds; i++)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
864 if (revents[i] & POLLOUT) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
865 alsa_write_out_thread_data();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
866 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
867 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
868 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
869 } else
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
870 xmms_usleep(10000);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
871
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
872 if (pause_request != paused)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
873 alsa_do_pause(pause_request);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
874
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
875 if (flush_request != -1) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
876 alsa_do_flush(flush_request);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
877 flush_request = -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
878 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
879 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
880
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
881 _error:
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
882 alsa_close_pcm();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
883 g_free(thread_buffer);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
884 thread_buffer = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
885
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
886 g_thread_exit(NULL);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
887
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
888 /* shut GCC up */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
889 return NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
890 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
891
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
892 /* open callback */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
893 int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
894 alsa_open(AFormat fmt, int rate, int nch)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
895 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
896 debug("Opening device");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
897 inputf = snd_format_from_xmms(fmt, rate, nch);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
898 effectf = snd_format_from_xmms(fmt, rate, nch);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
899
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
900 if (alsa_cfg.debug)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
901 snd_output_stdio_attach(&logs, stdout, 0);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
902
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
903 mmap = alsa_cfg.mmap;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
904
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
905 if (alsa_setup(inputf) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
906 alsa_close();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
907 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
908 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
909
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
910 if (!mixer)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
911 alsa_setup_mixer();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
912
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
913 convertb = xmms_convert_buffers_new();
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
914
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
915 output_time_offset = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
916 alsa_total_written = alsa_hw_written = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
917 going = TRUE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
918 paused = FALSE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
919
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
920 multi_thread = alsa_cfg.multi_thread;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
921 debug("ALSA: multi_thread = %d\n", multi_thread);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
922
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
923 if (multi_thread) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
924 thread_buffer_size = (guint64)alsa_cfg.thread_buffer_time * inputf->bps / 1000;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
925 if (thread_buffer_size < hw_buffer_size)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
926 thread_buffer_size = hw_buffer_size * 2;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
927 if (thread_buffer_size < 8192)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
928 thread_buffer_size = 8192;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
929 thread_buffer_size += hw_buffer_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
930 thread_buffer_size -= thread_buffer_size % hw_period_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
931 thread_buffer = g_malloc0(thread_buffer_size);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
932 wr_index = rd_index = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
933 pause_request = FALSE;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
934 flush_request = -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
935
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
936 audio_thread = g_thread_create(alsa_loop, NULL, TRUE, NULL);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
937 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
938
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
939 return 1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
940 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
941
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
942 static struct snd_format *
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
943 snd_format_from_xmms(AFormat fmt, int rate, int channels)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
944 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
945 struct snd_format *f = g_malloc(sizeof(struct snd_format));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
946 int i;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
947
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
948 f->xmms_format = fmt;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
949 f->format = SND_PCM_FORMAT_UNKNOWN;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
950
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
951 for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
952 if (format_table[i].xmms == fmt) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
953 f->format = format_table[i].alsa;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
954 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
955 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
956
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
957 /* Get rid of _NE */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
958 for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
959 if (format_table[i].alsa == f->format) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
960 f->xmms_format = format_table[i].xmms;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
961 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
962 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
963
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
964
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
965 f->rate = rate;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
966 f->channels = channels;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
967 f->sample_bits = snd_pcm_format_physical_width(f->format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
968 f->bps = (rate * f->sample_bits * channels) >> 3;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
969
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
970 return f;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
971 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
972
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
973 static int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
974 format_from_alsa(snd_pcm_format_t fmt)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
975 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
976 int i;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
977 for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
978 if (format_table[i].alsa == fmt)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
979 return format_table[i].xmms;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
980 g_warning("Unsupported format: %s", snd_pcm_format_name(fmt));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
981 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
982 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
983
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
984 static int
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
985 alsa_setup(struct snd_format *f)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
986 {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
987 int err;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
988 snd_pcm_hw_params_t *hwparams;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
989 snd_pcm_sw_params_t *swparams;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
990 int alsa_buffer_time;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
991 unsigned int alsa_period_time;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
992 snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
993
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
994 debug("alsa_setup");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
995
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
996 alsa_convert_func = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
997 alsa_stereo_convert_func = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
998 alsa_frequency_convert_func = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
999
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1000 g_free(outputf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1001 outputf = snd_format_from_xmms(f->xmms_format, f->rate, f->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1002
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1003 debug("Opening device: %s", alsa_cfg.pcm_device);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1004 /* FIXME: Can snd_pcm_open() return EAGAIN? */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1005 if ((err = snd_pcm_open(&alsa_pcm, alsa_cfg.pcm_device,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1006 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1007 g_warning("alsa_setup(): Failed to open pcm device (%s): %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1008 alsa_cfg.pcm_device, snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1009 alsa_pcm = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1010 g_free(outputf);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1011 outputf = NULL;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1012 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1013 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1014
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1015 /* doesn't care about non-blocking */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1016 /* snd_pcm_nonblock(alsa_pcm, 0); */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1017
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1018 if (alsa_cfg.debug) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1019 snd_pcm_info_t *info;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1020 int alsa_card, alsa_device, alsa_subdevice;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1021
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1022 snd_pcm_info_alloca(&info);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1023 snd_pcm_info(alsa_pcm, info);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1024 alsa_card = snd_pcm_info_get_card(info);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1025 alsa_device = snd_pcm_info_get_device(info);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1026 alsa_subdevice = snd_pcm_info_get_subdevice(info);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1027 printf("Card %i, Device %i, Subdevice %i\n",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1028 alsa_card, alsa_device, alsa_subdevice);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1029 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1030
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1031 snd_pcm_hw_params_alloca(&hwparams);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1032
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1033 if ((err = snd_pcm_hw_params_any(alsa_pcm, hwparams)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1034 g_warning("alsa_setup(): No configuration available for "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1035 "playback: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1036 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1037 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1038
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1039 if (mmap &&
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1040 (err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1041 SND_PCM_ACCESS_MMAP_INTERLEAVED))
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1042 < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1043 g_message("alsa_setup(): Cannot set mmap'ed mode: %s. "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1044 "falling back to direct write", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1045 mmap = 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1046 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1047
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1048 if (!mmap &&
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1049 (err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1050 SND_PCM_ACCESS_RW_INTERLEAVED)) <
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1051 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1052 g_warning("alsa_setup(): Cannot set direct write mode: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1053 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1054 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1055 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1056
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1057 if ((err =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1058 snd_pcm_hw_params_set_format(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1059 outputf->format)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1060 /*
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1061 * Try if one of these format work (one of them should work
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1062 * on almost all soundcards)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1063 */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1064 snd_pcm_format_t formats[] = { SND_PCM_FORMAT_S16_LE,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1065 SND_PCM_FORMAT_S16_BE,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1066 SND_PCM_FORMAT_U8
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1067 };
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1068 int i;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1069
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1070 for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1071 if (snd_pcm_hw_params_set_format(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1072 formats[i]) == 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1073 outputf->format = formats[i];
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1074 break;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1075 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1076 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1077 if (outputf->format != f->format) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1078 outputf->xmms_format = format_from_alsa(outputf->format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1079 debug("Converting format from %d to %d",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1080 f->xmms_format, outputf->xmms_format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1081 if (outputf->xmms_format < 0)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1082 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1083 alsa_convert_func =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1084 xmms_convert_get_func(outputf->xmms_format,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1085 f->xmms_format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1086 if (alsa_convert_func == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1087 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1088 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1089 else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1090 g_warning("alsa_setup(): Sample format not "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1091 "available for playback: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1092 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1093 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1094 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1095
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1096 snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1097 &outputf->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1098 if (outputf->channels != f->channels) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1099 debug("Converting channels from %d to %d",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1100 f->channels, outputf->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1101 alsa_stereo_convert_func =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1102 xmms_convert_get_channel_func(outputf->xmms_format,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1103 outputf->channels,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1104 f->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1105 if (alsa_stereo_convert_func == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1106 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1107 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1108
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1109 snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &outputf->rate, 0);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1110 if (outputf->rate == 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1111 g_warning("alsa_setup(): No usable samplerate available.");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1112 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1113 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1114 if (outputf->rate != f->rate) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1115 debug("Converting samplerate from %d to %d",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1116 f->rate, outputf->rate);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1117 alsa_frequency_convert_func =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1118 xmms_convert_get_frequency_func(outputf->xmms_format,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1119 outputf->channels);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1120 if (alsa_frequency_convert_func == NULL)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1121 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1122 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1123
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1124 outputf->sample_bits = snd_pcm_format_physical_width(outputf->format);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1125 outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1126
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1127 alsa_buffer_time = alsa_cfg.buffer_time * 1000;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1128 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1129 &alsa_buffer_time,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1130 0)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1131 g_warning("alsa_setup(): Set buffer time failed: %s.",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1132 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1133 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1134 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1135
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1136 alsa_period_time = alsa_cfg.period_time * 1000;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1137 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1138 &alsa_period_time,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1139 0)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1140 g_warning("alsa_setup(): Set period time failed: %s.",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1141 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1142 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1143 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1144
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1145 if (snd_pcm_hw_params(alsa_pcm, hwparams) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1146 if (alsa_cfg.debug)
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1147 snd_pcm_hw_params_dump(hwparams, logs);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1148 g_warning("alsa_setup(): Unable to install hw params");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1149 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1150 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1151
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1152 if ((err =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1153 snd_pcm_hw_params_get_buffer_size(hwparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1154 &alsa_buffer_size)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1155 g_warning("alsa_setup(): snd_pcm_hw_params_get_buffer_size() "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1156 "failed: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1157 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1158 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1159
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1160 if ((err =
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1161 snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1162 0)) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1163 g_warning("alsa_setup(): snd_pcm_hw_params_get_period_size() "
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1164 "failed: %s", snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1165 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1166 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1167
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1168 alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1169
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1170 snd_pcm_sw_params_alloca(&swparams);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1171 snd_pcm_sw_params_current(alsa_pcm, swparams);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1172
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1173 /* This has effect for non-mmap only */
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1174 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_pcm,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1175 swparams,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1176 alsa_buffer_size -
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1177 alsa_period_size) < 0))
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1178 g_warning("alsa_setup(): setting start " "threshold failed: %s",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1179 snd_strerror(-err));
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1180 if (snd_pcm_sw_params(alsa_pcm, swparams) < 0) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1181 g_warning("alsa_setup(): Unable to install sw params");
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1182 return -1;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1183 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1184
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1185 if (alsa_cfg.debug) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1186 snd_pcm_sw_params_dump(swparams, logs);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1187 snd_pcm_dump(alsa_pcm, logs);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1188 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1189
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1190 hw_buffer_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_buffer_size);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1191 hw_period_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_period_size);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1192 if (inputf->bps != outputf->bps) {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1193 hw_buffer_size_in = ((guint64)hw_buffer_size * inputf->bps +
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1194 outputf->bps/2) / outputf->bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1195 hw_period_size_in = ((guint64)hw_period_size * inputf->bps +
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1196 outputf->bps/2) / outputf->bps;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1197 } else {
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1198 hw_buffer_size_in = hw_buffer_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1199 hw_period_size_in = hw_period_size;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1200 }
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1201
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1202 debug("Device setup: buffer time: %i, size: %i.", alsa_buffer_time,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1203 hw_buffer_size);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1204 debug("Device setup: period time: %i, size: %i.", alsa_period_time,
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1205 hw_period_size);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1206 debug("bits per sample: %i; frame size: %i; Bps: %i",
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1207 snd_pcm_format_physical_width(outputf->format),
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1208 snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps);
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1209
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1210 return 0;
cb178e5ad177 [svn] Import audacious source.
nenolod
parents:
diff changeset
1211 }