|
a/sc2src/alsadirect.cpp |
|
b/sc2src/alsadirect.cpp |
|
... |
|
... |
46 |
#ifndef MIN
|
46 |
#ifndef MIN
|
47 |
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
47 |
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
48 |
#endif
|
48 |
#endif
|
49 |
|
49 |
|
50 |
// The queue for audio blocks ready for alsa. This is the maximum size
|
50 |
// The queue for audio blocks ready for alsa. This is the maximum size
|
51 |
// before enqueuing blocks
|
51 |
// before the upstream task blocks
|
52 |
static const unsigned int qs_hi = 100;
|
52 |
static const unsigned int qs_hi = 100;
|
53 |
|
53 |
|
54 |
// Queue size target including alsa buffers. There is no particular
|
54 |
// Queue size target including alsa buffers. There is no particular
|
55 |
// reason for the qs_hi/2 value. We could try something lower to
|
55 |
// reason for the qs_hi/2 value. We could try something lower to
|
56 |
// minimize latency
|
56 |
// minimize latency
|
|
... |
|
... |
128 |
LOGERR("alsawriter: waitminsz failed\n");
|
128 |
LOGERR("alsawriter: waitminsz failed\n");
|
129 |
alsaqueue.workerExit();
|
129 |
alsaqueue.workerExit();
|
130 |
return (void *)1;
|
130 |
return (void *)1;
|
131 |
}
|
131 |
}
|
132 |
}
|
132 |
}
|
|
|
133 |
|
133 |
AudioMessage *tsk = 0;
|
134 |
AudioMessage *tsk = 0;
|
134 |
size_t qsz;
|
|
|
135 |
if (!alsaqueue.take(&tsk, &qsz)) {
|
135 |
if (!alsaqueue.take(&tsk)) {
|
136 |
// TBD: reset alsa?
|
136 |
// TBD: reset alsa?
|
137 |
alsaqueue.workerExit();
|
137 |
alsaqueue.workerExit();
|
138 |
return (void*)1;
|
138 |
return (void*)1;
|
139 |
}
|
139 |
}
|
140 |
|
140 |
|
|
... |
|
... |
142 |
char *buf = tsk->m_buf;
|
142 |
char *buf = tsk->m_buf;
|
143 |
// This loop is copied from the alsa sample, but it should not
|
143 |
// This loop is copied from the alsa sample, but it should not
|
144 |
// be necessary, in synchronous mode, alsa is supposed to
|
144 |
// be necessary, in synchronous mode, alsa is supposed to
|
145 |
// perform complete writes except for errors or interrupts
|
145 |
// perform complete writes except for errors or interrupts
|
146 |
while (frames > 0) {
|
146 |
while (frames > 0) {
|
|
|
147 |
// LOGDEB("alsawriter: avail frames " << snd_pcm_avail(pcm) <<
|
|
|
148 |
// " writing " << frames << endl);
|
147 |
snd_pcm_sframes_t ret = snd_pcm_writei(pcm, tsk->m_buf, frames);
|
149 |
snd_pcm_sframes_t ret = snd_pcm_writei(pcm, tsk->m_buf, frames);
|
148 |
if (ret != int(frames)) {
|
150 |
if (ret != int(frames)) {
|
149 |
LOGERR("snd_pcm_writei(" << frames <<" frames) failed: ret: " <<
|
151 |
LOGERR("snd_pcm_writei(" << frames <<" frames) failed: ret: " <<
|
150 |
ret << endl);
|
152 |
ret << endl);
|
151 |
} else {
|
153 |
} else {
|
|
... |
|
... |
163 |
return (void*)1;
|
165 |
return (void*)1;
|
164 |
}
|
166 |
}
|
165 |
qinit = false;
|
167 |
qinit = false;
|
166 |
break;
|
168 |
break;
|
167 |
}
|
169 |
}
|
|
|
170 |
|
168 |
unsigned int bytes = tsk->frames_to_bytes(ret);
|
171 |
buf += tsk->frames_to_bytes(ret);
|
169 |
buf += bytes;
|
|
|
170 |
frames -= ret;
|
172 |
frames -= ret;
|
171 |
}
|
173 |
}
|
172 |
|
174 |
|
173 |
delete tsk;
|
175 |
delete tsk;
|
174 |
}
|
176 |
}
|
175 |
}
|
177 |
}
|
176 |
|
178 |
|
177 |
static bool alsa_init(const string& dev, AudioMessage *tsk)
|
179 |
static bool alsa_init(const string& dev, AudioMessage *tsk)
|
178 |
{
|
180 |
{
|
179 |
snd_pcm_hw_params_t *hwparams;
|
|
|
180 |
int err;
|
181 |
int err;
|
181 |
const char *cmd = "";
|
182 |
const char *cmd = "";
|
182 |
unsigned int actual_rate = tsk->m_freq;
|
|
|
183 |
|
183 |
|
184 |
if ((err = snd_pcm_open(&pcm, dev.c_str(),
|
184 |
if ((err = snd_pcm_open(&pcm, dev.c_str(),
|
185 |
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
185 |
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
186 |
LOGERR("alsa_init: snd_pcm_open " << dev << " " <<
|
186 |
LOGERR("alsa_init: snd_pcm_open " << dev << " " <<
|
187 |
snd_strerror(err) << endl);
|
187 |
snd_strerror(err) << endl);
|
188 |
return false;;
|
188 |
return false;;
|
189 |
}
|
189 |
}
|
|
|
190 |
|
|
|
191 |
snd_pcm_hw_params_t *hwparams;
|
190 |
if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) {
|
192 |
snd_pcm_hw_params_alloca(&hwparams);
|
191 |
LOGERR("alsa_init: snd_pcm_hw_params_malloc " <<
|
|
|
192 |
snd_strerror(err) << endl);
|
|
|
193 |
snd_pcm_close(pcm);
|
|
|
194 |
return false;
|
|
|
195 |
}
|
|
|
196 |
|
193 |
|
197 |
cmd = "snd_pcm_hw_params_any";
|
194 |
cmd = "snd_pcm_hw_params_any";
|
198 |
if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
|
195 |
if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0) {
|
199 |
goto error;
|
196 |
goto error;
|
200 |
}
|
197 |
}
|
|
... |
|
... |
214 |
if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams,
|
211 |
if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams,
|
215 |
tsk->m_chans)) < 0) {
|
212 |
tsk->m_chans)) < 0) {
|
216 |
goto error;
|
213 |
goto error;
|
217 |
}
|
214 |
}
|
218 |
cmd = "snd_pcm_hw_params_set_rate_near";
|
215 |
cmd = "snd_pcm_hw_params_set_rate_near";
|
|
|
216 |
unsigned int actual_rate;
|
|
|
217 |
actual_rate = tsk->m_freq;
|
219 |
if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams,
|
218 |
if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams,
|
220 |
&actual_rate, 0)) < 0) {
|
219 |
&actual_rate, 0)) < 0) {
|
221 |
goto error;
|
220 |
goto error;
|
222 |
}
|
221 |
}
|
223 |
if (actual_rate != tsk->m_freq) {
|
222 |
if (actual_rate != tsk->m_freq) {
|
224 |
LOGERR("snd_pcm_hw_params_set_rate_near: got actual rate "
|
223 |
LOGERR("snd_pcm_hw_params_set_rate_near: got actual rate "
|
225 |
<< actual_rate << endl);
|
224 |
<< actual_rate << endl);
|
226 |
goto error;
|
225 |
goto error;
|
227 |
}
|
226 |
}
|
|
|
227 |
|
|
|
228 |
// Note: we don't use these values, get them just for information purposes
|
228 |
unsigned int periodsmin, periodsmax;
|
229 |
unsigned int periodsmin, periodsmax;
|
229 |
snd_pcm_hw_params_get_periods_min(hwparams, &periodsmin, 0);
|
230 |
snd_pcm_hw_params_get_periods_min(hwparams, &periodsmin, 0);
|
230 |
snd_pcm_hw_params_get_periods_max(hwparams, &periodsmax, 0);
|
231 |
snd_pcm_hw_params_get_periods_max(hwparams, &periodsmax, 0);
|
231 |
snd_pcm_uframes_t bsmax, bsmin, prmin, prmax;
|
232 |
snd_pcm_uframes_t bsmax, bsmin, prmin, prmax;
|
232 |
snd_pcm_hw_params_get_buffer_size_min(hwparams, &bsmin);
|
233 |
snd_pcm_hw_params_get_buffer_size_min(hwparams, &bsmin);
|
|
... |
|
... |
239 |
|
240 |
|
240 |
cmd = "snd_pcm_hw_params_set_buffer_time_near";
|
241 |
cmd = "snd_pcm_hw_params_set_buffer_time_near";
|
241 |
unsigned int buftimereq;
|
242 |
unsigned int buftimereq;
|
242 |
buftimereq = buffer_time;
|
243 |
buftimereq = buffer_time;
|
243 |
if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams,
|
244 |
if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams,
|
244 |
&buffer_time, 0))
|
245 |
&buffer_time, 0)) < 0) {
|
245 |
< 0) {
|
|
|
246 |
goto error;
|
246 |
goto error;
|
247 |
}
|
247 |
}
|
248 |
LOGDEB("Alsa: set buffer_time_near: asked " <<buftimereq << " got " <<
|
248 |
LOGDEB("Alsa: set buffer_time_near: asked " << buftimereq << " got " <<
|
249 |
buffer_time << endl);
|
249 |
buffer_time << endl);
|
250 |
|
250 |
|
251 |
cmd = "snd_pcm_hw_params_set_period_time_near";
|
251 |
cmd = "snd_pcm_hw_params_set_period_time_near";
|
252 |
buftimereq = period_time;
|
252 |
buftimereq = period_time;
|
253 |
if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hwparams,
|
253 |
if ((err = snd_pcm_hw_params_set_period_time_near(pcm, hwparams,
|
254 |
&period_time, 0))
|
254 |
&period_time, 0)) < 0) {
|
255 |
< 0) {
|
|
|
256 |
goto error;
|
255 |
goto error;
|
257 |
}
|
256 |
}
|
258 |
LOGDEB("Alsa: set_period_time_near: asked " << buftimereq << " got " <<
|
257 |
LOGDEB("Alsa: set_period_time_near: asked " << buftimereq << " got " <<
|
259 |
period_time << endl);
|
258 |
period_time << endl);
|
260 |
|
259 |
|
|
... |
|
... |
266 |
cmd = "snd_pcm_hw_params";
|
265 |
cmd = "snd_pcm_hw_params";
|
267 |
if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0) {
|
266 |
if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0) {
|
268 |
goto error;
|
267 |
goto error;
|
269 |
}
|
268 |
}
|
270 |
|
269 |
|
271 |
snd_pcm_hw_params_free(hwparams);
|
|
|
272 |
|
|
|
273 |
/* configure SW params */
|
270 |
/* configure SW params */
|
274 |
snd_pcm_sw_params_t *swparams;
|
271 |
snd_pcm_sw_params_t *swparams;
|
275 |
snd_pcm_sw_params_alloca(&swparams);
|
272 |
snd_pcm_sw_params_alloca(&swparams);
|
276 |
|
273 |
|
277 |
cmd = "snd_pcm_sw_params_current";
|
274 |
cmd = "snd_pcm_sw_params_current";
|
|
... |
|
... |
297 |
|
294 |
|
298 |
return true;
|
295 |
return true;
|
299 |
|
296 |
|
300 |
error:
|
297 |
error:
|
301 |
LOGERR("alsa_init: " << cmd << " error:" << snd_strerror(err) << endl);
|
298 |
LOGERR("alsa_init: " << cmd << " error:" << snd_strerror(err) << endl);
|
302 |
snd_pcm_hw_params_free(hwparams);
|
|
|
303 |
return false;
|
299 |
return false;
|
304 |
}
|
300 |
}
|
305 |
|
301 |
|
306 |
// Current in-driver delay in samples
|
302 |
// Current in-driver delay in samples
|
307 |
static int alsadelay()
|
303 |
static int alsadelay()
|