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>
2017-09-25 16:46:50 +00:00
# include <math.h>
2016-03-01 17:40:38 +00:00
# include <alsa/asoundlib.h>
2017-11-18 07:06:06 +00:00
# include "../libsample/sample.h"
2017-11-18 07:58:57 +00:00
# include "../libdebug/debug.h"
2017-11-18 07:33:07 +00:00
# include "../libmobile/sender.h"
2016-03-01 17:40:38 +00:00
typedef struct sound {
snd_pcm_t * phandle , * chandle ;
int pchannels , cchannels ;
2020-07-26 11:13:01 +00:00
int channels ; /* required number of channels */
int samplerate ; /* required sample rate */
char * audiodev ; /* required device */
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 */
2017-09-25 16:46:50 +00:00
double rx_frequency [ 2 ] ; /* rx frequency of radio connected to channel */
dispmeasparam_t * dmp [ 2 ] ;
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 ;
}
2020-07-26 11:13:01 +00:00
static int dev_open ( sound_t * sound )
2016-08-07 15:22:24 +00:00
{
2020-07-26 11:13:01 +00:00
int rc , rc_rec , rc_play ;
rc_play = snd_pcm_open ( & sound - > phandle , sound - > audiodev , SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK ) ;
rc_rec = snd_pcm_open ( & sound - > chandle , sound - > audiodev , SND_PCM_STREAM_CAPTURE , SND_PCM_NONBLOCK ) ;
if ( rc_play < 0 & & rc_rec < 0 ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Failed to open '%s'! (%s) \n " , sound - > audiodev , snd_strerror ( rc_play ) ) ;
PDEBUG ( DSOUND , DEBUG_ERROR , " Run 'aplay -l' to get a list of available cards and devices. \n " ) ;
PDEBUG ( DSOUND , DEBUG_ERROR , " Then use 'hw:<card>:<device>' for audio device. \n " ) ;
return rc_play ;
}
if ( rc_play < 0 ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Failed to open '%s' for playback! (%s) Please select a device that supports both direction audio. \n " , sound - > audiodev , snd_strerror ( rc_play ) ) ;
return rc_play ;
}
if ( rc_rec < 0 ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Failed to open '%s' for capture! (%s) Please select a device that supports both direction audio. \n " , sound - > audiodev , snd_strerror ( rc_rec ) ) ;
return rc_rec ;
}
rc = set_hw_params ( sound - > phandle , sound - > samplerate , & sound - > pchannels ) ;
if ( rc < 0 ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Failed to set playback hw params \n " ) ;
return rc ;
}
if ( sound - > pchannels < sound - > channels ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Sound card only supports %d channel for playback. \n " , sound - > pchannels ) ;
return rc ;
}
PDEBUG ( DSOUND , DEBUG_DEBUG , " Playback with %d channels. \n " , sound - > pchannels ) ;
rc = set_hw_params ( sound - > chandle , sound - > samplerate , & sound - > cchannels ) ;
if ( rc < 0 ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Failed to set capture hw params \n " ) ;
return rc ;
}
if ( sound - > cchannels < sound - > channels ) {
PDEBUG ( DSOUND , DEBUG_ERROR , " Sound card only supports %d channel for capture. \n " , sound - > cchannels ) ;
return - EIO ;
}
PDEBUG ( DSOUND , DEBUG_DEBUG , " Capture with %d channels. \n " , sound - > cchannels ) ;
2016-08-07 15:22:24 +00:00
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 ;
}
2020-07-26 11:13:01 +00:00
static void dev_close ( sound_t * sound )
{
if ( sound - > phandle ! = NULL )
snd_pcm_close ( sound - > phandle ) ;
if ( sound - > chandle ! = NULL )
snd_pcm_close ( sound - > chandle ) ;
}
2019-12-05 16:24:30 +00:00
void * sound_open ( const char * audiodev , double __attribute__ ( ( unused ) ) * tx_frequency , double __attribute__ ( ( unused ) ) * rx_frequency , int __attribute__ ( ( unused ) ) * am , int channels , double __attribute__ ( ( unused ) ) paging_frequency , int samplerate , int __attribute ( ( unused ) ) latspl , double max_deviation , double __attribute__ ( ( unused ) ) max_modulation , double __attribute__ ( ( unused ) ) modulation_index )
2016-03-01 17:40:38 +00:00
{
sound_t * sound ;
2020-07-26 11:13:01 +00:00
int rc ;
2016-03-01 17:40:38 +00:00
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 ;
}
2021-01-25 14:16:29 +00:00
sound - > audiodev = strdup ( audiodev ) ; // is feed when closed
2020-07-26 11:13:01 +00:00
sound - > channels = channels ;
sound - > samplerate = samplerate ;
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 ) ;
2020-07-26 11:13:01 +00:00
rc = dev_open ( sound ) ;
2016-08-07 15:22:24 +00:00
if ( rc < 0 )
2016-03-01 17:40:38 +00:00
goto error ;
2016-07-02 06:04:43 +00:00
2017-09-25 16:46:50 +00:00
if ( rx_frequency ) {
sender_t * sender ;
int i ;
for ( i = 0 ; i < channels ; i + + ) {
sound - > rx_frequency [ i ] = rx_frequency [ i ] ;
sender = get_sender_by_empfangsfrequenz ( sound - > rx_frequency [ i ] ) ;
if ( ! sender )
continue ;
2018-01-21 08:30:00 +00:00
sound - > dmp [ i ] = display_measurements_add ( & sender - > dispmeas , " RX Level " , " %.1f dB " , DISPLAY_MEAS_PEAK , DISPLAY_MEAS_LEFT , - 96.0 , 0.0 , - INFINITY ) ;
2017-09-25 16:46:50 +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 ;
2020-07-26 11:13:01 +00:00
dev_close ( sound ) ;
free ( sound - > audiodev ) ;
2016-03-01 17:40:38 +00:00
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 ;
2018-01-27 14:52:33 +00:00
/* FALLTHRU */
2017-01-07 09:33:13 +00:00
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 ;
2018-01-27 14:52:33 +00:00
/* FALLTHRU */
2017-01-07 09:33:13 +00:00
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-08-19 10:27:05 +00:00
int sound_write ( void * inst , sample_t * * samples , uint8_t __attribute__ ( ( unused ) ) * * power , 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 ) {
2020-07-26 11:13:01 +00:00
dev_close ( sound ) ;
rc = dev_open ( sound ) ;
if ( rc < 0 )
return rc ;
2017-03-04 05:35:38 +00:00
sound_start ( sound ) ;
2020-07-26 11:13:01 +00:00
return - EPIPE ; /* indicate what happened */
2017-03-04 05:35:38 +00:00
}
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-10-09 18:49:14 +00:00
int sound_read ( void * inst , sample_t * * samples , int num , int channels , double * rf_level_db )
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 ;
2017-09-25 16:46:50 +00:00
int32_t max [ 2 ] , a ;
2016-07-02 06:04:43 +00:00
int in , rc ;
2016-03-01 17:40:38 +00:00
int i , ii ;
2021-01-01 21:11:48 +00:00
/* make valgrind happy, because snd_pcm_readi() does not seem to initially fill buffer with values */
2019-08-14 09:54:41 +00:00
memset ( buff , 0 , sizeof ( buff ) ) ;
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 ) {
2020-07-26 11:13:01 +00:00
dev_close ( sound ) ;
rc = dev_open ( sound ) ;
if ( rc < 0 )
return rc ;
2017-03-04 05:35:38 +00:00
sound_start ( sound ) ;
2020-07-26 11:13:01 +00:00
return - EPIPE ; /* indicate what happened */
2017-03-04 05:35:38 +00:00
}
2016-03-01 17:40:38 +00:00
return rc ;
}
2017-09-25 16:46:50 +00:00
if ( rc = = 0 )
return rc ;
2016-03-01 17:40:38 +00:00
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-09-25 16:46:50 +00:00
a = ( spl > = 0 ) ? spl : - spl ;
if ( i = = 0 | | a > max [ 0 ] )
max [ 0 ] = a ;
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-09-25 16:46:50 +00:00
spl = buff [ ii + + ] ;
a = ( spl > = 0 ) ? spl : - spl ;
if ( i = = 0 | | a > max [ 0 ] )
max [ 0 ] = a ;
samples [ 0 ] [ i ] = ( double ) spl * spl_deviation ;
spl = buff [ ii + + ] ;
a = ( spl > = 0 ) ? spl : - spl ;
if ( i = = 0 | | a > max [ 1 ] )
max [ 1 ] = a ;
samples [ 1 ] [ i ] = ( double ) spl * 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-09-25 16:46:50 +00:00
spl = buff [ ii + + ] ;
a = ( spl > = 0 ) ? spl : - spl ;
if ( i = = 0 | | a > max [ 0 ] )
max [ 0 ] = a ;
samples [ 0 ] [ i ] = ( double ) spl * 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
2017-09-25 16:46:50 +00:00
sender_t * sender ;
for ( i = 0 ; i < channels ; i + + ) {
sender = get_sender_by_empfangsfrequenz ( sound - > rx_frequency [ i ] ) ;
if ( ! sender )
continue ;
display_measurements_update ( sound - > dmp [ i ] , log10 ( ( double ) max [ i ] / 32768.0 ) * 20 , 0.0 ) ;
2018-01-20 14:54:35 +00:00
if ( rf_level_db )
rf_level_db [ i ] = 0.0 ;
2017-09-25 16:46:50 +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 ) {
2020-07-26 11:13:01 +00:00
dev_close ( sound ) ;
rc = dev_open ( sound ) ;
if ( rc < 0 )
return rc ;
2017-03-04 05:35:38 +00:00
sound_start ( sound ) ;
2020-07-26 11:13:01 +00:00
return - EPIPE ; /* indicate what happened */
2017-03-04 05:35:38 +00:00
}
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 ;
}