diff --git a/Makefile b/Makefile
index 0ae53948..be2aa07a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,9 @@
 # equal to some value.   Your mileage my vary.
 
 win := $(shell uname | grep CYGWIN)
+ifeq ($(win),)
+   win := $(shell uname | grep MINGW)
+endif
 dar := $(shell uname | grep Darwin)
 
 ifneq ($(win),)
diff --git a/Makefile.linux b/Makefile.linux
index be9bd593..5960a297 100644
--- a/Makefile.linux
+++ b/Makefile.linux
@@ -232,7 +232,7 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
 		hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
 		fcs_calc.o ax25_pad.o \
 		decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
-		gen_tone.o audio.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
+		gen_tone.o audio.o audio_ptt.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
 		ptt.o beacon.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.o \
 		dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
 		dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o \
diff --git a/Makefile.win b/Makefile.win
index 3a9d9f6f..524c7137 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -70,7 +70,7 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
 		hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
 		fcs_calc.o ax25_pad.o \
 		decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
-		gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
+		gen_tone.o morse.o audio_win.o audio_ptt_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
 		ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
 		dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
 		dwgps.o dwgpsnmea.o dtime_now.o \
diff --git a/audio.c b/audio.c
index 84aa854a..823aaf99 100644
--- a/audio.c
+++ b/audio.c
@@ -692,7 +692,6 @@ static int set_oss_params (int a, int fd, struct audio_s *pa)
 	char message[100];
 	int ossbuf_size_in_bytes;
 
-
 	err = ioctl (fd, SNDCTL_DSP_CHANNELS, &(pa->adev[a].num_channels));
    	if (err == -1) {
 	  text_color_set(DW_COLOR_ERROR);
@@ -1249,6 +1248,7 @@ int audio_flush (int a)
 	  }
 	  if (k < len) {
 	    /* presumably full but didn't block. */
+      dw_printf("problem\n");
 	    usleep (10000);
 	  }
 	  ptr += k;
diff --git a/audio.h b/audio.h
index 674c27ed..6e2e93cf 100644
--- a/audio.h
+++ b/audio.h
@@ -30,10 +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_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;
 
@@ -195,6 +202,18 @@ 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. */
+#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. */
+#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
 
 	        int ptt_model;		/* HAMLIB model.  -1 for AUTO.  2 for rigctld.  Others are radio model. */
diff --git a/audio_ptt.c b/audio_ptt.c
new file mode 100644
index 00000000..5188ac9a
--- /dev/null
+++ b/audio_ptt.c
@@ -0,0 +1,254 @@
+// 
+//    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 <http://www.gnu.org/licenses/>.
+//
+
+
+/*------------------------------------------------------------------
+ *
+ * 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 <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#if USE_ALSA
+#include <alsa/asoundlib.h>
+#else
+#include <errno.h>
+#ifdef __OpenBSD__
+#include <soundcard.h>
+#else
+#include <sys/soundcard.h>
+#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 = (int)( ( (double)save_audio_config_p->adev[a].samples_per_sec / (double)freq ) * ceil( (double)freq / 5.0 ) );
+		    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);
+      } else {
+        dw_printf("Failed to configure ALSA device. PTT tone will not be enabled.\n");
+      }
+		  snd_pcm_close (handle);
+    } else {
+      dw_printf("Failed to open ALSA device. PTT tone will not be enabled.\n");
+    }
+#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 >= 0) {
+     	int devcaps;
+      int num_channels;
+      int samples_per_sec;
+      int bits_per_sample;
+      int err;
+
+      num_channels = save_audio_config_p->adev[a].num_channels;
+      err = ioctl (oss_audio_device_fd, SNDCTL_DSP_CHANNELS, &num_channels);
+
+      if (err != -1) {
+        samples_per_sec = save_audio_config_p->adev[a].samples_per_sec;
+        err = ioctl (oss_audio_device_fd, SNDCTL_DSP_SPEED, &samples_per_sec);
+      }
+
+      if (err != -1) {
+        bits_per_sample = save_audio_config_p->adev[a].bits_per_sample;
+        err = ioctl (oss_audio_device_fd, SNDCTL_DSP_SETFMT, &bits_per_sample);
+      }
+
+      if (err != -1) {
+        err = ioctl (oss_audio_device_fd, SNDCTL_DSP_GETCAPS, &devcaps);
+      }
+
+      if (err != -1) {
+	      short* pnData;
+        short sample;
+        int nBufferLength;
+        int nSamples;
+        int written;
+        int i;
+        int j;
+    
+        nSamples = (int)( ( (double)samples_per_sec / (double)freq ) * ceil( (double)freq / 5.0 ) );
+        nBufferLength = num_channels * nSamples * sizeof(short);
+        pnData = (short*)malloc (nBufferLength);
+
+  	    for (i = 0; i < nSamples; i++) {
+	        sample = (short)( (double)SHRT_MAX * sin( ( (double)i * freq / (double)samples_per_sec ) * 2.0 * M_PI ) );
+
+          for (j = 0; j < num_channels; j++) {
+  	        if (channel == ADEVFIRSTCHAN( a ) + j) {
+              pnData[i*num_channels + j] = sample;
+            } else {
+  		        pnData[i*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) {
+            ioctl (oss_audio_device_fd, SNDCTL_DSP_RESET, NULL);
+
+            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) {
+            written = write (oss_audio_device_fd, pnData, nBufferLength);
+          }
+          else if (ptt_state == PTT_AUDIO_STATE_CLOSE) {
+            ioctl (oss_audio_device_fd, SNDCTL_DSP_RESET, NULL);
+
+            break;
+          }
+        }
+
+        free (pnData);
+      } else {
+        dw_printf("Failed to configure OSS device. PTT tone will not be enabled.\n");
+      }
+      close (oss_audio_device_fd);
+    } else {
+      dw_printf("Failed to open OSS device. PTT tone will not be enabled.\n");
+    }
+#endif
+  }
+}
+
+#endif
+
diff --git a/audio_ptt.h b/audio_ptt.h
new file mode 100644
index 00000000..d880b5fc
--- /dev/null
+++ b/audio_ptt.h
@@ -0,0 +1,11 @@
+
+#ifndef AUDIO_PTT_H
+#define AUDIO_PTT_H 1
+
+#if __WIN32__
+extern HANDLE start_ptt_thread ( struct audio_s *pa, int ch );
+#else
+extern int start_ptt_thread ( struct audio_s *pa, int ch );
+#endif
+
+#endif
\ No newline at end of file
diff --git a/audio_ptt_win.c b/audio_ptt_win.c
new file mode 100644
index 00000000..7ccdd378
--- /dev/null
+++ b/audio_ptt_win.c
@@ -0,0 +1,173 @@
+
+//
+//    This file is part of Dire Wolf, an amateur radio packet TNC.
+//
+//    Copyright (C) 2011, 2012, 2013, 2014, 2015  John Langner, WB2OSZ
+//
+//    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 <http://www.gnu.org/licenses/>.
+//
+
+
+/*------------------------------------------------------------------
+ *
+ * Module:      audio_ptt_win.c
+ *
+ * Purpose:   	Interface to audio device commonly called a "sound card" for
+ *		historical reasons.		
+ *
+ *		This version uses the native Windows sound interface.
+ *
+ *---------------------------------------------------------------*/
+
+#if __WIN32__
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <io.h>
+#include <fcntl.h>
+#include <math.h>
+#include <limits.h>
+
+#include <windows.h>		
+#include <mmsystem.h>
+
+#ifndef WAVE_FORMAT_96M16
+#define WAVE_FORMAT_96M16 0x40000
+#define WAVE_FORMAT_96S16 0x80000
+#endif
+
+#include "direwolf.h"
+#include "audio.h"
+#include "audio_stats.h"
+#include "textcolor.h"
+#include "ptt.h"
+#include "demod.h"		/* for alevel_t & demod_get_audio_level() */
+#include "audio_ptt.h"
+
+static struct audio_s          *save_audio_config_p;
+
+static unsigned __stdcall ptt_thread ( void *arg );
+
+HANDLE start_ptt_thread (struct audio_s *pa , int ch)
+{
+  save_audio_config_p = pa;
+
+  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;
+
+  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.
+    */
+
+    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;
+
+      pnData = (short*)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;
+          }
+        }
+      }
+
+      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 8090c859..166c4380 100644
--- a/config.c
+++ b/config.c
@@ -666,7 +666,16 @@ void config_init (char *fname, struct audio_s *p_audio_config,
 	    p_audio_config->achan[channel].octrl[ot].ptt_lpt_bit = 0;
 	    p_audio_config->achan[channel].octrl[ot].ptt_invert = 0;
 	    p_audio_config->achan[channel].octrl[ot].ptt_invert2 = 0;
-	  }
+        p_audio_config->achan[channel].octrl[ot].ptt_channel = 0;
+        p_audio_config->achan[channel].octrl[ot].ptt_frequency = PTT_FREQ_DEFAULT;
+#ifdef __WIN32__
+        p_audio_config->achan[channel].octrl[ot].ptt_start = NULL;
+        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
+      }
 
 	  p_audio_config->achan[channel].dwait = DEFAULT_DWAIT;				
 	  p_audio_config->achan[channel].slottime = DEFAULT_SLOTTIME;				
@@ -1582,7 +1591,57 @@ void config_init (char *fname, struct audio_s *p_audio_config,
 	      dw_printf ("Config file line %d: %s with RIG is only available when hamlib support is enabled.\n", line, otname);
 #endif
 	    }
-	    else  {
+        else if (strcasecmp(t, "CHANNEL") == 0) {
+          t = split(NULL, 0);
+          if (t == NULL) {
+            text_color_set( DW_COLOR_ERROR );
+            dw_printf ("Config file line %d: Missing channel number for %s.\n", line, otname);
+            continue;
+          }
+
+          int channel_ptt = atoi(t);
+
+          if (channel_ptt < 0 || channel_ptt >= MAX_CHANS) {
+            text_color_set( DW_COLOR_ERROR );
+            dw_printf ( "Config file line %d: Invalid PTT channel number for %s.\n", line, otname );
+            continue;
+          }
+
+          if (channel == channel_ptt) {
+            text_color_set( DW_COLOR_ERROR );
+            dw_printf ( "Config file line %d: PTT channel number must not be the same as the channel number itself.\n", line );
+            continue;
+          }
+
+          int freq_ptt = PTT_FREQ_DEFAULT;
+          
+          t = split(NULL, 0);
+          if (t != NULL) {
+            freq_ptt = atoi(t);
+
+            if (freq_ptt < PTT_FREQ_MIN || freq_ptt > PTT_FREQ_MAX) {
+              text_color_set( DW_COLOR_ERROR );
+              dw_printf ("Config file line %d: Invalid value %d for PTT frequency. Using default of %d.\n",
+                  line, freq_ptt, PTT_FREQ_DEFAULT );
+
+              freq_ptt = PTT_FREQ_DEFAULT;
+            }
+          }
+
+          p_audio_config->achan[channel].octrl[ot].ptt_method = PTT_METHOD_AUDIO;
+          p_audio_config->achan[channel].octrl[ot].ptt_channel = channel_ptt;
+          p_audio_config->achan[channel].octrl[ot].ptt_frequency = freq_ptt;
+#ifdef __WIN32__
+          p_audio_config->achan[channel].octrl[ot].ptt_start = CreateEvent (NULL, FALSE, FALSE, NULL);
+          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  {
 
 /* serial port case. */
 
diff --git a/direwolf.h b/direwolf.h
index 958e0932..347f4eb2 100644
--- a/direwolf.h
+++ b/direwolf.h
@@ -38,6 +38,14 @@
 #define MAX_RIGS MAX_CHANS
 #endif
 
+/*
+ * PTT frequency settings
+ */
+
+#define PTT_FREQ_MIN        50
+#define PTT_FREQ_MAX        20000
+#define PTT_FREQ_DEFAULT    1000
+
 /*
  * Get audio device number for given channel.
  * and first channel for given device.
diff --git a/direwolf.txt b/direwolf.txt
index c8577395..e45d9c17 100644
--- a/direwolf.txt
+++ b/direwolf.txt
@@ -234,10 +234,16 @@ C# Both can be used for interfaces that want them driven with opposite polarity.
 C#
 L# COM1 can be used instead of /dev/ttyS0, COM2 for /dev/ttyS1, and so on.
 L#
+C# With a suitable interface circuit an audio channel can also be used to  
+C# trigger the PTT control. The device should be specified as CHANNEL, 
+C# followed by the channel number and (optionally) the desired frequency, 
+C# in Hz, of the audio tone to be used. The frequency must be between  
+C# 50 and 20000 Hz and defaults to 1000 Hz.
 C
 C#PTT COM1 RTS
 C#PTT COM1 RTS -DTR
 L#PTT /dev/ttyUSB0 RTS
+C#PTT CHANNEL 1 1000
 C
 L#
 L# On Linux, you can also use general purpose I/O pins if
diff --git a/ptt.c b/ptt.c
index 749ada61..5ccd71bc 100644
--- a/ptt.c
+++ b/ptt.c
@@ -126,6 +126,7 @@ typedef int HANDLE;
 #include "textcolor.h"
 #include "audio.h"
 #include "ptt.h"
+#include "audio_ptt.h"
 
 
 #if __WIN32__
@@ -357,6 +358,13 @@ void ptt_init (struct audio_s *audio_config_p)
 {
 	int ch;
 	HANDLE fd = INVALID_HANDLE_VALUE;
+
+#if __WIN32__
+    HANDLE audio_ptt_th[MAX_CHANS];
+#else
+    pthread_t audio_ptt_tid[MAX_CHANS];
+#endif
+
 #if __WIN32__
 #else
 	int using_gpio;
@@ -386,7 +394,7 @@ void ptt_init (struct audio_s *audio_config_p)
 	    if (ptt_debug_level >= 2) {
 
 	      text_color_set(DW_COLOR_DEBUG);
-              dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
+              dw_printf ("ch=%d, %s method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d, channel=%d, freq=%d\n",
 		ch,
 		otnames[ot],
 		audio_config_p->achan[ch].octrl[ot].ptt_method, 
@@ -394,7 +402,9 @@ void ptt_init (struct audio_s *audio_config_p)
 		audio_config_p->achan[ch].octrl[ot].ptt_line,
 		audio_config_p->achan[ch].octrl[ot].ptt_gpio,
 		audio_config_p->achan[ch].octrl[ot].ptt_lpt_bit,
-		audio_config_p->achan[ch].octrl[ot].ptt_invert);
+		audio_config_p->achan[ch].octrl[ot].ptt_invert,
+        audio_config_p->achan[ch].octrl[ot].ptt_channel,
+        audio_config_p->achan[ch].octrl[ot].ptt_frequency );
 	    }
 	  }
 	}
@@ -501,6 +511,7 @@ void ptt_init (struct audio_s *audio_config_p)
 	        ptt_set (ot, ch, 0);
 
 	      }    /* if serial method. */
+
 	    }	 /* for each output type. */
 	  }    /* if channel valid. */
 	}    /* For each channel. */
@@ -747,6 +758,33 @@ void ptt_init (struct audio_s *audio_config_p)
 
 #endif
 
+    /*
+    * Set up audio channel.
+    */
+
+    for (ch = 0; ch<MAX_CHANS; ch++) {
+      if (audio_config_p->achan[ch].valid) {
+        if (audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_AUDIO) {
+#if __WIN32__
+          audio_ptt_th[ch] = start_ptt_thread (audio_config_p, ch);
+          if (audio_ptt_th[ch] == NULL) {
+            text_color_set(DW_COLOR_ERROR);
+            dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n", 
+                audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch);
+            return;
+          }
+#else
+	  audio_ptt_tid[ch] = start_ptt_thread (audio_config_p, ch);
+          if (audio_ptt_tid[ch] == 0) {
+            text_color_set(DW_COLOR_ERROR);
+            dw_printf ("Could not create audio_ptt thread on channel %d for PTT of channel %d.\n",
+                audio_config_p->achan[ch].octrl[OCTYPE_PTT].ptt_channel, ch );
+            return;
+          }
+#endif
+        }
+      }
+    }
 
 /* Why doesn't it transmit?  Probably forgot to specify PTT option. */
 
@@ -968,7 +1006,32 @@ void ptt_set (int ot, int chan, int ptt_signal)
 	}
 #endif
 
+    /*
+    * Using audio channel?
+    */
 
+    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);
+#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
+      {
+#ifdef __WIN32__
+        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 */
 
 /*-------------------------------------------------------------------
@@ -1056,7 +1119,7 @@ void ptt_term (void)
 	      ptt_set (ot, n, 0);
 	    }
 	  }
-	}
+    }
 
 	for (n = 0; n < MAX_CHANS; n++) {
 	  if (save_audio_config_p->achan[n].valid) {
@@ -1074,6 +1137,21 @@ void ptt_term (void)
 	  }
 	}
 
+    for (n = 0; n < MAX_CHANS; n++) {
+  	  if (save_audio_config_p->achan[n].valid) {
+        if (save_audio_config_p->achan[n].octrl[OCTYPE_PTT].ptt_method == PTT_METHOD_AUDIO) {
+#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
+        }
+      }
+    }
+
 #ifdef USE_HAMLIB
 
 	for (n = 0; n < MAX_CHANS; n++) {