mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-25 21:58:38 -05:00
- change from start_threads.c to start_alsa.c start_portaudio.c etc.
- split start_threads.c into start_alsa.c and start_portaudio.c - make configure/Makefile add start_alsa or start_portaudio as needed instead of start_threads Untested on ALSA, works fine with PORTAUDIO git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@100 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
1f1e1a965f
commit
36fcb937e3
@ -67,10 +67,10 @@ OBJS2C = ${SRCS2C:.c=.o}
|
||||
|
||||
# ok, so far for now
|
||||
# Windows @AUDIO@ will be jtaudio.c since it uses portaudio
|
||||
# for *nix @AUDIO@ will also be jtaudio.c and start_threads.c
|
||||
# for *nix @AUDIO@ will also be jtaudio.c and start_portaudio.c
|
||||
# for portaudio
|
||||
# for *nix @AUDIO@ will be start_threads.c for alsa
|
||||
# for *nix @AUDIO@ will be ?? for oss
|
||||
# for *nix @AUDIO@ will be start_alsa.c for alsa
|
||||
# for *nix @AUDIO@ will be start_oss.c for oss
|
||||
#
|
||||
# ptt_unix.c vs. ptt.c I'll sort out later.
|
||||
# ditto for cutil.c (only used on *nix)
|
||||
|
12
configure
vendored
12
configure
vendored
@ -2,7 +2,7 @@
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.53 for wsjt 0.9.
|
||||
#
|
||||
# $Id: configure.ac 76 2006-01-10 16:36:04Z va3db $
|
||||
# $Id: configure.ac 82 2006-01-10 21:35:37Z va3db $
|
||||
#
|
||||
# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
|
||||
# Free Software Foundation, Inc.
|
||||
@ -924,7 +924,7 @@ Free Software Foundation, Inc.
|
||||
This configure script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it.
|
||||
|
||||
$Id: configure.ac 76 2006-01-10 16:36:04Z va3db $
|
||||
$Id: configure.ac 82 2006-01-10 21:35:37Z va3db $
|
||||
_ACEOF
|
||||
exit 0
|
||||
fi
|
||||
@ -5729,7 +5729,7 @@ cat >>confdefs.h <<\_ACEOF
|
||||
#define USE_ALSA 1
|
||||
_ACEOF
|
||||
|
||||
AUDIO="start_threads.c"
|
||||
AUDIO="start_alsa.c"
|
||||
|
||||
LDFLAGS="${LDFLAGS} -lasound"
|
||||
CFLAGS="${CFLAGS} -DUSE_ALSA"
|
||||
@ -5742,8 +5742,10 @@ cat >>confdefs.h <<\_ACEOF
|
||||
#define USE_OSS 1
|
||||
_ACEOF
|
||||
|
||||
AUDIO="jtaudio.c"
|
||||
AUDIO="jtaudio.c start_oss.c"
|
||||
|
||||
CFLAGS="${CFLAGS} -DUSE_OSS"
|
||||
CPPFLAGS="${CPPFLAGS} -DUSE_OSS"
|
||||
fi
|
||||
|
||||
if test "$portaudio" = yes; then
|
||||
@ -5752,7 +5754,7 @@ cat >>confdefs.h <<\_ACEOF
|
||||
#define USE_PORTAUDIO 1
|
||||
_ACEOF
|
||||
|
||||
AUDIO="jtaudio.c start_threads.c"
|
||||
AUDIO="jtaudio.c start_portaudio.c"
|
||||
|
||||
LDFLAGS="${LDFLAGS} -lportaudio -lsamplerate"
|
||||
CFLAGS="${CFLAGS} -DUSE_PORTAUDIO"
|
||||
|
@ -233,21 +233,24 @@ fi
|
||||
|
||||
if test "$alsa" = yes; then
|
||||
AC_DEFINE(USE_ALSA, 1, [Define if you want ALSA used.])
|
||||
AC_SUBST(AUDIO, "start_threads.c")
|
||||
AC_SUBST(AUDIO, "start_alsa.c")
|
||||
LDFLAGS="${LDFLAGS} -lasound"
|
||||
CFLAGS="${CFLAGS} -DUSE_ALSA"
|
||||
CPPFLAGS="${CPPFLAGS} -DUSE_ALSA"
|
||||
fi
|
||||
|
||||
dnl still not sure what OSS will require, but heres a first guess -db
|
||||
if test "$oss" = yes; then
|
||||
AC_DEFINE(USE_OSS, 1, [Define if you want OSS used.])
|
||||
AC_SUBST(AUDIO, "jtaudio.c")
|
||||
AC_SUBST(AUDIO, "jtaudio.c start_oss.c")
|
||||
CFLAGS="${CFLAGS} -DUSE_OSS"
|
||||
CPPFLAGS="${CPPFLAGS} -DUSE_OSS"
|
||||
fi
|
||||
|
||||
dnl XXX
|
||||
if test "$portaudio" = yes; then
|
||||
AC_DEFINE(USE_PORTAUDIO, 1, [Define if you want PORTAUDIO used.])
|
||||
AC_SUBST(AUDIO, "jtaudio.c start_threads.c")
|
||||
AC_SUBST(AUDIO, "jtaudio.c start_portaudio.c")
|
||||
LDFLAGS="${LDFLAGS} -lportaudio -lsamplerate"
|
||||
CFLAGS="${CFLAGS} -DUSE_PORTAUDIO"
|
||||
CPPFLAGS="${CPPFLAGS} -DUSE_PORTAUDIO"
|
||||
|
540
start_alsa.c
Normal file
540
start_alsa.c
Normal file
@ -0,0 +1,540 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include "conf.h"
|
||||
|
||||
#if 0
|
||||
#define ALSA_LOG
|
||||
#define ALSA_LOG_BUFFERS
|
||||
#endif
|
||||
#if 0
|
||||
#define ALSA_PLAYBACK_LOG
|
||||
#define ALSA_CAPTURE_LOG
|
||||
#endif
|
||||
#define BUFFER_TIME 2000*1000
|
||||
|
||||
|
||||
typedef struct alsa_driver_s {
|
||||
snd_pcm_t *audio_fd;
|
||||
int capabilities;
|
||||
int open_mode;
|
||||
int has_pause_resume;
|
||||
int is_paused;
|
||||
int32_t output_sample_rate, input_sample_rate;
|
||||
double sample_rate_factor;
|
||||
uint32_t num_channels;
|
||||
uint32_t bits_per_sample;
|
||||
uint32_t bytes_per_frame;
|
||||
uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */
|
||||
int16_t *app_buffer_y1;
|
||||
int16_t *app_buffer_y2;
|
||||
int *app_buffer_offset;
|
||||
int app_buffer_length;
|
||||
double *Tsec;
|
||||
double *tbuf;
|
||||
int *ibuf;
|
||||
int *ndsec;
|
||||
int *tx_ok;
|
||||
int tx_starting;
|
||||
int tx_offset;
|
||||
int *tr_period;
|
||||
int *nwave;
|
||||
int *nmode;
|
||||
int *transmitting;
|
||||
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
int32_t mmap;
|
||||
} alsa_driver_t;
|
||||
|
||||
alsa_driver_t alsa_driver_playback;
|
||||
alsa_driver_t alsa_driver_capture;
|
||||
void *alsa_capture_buffers[2];
|
||||
void *alsa_playback_buffers[2];
|
||||
|
||||
static snd_output_t *jcd_out;
|
||||
|
||||
/*
|
||||
* open the audio device for writing to
|
||||
*/
|
||||
static int ao_alsa_open(alsa_driver_t *this_gen, int32_t *input_rate, snd_pcm_stream_t direction ) {
|
||||
alsa_driver_t *this = (alsa_driver_t *) this_gen;
|
||||
char *pcm_device;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_sw_params_t *swparams;
|
||||
snd_pcm_access_mask_t *mask;
|
||||
snd_pcm_uframes_t period_size_min;
|
||||
snd_pcm_uframes_t period_size_max;
|
||||
snd_pcm_uframes_t buffer_size_min;
|
||||
snd_pcm_uframes_t buffer_size_max;
|
||||
snd_pcm_format_t format;
|
||||
uint32_t buffer_time=BUFFER_TIME;
|
||||
snd_pcm_uframes_t buffer_time_to_size;
|
||||
int err, dir;
|
||||
int open_mode=1; /* NONBLOCK */
|
||||
/* int open_mode=0; BLOCK */
|
||||
int32_t rate=*input_rate;
|
||||
this->input_sample_rate=*input_rate;
|
||||
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
snd_pcm_sw_params_alloca(&swparams);
|
||||
err = snd_output_stdio_attach(&jcd_out, stdout, 0);
|
||||
|
||||
this->num_channels = 2;
|
||||
pcm_device="default";
|
||||
#ifdef ALSA_LOG
|
||||
printf("audio_alsa_out: Audio Device name = %s\n",pcm_device);
|
||||
printf("audio_alsa_out: Number of channels = %d\n",this->num_channels);
|
||||
#endif
|
||||
|
||||
if (this->audio_fd) {
|
||||
printf("audio_alsa_out:Already open...WHY!");
|
||||
snd_pcm_close (this->audio_fd);
|
||||
this->audio_fd = NULL;
|
||||
}
|
||||
|
||||
this->bytes_in_buffer = 0;
|
||||
/*
|
||||
* open audio device
|
||||
*/
|
||||
err=snd_pcm_open(&this->audio_fd, pcm_device, direction, open_mode);
|
||||
if(err <0 ) {
|
||||
printf ("audio_alsa_out: snd_pcm_open() of %s failed: %s\n", pcm_device, snd_strerror(err));
|
||||
printf ("audio_alsa_out: >>> check if another program already uses PCM <<<\n");
|
||||
return 0;
|
||||
}
|
||||
/* printf ("audio_alsa_out: snd_pcm_open() opened %s\n", pcm_device); */
|
||||
/* We wanted non blocking open but now put it back to normal */
|
||||
//snd_pcm_nonblock(this->audio_fd, 0);
|
||||
snd_pcm_nonblock(this->audio_fd, 1);
|
||||
/*
|
||||
* configure audio device
|
||||
*/
|
||||
err = snd_pcm_hw_params_any(this->audio_fd, params);
|
||||
if (err < 0) {
|
||||
printf ("audio_alsa_out: broken configuration for this PCM: no configurations available: %s\n"),
|
||||
snd_strerror(err);
|
||||
goto close;
|
||||
}
|
||||
/* set interleaved access */
|
||||
if (this->mmap != 0) {
|
||||
mask = alloca(snd_pcm_access_mask_sizeof());
|
||||
snd_pcm_access_mask_none(mask);
|
||||
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
|
||||
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
|
||||
snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
|
||||
err = snd_pcm_hw_params_set_access_mask(this->audio_fd, params, mask);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: mmap not availiable, falling back to compatiblity mode\n");
|
||||
this->mmap=0;
|
||||
err = snd_pcm_hw_params_set_access(this->audio_fd, params,
|
||||
SND_PCM_ACCESS_RW_NONINTERLEAVED);
|
||||
}
|
||||
} else {
|
||||
err = snd_pcm_hw_params_set_access(this->audio_fd, params,
|
||||
SND_PCM_ACCESS_RW_NONINTERLEAVED);
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: access type not available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* set the sample format S16 */
|
||||
/* ALSA automatically appends _LE or _BE depending on the CPU */
|
||||
format = SND_PCM_FORMAT_S16;
|
||||
err = snd_pcm_hw_params_set_format(this->audio_fd, params, format );
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: sample format non available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* set the number of channels */
|
||||
err = snd_pcm_hw_params_set_channels(this->audio_fd, params, this->num_channels);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Cannot set number of channels to %d (err=%d:%s)\n",
|
||||
this->num_channels, err, snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
#if SND_LIB_VERSION >= 0x010009
|
||||
/* Restrict a configuration space to contain only real hardware rates */
|
||||
err = snd_pcm_hw_params_set_rate_resample(this->audio_fd, params, 0);
|
||||
#endif
|
||||
/* set the stream rate [Hz] */
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_set_rate_near(this->audio_fd, params, &rate, &dir);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: rate not available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
this->output_sample_rate = (uint32_t)rate;
|
||||
if (this->input_sample_rate != this->output_sample_rate) {
|
||||
printf ( "audio_alsa_out: audio rate : %d requested, %d provided by device/sec\n",
|
||||
this->input_sample_rate, this->output_sample_rate);
|
||||
}
|
||||
buffer_time_to_size = ( (uint64_t)buffer_time * rate) / 1000000;
|
||||
err = snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
|
||||
err = snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_get_period_size_min(params, &period_size_min,&dir);
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_get_period_size_max(params, &period_size_max,&dir);
|
||||
#ifdef ALSA_LOG_BUFFERS
|
||||
printf("Buffer size range from %lu to %lu\n",buffer_size_min, buffer_size_max);
|
||||
printf("Period size range from %lu to %lu\n",period_size_min, period_size_max);
|
||||
printf("Buffer time size %lu\n",buffer_time_to_size);
|
||||
#endif
|
||||
this->buffer_size = buffer_time_to_size;
|
||||
if (buffer_size_max < this->buffer_size)
|
||||
this->buffer_size = buffer_size_max;
|
||||
if (buffer_size_min > this->buffer_size)
|
||||
this->buffer_size = buffer_size_min;
|
||||
this->period_size = this->buffer_size/8;
|
||||
if (this->period_size > 2048)
|
||||
this->period_size = 2048;
|
||||
this->buffer_size = this->period_size*8;
|
||||
#ifdef ALSA_LOG_BUFFERS
|
||||
printf("To choose buffer_size = %ld\n",this->buffer_size);
|
||||
printf("To choose period_size = %ld\n",this->period_size);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Set period to buffer size ratios at 8 periods to 1 buffer */
|
||||
dir=-1;
|
||||
periods=8;
|
||||
err = snd_pcm_hw_params_set_periods_near(this->audio_fd, params, &periods ,&dir);
|
||||
if (err < 0) {
|
||||
xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
|
||||
"audio_alsa_out: unable to set any periods: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* set the ring-buffer time [us] (large enough for x us|y samples ...) */
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_set_buffer_time_near(this->audio_fd, params, &buffer_time, &dir);
|
||||
if (err < 0) {
|
||||
xprintf (this->class->xine, XINE_VERBOSITY_DEBUG,
|
||||
"audio_alsa_out: buffer time not available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
#endif
|
||||
#if 1
|
||||
/* set the period time [us] (interrupt every x us|y samples ...) */
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_set_period_size_near(this->audio_fd, params, &(this->period_size), &dir);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: period time not available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
#endif
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_get_period_size(params, &(this->period_size), &dir);
|
||||
|
||||
dir=0;
|
||||
err = snd_pcm_hw_params_set_buffer_size_near(this->audio_fd, params, &(this->buffer_size));
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: buffer time not available: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
err = snd_pcm_hw_params_get_buffer_size(params, &(this->buffer_size));
|
||||
#ifdef ALSA_LOG_BUFFERS
|
||||
printf("was set period_size = %ld\n",this->period_size);
|
||||
printf("was set buffer_size = %ld\n",this->buffer_size);
|
||||
#endif
|
||||
if (2*this->period_size > this->buffer_size) {
|
||||
printf ( "audio_alsa_out: buffer to small, could not use\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
/* write the parameters to device */
|
||||
err = snd_pcm_hw_params(this->audio_fd, params);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: pcm hw_params failed: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* Check for pause/resume support */
|
||||
this->has_pause_resume = ( snd_pcm_hw_params_can_pause (params)
|
||||
&& snd_pcm_hw_params_can_resume (params) );
|
||||
// printf( "audio_alsa_out:open pause_resume=%d\n", this->has_pause_resume);
|
||||
this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate;
|
||||
this->bytes_per_frame = snd_pcm_frames_to_bytes (this->audio_fd, 1);
|
||||
/*
|
||||
* audio buffer size handling
|
||||
*/
|
||||
/* Copy current parameters into swparams */
|
||||
err = snd_pcm_sw_params_current(this->audio_fd, swparams);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to determine current swparams: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* align all transfers to 1 sample */
|
||||
err = snd_pcm_sw_params_set_xfer_align(this->audio_fd, swparams, 1);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to set transfer alignment: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
/* allow the transfer when at least period_size samples can be processed */
|
||||
err = snd_pcm_sw_params_set_avail_min(this->audio_fd, swparams, this->period_size);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to set available min: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
if (direction == SND_PCM_STREAM_PLAYBACK) {
|
||||
/* start the transfer when the buffer contains at least period_size samples */
|
||||
err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, this->buffer_size);
|
||||
} else {
|
||||
err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, -1);
|
||||
}
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to set start threshold: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
|
||||
if (direction == SND_PCM_STREAM_PLAYBACK) {
|
||||
/* never stop the transfer, even on xruns */
|
||||
err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size);
|
||||
} else {
|
||||
err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size);
|
||||
}
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to set stop threshold: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
|
||||
/* Install swparams into current parameters */
|
||||
err = snd_pcm_sw_params(this->audio_fd, swparams);
|
||||
if (err < 0) {
|
||||
printf ( "audio_alsa_out: Unable to set swparams: %s\n", snd_strerror(err));
|
||||
goto close;
|
||||
}
|
||||
#ifdef ALSA_LOG
|
||||
snd_pcm_dump_setup(this->audio_fd, jcd_out);
|
||||
snd_pcm_sw_params_dump(swparams, jcd_out);
|
||||
#endif
|
||||
|
||||
return this->output_sample_rate;
|
||||
|
||||
close:
|
||||
snd_pcm_close (this->audio_fd);
|
||||
this->audio_fd=NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t zero_buffer[65536];
|
||||
|
||||
int playback_callback(alsa_driver_t *alsa_driver_playback) {
|
||||
alsa_driver_t *this = alsa_driver_playback;
|
||||
int result;
|
||||
struct timeval tv;
|
||||
double stime;
|
||||
int nsec;
|
||||
int i,n;
|
||||
static int ic;
|
||||
int16_t b0[2048];
|
||||
|
||||
// printf("playback callback\n");
|
||||
gettimeofday(&tv, NULL);
|
||||
stime = (double) tv.tv_sec + ((double)tv.tv_usec / 1000000.0) +
|
||||
*(this->ndsec) * 0.1;
|
||||
*(this->Tsec) = stime;
|
||||
if(!(this->tx_starting) && (*(this->tx_ok)) ) {
|
||||
nsec = (int)stime;
|
||||
n = nsec / *(this->tr_period);
|
||||
ic = (int)(stime - *(this->tr_period) * n) * this->output_sample_rate;
|
||||
ic = ic % *(this->nwave);
|
||||
this->tx_offset = ic;
|
||||
}
|
||||
this->tx_starting = *(this->tx_ok);
|
||||
*(this->transmitting) = *(this->tx_ok);
|
||||
if(*(this->tx_ok)) {
|
||||
/*
|
||||
alsa_playback_buffers[0] = this->app_buffer_y1 + this->tx_offset;
|
||||
alsa_playback_buffers[1] = this->app_buffer_y1 + this->tx_offset;
|
||||
*/
|
||||
alsa_playback_buffers[0] = b0;
|
||||
alsa_playback_buffers[1] = b0;
|
||||
for(i=0; i<this->period_size; i++) {
|
||||
b0[i]=this->app_buffer_y1[ic];
|
||||
ic++;
|
||||
if(ic >= *this->nwave) {
|
||||
ic=ic % *this->nwave;
|
||||
if(*this->nmode == 2)
|
||||
*this->tx_ok=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alsa_playback_buffers[0] = zero_buffer;
|
||||
alsa_playback_buffers[1] = zero_buffer;
|
||||
}
|
||||
result = snd_pcm_writen(this->audio_fd, alsa_playback_buffers, this->period_size);
|
||||
this->tx_offset += this->period_size;
|
||||
if (result != this->period_size) {
|
||||
printf("playback writei failed. Expected %d samples, sent only %d\n", this->period_size, result);
|
||||
#ifdef ALSA_PLAYBACK_LOG
|
||||
snd_pcm_status_t *pcm_stat;
|
||||
snd_pcm_status_alloca(&pcm_stat);
|
||||
snd_pcm_status(this->audio_fd, pcm_stat);
|
||||
snd_pcm_status_dump(pcm_stat, jcd_out);
|
||||
#endif
|
||||
}
|
||||
fivehztx_(); //Call fortran routine
|
||||
}
|
||||
|
||||
int capture_callback(alsa_driver_t *alsa_driver_capture) {
|
||||
alsa_driver_t *this = alsa_driver_capture;
|
||||
int result;
|
||||
struct timeval tv;
|
||||
double stime;
|
||||
int ib;
|
||||
#ifdef ALSA_CAPTURE_LOG
|
||||
printf("capture callback %d samples\n", this->period_size);
|
||||
#endif
|
||||
#ifdef ALSA_CAPTURE_LOG
|
||||
snd_pcm_status_t *pcm_stat;
|
||||
snd_pcm_status_alloca(&pcm_stat);
|
||||
snd_pcm_status(this->audio_fd, pcm_stat);
|
||||
snd_pcm_status_dump(pcm_stat, jcd_out);
|
||||
#endif
|
||||
gettimeofday(&tv, NULL);
|
||||
stime = (double) tv.tv_sec + ((double)tv.tv_usec / 1000000.0) +
|
||||
*(this->ndsec) * 0.1;
|
||||
*(this->Tsec) = stime;
|
||||
ib=*(this->ibuf);
|
||||
this->tbuf[ib++] = stime;
|
||||
if(ib>=1024)
|
||||
ib = 0;
|
||||
*(this->ibuf) = ib;
|
||||
|
||||
alsa_capture_buffers[0]=this->app_buffer_y1 + *(this->app_buffer_offset);
|
||||
alsa_capture_buffers[1]=this->app_buffer_y2 + *(this->app_buffer_offset);
|
||||
result = snd_pcm_readn(this->audio_fd, alsa_capture_buffers, this->period_size);
|
||||
*(this->app_buffer_offset) += this->period_size;
|
||||
if ( *(this->app_buffer_offset) >= this->app_buffer_length )
|
||||
*(this->app_buffer_offset)=0; /* FIXME: implement proper wrapping */
|
||||
#ifdef ALSA_CAPTURE_LOG
|
||||
printf("result=%d\n",result);
|
||||
snd_pcm_status(this->audio_fd, pcm_stat);
|
||||
snd_pcm_status_dump(pcm_stat, jcd_out);
|
||||
#endif
|
||||
fivehz_(); //Call fortran routine
|
||||
}
|
||||
|
||||
int playback_xrun(alsa_driver_t *alsa_driver_playback) {
|
||||
alsa_driver_t *this = alsa_driver_playback;
|
||||
snd_pcm_status_t *pcm_stat;
|
||||
snd_pcm_status_alloca(&pcm_stat);
|
||||
printf("playback xrun\n");
|
||||
snd_pcm_status(this->audio_fd, pcm_stat);
|
||||
snd_pcm_status_dump(pcm_stat, jcd_out);
|
||||
snd_pcm_prepare(this->audio_fd);
|
||||
}
|
||||
|
||||
int capture_xrun(alsa_driver_t *alsa_driver_capture) {
|
||||
alsa_driver_t *this = alsa_driver_capture;
|
||||
snd_pcm_status_t *pcm_stat;
|
||||
snd_pcm_status_alloca(&pcm_stat);
|
||||
printf("capture xrun\n");
|
||||
snd_pcm_status(this->audio_fd, pcm_stat);
|
||||
snd_pcm_status_dump(pcm_stat, jcd_out);
|
||||
}
|
||||
|
||||
void ao_alsa_loop(void *iarg) {
|
||||
int playback_nfds;
|
||||
int capture_nfds;
|
||||
struct pollfd *pfd;
|
||||
int nfds;
|
||||
int capture_index;
|
||||
unsigned short playback_revents;
|
||||
unsigned short capture_revents;
|
||||
playback_nfds = snd_pcm_poll_descriptors_count (
|
||||
alsa_driver_playback.audio_fd);
|
||||
capture_nfds = snd_pcm_poll_descriptors_count (
|
||||
alsa_driver_capture.audio_fd);
|
||||
pfd = (struct pollfd *) malloc (sizeof (struct pollfd) *
|
||||
(playback_nfds + capture_nfds));
|
||||
|
||||
nfds=0;
|
||||
snd_pcm_poll_descriptors (alsa_driver_playback.audio_fd,
|
||||
&pfd[0],
|
||||
playback_nfds);
|
||||
nfds += playback_nfds;
|
||||
snd_pcm_poll_descriptors (alsa_driver_capture.audio_fd,
|
||||
&pfd[nfds],
|
||||
capture_nfds);
|
||||
capture_index = nfds;
|
||||
nfds += capture_nfds;
|
||||
while(1) {
|
||||
if (poll (pfd, nfds, 100000) < 0) {
|
||||
printf("poll failed\n");
|
||||
return;
|
||||
}
|
||||
snd_pcm_poll_descriptors_revents(alsa_driver_playback.audio_fd, &pfd[0], playback_nfds, &playback_revents);
|
||||
snd_pcm_poll_descriptors_revents(alsa_driver_capture.audio_fd, &pfd[capture_index], capture_nfds, &capture_revents);
|
||||
//if ((playback_revents & POLLERR) || ((capture_revents) & POLLERR)) {
|
||||
if (((capture_revents) & POLLERR)) {
|
||||
printf("pollerr\n");
|
||||
capture_xrun(&alsa_driver_capture);
|
||||
return;
|
||||
}
|
||||
if (((playback_revents) & POLLERR)) {
|
||||
printf("pollerr\n");
|
||||
playback_xrun(&alsa_driver_capture);
|
||||
return;
|
||||
}
|
||||
if (playback_revents & POLLOUT) {
|
||||
playback_callback(&alsa_driver_playback);
|
||||
}
|
||||
if (capture_revents & POLLIN) {
|
||||
capture_callback(&alsa_driver_capture);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
extern void decode1_(int *iarg);
|
||||
|
||||
int start_threads_(int *ndevin, int *ndevout, short y1[], short y2[],
|
||||
int *nbuflen, int *iwrite, short iwave[],
|
||||
int *nwave, int *nfsample, int *nsamperbuf,
|
||||
int *TRPeriod, int *TxOK, int *ndebug,
|
||||
int *Transmitting, double *Tsec, int *ngo, int *nmode,
|
||||
double tbuf[], int *ibuf, int *ndsec)
|
||||
{
|
||||
pthread_t thread1,thread2;
|
||||
int iret1,iret2;
|
||||
int iarg1 = 1,iarg2 = 2;
|
||||
//int32_t rate=11025;
|
||||
int32_t rate=*nfsample;
|
||||
alsa_driver_capture.app_buffer_y1 = y1;
|
||||
alsa_driver_capture.app_buffer_y2 = y2;
|
||||
alsa_driver_capture.app_buffer_offset = iwrite;
|
||||
alsa_driver_capture.app_buffer_length = *nbuflen;
|
||||
alsa_driver_capture.Tsec = Tsec;
|
||||
alsa_driver_capture.tbuf = tbuf;
|
||||
alsa_driver_capture.ibuf = ibuf;
|
||||
alsa_driver_capture.ndsec = ndsec;
|
||||
alsa_driver_playback.Tsec = Tsec;
|
||||
alsa_driver_playback.app_buffer_y1 = iwave;
|
||||
alsa_driver_playback.tx_ok = TxOK;
|
||||
alsa_driver_playback.tr_period = TRPeriod;
|
||||
alsa_driver_playback.nwave = nwave;
|
||||
alsa_driver_playback.nmode = nmode;
|
||||
alsa_driver_playback.transmitting = Transmitting;
|
||||
alsa_driver_playback.ndsec = ndsec;
|
||||
// printf("start_threads: creating thread for decode1\n");
|
||||
iret1 = pthread_create(&thread1,NULL,decode1_,&iarg1);
|
||||
/* Open audio card. */
|
||||
printf("Starting alsa routines.\n");
|
||||
ao_alsa_open(&alsa_driver_playback, &rate, SND_PCM_STREAM_PLAYBACK);
|
||||
ao_alsa_open(&alsa_driver_capture, &rate, SND_PCM_STREAM_CAPTURE);
|
||||
|
||||
/*
|
||||
* Start audio io thread
|
||||
*/
|
||||
iret2 = pthread_create(&thread2, NULL, ao_alsa_loop, NULL);
|
||||
snd_pcm_prepare(alsa_driver_capture.audio_fd);
|
||||
snd_pcm_start(alsa_driver_capture.audio_fd);
|
||||
snd_pcm_prepare(alsa_driver_playback.audio_fd);
|
||||
//snd_pcm_start(alsa_driver_playback.audio_fd);
|
||||
}
|
27
start_portaudio.c
Normal file
27
start_portaudio.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include "conf.h"
|
||||
|
||||
extern void decode1_(int *iarg);
|
||||
extern void a2d_(int *iarg);
|
||||
|
||||
int start_threads_(int *ndevin, int *ndevout, short y1[], short y2[],
|
||||
int *nbuflen, int *iwrite, short iwave[],
|
||||
int *nwave, int *nfsample, int *nsamperbuf,
|
||||
int *TRPeriod, int *TxOK, int *ndebug,
|
||||
int *Transmitting, double *Tsec, int *ngo, int *nmode,
|
||||
double tbuf[], int *ibuf, int *ndsec)
|
||||
{
|
||||
pthread_t thread1,thread2;
|
||||
int iret1,iret2;
|
||||
int iarg1 = 1,iarg2 = 2;
|
||||
|
||||
/* snd_pcm_start */
|
||||
// printf("start_threads: creating thread for a2d\n");
|
||||
iret1 = pthread_create(&thread1,NULL,a2d_,&iarg1);
|
||||
// printf("start_threads: creating thread for decode1_\n");
|
||||
iret2 = pthread_create(&thread2,NULL,decode1_,&iarg2);
|
||||
}
|
Loading…
Reference in New Issue
Block a user