/*

	Play sound buffer
	
*/

#include "netfone.h"

/*  GSMDECOMP  --  Uncompress the contents of a sound buffer using GSM.  */

static void gsmdecomp(LPCLIENT_DATA pClientData, soundbuf *sb)
{
    gsm_signal dst[160];
    int i, j, l = 0;
    char *dpx = ((char *) sb->buffer.buffer_val) + sizeof(short);
    static char dcb[BUFL];
    short declen = ntohs(*((short *) sb->buffer.buffer_val));
    
    if (declen <= 0 || declen > 1600) {
        declen = 1600;
    }
    for (i = 0; i < (int) (sb->buffer.buffer_len - sizeof(short));
                i += sizeof(gsm_frame))
	{
		// Decode audio using client's gsm handle.
        gsm_decode(pClientData->gsmh, (gsm_byte *) dpx, dst);
        dpx += sizeof(gsm_frame);
        
		for (j = 0; j < 160; j++)
		{
            dcb[l++] = audio_s2u(dst[j]);
        }
    }
    memcpy(sb->buffer.buffer_val, dcb, declen);
    sb->buffer.buffer_len = declen;
}

/*	ADPCMDECOMP  --  Decompress the contents of a sound buffer using ADPCM.  */

void adpcmdecomp( struct soundbuf *sb)
{
#define TINY_PACKETS 512
	char *dp = (char *) sb->buffer.buffer_val;
	unsigned char *sp;
	static unsigned char dob[TINY_PACKETS * 2];
	struct adpcm_state adpcm;

	/* Restore the decoder state from the copy saved in the packet,
       independent of the byte order of the machine we're running on. */

	sp = (unsigned char *) dp + (sb->buffer.buffer_len - 3);
	adpcm.valprev = (short) ((((int) sp[0]) << 8) | ((int) sp[1]));
	adpcm.index = sp[2];
	sb->buffer.buffer_len -= 3;

	adpcm_decoder_u(dp, dob, (int) (sb->buffer.buffer_len * 2), &adpcm);
	sb->buffer.buffer_len *= 2;
	memcpy(dp, dob, (size_t) sb->buffer.buffer_len);
}

/*	LPCDECOMP  --  Uncompress the contents of a sound buffer using LPC.  */

static void lpcdecomp(struct soundbuf *sb, LPCLIENT_DATA c)
{
	int i, l = 0;
	char *dpx = ((char *) sb->buffer.buffer_val) + sizeof(short);
	static char dcb[LPC_FRAME_SIZE * 10];
	short declen = ntohs(*((short *) sb->buffer.buffer_val));

	if (declen <= 0 || declen > LPC_FRAME_SIZE * 10) {
		declen = LPC_FRAME_SIZE * 10;
	}
	for (i = 0; l < declen; i += sizeof(lpcparams_t)) {
		lpcparams_t *lp = (lpcparams_t *) (dpx + i);
		
		lpc_synthesize(dcb + l, lp, &(c->lpc_state));
		l += LPC_FRAME_SIZE;
	}
	memcpy(sb->buffer.buffer_val, dcb, declen);
	sb->buffer.buffer_len = declen;
}

/*	LPC10DECOMP  --  Uncompress the contents of a sound buffer using LPC10.  */

static void lpc10decomp(struct soundbuf *sb, LPCLIENT_DATA c)
{
	int j;
	char *dpx = ((char *) sb->buffer.buffer_val);
	char dcb[BUFL];

	j = lpc10decode(dpx, dcb, sb->buffer.buffer_len);
	memcpy(sb->buffer.buffer_val, dcb, j);
	sb->buffer.buffer_len = j;
}

/*	CELPDECOMP	--	Uncompress the contents of a sound buffer encoded in CELP.	*/

static void celpdecomp(struct soundbuf *sb, LPCLIENT_DATA c)
{
	short dst[240];
	unsigned int i;
	int j, l = 0;
	char *dpx = ((char *) sb->buffer.buffer_val) + sizeof(short);
	static char dcb[BUFL];
	short declen = ntohs(*((short *) sb->buffer.buffer_val));

	if (declen <= 0 || declen > 1920) {
		declen = 1920;
	}
	for (i = 0; i < sb->buffer.buffer_len - sizeof(short);
				i += 18) {
#ifdef CELP_USE_CONTEXT
		if (c->d_celp_ctx == NULL) {
			c->d_celp_ctx = (struct celp_context *) GlobalAllocPtr(GPTR, sizeof(struct celp_context));
			if (c->d_celp_ctx == NULL) {
				return;
			}
			celp_context_init(c->d_celp_ctx);
			celp_init(c->d_celp_ctx, FALSE);
		}
		celp_decode(c->d_celp_ctx, dpx, dst);
#else
		celp_decode(dpx, dst);
#endif
		dpx += 18;
		for (j = 0; j < 240; j++) {
			dcb[l++] = audio_s2u(dst[j]);
		}
	}
	memcpy(sb->buffer.buffer_val, dcb, declen);
	sb->buffer.buffer_len = declen;
}

//	AES_cbc_decrypt  --  Decrypt buffer with AES.

void AES_cbc_decrypt(unsigned char *in,
					 unsigned char *out,
					 int len, aes_ctx *ctx)
{
	int i, j;
	unsigned char feedback[AES_BLOCK_SIZE], fbnext[AES_BLOCK_SIZE];
	
	//	Initially zero the feedback buffer.
	memset(feedback, 0, AES_BLOCK_SIZE);
	Assert((len % AES_BLOCK_SIZE) == 0);		// Attempt to encrypt non-multiple of block length
	
	//	Loop over encryption blocks in the buffer.
	for (i = 0; i < len; i += AES_BLOCK_SIZE) {
		//	Save encrypted block as feedback for the following block.
		memcpy(fbnext, in, AES_BLOCK_SIZE);
		//	Decrypt the current block.
		aes_dec_blk(in, out, ctx);
		//	XOR it with the encrypted previous block saved in feedback.
		for (j = 0; j < AES_BLOCK_SIZE; j++) {
			out[j] ^= feedback[j];
		}
		//	Move saved encrypted present block to feedback buffer.
		memcpy(feedback, fbnext, AES_BLOCK_SIZE);
		//	Advance input and output pointers to next block.
		in += AES_BLOCK_SIZE;
		out += AES_BLOCK_SIZE;
	}
}

/*	DECODESOUNDPACKET  --  Decode a sound buffer into a Windows
						   LPWAVEHDR structure compatible with the audio
						   output device.  The sound buffer is decrypted,
						   decompressed, sample-rate adjusted, and
						   bits-per-sample transformed as required.
						   
						   If saveSamp is TRUE, the decrypted and
						   decompressed 8000 u-law sample per second
						   canonical data will be saved in a dynamically buffer
						   linked to the end of the WAVEHDR.  This is used
						   to permit the Audio Monitor to show the spectrum in
						   real time as the audio is played.  Note that if you
						   set saveSamp, your wh buffer *must* have room at
						   the end after sizeof(SAVEHDR) to hold the required
						   (char *) for the saved sample buffer.  */
						   
static void decodeSoundPacket(LPCLIENT_DATA pClientData, soundbuf *d,
							  int bitsPerSample, int samplesPerSecond, LPWAVEHDR wh,
							  BOOL saveSamp)
{
	short *sbuf;
	unsigned char *ulp;
	int i, len;
    char *val, **specsamp;
    static unsigned char auxbuf[BUFL + 2];
	int bufferMicroseconds;
#ifdef CRYPTO    
    char bbuf[8], tbuf[8];
#endif    
    	
	/* If the audio monitor is displayed and displaying input,
	   hide the original samples in a buffer linked to a
	   cell at the end of the wave header so we can update the
	   spectrum synchronously with the playing of the audio. */

	if (saveSamp) {
		specsamp = (char **) (((char *) wh) + sizeof(WAVEHDR));
		*specsamp = NULL;
	}
	
	/* Perform requested decryption and decompression of the
	   received data. */
	   
    len = (int) d->buffer.buffer_len;
    val = d->buffer.buffer_val;

    /* If the fSetDest bit is on, turn up the volume all the way
       if fDestJack is set.  This indicates an attempt to get the
       user's attention, even in case he's turned the volume all
       the way down.  This only happens if the user has requested
       it by setting the "Set Maximum Volume on Ring" workaround.
       Why?  Well, for public consumption we say that it's annoying
       to allow a remote user to override your chosen volume level.
       In reality, the primary motivation is that volume setting is
       one of the buggiest areas in sound card drivers and, without
       naming names, a recent (admittedly beta) driver from the
       largest vendor of sound cards for a (supposedly final release)
       operating system from the largest vendor of such products
       appears to zero the microphone gain whenever you set the output
       volume.  Imagine what fun this causes for users and how many
       E-mails to your humble author this results in.  So, pull it
       unless the user explicitly enables the volume reset. */

    if (waAudioRingMaxVolume && (d->compression & fSetDest)) {
        if (!(d->compression & fDestJack)) {
        	waveOutSetVolume(hWaveOut, (DWORD) MAKELONG(0xFFFF, 0xFFFF));
        }
    }

#ifdef CRYPTO	    

    /* If message is encrypted, decrypt. */

	//	Key file
    if ((d->compression & fEncOTP) && (pClientData->otpFileName[0])) {
        int i, slen = (len + 15) & (~15);

        for (i = 0; i < slen; i ++) {
            val[i] ^= pClientData->otp[i];
        }
    }
    
    //	PGP/IDEA
    if ((d->compression & fEncPGP)) {
        unsigned short iv[4];
        int slen = (len + 7) & (~7);
        char twibble[16];
        
        /*	Special gimmick: if we receive a PGP-encrypted packet while
        	we're still waiting for PGP to complete decrypting the session
        	key, ditch it.  This is a lot easier on the user's ears when
        	he's trying furiously to enter the private key phrase.  */
        
        Assert(pClientData != NULL);
        if (pClientData->pgpFileName[0] != 0) {
			propeller(IDC_PH_INPUT_LOST, ++inputPacketsLost);
			return;
        } else if (pClientData->pgpkey[0] != 0) { 
	        memcpy(twibble, pClientData->pgpkey + 1, 16);
	        memset(iv, 0, sizeof(iv));
	        initcfb_idea(iv, twibble, TRUE);
	        ideacfb(val, slen);
	        close_idea();
        }
    }

	//	AES
    if ((d->compression & fEncAES) && pClientData->aes_spec) {
		int slen = (len + 15) & (~15);

        Assert(pClientData != NULL);
		AES_cbc_decrypt((unsigned char *) val, (unsigned char *) val,
					slen, &(pClientData->aesDkey));
    }

	//	Blowfish
    if ((d->compression & fEncBF) && pClientData->blowfish_spec) {
        unsigned char iv[8];
        int slen = (len + 7) & (~7);
        
        Assert(pClientData != NULL);
        memset(iv, 0, sizeof(iv));
        BF_cbc_encrypt((unsigned char *) val,
					   (unsigned char *) val,
					   slen, &(pClientData->blowfishkey), iv, BF_DECRYPT);
    }
    
    //	IDEA
    if ((d->compression & fEncIDEA) && pClientData->ideaKeyString[0]) {
        unsigned short iv[4];
        int slen = (len + 7) & (~7);
        char twibble[16];
        
        Assert(pClientData != NULL);
        memcpy(twibble, pClientData->ideakey + 1, 16);
        memset(iv, 0, sizeof(iv));
        initcfb_idea(iv, twibble, TRUE);
        ideacfb(val, slen);
        close_idea();
    }

	//	DES
    if ((d->compression & fEncDES) && pClientData->desKeyString[0]) {
        int i;
        char twibble[8];
        
        Assert(pClientData != NULL);
        memcpy(twibble, pClientData->deskey + 1, 8);
        setkey(twibble);
        for (i = 0; i < len; i += 8) {
            memcpy(tbuf, val + i, 8);
            dedes(val + i);

            /* Reverse cipher block chaining. */

            if (i > 0) {
                int j;

                for (j = 0; j < 8; j++) {
                    val[(i + j)] ^= bbuf[j];
                }
            }
            memcpy(bbuf, tbuf, 8);
        }
    }
#endif    

    /* If message is compressed, decompress appropriately. */

    if (d->compression & fCompGSM) {
        Assert(pClientData != NULL);
        gsmdecomp(pClientData, d);
        len = (int) d->buffer.buffer_len;
    }
    
    if (d->compression & fCompADPCM) {
    	adpcmdecomp(d);
        len = (int) d->buffer.buffer_len;
    }
    
    if (d->compression & fCompLPC) {
        Assert(pClientData != NULL);
    	lpcdecomp(d, pClientData);
        len = (int) d->buffer.buffer_len;
    }

	if (d->compression & fCompLPC10) {
        Assert(pClientData != NULL);
		lpc10decomp(d, pClientData);
		len = (int) d->buffer.buffer_len;
	}

	if (d->compression & fCompCELP) {
        Assert(pClientData != NULL);
		celpdecomp(d, pClientData);
		len = (int) d->buffer.buffer_len;
	}

    if (d->compression & fComp2X) {
		int olen = len * 2;
		
		Assert(olen < (sizeof auxbuf));
        Assert(pClientData != NULL);
		rate_flow(&pClientData->rateconv,
				  (unsigned char *) val, (unsigned char *) auxbuf,
				  &len, &olen);
		len = olen;
		memcpy(val, auxbuf, len);
		d->buffer.buffer_len = len;
    }

	/*	If we're performing rate adjustment on the audio to compensate
		for receiving audio more rapidly than our hardware can play
		it, convert the data in the sound buffer to the desired
		rate.  Note that we perform the conversion here at the moment
		the sound buffer is in generic form: ulaw at 8000 samples
		per second.
		
		If the requested
	    rate would cause the output buffer to overflow, the length is
	    limited to that of the buffer, truncating any additional
	    audio in the packet.  In practice, this only happens with
	    absurdly large rate reductions which would render the audio
	    incomprehensible in any case. */
		   
	if (currentOutputRate != EXCHANGE_SAMPLE_RATE) {
		int is = len, os = ((len * currentOutputRate) + (EXCHANGE_SAMPLE_RATE - 1)) / EXCHANGE_SAMPLE_RATE;
		rate_t r;

		if (os > BUFL) {
			os = BUFL;			/* Constrain length to output buffer size */
		}
		rate_start(&r, EXCHANGE_SAMPLE_RATE, currentOutputRate);
		rate_flow(&r, (unsigned char *) val, (unsigned char *) auxbuf, &is, &os);
		memcpy(val, auxbuf, os);
		len = os;
        cPrintf("Resampled %ld to %ld samples at %d samples/sec.\n", d->buffer.buffer_len, len, currentOutputRate);
		d->buffer.buffer_len = len;
	}

	/*	If monitoring received audio, save original ulaw samples
		in a buffer linked to the end of the wave packet so they
		can be passed to the audio monitor right after they're
		done playing.  */

	if (saveSamp && (hDlgSpectral && !spectrumTransmitOnly)) {
		char *specbuf = malloc(len + sizeof(WORD));

		if (specbuf != NULL) {
			*((WORD *) specbuf) = len;
			memcpy(specbuf + sizeof(WORD), val, len);
			*specsamp = specbuf;
		}
	}

	/*	Compute time, in microseconds, it will take to play the samples in
		this buffer.  We compute this while the contents are in common 8000
		samples per second u-law, before any transformation into device-specific
		format.  */

	bufferMicroseconds = len * (1000000 / 8000);
	cPrintf("Microseconds in buffer: %ld", bufferMicroseconds);
    
    if (samplesPerSecond == 11025) {
	    if (bitsPerSample == 16) {	   
			
			/* Convert the resulting u-law samples in the sound buffer
			   to 16 bit signed linear format. */
			   
			wh->lpData = (LPSTR) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
				(DWORD) ((((BUFL * ((DWORD) sizeof(short)) * 12) / 8) + sizeof(int)))); 
			if (wh->lpData == NULL) {
				GlobalFreePtr(wh);
				return;
			}
			sbuf = (short *) wh->lpData;
			ulp = (unsigned char *) val;
			
			for (i = 0; i < len; i++) {
				int j = i & 7;
				*sbuf++ = audio_u2s(*ulp);
				//	This should be written out for better optimisation
				if (j > 0 && !(j & 1)) {
					*sbuf++ = audio_u2s(*ulp);
				} else if (j % 320 == 319) {
					*sbuf++ = audio_u2s(*ulp);
				}
				ulp++; 
			}
			wh->dwBufferLength = wh->dwBytesRecorded =
				(((LPSTR) sbuf) - wh->lpData);
		} else if (bitsPerSample == 8) {
			BYTE *bbuf;
			
			/* Convert the resulting u-law samples in the sound buffer
			   to 8 bit PCM format. */
			   
			wh->lpData = (LPSTR) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
				(DWORD) ((((BUFL * ((DWORD) sizeof(short)) * 12) / 16)) + sizeof(int))); 
			if (wh->lpData == NULL) {
				GlobalFreePtr(wh);
				return;
			}
			bbuf = (BYTE *) wh->lpData;
			ulp = (unsigned char *) val;
	
			for (i = 0; i < len; i++) {
				int j = i & 7;
				*bbuf++ = audio_u2c(*ulp);
				//	This should be written out for better optimisation
				if (j > 0 && !(j & 1)) {
					*bbuf++ = audio_u2c(*ulp);
				} else if (j % 320 == 319) {
					*bbuf++ = audio_u2c(*ulp);
				}
				ulp++; 
			}
			wh->dwBufferLength = wh->dwBytesRecorded =
				(((LPSTR) bbuf) - wh->lpData);
		}
	} else {	// samplesPerSecond == 8000
	    if (bitsPerSample == 16) {	   
			
			/* Convert the resulting u-law samples in the sound buffer
			   to 16 bit signed linear format. */
			   
			wh->lpData = (LPSTR) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
				(DWORD) ((len * sizeof(short)) + sizeof(int))); 
			if (wh->lpData == NULL) {
				GlobalFreePtr(wh);
				return;
			}
			sbuf = (short *) wh->lpData;
			ulp = (unsigned char *) val;
			
			for (i = 0; i < len; i++) {
				*sbuf++ = audio_u2s(*ulp++);
			}
			wh->dwBufferLength = wh->dwBytesRecorded =
				(((LPSTR) sbuf) - wh->lpData);
		} else if (bitsPerSample == 8) {
			BYTE  *bbuf;
			
			/* Convert the resulting u-law samples in the sound buffer
			   to 8 bit PCM format. */
			   
			wh->lpData = (LPSTR) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
				(DWORD) ((len * sizeof(BYTE)) + sizeof(int))); 
			if (wh->lpData == NULL) {
				GlobalFreePtr(wh);
				return;
			}
			bbuf = (BYTE  *) wh->lpData;
			ulp = (unsigned char *) val;
	
			for (i = 0; i < len; i++) {
				*bbuf++ = audio_u2c(*ulp++);
			}
			wh->dwBufferLength = wh->dwBytesRecorded =
				(((LPSTR) bbuf) - wh->lpData);
		}
	}

	//	Stuff the time it will take to play these samples at the end of the buffer

	memcpy(wh->lpData + wh->dwBufferLength, &bufferMicroseconds, sizeof bufferMicroseconds);
}

/*  PLAYSOUND  --  Play a sound buffer, decrypting and decompressing
				   as required.  */
				   
void playSound(HWND hWnd, LPCLIENT_DATA pClientData, soundbuf *d,
			   int bitsPerSample, int samplesPerSecond)
{
	LPWAVEHDR wh;
	WORD stat;
	int bufferMicroseconds;
    
    /*	If the message queue is close to exhaustion, ditch the output
    	buffer to avoid a hangup due to queue overflow.  */
    	
    if (outputPending >= ((3 * messageQueueSize) / 4)) {
		propeller(IDC_PH_INPUT_LOST, ++inputPacketsLost);
    	return;
    }
	
	wh = (LPWAVEHDR) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
			sizeof(WAVEHDR) + sizeof(CHAR *));
	if (wh == NULL) {
		return;
	}

	decodeSoundPacket(pClientData, d, bitsPerSample, samplesPerSecond, wh, TRUE);
	
	/*	Recover time it will take to play these samples which decodeSoundPacket
		stuffed at the end of the sample data.  */
		
	memcpy(&bufferMicroseconds, wh->lpData + wh->dwBufferLength, sizeof bufferMicroseconds);
    
    /*	Give the answering machine a chance to save the buffer.  Note that
		at this point the sound buffer is in canonical form: no encryption,
		and uncompressed u-law at 8000 samples/second.  As playSound() is,
		itself, invoked by the answering machine to replay sound packets
		saved in the incoming message file, it must take care to set the
		fPlayback bit so they're not stored right back into the answering
		machine.  */
    
    if (!(d->compression & fPlayback)) {
		char userId[1024];
		
		strcpy(userId, pClientData->szHost);
		/*	Note: the only circumstances in which the userId buffer risks
			overflow are in a direct attack.  Consequently, we needn't go
			beyond protecting ourselves here.  */
		if ((pClientData->email[0] != 0) || (pClientData->uname != NULL)) {
			strcat(userId, ";");
			if ((pClientData->email[0] != 0) &&
				((strlen(userId) + strlen(pClientData->email) + 2) < (sizeof userId))) {
				strcat(userId, pClientData->email);
			}
 			strcat(userId, ";");
 			if ((pClientData->uname != NULL) &&
 				((strlen(userId) + strlen(pClientData->uname) + 2) < (sizeof userId))) {
				strcat(userId, pClientData->uname);
			}
		}
		answerSave(pClientData->inetSock.sin_addr, userId, d);
    }
	
	wh->dwFlags = 0;
	waveOutPrepareHeader(hWaveOut, wh, sizeof(WAVEHDR));
#ifdef DELAY_OUTPUT
	if (outputPending == 0)
		waveOutPause(hWaveOut);
	else if (outputPending == 10)
		waveOutRestart(hWaveOut);
#endif

	/* If output is paused due to anti-jitter, but we've used up half
	   our message queue with held packets, start output anyway.  A
	   little jitter is better than packets discarded due to the
	   message queue limitation. */

	if (jitterPause && (outputPending >= (messageQueueSize / 2))) {
		jitterPause = FALSE;
		waveOutRestart(hWaveOut);
//OutputDebugString("Restart for queue length\r\n");		
	}
	 
	stat = waveOutWrite(hWaveOut, wh, sizeof(WAVEHDR));
	if (stat == 0) {

		/*	Increment number of pending output buffers and compute the
			number of milliseconds it will take to play these buffers
			at the nominal output sample rate.  This is then used to
			update an exponentially smoothed moving average of the length
			of the output queue in microseconds.  */

		outputPending++;
		microsecondsPending += bufferMicroseconds;
		smoothedMicrosecondsPending = smoothedMicrosecondsPending + (microsecondsPending - smoothedMicrosecondsPending) * 0.1;
cPrintf("+ time pending = %.2g", smoothedMicrosecondsPending / 1000000.0);

		/*	Unless disabled by the workaround waAudioNoOutputRateAdjustment,
			compare the smoothed estimate of the time it will take to clear the
			output queue to the chosen jitter interval.  If it's greater than
			the jitter interval by a prescribed amount, adjust the output sample
			rate to speed up the output rate of subsequently arriving samples.  */

		if (!waAudioNoOutputRateAdjustment) {
			int excessQueue = (int) ((smoothedMicrosecondsPending / 1000.0) - min(jitterBuf, AORA_MINIMUM_DELAY));

			if (excessQueue > AORA_ACTION_DELAY) {
				currentOutputRate = EXCHANGE_SAMPLE_RATE -
					((EXCHANGE_SAMPLE_RATE * AORA_MAXIMUM_RATE_PERCENT *
						min(excessQueue - AORA_ACTION_DELAY, AORA_MAXIMUM_RATE_DELAY)) / (AORA_MAXIMUM_RATE_DELAY * 100));
			} else {
				currentOutputRate = EXCHANGE_SAMPLE_RATE;
			}
			cPrintf("+ Excess queue length: %d msec.  Rate = %d", excessQueue, currentOutputRate);
		}

		//	Update the output queue length and time in the extended status dialogue
		if (hDlgPropeller != NULL) {
			char s[80];
					
			if (outputPending == 0) {
				wsprintf(s, Format(6));
			} else {
				sprintf(s, Format(7), outputPending, microsecondsPending / 1000000.0);
			}
			SetDlgItemText(hDlgPropeller, IDC_PH_AUDIO_OUT_QUEUE, s);
		}
	} else {	
	    char et[MAXERRORLENGTH];
	    	
	    waveOutGetErrorText(stat, et, sizeof et);
	    waveOutUnprepareHeader(hWaveOut, wh, sizeof(WAVEHDR));
	    GlobalFreePtr(wh);
        MsgBox(hWnd, MB_OK | MB_ICONEXCLAMATION, Format(45), et);
	    return;
	}
}

/*  DECODEANSWERPACKET  --  Decode a sound packet saved by the answering machine
							so that it can be saved in a .WAV file.  */
				   
void decodeAnswerPacket(soundbuf *d, int bitsPerSample, int samplesPerSecond,
						LPSTR *pcmData, DWORD *pcmLength)
{
	WAVEHDR wh;

	decodeSoundPacket(NULL, d, bitsPerSample, samplesPerSecond, &wh, FALSE);
	*pcmData = wh.lpData;
	*pcmLength = wh.dwBytesRecorded;

}