// // This file is part of Dire Wolf, an amateur radio packet TNC. // // Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ // Copyright (C) 2017 Andrew Walker, VA7YAA // // 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 2 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 . // /*------------------------------------------------------------------ * * Module: audio_ptt.c * * Purpose: Interface to audio device commonly called a "sound card" for * historical reasons. * * This version uses the native Windows sound interface. * *---------------------------------------------------------------*/ #if __WIN32__ #else #include #include #include #if USE_ALSA #include #else #include #ifdef __OpenBSD__ #include #else #include #endif #endif #include "direwolf.h" #include "audio.h" #include "audio_stats.h" #include "textcolor.h" #include "ptt.h" #include "audio_ptt.h" #if USE_ALSA static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *name, char *dir); //static void alsa_select_device (char *pick_dev, int direction, char *result); #else static int set_oss_params (int a, int fd, struct audio_s *pa); #endif static struct audio_s *save_audio_config_p; static void * ptt_thread (void *arg); int start_ptt_thread (struct audio_s *pa, int ch) { pthread_t tid = 0; int e; save_audio_config_p = pa; e = pthread_create (&tid, NULL, ptt_thread, (void*)(long)ch); return tid; } static void * ptt_thread (void *arg) { 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 ); if( save_audio_config_p->adev[a].defined ) { #if USE_ALSA snd_pcm_t *handle; int err; err = snd_pcm_open(&handle, save_audio_config_p->adev[a].adevice_out, SND_PCM_STREAM_PLAYBACK, 0); if (err == 0) { 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 sample; 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); 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; } } } 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); if (ptt_state == PTT_AUDIO_STATE_STOP) { snd_pcm_drop (handle); 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); 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); break; } } free (pnData); } snd_pcm_close (handle); } #else int oss_audio_device_fd; oss_audio_device_fd = open (save_audio_config_p->adev[a].adevice_out, O_WRONLY); if (oss_audio_device_fd != -1) { } #endif } } #endif