mp3gw / main.c /
687e985 7 years ago
1 contributor
695 lines | 20.231kb
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <pcap.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>
#include <time.h> 
#include <pthread.h>

#include <mpg123.h> //Decode
#include <twolame.h> //Encode
#include <sndfile.h> //Dump

#define APP_NAME "mp3gw"
#define APP_VERSION "0.0.1"
#define APP_DATE "2014-05-06"
#define APP_DESCRIPTION "Small utility to transcode on the fly mp3 stream"

#define APP_USER_AGENT "mp3gw/0.0.1 (2014-05-06)"
//#define APP_FAKE_USER_AGENT "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; WOW64; Trident/4.0; SLCC1)"
#define APP_FAKE_USER_AGENT "Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130912 Firefox/17.0"


#ifndef MAX_SIZE
	#define MAX_SIZE 256
#endif //MAX_SIZE

#ifndef MAX_DOTTED_IP_SIZE
	#define MAX_DOTTED_IP_SIZE 16
#endif //MAX_DOTTED_IP_SIZE

#ifndef MAX_LISTEN
	#define MAX_LISTEN 10
#endif //MAX_LISTEN

#ifndef RECV_BUFF_SIZE
	#define RECV_BUFF_SIZE 16384
#endif //RECV_BUFF_SIZE

#ifndef SEND_BUFF_SIZE
	#define SEND_BUFF_SIZE 1024
#endif //SEND_BUFF_SIZE

#ifndef CLI_DEFAULT_PORT
	#define CLI_DEFAULT_PORT 80
#endif //CLI_DEFAULT_PORT

#define DEBUG
#ifdef DEBUG
#define DEBUG_PRINT(...) do{ fprintf( stderr,"[DEBUG]%s:%d:%s() ",__FILE__,__LINE__,__FUNCTION__);fprintf( stderr, __VA_ARGS__ ); } while( false )
#else
#define DEBUG_PRINT(...)
#endif

#define INFO_PRINT(...) do{ fprintf( stderr,"[INFO]");fprintf( stderr, __VA_ARGS__ ); } while( false )
#define WARN_PRINT(...) do{ fprintf( stderr,"[WARN]");fprintf( stderr, __VA_ARGS__ ); } while( false )
#define ERR_PRINT(...) do{ fprintf( stderr,"[ERROR]");fprintf( stderr, __VA_ARGS__ ); } while( false )
#define CRIT_PRINT(...) do{ fprintf( stderr,"[CRITICAL]");fprintf( stderr, __VA_ARGS__ ); } while( false )

typedef struct client_cnx_t_ {
	char ip_addr[MAX_SIZE];
	char uri[MAX_SIZE];
	char ip_addr_hr[MAX_DOTTED_IP_SIZE];
	uint16_t tcp_port;
} client_cnx_t;


//MPG123 Constants & Definitions
static mpg123_handle *hdlMPG = NULL;

//Twolame Constants & Definitions
static twolame_options *encodeOptions = NULL;
const int32_t MP3_OUTPUT_bitrate = 64;//in kbps
//~ const int32_t MP3_OUTPUT_bitrate = 32;//in kbps
//~ const int32_t MP3_OUTPUT_bitrate = 64;//in kbps
//~ const int32_t MP3_OUTPUT_mode = TWOLAME_MONO;//TWOLAME_MONO or TWOLAME_STEREO
const int32_t MP3_OUTPUT_mode = TWOLAME_STEREO;//TWOLAME_MONO or TWOLAME_STEREO

//SNDFILE Constants & Definitions
#define WAVDUMP
#define MP3DUMP
//#define USE_RESAMPLE

#ifdef WAVDUMP
	const char *cst_output_dump_file = "output.wav";
#endif //WAVDUMP

#ifdef MP3DUMP
	const char *cst_output_dump_file_mp3 = "output.mp3";
	static FILE* mp3file = NULL;
#endif //MP3DUMP

#ifdef USE_RESAMPLE
	#define DOWNSAMPLING_FACTOR_2 2
	#define DOWNSAMPLING_FACTOR_4 4
#endif //USE_RESAMPLE

static client_cnx_t s_cli_connection;
static int32_t sock_cli = 0;
static int32_t sock_srv = 0;
static int32_t sock_srv_cli = 0;
static int32_t s_keep_running = 1;
static int32_t s_exit_program = 0;
static uint16_t s_srv_port = 0;
static pthread_t thread_id;
static int32_t s_input_stream_channels = 0;

void usage()
{	
	printf( "%s (%s) %s\nDescription :\n\t%s\nUsage :\n\t%s -a <server_ip> -p <server_port> -u <uri> -P <local_port>\n", APP_NAME, APP_VERSION, APP_DATE, APP_DESCRIPTION, APP_NAME );
}

int32_t MsgSend(int sock, uint8_t *msg, int32_t len )
{
	 int nbSent = write(sock,msg,len);
	 DEBUG_PRINT("Sent %d bytes\n", nbSent );
	 return nbSent;	 
}

int32_t MsgPayloadStart(char *msg, int32_t len)
{
	char seed[]="\r\n\r\n";
	char substr[4]="";
	int32_t pos = 0;
	bool found = false;
	while( ( false == found ) && ( pos < len ) )
	{
		strncpy(substr,(msg+pos),strlen(seed));
		if( 0 == strncmp(substr,seed,strlen(seed)) )
		{
			found=true;
			DEBUG_PRINT("End-of-Headers found at %d\n", pos );
			return pos;
		}
		pos+=strlen(seed);
	}
	return 0;
}
void options(int32_t num_args, char** args )
{
	int32_t i = 0;
	for( i = 1; i < num_args; i++ )
	{
		if( 0 == strcmp( "-a", args[i] ) )
		{
			if( NULL != args[i+1] )
			{
				strncpy( s_cli_connection.ip_addr, args[i+1], MAX_SIZE );
				i++;
			}
		}
		else if( 0 == strcmp( "-p", args[i] ) )
		{
			if( NULL != args[i+1] )
			{
				s_cli_connection.tcp_port = atoi(args[i+1]);
				i++;
			}
		}
		else if( 0 == strcmp( "-u", args[i] ) )
		{
			if( NULL != args[i+1] )
			{
				strncpy( s_cli_connection.uri, args[i+1], MAX_SIZE );
				i++;
			}
		}
		else if( 0 == strcmp( "-P", args[i] ) )
		{
			if( NULL != args[i+1] )
			{
				s_srv_port = atoi(args[i+1]);
				i++;
			}
		}
	}	
}

void sig_int_handler()
{
	DEBUG_PRINT("sig_int_handler");
	s_keep_running = 0;
	s_exit_program = 1;
	if( 0 != hdlMPG )
	{
		mpg123_delete(hdlMPG);
		hdlMPG = 0;
	}
	if( NULL != encodeOptions )
	{
		twolame_close(&encodeOptions);
		encodeOptions=NULL;
	}
	
#ifdef MP3DUMP
	if( NULL != mp3file )
	{
		fclose(mp3file);
		mp3file = NULL;
	}
#endif //MP3DUMP
	//~ exit(0);
	
	close(sock_cli);
	close(sock_srv);
	close(sock_srv_cli);
}

int32_t parse_payload(uint16_t sizeBuff, uint8_t *Buff )
{
	int32_t retVal = 0;
	uint8_t response_ok[MAX_SIZE]= "HTTP/1.1 200 OK\r\n";
	retVal = memcmp( response_ok, Buff, strlen((char*)response_ok) );
	if( 0 == retVal )
	{
		DEBUG_PRINT("==========================");
		DEBUG_PRINT( "HTTP Headers present" );
		DEBUG_PRINT("%s", Buff);
		DEBUG_PRINT("==========================");
	}
	//TODO: Return begining of payload offset
	return retVal;
}

void *thread_loop(void *);

void twolameCreate()
{
	INFO_PRINT("libtwolame/%s\n", get_twolame_version());
	encodeOptions = twolame_init();
	twolame_set_version(encodeOptions, TWOLAME_MPEG1);
	twolame_set_bitrate(encodeOptions, MP3_OUTPUT_bitrate);
	twolame_set_mode(encodeOptions, MP3_OUTPUT_mode);
	twolame_set_emphasis(encodeOptions,  TWOLAME_EMPHASIS_N );
}

void mpg123Create()
{
	int32_t ret = 0;
	INFO_PRINT("libmpg123 API version %d\n", MPG123_API_VERSION);
	mpg123_init();
	hdlMPG = mpg123_new(NULL, &ret);
	if(NULL == hdlMPG)
	{
		ERR_PRINT("libmpg123 new %s\n", mpg123_plain_strerror(ret));
		return;
	}
	mpg123_open_feed(hdlMPG);
	if( NULL == hdlMPG )
	{
		ERR_PRINT("libmpg123 open" );
	}
}

#ifdef USE_RESAMPLE
void downsample_signed16_by_2(const uint16_t sz_data_in, const int16_t *data_in, uint16_t *sz_data_out, int16_t *data_out)
{
	uint16_t i = 0;
	if( 1 == s_input_stream_channels )
	{
		for(i = 0; i < sz_data_in; i=i+DOWNSAMPLING_FACTOR_2 )
		{
			data_out[i/DOWNSAMPLING_FACTOR_2] = (data_in[ i ]/DOWNSAMPLING_FACTOR_2) + (data_in[ i+1 ]/DOWNSAMPLING_FACTOR_2);
			*sz_data_out=i/DOWNSAMPLING_FACTOR_2;
		}
	}
	else
	{
		for(i = 1; i < (sz_data_in/s_input_stream_channels); i=i+DOWNSAMPLING_FACTOR_2 )
		{
			data_out[i/DOWNSAMPLING_FACTOR_2] = (data_in[ i ]/DOWNSAMPLING_FACTOR_2) + (data_in[ i+1 ]/DOWNSAMPLING_FACTOR_2);
			//~ data_out[i/DOWNSAMPLING_FACTOR_2] = data_in[ i ];
			*sz_data_out=i/DOWNSAMPLING_FACTOR_2;
		}	
	}
	
	*sz_data_out = sizeof(int16_t)*(*sz_data_out);
}
#endif //USE_RESAMPLE

void monorealizer(const uint16_t sz_data_in, const int16_t *data_in, uint16_t *sz_data_out, int16_t *data_out)
{
	DEBUG_PRINT("monorealizer");
	//~ uint16_t i = 0;
	//~ for(i = 0; i < sz_data_in/2; i=i+2 )
	//~ {
		//~ data_out[i/2] = (data_in[ i ]/2) - (data_in[ i+1 ]/2);
		//~ data_out[i/2] = (data_in[ i ]/2) + (data_in[ i+1 ]/2);
		//~ data_out[i/2] = ( data_in[ i ] + data_in[ i+1 ] )/2;
		//~ data_out[i/2] = ( data_in[ i ] - data_in[ i+1 ] )/2;
		//~ *sz_data_out=i/2;
	//~ }	
	//~ *sz_data_out = sizeof(int16_t)*(*sz_data_out);
	*sz_data_out = sz_data_in;
	memcpy(data_out,data_in,sizeof(int16_t)*sz_data_in);
}

int32_t main(int32_t argc, char **argv )
{
	char srvMesg[MAX_SIZE];

	struct sockaddr_in local_serv_addr;
	struct sockaddr_in local_cli_addr;

	time_t ticks;
	
	if( 1 == argc )
	{
		usage();
		exit(-1);
	}
	signal(SIGINT, sig_int_handler);
	
	//This is dirty
    struct sigaction new_actn, old_actn;
	new_actn.sa_handler = SIG_IGN;
	sigemptyset (&new_actn.sa_mask);
	new_actn.sa_flags = 0;
	sigaction (SIGPIPE, &new_actn, &old_actn);
	
	printf( "%s/%s (%s)\n", APP_NAME, APP_VERSION, APP_DATE );
	options( argc, argv );
	
	INFO_PRINT("Listening on port %d\n", s_srv_port );
	sock_srv = socket(AF_INET , SOCK_STREAM , 0);
    if( sock_srv < 0 )
    {
        CRIT_PRINT("opening socket");
        exit(1);
    }
	local_serv_addr.sin_family = AF_INET;
    local_serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    local_serv_addr.sin_port = htons(s_srv_port);
    int32_t optval = 1;
	setsockopt(sock_srv, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
		
    if( 0 != bind(sock_srv, (struct sockaddr*)&local_serv_addr, sizeof(local_serv_addr)) )
    {
		CRIT_PRINT("binding socket");
		exit(4);
	}
	listen(sock_srv, MAX_LISTEN);
	
	int32_t c = sizeof(struct sockaddr_in);
	while(0 == s_exit_program)
    {
		sock_srv_cli = accept(sock_srv, (struct sockaddr *)&local_cli_addr, (socklen_t*)&c);
		ticks = time(NULL);
		if( 0 == s_exit_program )
		{
			snprintf(srvMesg, sizeof(srvMesg), "%.24s : incoming Connection from %s:%d\n", ctime(&ticks), inet_ntoa(local_cli_addr.sin_addr), ntohs(local_cli_addr.sin_port) );
			INFO_PRINT("%s", srvMesg );
			s_keep_running = 1;
			if( 0 > (pthread_create( &thread_id, NULL ,  thread_loop , (void*) &sock_srv_cli) ) )
			{
				CRIT_PRINT("thread creation\n");
				return 1;
			}
			if( 0 == s_exit_program )
			{
				INFO_PRINT("Listening on port %d\n", s_srv_port );
			}
		}
         
        //Now join the thread , so that we dont terminate before the thread
		//~ pthread_join( thread_id, NULL);
		//~ pthread_detach(thread_id);
    }
	close(sock_srv);
	DEBUG_PRINT("clean exit\n");
	return 0;
}

void *thread_loop(void *socket_desc)
{
	DEBUG_PRINT("START\n");
	struct sockaddr_in serv_addr;
	struct hostent *server;
	uint8_t recvBuff[RECV_BUFF_SIZE];
	uint8_t sendBuff[SEND_BUFF_SIZE];
	uint16_t numRecvBuff=0;
	uint16_t numSendBuff=0;
	int32_t ret=0;

#ifdef USE_RESAMPLE
	uint8_t downBuff[SEND_BUFF_SIZE];
	uint16_t numDownBuff=0;
#endif //USE_RESAMPLE

	int64_t input_stream_rate;
	int32_t input_stream_channels;
	int32_t input_stream_enc;
	
	#ifdef WAVDUMP
		SNDFILE* sndfile = NULL;
		SF_INFO sfinfo;
	#endif //WAVDUMP
	
	int32_t  mp2fill_size = 0;
	uint8_t* snd_buffer = NULL;
	size_t snd_buffer_size = 0;
	
	memset(recvBuff, 0,RECV_BUFF_SIZE);
	memset(sendBuff, 0,SEND_BUFF_SIZE);
	#ifdef USE_RESAMPLE
		memset(downBuff, 0,SEND_BUFF_SIZE);
	#endif //USE_RESAMPLE
	
	#ifdef MP3DUMP
		mp3file = fopen(cst_output_dump_file_mp3, "wb");
	#endif //MP3DUMP
		
	int sock = *(int*)socket_desc;
          
	INFO_PRINT("Connecting to %s:%d\n", s_cli_connection.ip_addr, s_cli_connection.tcp_port );
		
	sock_cli = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_cli < 0) 
    {
        CRIT_PRINT("opening socket\n");
        exit(1);
    }
    
    server = gethostbyname(s_cli_connection.ip_addr);
    if (server == NULL) {
        CRIT_PRINT("no such host\n");
        exit(2);
    }
    
	mpg123Create();
	twolameCreate();
        
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
           (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);
    serv_addr.sin_port = htons(s_cli_connection.tcp_port);
    strncpy( s_cli_connection.ip_addr_hr, inet_ntoa(serv_addr.sin_addr), MAX_DOTTED_IP_SIZE );
    INFO_PRINT("Redirecting to %s:%d\n", s_cli_connection.ip_addr_hr, s_cli_connection.tcp_port );
    
    if (connect(sock_cli, (const struct sockaddr*)&serv_addr, sizeof(serv_addr) ) < 0) 
    {
		CRIT_PRINT("connecting\n");
		exit(3);
    }
	
    sprintf( (char*)sendBuff, "GET http://%s:%d/%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\nIcy-MetaData: 0\r\nConnection: close\r\n\r\n",
			s_cli_connection.ip_addr,
			s_cli_connection.tcp_port,
			s_cli_connection.uri,
			s_cli_connection.ip_addr,
			//~ APP_USER_AGENT );
			APP_FAKE_USER_AGENT );

    DEBUG_PRINT("Sending Request\n");
    //~ numSendBuff = write(sock_cli,sendBuff,strlen((char*)sendBuff));
    numSendBuff = MsgSend(sock_cli,sendBuff,strlen((char*)sendBuff));
    //~ DEBUG_PRINT("Sent %d bytes\n",numSendBuff);
    uint64_t bytesReceived = 0;
	uint64_t pktReceived = 0;
	uint64_t pktSent = 0;
	int32_t	retSockWrite = 0;
    while( (1 == s_keep_running) && (0 == s_exit_program) )
    {
		bzero(recvBuff,RECV_BUFF_SIZE);
		numRecvBuff += read(sock_cli,recvBuff,RECV_BUFF_SIZE);
		int pktBuff=1;
		while( numRecvBuff < RECV_BUFF_SIZE )
		{
			//~ DEBUG_PRINT("Buffering %d packet (%d/%d)\n", pktBuff++, numRecvBuff, RECV_BUFF_SIZE);
			numRecvBuff += read(sock_cli,(recvBuff+numRecvBuff),RECV_BUFF_SIZE);
		}
		INFO_PRINT("Done Buffering\n");
		if( NULL != hdlMPG )
		{
			//Strip HTTP Headers needed
			int payload_start = MsgPayloadStart((char*)recvBuff,numRecvBuff);
			ret = mpg123_decode(hdlMPG,(recvBuff + payload_start),(numRecvBuff-payload_start),sendBuff,SEND_BUFF_SIZE,(size_t*)&numSendBuff);
			//~ int i = 0;
			//~ for( i = payload_start; i < (numRecvBuff-payload_start); i++ )
			//~ {
				//~ printf("%c", recvBuff[i]);
			//~ }
			//~ printf("\n");
			if( 0 != payload_start )
			{
				int nbsent = MsgSend(sock , recvBuff, payload_start);
				DEBUG_PRINT("Sent to client %d bytes\n", nbsent );
			}
			if(ret == MPG123_NEW_FORMAT)
			{
				snd_buffer_size = mpg123_outblock(hdlMPG);
				mpg123_getformat(hdlMPG, &input_stream_rate, &input_stream_channels, &input_stream_enc);
				INFO_PRINT("Input Stream : %li Hz %i channels\n", input_stream_rate, input_stream_channels);
				if(input_stream_enc != MPG123_ENC_SIGNED_16 && input_stream_enc != MPG123_ENC_FLOAT_32)
				{
					ERR_PRINT("Bad encoding: 0x%x\n", input_stream_enc );
				}
				mpg123_format_none(hdlMPG);
				mpg123_format(hdlMPG, input_stream_rate, input_stream_channels, input_stream_enc);
				s_input_stream_channels=input_stream_channels;
				
				#ifdef WAVDUMP
					bzero(&sfinfo, sizeof(sfinfo) );
					sfinfo.samplerate = input_stream_rate;
					sfinfo.channels = input_stream_channels;
					sfinfo.format = SF_FORMAT_WAV|(input_stream_enc == MPG123_ENC_SIGNED_16 ? SF_FORMAT_PCM_16 : SF_FORMAT_FLOAT);
					INFO_PRINT("Creating WAV with %i channels and %liHz.\n", input_stream_channels, input_stream_rate);
					sndfile = sf_open(cst_output_dump_file, SFM_WRITE, &sfinfo);

					if( MPG123_ENC_SIGNED_16 == input_stream_enc )
					{
						sf_write_short(sndfile, (short*)sendBuff, numSendBuff/sizeof(short));
					}
					else
					{
						sf_write_float(sndfile, (float*)sendBuff, numSendBuff/sizeof(float));
					}
				#endif //WAVDUMP
				
				if( NULL == snd_buffer )
				{
					snd_buffer = malloc( snd_buffer_size );
				}

				twolame_set_num_channels(encodeOptions, input_stream_channels );
				#ifndef USE_RESAMPLE
					twolame_set_in_samplerate(encodeOptions, input_stream_rate);
					twolame_set_out_samplerate(encodeOptions, input_stream_rate);
					INFO_PRINT( "libtwolame samplerate : %ld Hz\n",input_stream_rate );
				#else
					twolame_set_in_samplerate(encodeOptions, input_stream_rate/DOWNSAMPLING_FACTOR_2);
					twolame_set_out_samplerate(encodeOptions, input_stream_rate/DOWNSAMPLING_FACTOR_2);
					INFO_PRINT( "libtwolame samplerate : %ld Hz\n",input_stream_rate/DOWNSAMPLING_FACTOR_2 );
				#endif //USE_RESAMPLE
				
				INFO_PRINT( "libtwolame bitrate    : %d kbps\n",MP3_OUTPUT_bitrate );
				//~ twolame_set_verbosity(encodeOptions, 4);
				//~ twolame_print_config(encodeOptions);
				if( TWOLAME_MONO == MP3_OUTPUT_mode )
				{
					INFO_PRINT( "libtwolame channels   : Mono\n" );
				}
				else
				{
					INFO_PRINT( "libtwolame channels   : Stereo\n" );
				}
				
				if (twolame_init_params(encodeOptions) != 0) {
					CRIT_PRINT("twolame_init_params\n");
					exit(15);
				}
				if( MPG123_ENC_SIGNED_16 == input_stream_enc )
				{
					INFO_PRINT( "Sample format : MPG123_ENC_SIGNED_16\n" );
				}
				else
				{
					INFO_PRINT( "Sample format : MPG123_ENC_FLOAT_32\n" );
				}
				if( MPG123_ENC_SIGNED_16 == input_stream_enc )
				{
					//TODO : Add Monorealizer
					if( input_stream_channels == 1 )
					{
						#ifndef USE_RESAMPLE
							mp2fill_size = twolame_encode_buffer_interleaved(encodeOptions, (const int16_t*)sendBuff, numSendBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
						#else
							downsample_signed16_by_2(numSendBuff/sizeof(int16_t), (const int16_t*)sendBuff, &numDownBuff, (int16_t*)&downBuff);
							mp2fill_size = twolame_encode_buffer_interleaved(encodeOptions, (const int16_t*)downBuff, numDownBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
						#endif //USE_RESAMPLE
					}
					else
					{
						//~ monorealizer( numSendBuff/sizeof(int16_t), (const int16_t*)sendBuff, &numDownBuff, (int16_t*)&downBuff);
						//~ mp2fill_size = twolame_encode_buffer(encodeOptions, (const int16_t*)sendBuff, (const int16_t*)sendBuff, numSendBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
						mp2fill_size = twolame_encode_buffer_interleaved(encodeOptions, (const int16_t*)sendBuff, numSendBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
					}					
					#ifdef MP3DUMP
						fwrite(snd_buffer, sizeof(uint8_t), mp2fill_size, mp3file);
					#endif //MP3DUMP
				}
				else
				{
					mp2fill_size = twolame_encode_buffer_float32(encodeOptions, (const float*)sendBuff, NULL, numSendBuff/sizeof(float),snd_buffer, snd_buffer_size);
				}
				//~ int nbsent = write(sock , snd_buffer, mp2fill_size);
				if( 0 != mp2fill_size )
				{
					int nbsent = MsgSend(sock , snd_buffer, mp2fill_size);
					DEBUG_PRINT("Sent to client %d bytes (expecting %d bytes)\n", nbsent, mp2fill_size );
				}
			}
			else if( ( ret != MPG123_OK ) && ( ret != MPG123_NEED_MORE ) )
			{
				ERR_PRINT("mpg123_decode format is %d\n", ret );
			}
			
			//~ while(ret != MPG123_ERR && ret != MPG123_NEED_MORE)
			while(ret == MPG123_OK )
			{
				ret = mpg123_decode(hdlMPG,NULL,0,sendBuff,SEND_BUFF_SIZE,(size_t*)&numSendBuff);
				#ifdef WAVDUMP
					if( MPG123_ENC_SIGNED_16 == input_stream_enc )
					{
						sf_write_short(sndfile, (int16_t*)sendBuff, numSendBuff/sizeof(int16_t));
					}
					else
					{
						sf_write_float(sndfile, (float*)sendBuff, numSendBuff/sizeof(float));
					}
				#endif //WAVDUMP
						
				if( MPG123_ENC_SIGNED_16 == input_stream_enc )
				{
					#ifndef USE_RESAMPLE
						mp2fill_size = twolame_encode_buffer_interleaved(encodeOptions, (const int16_t*)sendBuff, numSendBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
					#else
						downsample_signed16_by_2(numSendBuff/sizeof(int16_t), (const int16_t*)sendBuff, &numDownBuff, (int16_t*)&downBuff);
						mp2fill_size = twolame_encode_buffer_interleaved(encodeOptions, (const int16_t*)downBuff, numDownBuff/sizeof(int16_t),snd_buffer, snd_buffer_size);
					#endif //USE_RESAMPLE
										
					#ifdef MP3DUMP
						fwrite(snd_buffer, sizeof(unsigned char), mp2fill_size, mp3file);
					#endif //MP3DUMP					
				}
				else
				{
					mp2fill_size = twolame_encode_buffer_float32(encodeOptions, (const float*)sendBuff, NULL, numSendBuff/sizeof(float),snd_buffer, snd_buffer_size);
				}

				retSockWrite = write(sock , snd_buffer, mp2fill_size);
				if( 0 > retSockWrite )
				{
					if( 0 != s_keep_running )
					{
						ERR_PRINT("write failed\n");
						s_keep_running = 0;
					}
				}
			}
			//~ write(sock , recvBuff , numRecvBuff);
			if( 0 != mp2fill_size )
			{
				int nbsent = MsgSend(sock , snd_buffer, mp2fill_size);
				DEBUG_PRINT("Sent to client %d bytes (expecting %d bytes)\n", nbsent, mp2fill_size );
			}
		}
		else
		{
			ERR_PRINT("hdlMPG NULL\n" );
		}
		
		pktReceived++;
		bytesReceived+=numRecvBuff;
		numRecvBuff=0;
		pktSent++;		
		printf( "Received %ld packets (%ld bytes)/Sent %ld packets\r\b", pktReceived, bytesReceived, pktSent );
	}
    if (NULL != snd_buffer )
    {
		free(snd_buffer);
	}
    close(sock_cli);
	printf( "\nStopping after receiving %ld packets                      \n", pktReceived );
	
	#ifdef MP3DUMP
		if( NULL != mp3file )
		{
			fclose(mp3file);
			mp3file = NULL;
		}
	#endif //MP3DUMP
	
	if( 0 != hdlMPG )
	{
		mpg123_delete(hdlMPG);
		hdlMPG = 0;
	}
	if( NULL != encodeOptions )
	{
		twolame_close(&encodeOptions);
		encodeOptions=NULL;
	}

	close(sock);
	return 0;
}