Summary: Implements audio playback (TX) for ALSA.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@46 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
J C Dutton 2006-01-05 00:08:26 +00:00
parent 821f4c3b14
commit 445a0f7985
2 changed files with 112 additions and 37 deletions

View File

@ -5,10 +5,14 @@
#include <inttypes.h> #include <inttypes.h>
#include <time.h> #include <time.h>
#if 0 #if 1
#define ALSA_LOG #define ALSA_LOG
#define ALSA_LOG_BUFFERS #define ALSA_LOG_BUFFERS
#endif #endif
#if 0
#define ALSA_PLAYBACK_LOG
#define ALSA_CAPTURE_LOG
#endif
#define BUFFER_TIME 2000*1000 #define BUFFER_TIME 2000*1000
@ -32,6 +36,12 @@ typedef struct alsa_driver_s {
double *tbuf; double *tbuf;
int *ibuf; int *ibuf;
int *ndsec; int *ndsec;
int *tx_ok;
int tx_starting;
int tx_offset;
int *tr_period;
int *nwave;
int *transmitting;
snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size;
@ -40,7 +50,8 @@ typedef struct alsa_driver_s {
alsa_driver_t alsa_driver_playback; alsa_driver_t alsa_driver_playback;
alsa_driver_t alsa_driver_capture; alsa_driver_t alsa_driver_capture;
void *alsa_buffers[2]; void *alsa_capture_buffers[2];
void *alsa_playback_buffers[2];
static snd_output_t *jcd_out; static snd_output_t *jcd_out;
@ -173,9 +184,13 @@ static int ao_alsa_open(alsa_driver_t *this_gen, int32_t *input_rate, snd_pcm_st
printf("Buffer time size %lu\n",buffer_time_to_size); printf("Buffer time size %lu\n",buffer_time_to_size);
#endif #endif
this->buffer_size = buffer_time_to_size; this->buffer_size = buffer_time_to_size;
if (buffer_size_max < this->buffer_size) this->buffer_size = buffer_size_max; if (buffer_size_max < this->buffer_size)
if (buffer_size_min > this->buffer_size) this->buffer_size = buffer_size_min; 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; this->period_size = this->buffer_size/8;
if (this->period_size > 2048)
this->period_size = 2048;
this->buffer_size = this->period_size*8; this->buffer_size = this->period_size*8;
#ifdef ALSA_LOG_BUFFERS #ifdef ALSA_LOG_BUFFERS
printf("To choose buffer_size = %ld\n",this->buffer_size); printf("To choose buffer_size = %ld\n",this->buffer_size);
@ -264,7 +279,7 @@ static int ao_alsa_open(alsa_driver_t *this_gen, int32_t *input_rate, snd_pcm_st
} }
if (direction == SND_PCM_STREAM_PLAYBACK) { if (direction == SND_PCM_STREAM_PLAYBACK) {
/* start the transfer when the buffer contains at least period_size samples */ /* start the transfer when the buffer contains at least period_size samples */
err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, 0); err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, this->buffer_size);
} else { } else {
err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, -1); err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, -1);
} }
@ -275,7 +290,7 @@ static int ao_alsa_open(alsa_driver_t *this_gen, int32_t *input_rate, snd_pcm_st
if (direction == SND_PCM_STREAM_PLAYBACK) { if (direction == SND_PCM_STREAM_PLAYBACK) {
/* never stop the transfer, even on xruns */ /* never stop the transfer, even on xruns */
err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, 0); err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size);
} else { } else {
err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size); err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size);
} }
@ -303,11 +318,49 @@ close:
return 0; return 0;
} }
int16_t zero_buffer[65536];
int playback_callback(alsa_driver_t *alsa_driver_playback) { int playback_callback(alsa_driver_t *alsa_driver_playback) {
alsa_driver_t *this = alsa_driver_playback; alsa_driver_t *this = alsa_driver_playback;
printf("playback callback\n"); int result;
//snd_pcm_writen(this->audio_fd, alsa_buffers, this->period_size); struct timeval tv;
//fivehztx_(); //Call fortran routine double stime;
int nsec;
int n;
// printf("playback callback\n");
gettimeofday(&tv, NULL);
stime = (double) tv.tv_sec + ((double)tv.tv_usec / 1000000.0);
*(this->Tsec) = stime;
if(!(this->tx_starting) && (*(this->tx_ok)) ) {
int ic;
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;
} 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) { int capture_callback(alsa_driver_t *alsa_driver_capture) {
@ -316,10 +369,10 @@ int capture_callback(alsa_driver_t *alsa_driver_capture) {
struct timeval tv; struct timeval tv;
double stime; double stime;
int ib; int ib;
#ifdef ALSA_LOG #ifdef ALSA_CAPTURE_LOG
printf("capture callback %d samples\n", this->period_size); printf("capture callback %d samples\n", this->period_size);
#endif #endif
#ifdef ALSA_LOG #ifdef ALSA_CAPTURE_LOG
snd_pcm_status_t *pcm_stat; snd_pcm_status_t *pcm_stat;
snd_pcm_status_alloca(&pcm_stat); snd_pcm_status_alloca(&pcm_stat);
snd_pcm_status(this->audio_fd, pcm_stat); snd_pcm_status(this->audio_fd, pcm_stat);
@ -331,16 +384,17 @@ int capture_callback(alsa_driver_t *alsa_driver_capture) {
*(this->Tsec) = stime; *(this->Tsec) = stime;
ib=*(this->ibuf); ib=*(this->ibuf);
this->tbuf[ib++] = stime; this->tbuf[ib++] = stime;
if(ib>=1024) ib=0; if(ib>=1024)
ib = 0;
*(this->ibuf) = ib; *(this->ibuf) = ib;
alsa_buffers[0]=this->app_buffer_y1 + *(this->app_buffer_offset); alsa_capture_buffers[0]=this->app_buffer_y1 + *(this->app_buffer_offset);
alsa_buffers[1]=this->app_buffer_y2 + *(this->app_buffer_offset); alsa_capture_buffers[1]=this->app_buffer_y2 + *(this->app_buffer_offset);
result = snd_pcm_readn(this->audio_fd, alsa_buffers, this->period_size); result = snd_pcm_readn(this->audio_fd, alsa_capture_buffers, this->period_size);
*(this->app_buffer_offset) += this->period_size; *(this->app_buffer_offset) += this->period_size;
if ( *(this->app_buffer_offset) >= this->app_buffer_length ) if ( *(this->app_buffer_offset) >= this->app_buffer_length )
*(this->app_buffer_offset)=0; /* FIXME: implement proper wrapping */ *(this->app_buffer_offset)=0; /* FIXME: implement proper wrapping */
#ifdef ALSA_LOG #ifdef ALSA_CAPTURE_LOG
printf("result=%d\n",result); printf("result=%d\n",result);
snd_pcm_status(this->audio_fd, pcm_stat); snd_pcm_status(this->audio_fd, pcm_stat);
snd_pcm_status_dump(pcm_stat, jcd_out); snd_pcm_status_dump(pcm_stat, jcd_out);
@ -348,6 +402,16 @@ int capture_callback(alsa_driver_t *alsa_driver_capture) {
fivehz_(); //Call fortran routine 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) { int capture_xrun(alsa_driver_t *alsa_driver_capture) {
alsa_driver_t *this = alsa_driver_capture; alsa_driver_t *this = alsa_driver_capture;
snd_pcm_status_t *pcm_stat; snd_pcm_status_t *pcm_stat;
@ -373,12 +437,10 @@ void ao_alsa_loop(void *iarg) {
(playback_nfds + capture_nfds)); (playback_nfds + capture_nfds));
nfds=0; nfds=0;
#if 0
snd_pcm_poll_descriptors (alsa_driver_playback.audio_fd, snd_pcm_poll_descriptors (alsa_driver_playback.audio_fd,
&pfd[0], &pfd[0],
playback_nfds); playback_nfds);
nfds += playback_nfds; nfds += playback_nfds;
#endif
snd_pcm_poll_descriptors (alsa_driver_capture.audio_fd, snd_pcm_poll_descriptors (alsa_driver_capture.audio_fd,
&pfd[nfds], &pfd[nfds],
capture_nfds); capture_nfds);
@ -389,7 +451,7 @@ void ao_alsa_loop(void *iarg) {
printf("poll failed\n"); printf("poll failed\n");
return; return;
} }
//snd_pcm_poll_descriptors_revents(alsa_driver_playback.audio_fd, &pfd[0], playback_nfds, &playback_revents); 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); 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 ((playback_revents & POLLERR) || ((capture_revents) & POLLERR)) {
if (((capture_revents) & POLLERR)) { if (((capture_revents) & POLLERR)) {
@ -397,11 +459,14 @@ void ao_alsa_loop(void *iarg) {
capture_xrun(&alsa_driver_capture); capture_xrun(&alsa_driver_capture);
return; return;
} }
#if 0 if (((playback_revents) & POLLERR)) {
printf("pollerr\n");
playback_xrun(&alsa_driver_capture);
return;
}
if (playback_revents & POLLOUT) { if (playback_revents & POLLOUT) {
playback_callback(&alsa_driver_playback); playback_callback(&alsa_driver_playback);
} }
#endif
if (capture_revents & POLLIN) { if (capture_revents & POLLIN) {
capture_callback(&alsa_driver_capture); capture_callback(&alsa_driver_capture);
} }
@ -432,6 +497,13 @@ int start_threads_(int *ndevin, int *ndevout, short y1[], short y2[],
alsa_driver_capture.tbuf = tbuf; alsa_driver_capture.tbuf = tbuf;
alsa_driver_capture.ibuf = ibuf; alsa_driver_capture.ibuf = ibuf;
alsa_driver_capture.ndsec = ndsec; 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.transmitting = Transmitting;
alsa_driver_capture.ndsec=ndsec;
printf("start threads called\n"); printf("start threads called\n");
iret1 = pthread_create(&thread1,NULL,decode1_,&iarg1); iret1 = pthread_create(&thread1,NULL,decode1_,&iarg1);
@ -445,6 +517,8 @@ int start_threads_(int *ndevin, int *ndevout, short y1[], short y2[],
iret2 = pthread_create(&thread2, NULL, ao_alsa_loop, NULL); iret2 = pthread_create(&thread2, NULL, ao_alsa_loop, NULL);
snd_pcm_prepare(alsa_driver_capture.audio_fd); snd_pcm_prepare(alsa_driver_capture.audio_fd);
snd_pcm_start(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);
/* snd_pcm_start */ /* snd_pcm_start */
//iret2 = pthread_create(&thread2,NULL,a2d_,&iarg2); //iret2 = pthread_create(&thread2,NULL,a2d_,&iarg2);

View File

@ -1300,7 +1300,8 @@ def update():
nmsg=int(Audio.gcom2.nmsg) nmsg=int(Audio.gcom2.nmsg)
t=g.ftnstr(Audio.gcom2.sending) t=g.ftnstr(Audio.gcom2.sending)
if t[:3]=="CQ ": nsked.set(0) if t[:3]=="CQ ": nsked.set(0)
t="Transmitting: "+t[:nmsg] # t="Transmitting: "+t[:nmsg]
t="Transmitting: "
# t="Txing: "+t[:nmsg] # t="Txing: "+t[:nmsg]
bgcolor='yellow' bgcolor='yellow'
if Audio.gcom2.sendingsh==1: bgcolor='#66FFFF' if Audio.gcom2.sendingsh==1: bgcolor='#66FFFF'