www.pudn.com > exosip.rar > sound-win32.cpp


/* 
 * josua - Jack's open sip User Agent 
 * 
 * Copyright (C) 2002,2003   Aymeric Moizard  
 * 
 * This 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, 
 * or (at your option) any later version. 
 * 
 * This 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 dpkg; if not, write to the Free Software 
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 */ 
 
#include "stdafx.h" 
#include "jcalls.h" 
#include "sdptools.h" 
#include  
 
#ifdef WIN32 
 
 
#include  
#include  
#include  
#include  
 
 
WAVEFORMATEX wfx; 
 
#define MAX_IN_BUFFERS 32 
#define USED_IN_BUFFERS 6 
#define MAX_OUT_BUFFERS 32 
#define USED_OUT_BUFFERS 32 
 
 
unsigned int waveoutDeviceID = WAVE_MAPPER; 
WAVEHDR waveHdrOut[MAX_OUT_BUFFERS]; 
HWAVEOUT hWaveOut; 
char dataBufferOut[MAX_OUT_BUFFERS][3200]; 
 
unsigned int waveinDeviceID = WAVE_MAPPER; 
HWAVEIN hWaveIn; 
WAVEHDR waveHdrIn[MAX_IN_BUFFERS]; 
char dataBufferIn[MAX_IN_BUFFERS][3200]; 
 
call_t *current_call = NULL; 
 
 
 
extern "C" void va_g729a_init_encoder(); 
extern "C" void va_g729a_encoder(short *speech, unsigned char *bitstream); 
extern "C" void va_g729a_init_decoder(); 
extern "C" void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi); 
 
 
static void CALLBACK 
SpeakerCallback (HWAVEOUT _hWaveOut, UINT uMsg, DWORD dwInstance, 
                 DWORD dwParam1, DWORD dwParam2) 
{ 
	WAVEHDR *wHdr; 
	 
	switch (uMsg) 
    { 
	case WOM_OPEN: 
        fprintf (stderr, "SpeakerCallback : WOM_OPEN\n"); 
        break; 
	case WOM_CLOSE: 
        fprintf (stderr, "SpeakerCallback : WOM_CLOSE\n"); 
        break; 
	case WOM_DONE: 
        fprintf (stderr, "SpeakerCallback : WOM_DONE\n"); 
        wHdr = (WAVEHDR *) dwParam1; 
        break; 
	default: 
        break; 
    } 
} 
 
 
static void CALLBACK 
WaveInCallback (HWAVEIN hWaveIn, UINT uMsg, DWORD dwInstance, DWORD dwParam1, 
                DWORD dwParam2) 
{ 
	WAVEHDR *wHdr; 
	MMRESULT mr = NOERROR; 
	char szSendBuffer[1024]; 
	int nLen = sizeof(szSendBuffer); 
	switch (uMsg) 
    { 
	case WIM_OPEN: 
        break; 
	case WIM_CLOSE: 
        break; 
	case WIM_DATA: 
        wHdr = (WAVEHDR *) dwParam1; 
        if (current_call == NULL) 
			return; 
        mr = waveInAddBuffer (hWaveIn, &(waveHdrIn[wHdr->dwUser]), 
			sizeof (waveHdrIn[wHdr->dwUser])); 
        if (mr == MMSYSERR_NOERROR) 
		{ 
            static int timestamp = 0; 
			 
            if (current_call) 
			{ 
				EncodeAudioData(wHdr->lpData, wHdr->dwBytesRecorded, 
								szSendBuffer,&nLen); 
                rtp_session_send_with_ts (current_call->rtp_session, 
					(BYTE*)szSendBuffer, nLen, 
					timestamp); 
                timestamp += nLen; 
			} 
		} 
        break; 
	default: 
        break; 
    } 
} 
 
bool EncodeAudioData(char *pin,int len,char* pout,int* lenr) 
{ 
	bool bRet = false; 
	 
	va_g729a_encoder((short*)pin,(BYTE*)pout); 
	va_g729a_encoder((short*)(pin+320),(BYTE*)pout+20); 
	va_g729a_encoder((short*)(pin+640),(BYTE*)pout+40); 
	va_g729a_encoder((short*)(pin+800),(BYTE*)pout+50); 
 
	*lenr = 60; 
 
	bRet = true; 
RET: 
	return bRet; 
} 
 
bool DecodeAudioData(char *pin,int len,char* pout,int* lenr) 
{ 
	bool bRet = false; 
 
	va_g729a_decoder((BYTE*)pin,(short*)(pout),0); 
	va_g729a_decoder((BYTE*)pin+20,(short*)(pout+320),0); 
	va_g729a_decoder((BYTE*)pin+40,(short*)(pout+640),0); 
	va_g729a_decoder((BYTE*)pin+50,(short*)(pout+800),0); 
 
	*lenr=960; 
	 
	bRet=true; 
RET: 
	return bRet; 
} 
 
int os_sound_init () 
{ 
	ortp_init (); 
	ortp_scheduler_init (); 
 
	va_g729a_init_encoder(); 
	va_g729a_init_decoder(); 
 
	return 0; 
} 
 
 
int open_sndcard (int format) 
{ 
	MMRESULT mr = NOERROR; 
	 
	WAVEFORMATEX wfx; 
	wfx.wFormatTag = WAVE_FORMAT_PCM; 
	wfx.nChannels = 1; 
	wfx.nSamplesPerSec = 8000; 
	wfx.nAvgBytesPerSec = 1 * 8000 * 16 / 8; 
	wfx.nBlockAlign = 16 * 1 / 8; 
	wfx.wBitsPerSample = 16; 
	wfx.cbSize = 0; 
 
	mr = waveOutOpen (&hWaveOut, waveoutDeviceID, &wfx,(DWORD)0,0,CALLBACK_NULL); 
	if (mr == NOERROR) 
    { 
		int i; 
		 
		for (i = 0; i < USED_OUT_BUFFERS; i++) 
        { 
			memset (&(waveHdrOut[i]), 0, sizeof (waveHdrOut[i])); 
			waveHdrOut[i].lpData = dataBufferOut[i]; 
			waveHdrOut[i].dwBufferLength = 960; /* frameSize */ 
 
			waveHdrOut[i].dwFlags = 0; 
			waveHdrOut[i].dwUser = i; 
			 
			mr = waveOutPrepareHeader (hWaveOut, &(waveHdrOut[i]),sizeof (waveHdrOut[i])); 
        } 
    } 
	 
	 
	mr = waveInOpen (&hWaveIn, waveinDeviceID, &wfx, (DWORD) WaveInCallback, 0, 
		CALLBACK_FUNCTION); 
 
	if (mr == MMSYSERR_NOERROR) 
    { 
		int i; 
		 
		for (i = 0; i < MAX_IN_BUFFERS; i++) 
        { 
			waveHdrIn[i].lpData = dataBufferIn[i]; 
			waveHdrIn[i].dwBufferLength = 960;    /* frameSize */ 
			waveHdrIn[i].dwFlags = 0; 
			waveHdrIn[i].dwUser = i; 
			mr = waveInPrepareHeader (hWaveIn, &(waveHdrIn[i]), sizeof (waveHdrIn[i])); 
			if (mr == MMSYSERR_NOERROR) 
            { 
				mr = waveInAddBuffer (hWaveIn, &(waveHdrIn[i]), sizeof (waveHdrIn[i])); 
			} 
        } 
		mr = waveInStart (hWaveIn); 
		if (mr != MMSYSERR_NOERROR) 
        { 
			exit (-1); 
			return -1; 
        } 
    } 
	return 0; 
} 
 
void * os_sound_start_thread (void *_ca) 
{ 
	int pos_whdr = 0; 
	call_t *ca = (call_t *) _ca; 
	char data_in[3000]; 
	char szBuffer[2048]; 
	int nLen = 2048; 
	int have_more; 
	int timestamp = 0; 
	int i; 
	 
	current_call = ca; 
	 
	while (ca->enable_audio != -1) 
    { 
		int length; 
		static int sound_played = 0; 
		static int cpt = 0; 
		 
		memset (data_in, 0, 3000); 
		if (ca->payload == 3) 
			length = 260;           /* 280 ?? */ 
		else 
			length = 160; 
		 
		i =	rtp_session_recv_with_ts (ca->rtp_session, (unsigned char*)data_in, length, timestamp, 
			&have_more); 
		if (i > 0) 
        { 
			MMRESULT mr = NOERROR; 
			 
			DecodeAudioData(data_in,i,szBuffer,&nLen); 
 
			memset (waveHdrOut[pos_whdr].lpData, 0, length); 
			memcpy (waveHdrOut[pos_whdr].lpData, szBuffer, nLen); 
			waveHdrOut[pos_whdr].dwBufferLength = nLen; 
			mr = waveOutWrite (hWaveOut, &waveHdrOut[pos_whdr], 
				sizeof (waveHdrOut[pos_whdr])); 
			 
			pos_whdr++; 
			if (pos_whdr == USED_OUT_BUFFERS) 
            { 
				pos_whdr = 0;     /* loop over the prepared blocks */ 
            } 
			if (mr != MMSYSERR_NOERROR) 
				switch (mr) 
			{ 
                case MMSYSERR_INVALHANDLE: 
					fprintf (stderr, 
						"__call_free: waveOutWrite: 0x%i MMSYSERR_INVALHANDLE\n", 
						mr); 
					break; 
                case MMSYSERR_NODRIVER: 
					fprintf (stderr, 
						"__call_free: waveOutWrite: 0x%i MMSYSERR_NODRIVER\n", 
						mr); 
					break; 
                case MMSYSERR_NOMEM: 
					fprintf (stderr, 
						"__call_free: waveOutWrite: 0x%i MMSYSERR_NOMEM\n", mr); 
					break; 
                case WAVERR_UNPREPARED: 
					fprintf (stderr, 
						"__call_free: waveOutWrite: 0x%i WAVERR_UNPREPARED\n", 
						mr); 
					break; 
                case WAVERR_STILLPLAYING: 
					fprintf (stderr, 
						"__call_free: waveOutWrite: 0x%i WAVERR_STILLPLAYING\n", 
						mr); 
                default: 
					fprintf (stderr, "__call_free: waveOutWrite: 0x%i\n", mr); 
			} else 
				++sound_played; 
			fprintf (stderr, "sound played = %i\n", sound_played); 
			fprintf (stderr, "cpt = %i\n", ++cpt); 
        } 
		timestamp += length; 
    } 
	current_call = NULL; 
	return NULL; 
} 
 
int 
os_sound_start (call_t * ca, int port) 
{ 
	int format = WAVE_FORMAT_MULAW; 
	char localip[128]; 
	 
	eXosip_guess_localip (AF_INET, localip, 128); 
	 
	 
	if (open_sndcard (format) != 0) 
		return -1; 
	 
	ca->rtp_session = rtp_session_new (RTP_SESSION_SENDRECV); 
	rtp_session_set_scheduling_mode (ca->rtp_session, 1); /* yes */ 
	rtp_session_set_blocking_mode (ca->rtp_session, 1); 
	 
	rtp_session_set_profile (ca->rtp_session, &av_profile); 
	rtp_session_set_jitter_compensation (ca->rtp_session, 60); 
	rtp_session_set_local_addr (ca->rtp_session, localip, port); 
	rtp_session_set_remote_addr (ca->rtp_session, 
		ca->remote_sdp_audio_ip, ca->remote_sdp_audio_port); 
	rtp_session_set_payload_type (ca->rtp_session, ca->payload); 
	rtp_session_signal_connect (ca->rtp_session, "telephone-event", 
		(RtpCallback) rcv_telephone_event, /*ca*/0); 
	 
	ca->audio_thread = osip_thread_create (20000, os_sound_start_thread, ca); 
	return 0; 
} 
 
void 
os_sound_close (call_t * ca) 
{ 
	osip_thread_join (ca->audio_thread); 
	osip_free (ca->audio_thread); 
	rtp_session_signal_disconnect_by_callback (ca->rtp_session, 
		"telephone-event", 
		(RtpCallback) rcv_telephone_event); 
	rtp_session_destroy (ca->rtp_session); 
	 
/*	waveInReset (hWaveIn); 
	waveInClose (hWaveIn); 
	waveOutReset (hWaveOut); 
	waveOutClose (hWaveOut);*/ 
} 
 
#endif