diff --git a/audio.h b/audio.h index fdf4210..6e2e93c 100644 --- a/audio.h +++ b/audio.h @@ -30,11 +30,17 @@ enum ptt_method_e { PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */ PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */ PTT_METHOD_LPT, /* Parallel printer port, Linux only. */ - PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */ - PTT_METHOD_AUDIO }; /* Audio channel. */ + PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */ + PTT_METHOD_AUDIO }; /* Audio channel. */ typedef enum ptt_method_e ptt_method_t; +enum ptt_audio_state_e { + PTT_AUDIO_STATE_STOP, + PTT_AUDIO_STATE_START, + PTT_AUDIO_STATE_CLOSE }; +typedef enum ptt_audio_state_e ptt_audio_state_t; + enum ptt_line_e { PTT_LINE_NONE = 0, PTT_LINE_RTS = 1, PTT_LINE_DTR = 2 }; // Important: 0 for neither. typedef enum ptt_line_e ptt_line_t; @@ -196,14 +202,16 @@ struct audio_s { int ptt_invert; /* Invert the output. */ int ptt_invert2; /* Invert the secondary output. */ - int ptt_channel; /* Channel number for audio PTT. */ - int ptt_frequency; /* Audio frequency for audio PTT. */ + int ptt_channel; /* Channel number for audio PTT. */ + int ptt_frequency; /* Audio frequency for audio PTT. */ #if __WIN32__ - HANDLE ptt_start; /* Handle for event that starts ptt tone. */ - HANDLE ptt_stop; /* Handle for event that stops ptt tone. */ - HANDLE ptt_close; /* Handle for event that closes ptt. */ + HANDLE ptt_start; /* Handle for event that starts ptt tone. */ + HANDLE ptt_stop; /* Handle for event that stops ptt tone. */ + HANDLE ptt_close; /* Handle for event that closes ptt. */ #else - + pthread_mutex_t ptt_mutex; /* Mutex for controlling ptt tone state. */ + pthread_cond_t ptt_condition; /* Condition for controlling ptt tone state. */ + ptt_audio_state_t ptt_state; /* State of ptt tone. */ #endif #ifdef USE_HAMLIB diff --git a/audio_ptt.c b/audio_ptt.c index ae91e3f..19bc4fd 100644 --- a/audio_ptt.c +++ b/audio_ptt.c @@ -91,67 +91,64 @@ static void * ptt_thread (void *arg) err = snd_pcm_open(&handle, save_audio_config_p->adev[a].adevice_out, SND_PCM_STREAM_PLAYBACK, 0); if (err == 0) { - snd_pcm_sframes_t frames; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; err = snd_pcm_set_params(handle, format, SND_PCM_ACCESS_RW_INTERLEAVED, save_audio_config_p->adev[a].num_channels, save_audio_config_p->adev[a].samples_per_sec, 1, 500000); if (err == 0) { - short* pnData; + short* pnData; short sample; - int nSamples = save_audio_config_p->adev[a].samples_per_sec / 10; + int nSamples = save_audio_config_p->adev[a].samples_per_sec / 5; int nBufferLength = save_audio_config_p->adev[a].num_channels * nSamples * sizeof(short); int i; + int j; pnData = (short*)malloc (nBufferLength); - if (save_audio_config_p->adev[a].num_channels == 1) { - for (i = 0; i < nSamples; i++) { - sample = (short)( (double)SHRT_MAX * sin( ( (double)i * freq / (double)save_audio_config_p->adev[a].samples_per_sec ) * 2.0 * M_PI ) ); - pnData[i] = sample; + for (i = 0; i < nSamples; i++) { + sample = (short)( (double)SHRT_MAX * sin( ( (double)i * freq / (double)save_audio_config_p->adev[a].samples_per_sec ) * 2.0 * M_PI ) ); + + for (j = 0; j < save_audio_config_p->adev[a].num_channels; j++) { + if (channel == ADEVFIRSTCHAN( a ) + j) { + pnData[i*save_audio_config_p->adev[a].num_channels + j] = sample; + } else { + pnData[i*save_audio_config_p->adev[a].num_channels + j] = 0; + } } } - else { - for (i = 0; i < nSamples; i++) { - sample = (short)( (double)SHRT_MAX * sin( ( (double)i * freq / (double)save_audio_config_p->adev[a].samples_per_sec ) * 2.0 * M_PI ) ); - if (channel == ADEVFIRSTCHAN( a )) { + + while (1) { + pthread_mutex_lock (&save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_mutex); + ptt_audio_state_t ptt_state = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_state; + pthread_mutex_unlock (&save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_mutex); - // Stereo, left channel. + if (ptt_state == PTT_AUDIO_STATE_STOP) { + snd_pcm_drop (handle); - pnData[i*2 + 0] = sample; - pnData[i*2 + 1] = 0; - } - else { + pthread_mutex_lock (&save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_mutex); + pthread_cond_wait (&save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_condition, &save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_mutex); + ptt_state = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_state; + pthread_mutex_unlock (&save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_mutex); - // Stereo, right channel. + if (ptt_state == PTT_AUDIO_STATE_START) { + snd_pcm_prepare (handle); + } + } + + if (ptt_state == PTT_AUDIO_STATE_START) { + snd_pcm_writei (handle, pnData, nSamples); + } + else if (ptt_state == PTT_AUDIO_STATE_CLOSE) { + snd_pcm_drop (handle); - pnData[i*2 + 0] = 0; - pnData[i*2 + 1] = sample; - } - } - } - - // - // ptt_set on - // - - for (i=0; i<50; i++) { - frames = snd_pcm_writei(handle, pnData, nSamples); - } - - // - // ptt_set off - // - - // - // close - // + break; + } + } free (pnData); } - - snd_pcm_close(handle); + snd_pcm_close (handle); } #else int oss_audio_device_fd; @@ -165,3 +162,4 @@ static void * ptt_thread (void *arg) } #endif + diff --git a/audio_ptt_win.c b/audio_ptt_win.c index 92c0c50..e690ea4 100644 --- a/audio_ptt_win.c +++ b/audio_ptt_win.c @@ -64,126 +64,110 @@ static unsigned __stdcall ptt_thread ( void *arg ); HANDLE start_ptt_thread (struct audio_s *pa , int ch) { - save_audio_config_p = pa; + save_audio_config_p = pa; - return (HANDLE)_beginthreadex (NULL, 0, ptt_thread, (void*)(long)ch, 0, NULL); + return (HANDLE)_beginthreadex (NULL, 0, ptt_thread, (void*)(long)ch, 0, NULL); } unsigned __stdcall ptt_thread (void *arg) { - WAVEFORMATEX wf; - HWAVEOUT hWaveOut; - int ch = (int)(long)arg; // channel number. - int channel = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel; - int freq = save_audio_config_p->achan[channel].octrl[OCTYPE_PTT].ptt_frequency; - int a = ACHAN2ADEV( channel ); - int err; + WAVEFORMATEX wf; + HWAVEOUT hWaveOut; + int ch = (int)(long)arg; // channel number. + int channel = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel; + int freq = save_audio_config_p->achan[channel].octrl[OCTYPE_PTT].ptt_frequency; + int a = ACHAN2ADEV( channel ); + int err; - if( save_audio_config_p->adev[a].defined ) { - wf.wFormatTag = WAVE_FORMAT_PCM; - wf.nChannels = save_audio_config_p->adev[a].num_channels; - wf.nSamplesPerSec = save_audio_config_p->adev[a].samples_per_sec; - wf.wBitsPerSample = save_audio_config_p->adev[a].bits_per_sample; - wf.nBlockAlign = ( wf.wBitsPerSample / 8 ) * wf.nChannels; - wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; - wf.cbSize = 0; + if (save_audio_config_p->adev[a].defined) { + wf.wFormatTag = WAVE_FORMAT_PCM; + wf.nChannels = save_audio_config_p->adev[a].num_channels; + wf.nSamplesPerSec = save_audio_config_p->adev[a].samples_per_sec; + wf.wBitsPerSample = save_audio_config_p->adev[a].bits_per_sample; + wf.nBlockAlign = ( wf.wBitsPerSample / 8 ) * wf.nChannels; + wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; + wf.cbSize = 0; - /* - * Open the audio output device. - * Soundcard is only possibility at this time. - */ + /* + * Open the audio output device. + * Soundcard is only possibility at this time. + */ - err = waveOutOpen ( &hWaveOut, atoi( save_audio_config_p->adev[a].adevice_out ), &wf, (DWORD_PTR)NULL, 0, CALLBACK_NULL ); - if( err == MMSYSERR_NOERROR ) { - WAVEHDR waveHeader; - short* pnData; - short sample; - int nSamples = save_audio_config_p->adev[a].samples_per_sec / freq; - int i; + err = waveOutOpen ( &hWaveOut, atoi( save_audio_config_p->adev[a].adevice_out ), &wf, (DWORD_PTR)NULL, 0, CALLBACK_NULL ); + if (err == MMSYSERR_NOERROR) { + WAVEHDR waveHeader; + short* pnData; + short sample; + int nSamples = save_audio_config_p->adev[a].samples_per_sec / freq; + int i; + int j; - waveHeader.dwBufferLength = save_audio_config_p->adev[a].num_channels * nSamples * sizeof( short ); - waveHeader.lpData = malloc( waveHeader.dwBufferLength ); - waveHeader.dwUser = 0; - waveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; - waveHeader.dwLoops = 0xFFFF; + waveHeader.dwBufferLength = save_audio_config_p->adev[a].num_channels * nSamples * sizeof( short ); + waveHeader.lpData = malloc( waveHeader.dwBufferLength ); + waveHeader.dwUser = 0; + waveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; + waveHeader.dwLoops = 0xFFFF; - pnData = (short*)waveHeader.lpData; + pnData = (short*)waveHeader.lpData; - if( save_audio_config_p->adev[a].num_channels == 1 ) { - for( i = 0; i < nSamples; i++ ) { - sample = (short)( (double)SHRT_MAX * sin( ( (double)i / (double)nSamples ) * 2.0 * M_PI ) ); - pnData[i] = sample; - } - } - else { - for( i = 0; i < nSamples; i++ ) { - sample = (short)( (double)SHRT_MAX * sin( ( (double)i / (double)nSamples ) * 2.0 * M_PI ) ); - if( channel == ADEVFIRSTCHAN( a ) ) { - - // Stereo, left channel. - - pnData[i*2 + 0] = sample; - pnData[i*2 + 1] = 0; - } - else { - - // Stereo, right channel. - - pnData[i*2 + 0] = 0; - pnData[i*2 + 1] = sample; - } - } - } - - err = waveOutPrepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); - if( err == MMSYSERR_NOERROR ) { - HANDLE handles[3]; - DWORD dwWait; - - handles[0] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_start; - handles[1] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_stop; - handles[2] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_close; - - while( 1 ) - { - dwWait = WaitForMultipleObjects ( 3, handles, FALSE, INFINITE ); - - if( dwWait == WAIT_OBJECT_0 + 0 ) - { - // - // ptt_set on - // - - waveOutWrite ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); - } - else if( dwWait == WAIT_OBJECT_0 + 1 ) - { - // - // ptt_set off - // - - waveOutReset ( hWaveOut ); - } - else if( dwWait == WAIT_OBJECT_0 + 2 ) - { - // - // close - // - - waveOutReset ( hWaveOut ); - waveOutUnprepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); - - break; - } - } - } - - waveOutClose ( hWaveOut ); - - free( waveHeader.lpData ); + for (i = 0; i < nSamples; i++) { + sample = (short)( (double)SHRT_MAX * sin( ( (double)i / (double)nSamples ) * 2.0 * M_PI ) ); + + for (j = 0; j < save_audio_config_p->adev[a].num_channels; j++) { + if (channel == ADEVFIRSTCHAN( a ) + j) { + pnData[i*save_audio_config_p->adev[a].num_channels + j] = sample; + } else { + pnData[i*save_audio_config_p->adev[a].num_channels + j] = 0; + } } - } + } - return 0; + err = waveOutPrepareHeader (hWaveOut, &waveHeader, sizeof( WAVEHDR )); + if (err == MMSYSERR_NOERROR) { + HANDLE handles[3]; + DWORD dwWait; + + handles[0] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_start; + handles[1] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_stop; + handles[2] = save_audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_close; + + while (1) + { + dwWait = WaitForMultipleObjects (3, handles, FALSE, INFINITE); + + if (dwWait == WAIT_OBJECT_0 + 0) { + // + // ptt_set on + // + + waveOutWrite ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); + } + else if (dwWait == WAIT_OBJECT_0 + 1) { + // + // ptt_set off + // + + waveOutReset ( hWaveOut ); + } + else if( dwWait == WAIT_OBJECT_0 + 2 ) { + // + // close + // + + waveOutReset ( hWaveOut ); + waveOutUnprepareHeader ( hWaveOut, &waveHeader, sizeof( WAVEHDR ) ); + + break; + } + } + } + + waveOutClose ( hWaveOut ); + + free( waveHeader.lpData ); + } + } + + return 0; } #endif diff --git a/config.c b/config.c index e8b828d..363d9de 100644 --- a/config.c +++ b/config.c @@ -673,6 +673,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_audio_config->achan[channel].octrl[ot].ptt_stop = NULL; p_audio_config->achan[channel].octrl[ot].ptt_close = NULL; #else + p_audio_config->achan[channel].octrl[ot].ptt_state = PTT_AUDIO_STATE_STOP; #endif } @@ -1635,6 +1636,9 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_audio_config->achan[channel].octrl[ot].ptt_stop = CreateEvent (NULL, FALSE, FALSE, NULL); p_audio_config->achan[channel].octrl[ot].ptt_close = CreateEvent (NULL, FALSE, FALSE, NULL); #else + p_audio_config->achan[channel].octrl[ot].ptt_state = PTT_AUDIO_STATE_STOP; + pthread_mutex_init(&p_audio_config->achan[channel].octrl[ot].ptt_mutex, 0); + pthread_cond_init(&p_audio_config->achan[channel].octrl[ot].ptt_condition, 0); #endif } else { diff --git a/ptt.c b/ptt.c index 1b2e34c..bec7a97 100644 --- a/ptt.c +++ b/ptt.c @@ -1010,22 +1010,27 @@ void ptt_set (int ot, int chan, int ptt_signal) * Using audio channel? */ - if( save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_AUDIO ) { - if( ptt_signal ) { + if (save_audio_config_p->achan[chan].octrl[ot].ptt_method == PTT_METHOD_AUDIO) { + if (ptt_signal) { #ifdef __WIN32__ - SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_start ); + SetEvent (save_audio_config_p->achan[chan].octrl[ot].ptt_start); #else - + pthread_mutex_lock (&save_audio_config_p->achan[chan].octrl[ot].ptt_mutex); + save_audio_config_p->achan[chan].octrl[ot].ptt_state = PTT_AUDIO_STATE_START; + pthread_cond_signal (&save_audio_config_p->achan[chan].octrl[ot].ptt_condition); + pthread_mutex_unlock (&save_audio_config_p->achan[chan].octrl[ot].ptt_mutex); #endif - } - else - { + } + else + { #ifdef __WIN32__ - SetEvent( save_audio_config_p->achan[chan].octrl[ot].ptt_stop ); + SetEvent (save_audio_config_p->achan[chan].octrl[ot].ptt_stop); #else - + pthread_mutex_lock (&save_audio_config_p->achan[chan].octrl[ot].ptt_mutex); + save_audio_config_p->achan[chan].octrl[ot].ptt_state = PTT_AUDIO_STATE_STOP; + pthread_mutex_unlock (&save_audio_config_p->achan[chan].octrl[ot].ptt_mutex); #endif - } + } } } /* end ptt_set */ @@ -1137,7 +1142,10 @@ void ptt_term (void) #ifdef __WIN32__ SetEvent (save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_close) ; #else - + pthread_mutex_lock (&save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_mutex); + save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_state = PTT_AUDIO_STATE_CLOSE; + pthread_cond_signal (&save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_condition); + pthread_mutex_unlock (&save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_mutex); #endif } }