2016-03-01 17:40:38 +00:00
|
|
|
/* Sound device access
|
|
|
|
*
|
|
|
|
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <alsa/asoundlib.h>
|
2017-01-27 15:57:34 +00:00
|
|
|
#include "sample.h"
|
2016-03-01 17:40:38 +00:00
|
|
|
#include "debug.h"
|
2017-01-07 09:33:13 +00:00
|
|
|
#include "sender.h"
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
typedef struct sound {
|
|
|
|
snd_pcm_t *phandle, *chandle;
|
|
|
|
int pchannels, cchannels;
|
2017-01-29 06:25:12 +00:00
|
|
|
double spl_deviation; /* how much deviation is one sample step */
|
2017-01-07 09:33:13 +00:00
|
|
|
double paging_phaseshift; /* phase to shift every sample */
|
|
|
|
double paging_phase; /* current phase */
|
2016-03-01 17:40:38 +00:00
|
|
|
} sound_t;
|
|
|
|
|
|
|
|
static int set_hw_params(snd_pcm_t *handle, int samplerate, int *channels)
|
|
|
|
{
|
|
|
|
snd_pcm_hw_params_t *hw_params = NULL;
|
|
|
|
int rc;
|
|
|
|
unsigned int rrate;
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params_malloc(&hw_params);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to allocate hw_params! (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params_any(handle, hw_params);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set real hardware rate (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set access to interleaved (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_S16);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set sample format (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rrate = samplerate;
|
|
|
|
rc = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set sample rate (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
2016-10-07 06:55:18 +00:00
|
|
|
if ((int)rrate != samplerate) {
|
2016-03-01 17:40:38 +00:00
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Rate doesn't match (requested %dHz, get %dHz)\n", samplerate, rrate);
|
|
|
|
rc = -EIO;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
*channels = 1;
|
|
|
|
rc = snd_pcm_hw_params_set_channels(handle, hw_params, *channels);
|
|
|
|
if (rc < 0) {
|
|
|
|
*channels = 2;
|
|
|
|
rc = snd_pcm_hw_params_set_channels(handle, hw_params, *channels);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set channel count to 1 nor 2 (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_hw_params(handle, hw_params);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot set parameters (%s)\n", snd_strerror(rc));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
snd_pcm_hw_params_free(hw_params);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (hw_params) {
|
|
|
|
snd_pcm_hw_params_free(hw_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-08-07 15:22:24 +00:00
|
|
|
static int sound_prepare(sound_t *sound)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = snd_pcm_prepare(sound->phandle);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot prepare audio interface for use (%s)\n", snd_strerror(rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = snd_pcm_prepare(sound->chandle);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "cannot prepare audio interface for use (%s)\n", snd_strerror(rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
void *sound_open(const char *audiodev, double __attribute__((unused)) *tx_frequency, double __attribute__((unused)) *rx_frequency, int channels, double __attribute__((unused)) paging_frequency, int samplerate, double max_deviation, double __attribute__((unused)) max_modulation)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
sound_t *sound;
|
|
|
|
int rc;
|
|
|
|
|
2017-01-04 13:14:02 +00:00
|
|
|
if (channels < 1 || channels > 2) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Cannot use more than two channels with the same sound card!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
sound = calloc(1, sizeof(sound_t));
|
|
|
|
if (!sound) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to alloc memory!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
sound->spl_deviation = max_deviation / 32767.0;
|
2017-01-07 09:33:13 +00:00
|
|
|
sound->paging_phaseshift = 1.0 / ((double)samplerate / 1000.0);
|
|
|
|
|
2017-01-04 13:14:02 +00:00
|
|
|
rc = snd_pcm_open(&sound->phandle, audiodev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
2016-03-01 17:40:38 +00:00
|
|
|
if (rc < 0) {
|
2017-01-04 13:14:02 +00:00
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to open '%s' for playback! (%s)\n", audiodev, snd_strerror(rc));
|
2016-03-01 17:40:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-01-04 13:14:02 +00:00
|
|
|
rc = snd_pcm_open(&sound->chandle, audiodev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
2016-03-01 17:40:38 +00:00
|
|
|
if (rc < 0) {
|
2017-01-04 13:14:02 +00:00
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to open '%s' for capture! (%s)\n", audiodev, snd_strerror(rc));
|
2016-03-01 17:40:38 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = set_hw_params(sound->phandle, samplerate, &sound->pchannels);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to set playback hw params\n");
|
|
|
|
goto error;
|
|
|
|
}
|
2017-01-04 13:14:02 +00:00
|
|
|
if (sound->pchannels < channels) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Sound card only supports %d channel for playback.\n", sound->pchannels);
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
PDEBUG(DSOUND, DEBUG_DEBUG, "Playback with %d channels.\n", sound->pchannels);
|
|
|
|
|
|
|
|
rc = set_hw_params(sound->chandle, samplerate, &sound->cchannels);
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Failed to set capture hw params\n");
|
|
|
|
goto error;
|
|
|
|
}
|
2017-01-04 13:14:02 +00:00
|
|
|
if (sound->cchannels < channels) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Sound card only supports %d channel for capture.\n", sound->cchannels);
|
|
|
|
goto error;
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
PDEBUG(DSOUND, DEBUG_DEBUG, "Capture with %d channels.\n", sound->cchannels);
|
|
|
|
|
2016-08-07 15:22:24 +00:00
|
|
|
rc = sound_prepare(sound);
|
|
|
|
if (rc < 0)
|
2016-03-01 17:40:38 +00:00
|
|
|
goto error;
|
2016-07-02 06:04:43 +00:00
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
return sound;
|
|
|
|
|
|
|
|
error:
|
|
|
|
sound_close(sound);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-25 06:09:53 +00:00
|
|
|
/* start streaming */
|
|
|
|
int sound_start(void *inst)
|
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
|
|
|
int16_t buff[2];
|
|
|
|
|
|
|
|
/* trigger capturing */
|
|
|
|
snd_pcm_readi(sound->chandle, buff, 1);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
void sound_close(void *inst)
|
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
|
|
|
|
2016-10-07 06:55:18 +00:00
|
|
|
if (sound->phandle != NULL)
|
2016-03-01 17:40:38 +00:00
|
|
|
snd_pcm_close(sound->phandle);
|
2016-10-07 06:55:18 +00:00
|
|
|
if (sound->chandle != NULL)
|
2016-03-01 17:40:38 +00:00
|
|
|
snd_pcm_close(sound->chandle);
|
|
|
|
free(sound);
|
|
|
|
}
|
|
|
|
|
2017-01-07 09:33:13 +00:00
|
|
|
static void gen_paging_tone(sound_t *sound, int16_t *samples, int length, enum paging_signal paging_signal, int on)
|
|
|
|
{
|
|
|
|
double phaseshift, phase;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
switch (paging_signal) {
|
|
|
|
case PAGING_SIGNAL_NOTONE:
|
|
|
|
/* no tone if paging signal is on */
|
|
|
|
on = !on;
|
|
|
|
// fall through
|
|
|
|
case PAGING_SIGNAL_TONE:
|
|
|
|
/* tone if paging signal is on */
|
|
|
|
if (on) {
|
|
|
|
phaseshift = sound->paging_phaseshift;
|
|
|
|
phase = sound->paging_phase;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
if (phase < 0.5)
|
|
|
|
*samples++ = 30000;
|
|
|
|
else
|
|
|
|
*samples++ = -30000;
|
|
|
|
phase += phaseshift;
|
|
|
|
if (phase >= 1.0)
|
|
|
|
phase -= 1.0;
|
|
|
|
}
|
|
|
|
sound->paging_phase = phase;
|
|
|
|
} else
|
|
|
|
memset(samples, 0, length << 1);
|
|
|
|
break;
|
|
|
|
case PAGING_SIGNAL_NEGATIVE:
|
|
|
|
/* negative signal if paging signal is on */
|
|
|
|
on = !on;
|
|
|
|
// fall through
|
|
|
|
case PAGING_SIGNAL_POSITIVE:
|
|
|
|
/* positive signal if paging signal is on */
|
|
|
|
if (on)
|
|
|
|
memset(samples, 127, length << 1);
|
|
|
|
else
|
|
|
|
memset(samples, 128, length << 1);
|
|
|
|
break;
|
|
|
|
case PAGING_SIGNAL_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
2017-01-29 06:25:12 +00:00
|
|
|
double spl_deviation = sound->spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
int32_t value;
|
2017-01-03 11:31:59 +00:00
|
|
|
int16_t buff[num << 1];
|
2016-03-01 17:40:38 +00:00
|
|
|
int rc;
|
|
|
|
int i, ii;
|
|
|
|
|
|
|
|
if (sound->pchannels == 2) {
|
2017-01-27 15:57:34 +00:00
|
|
|
/* two channels */
|
2017-01-07 09:33:13 +00:00
|
|
|
if (paging_signal && on && paging_signal[0] != PAGING_SIGNAL_NONE) {
|
|
|
|
int16_t paging[num << 1];
|
|
|
|
gen_paging_tone(sound, paging, num, paging_signal[0], on[0]);
|
2017-01-03 11:31:59 +00:00
|
|
|
for (i = 0, ii = 0; i < num; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
value = samples[0][i] / spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
if (value > 32767)
|
|
|
|
value = 32767;
|
|
|
|
else if (value < -32767)
|
|
|
|
value = -32767;
|
|
|
|
buff[ii++] = value;
|
2017-01-07 09:33:13 +00:00
|
|
|
buff[ii++] = paging[i];
|
|
|
|
}
|
|
|
|
} else if (channels == 2) {
|
|
|
|
for (i = 0, ii = 0; i < num; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
value = samples[0][i] / spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
if (value > 32767)
|
|
|
|
value = 32767;
|
|
|
|
else if (value < -32767)
|
|
|
|
value = -32767;
|
|
|
|
buff[ii++] = value;
|
2017-01-29 06:25:12 +00:00
|
|
|
value = samples[1][i] / spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
if (value > 32767)
|
|
|
|
value = 32767;
|
|
|
|
else if (value < -32767)
|
|
|
|
value = -32767;
|
|
|
|
buff[ii++] = value;
|
2017-01-03 11:31:59 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0, ii = 0; i < num; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
value = samples[0][i] / spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
if (value > 32767)
|
|
|
|
value = 32767;
|
|
|
|
else if (value < -32767)
|
|
|
|
value = -32767;
|
|
|
|
buff[ii++] = value;
|
|
|
|
buff[ii++] = value;
|
2017-01-03 11:31:59 +00:00
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-01-27 15:57:34 +00:00
|
|
|
} else {
|
|
|
|
/* one channel */
|
|
|
|
for (i = 0, ii = 0; i < num; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
value = samples[0][i] / spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
if (value > 32767)
|
|
|
|
value = 32767;
|
|
|
|
else if (value < -32767)
|
|
|
|
value = -32767;
|
|
|
|
buff[ii++] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rc = snd_pcm_writei(sound->phandle, buff, num);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "failed to write audio to interface (%s)\n", snd_strerror(rc));
|
2017-03-04 05:35:38 +00:00
|
|
|
if (rc == -EPIPE) {
|
2016-08-07 15:22:24 +00:00
|
|
|
sound_prepare(sound);
|
2017-03-04 05:35:38 +00:00
|
|
|
sound_start(sound);
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != num)
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "short write to audio interface, written %d bytes, got %d bytes\n", num, rc);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-08-13 13:19:12 +00:00
|
|
|
#define KEEP_FRAMES 8 /* minimum frames not to read, due to bug in ALSA */
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
int sound_read(void *inst, sample_t **samples, int num, int channels)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
2017-01-29 06:25:12 +00:00
|
|
|
double spl_deviation = sound->spl_deviation;
|
2016-03-01 17:40:38 +00:00
|
|
|
int16_t buff[num << 1];
|
2017-01-03 11:31:59 +00:00
|
|
|
int32_t spl;
|
2016-07-02 06:04:43 +00:00
|
|
|
int in, rc;
|
2016-03-01 17:40:38 +00:00
|
|
|
int i, ii;
|
|
|
|
|
2016-07-02 06:04:43 +00:00
|
|
|
/* get samples in rx buffer */
|
|
|
|
in = snd_pcm_avail(sound->chandle);
|
2016-08-13 13:19:12 +00:00
|
|
|
/* if not more than KEEP_FRAMES frames available, try next time */
|
|
|
|
if (in <= KEEP_FRAMES)
|
2016-07-02 06:04:43 +00:00
|
|
|
return 0;
|
2016-08-13 13:19:12 +00:00
|
|
|
/* read some frames less than in buffer, because snd_pcm_readi() seems
|
|
|
|
* to corrupt last frames */
|
|
|
|
in -= KEEP_FRAMES;
|
2016-07-02 06:04:43 +00:00
|
|
|
if (in > num)
|
|
|
|
in = num;
|
|
|
|
|
2017-01-27 15:57:34 +00:00
|
|
|
rc = snd_pcm_readi(sound->chandle, buff, in);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
if (errno == EAGAIN)
|
|
|
|
return 0;
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "failed to read audio from interface (%s)\n", snd_strerror(rc));
|
|
|
|
/* recover read */
|
2017-03-04 05:35:38 +00:00
|
|
|
if (rc == -EPIPE) {
|
2016-08-07 15:22:24 +00:00
|
|
|
sound_prepare(sound);
|
2017-03-04 05:35:38 +00:00
|
|
|
sound_start(sound);
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sound->cchannels == 2) {
|
2017-01-03 11:31:59 +00:00
|
|
|
if (channels < 2) {
|
|
|
|
for (i = 0, ii = 0; i < rc; i++) {
|
|
|
|
spl = buff[ii++];
|
|
|
|
spl += buff[ii++];
|
2017-01-29 06:25:12 +00:00
|
|
|
samples[0][i] = (double)spl * spl_deviation;
|
2017-01-03 11:31:59 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0, ii = 0; i < rc; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
samples[0][i] = (double)buff[ii++] * spl_deviation;
|
|
|
|
samples[1][i] = (double)buff[ii++] * spl_deviation;
|
2017-01-03 11:31:59 +00:00
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-01-27 15:57:34 +00:00
|
|
|
} else {
|
|
|
|
for (i = 0, ii = 0; i < rc; i++) {
|
2017-01-29 06:25:12 +00:00
|
|
|
samples[0][i] = (double)buff[ii++] * spl_deviation;
|
2017-01-27 15:57:34 +00:00
|
|
|
}
|
2017-01-03 11:31:59 +00:00
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-03-04 05:35:38 +00:00
|
|
|
* get playback buffer space
|
2016-03-01 17:40:38 +00:00
|
|
|
*
|
2017-03-04 05:35:38 +00:00
|
|
|
* return number of samples to be sent */
|
|
|
|
int sound_get_tosend(void *inst, int latspl)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
|
|
|
int rc;
|
|
|
|
snd_pcm_sframes_t delay;
|
2017-03-04 05:35:38 +00:00
|
|
|
int tosend;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
rc = snd_pcm_delay(sound->phandle, &delay);
|
|
|
|
if (rc < 0) {
|
2016-02-16 17:56:55 +00:00
|
|
|
if (rc == -32)
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "Buffer underrun: Please use higher latency and enable real time scheduling\n");
|
|
|
|
else
|
|
|
|
PDEBUG(DSOUND, DEBUG_ERROR, "failed to get delay from interface (%s)\n", snd_strerror(rc));
|
2017-03-04 05:35:38 +00:00
|
|
|
if (rc == -EPIPE) {
|
2016-08-07 15:22:24 +00:00
|
|
|
sound_prepare(sound);
|
2017-03-04 05:35:38 +00:00
|
|
|
sound_start(sound);
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-03-04 05:35:38 +00:00
|
|
|
tosend = latspl - delay;
|
|
|
|
return tosend;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2016-04-25 18:20:54 +00:00
|
|
|
int sound_is_stereo_capture(void *inst)
|
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
|
|
|
|
|
|
|
if (sound->cchannels == 2)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sound_is_stereo_playback(void *inst)
|
|
|
|
{
|
|
|
|
sound_t *sound = (sound_t *)inst;
|
|
|
|
|
|
|
|
if (sound->pchannels == 2)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|