Example #1
0
int main(int argc, char *argv[])
{
    struct CODEC2 *codec2;
    FILE          *fin;
    FILE          *fout;
    short         *buf;
    unsigned char *bits;
    int            nsam, nbit, i, r;

    for(i=0; i<10; i++) {
        r = codec2_rand();
        printf("[%d] r = %d\n", i, r);
    }

    if (argc != 3) {
	printf("usage: %s InputRawSpeechFile OutputRawSpeechFile\n", argv[0]);
	exit(1);
    }

    if ( (fin = fopen(argv[1],"rb")) == NULL ) {
	fprintf(stderr, "Error opening input speech file: %s: %s.\n",
         argv[1], strerror(errno));
	exit(1);
    }

    if ( (fout = fopen(argv[2],"wb")) == NULL ) {
	fprintf(stderr, "Error opening output speech file: %s: %s.\n",
         argv[2], strerror(errno));
	exit(1);
    }

    #ifdef DUMP
    dump_on("c2demo");
    #endif

    /* Note only one set of Codec 2 states is required for an encoder
       and decoder pair. */

    codec2 = codec2_create(CODEC2_MODE_1300);
    nsam = codec2_samples_per_frame(codec2);
    buf = (short*)malloc(nsam*sizeof(short));
    nbit = codec2_bits_per_frame(codec2);
    bits = (unsigned char*)malloc(nbit*sizeof(char));

    while(fread(buf, sizeof(short), nsam, fin) == (size_t)nsam) {
	codec2_encode(codec2, bits, buf);
	codec2_decode(codec2, buf, bits);
	fwrite(buf, sizeof(short), nsam, fout);
    }

    free(buf);
    free(bits);
    codec2_destroy(codec2);

    fclose(fin);
    fclose(fout);

    return 0;
}
int freedv_create() {
    fdmdv = fdmdv_create();
    codec2 = codec2_create(CODEC2_MODE_1400);
    fprintf(stderr, "Created context\n");

    output_buf = (short*)malloc(2*sizeof(short)*codec2_samples_per_frame(codec2)); 
    return (output_buf && fdmdv && codec2);
}
Example #3
0
static int decode(struct audec_state *ads, int16_t *sampv,
		  size_t *sampc, const uint8_t *buf, size_t len)
{
	if (!sampv || !sampc || !buf)
		return EINVAL;

	if (*sampc < (size_t)codec2_samples_per_frame(ads->c2))
		return ENOMEM;
	if (len < (size_t)codec2_bits_per_frame(ads->c2)/8)
		return EPROTO;

	codec2_decode(ads->c2, sampv, buf);

	*sampc = codec2_samples_per_frame(ads->c2);

	return 0;
}
Example #4
0
static void c2demo(int mode, char inputfile[], char outputfile[])
{
    struct CODEC2 *codec2;
    short         *inbuf, *outbuf;
    unsigned char *bits;
    int            nsam, nbit;
    FILE          *fin, *fout;
    int            frame;
    PROFILE_VAR(enc_start, dec_start);

    codec2 = codec2_create(mode);
    nsam = codec2_samples_per_frame(codec2);
    outbuf = (short*)malloc(nsam*sizeof(short));
    inbuf = (short*)malloc(nsam*sizeof(short));
    nbit = codec2_bits_per_frame(codec2);
    bits = (unsigned char*)malloc(nbit*sizeof(char));

    fin = fopen(inputfile, "rb");
    if (fin == NULL) {
        printf("Error opening input file: %s\n\nTerminating....\n",inputfile);
        exit(1);
    }

    fout = fopen(outputfile, "wb");
    if (fout == NULL) {
        printf("Error opening output file: %s\n\nTerminating....\n",outputfile);
        exit(1);
    }

#ifdef DUMP
    dump_on("stm32f4");
#endif
    frame = 0;

    while (fread(inbuf, sizeof(short), nsam, fin) == nsam) {
        PROFILE_SAMPLE(enc_start);
        codec2_encode(codec2, bits, inbuf);
        PROFILE_SAMPLE_AND_LOG(dec_start, enc_start, "  enc");
        codec2_decode(codec2, outbuf, bits);
        PROFILE_SAMPLE_AND_LOG2(dec_start, "  dec");
        PROFILE_SAMPLE_AND_LOG2(enc_start, "  enc & dec");
        fwrite((char*)outbuf, sizeof(short), nsam, fout);
        printf("frame: %d\n", ++frame);
        machdep_profile_print_logged_samples();
    }

#ifdef DUMP
    dump_off("sm32f4");
#endif

    fclose(fin);
    fclose(fout);
    free(inbuf);
    free(outbuf);
    free(bits);
    codec2_destroy(codec2);
}
Example #5
0
static void c2speedtest(int mode, char inputfile[])
{
    struct CODEC2 *codec2;
    short         *inbuf, *outbuf, *pinbuf, *dummy_buf;
    unsigned char *bits;
    int            nsam, nbit, nframes;
    FILE          *fin;
    int            f, nread;

    codec2 = codec2_create(mode);
    nsam = codec2_samples_per_frame(codec2);
    nframes = SPEED_TEST_SAMPLES/nsam;
    outbuf = (short*)malloc(nsam*sizeof(short));
    inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));
    nbit = codec2_bits_per_frame(codec2);
    bits = (unsigned char*)malloc(nbit*sizeof(char));
    dummy_buf = (short*)malloc(2*nsam*sizeof(short));

    fin = fopen(inputfile, "rb");
    if (fin == NULL) {
        printf("Error opening input file: %s\nTerminating....\n",inputfile);
        exit(1);
    }

    printf("reading samples ....\n");
    nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);
    if (nread != SPEED_TEST_SAMPLES) {
        printf("error reading %s, %d samples reqd, %d read\n", 
               inputfile, SPEED_TEST_SAMPLES, nread);
    }
    fclose(fin);
    
    pinbuf = inbuf;
    for(f=0; f<nframes; f++) {
        //printf("read ADC\n");
        while(adc1_read(dummy_buf, nsam*2) == -1);  /* runs at Fs = 16kHz */

        //printf("Codec 2 enc\n");
	GPIOD->ODR = (1 << 13);
        codec2_encode(codec2, bits, pinbuf);
        pinbuf += nsam;
	GPIOD->ODR &= ~(1 << 13);
        //printf("Codec 2 dec\n");
	codec2_decode(codec2, outbuf, bits);
        
        //printf("write to DAC\n");
        while(dac1_write(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */
        //printf(".");
    }

    free(inbuf);
    free(outbuf);
    free(bits);
    codec2_destroy(codec2);
}
Example #6
0
int freedv_create() {
    pthread_mutex_init(&mutex, NULL);

    int src_error;
    insrc1 = src_new(SRC_SINC_FASTEST, 1, &src_error);

    fdmdv = fdmdv_create();
    codec2 = codec2_create(CODEC2_MODE_1400);
    output_buf =
        (short*)malloc(2*sizeof(short)*codec2_samples_per_frame(codec2));

    return 1;
}
Example #7
0
static int encode(struct auenc_state *aes, uint8_t *buf,
		  size_t *len, const int16_t *sampv, size_t sampc)
{
	if (!buf || !len || !sampv)
		return EINVAL;

	if (*len < (size_t)codec2_bits_per_frame(aes->c2)/8)
		return ENOMEM;
	if (sampc != (size_t)codec2_samples_per_frame(aes->c2))
		return EPROTO;

	codec2_encode(aes->c2, buf, (short *)sampv);

	*len = codec2_bits_per_frame(aes->c2)/8;

	return 0;
}
/**
 * @brief Process a single stereo audio sample.
 *
 * Operates only on as_conf_cache, and requires no synchronization as
 * long as the calling thread is always iq_thread.
 */
void audio_stream_put_samples(short left_sample,short right_sample) {
    int audio_buffer_length;

    sdr_thread_assert_id(&audiostream_tid);

    /* FIXME: This really only applies once, at startup */
    if (!audio_buffer) {
        allocate_audio_buffer();
	samples_per_frame = codec2_samples_per_frame( codec2 );
	bits_per_frame = codec2_bits_per_frame( codec2 );
	codec2_buffer = (short *) malloc( sizeof( short ) * samples_per_frame );
	bits = (unsigned char *) malloc( sizeof( unsigned char ) * BITS_SIZE );
    }

    // samples are delivered at 48K or 8K depending on audiostream_conf.samplerate
    // codec2 encoding works only for 8K

        int offset;
        // use this sample and convert to a-law or PCM or codec2
        if(as_conf_cache.channels==1) {
            switch (as_conf_cache.encoding) {
            default: /* ALAW */
            case ENCODING_ALAW:
                offset = audio_stream_buffer_insert + AUDIO_BUFFER_HEADER_SIZE;
                audio_buffer[offset] = alaw((left_sample + right_sample) / 2);
                break;
            case ENCODING_PCM:
                offset = audio_stream_buffer_insert * 2 + AUDIO_BUFFER_HEADER_SIZE;
                /* PCM on the wire is always LE? */
                audio_buffer[offset] = (left_sample/2 + right_sample/2) & 0xff;
                audio_buffer[offset + 1] = (left_sample/2 + right_sample/2) >> 8;
                break;
            case ENCODING_CODEC2:
                codec2_buffer[audio_stream_buffer_insert] = left_sample/2 + right_sample/2;
                break;
            }
        } else {
            switch (as_conf_cache.encoding) {
Example #9
0
static int encode_update(struct auenc_state **aesp,
			 const struct aucodec *ac,
			 struct auenc_param *prm, const char *fmtp)
{
	struct auenc_state *st;
	int err = 0;
	(void)prm;
	(void)fmtp;

	if (!aesp || !ac)
		return EINVAL;

	if (*aesp)
		return 0;

	st = mem_zalloc(sizeof(*st), encode_destructor);
	if (!st)
		return ENOMEM;

	st->c2 = codec2_create(CODEC2_MODE);
	if (!st->c2) {
		err = ENOMEM;
		goto out;
	}

	info("codec2: %d samples per frame, %d bits per frame\n",
	     codec2_samples_per_frame(st->c2),
	     codec2_bits_per_frame(st->c2));

 out:
	if (err)
		mem_deref(st);
	else
		*aesp = st;

	return err;
}
Example #10
0
int main (int argc, char ** argv) {
int buffersize;
int stereo;
int samplerate;
int numBytes;
int numSample;
int maxnumchannel_input;

// state of keypress
int state, oldstate;

// vars for portaudio
char * portaudiodevice;
int exact=0;
PaStreamParameters inputParameters;
PaStream * stream;
PaError pa_ret;

const PaDeviceInfo *devinfo;

// vars for networking
char * ipaddrtxtin;
int udpport;
struct sockaddr_in * udp_aiaddr_in = NULL;
struct sockaddr_in6 * udp_aiaddr_in6 = NULL;
struct sockaddr * sendto_aiaddr = NULL; // structure used for sendto
int sendto_sizeaiaddr=0; // size of structed used for sendto
int udpsd;
int udp_family;

char ipaddrtxt[INET6_ADDRSTRLEN];

// vars for getaddrinfo
struct addrinfo * hint;
struct addrinfo * info;

// for SAMPLE RATE CONVERSION
SRC_STATE *src=NULL;
SRC_DATA src_data;
int src_error;

// vars for codec2
void *codec2;
unsigned char *c2_buff;
int mode, nc2byte;

// vars for audio
int16_t * audiobuffer;
float * inaudiobuffer_f = NULL;
float * outaudiobuffer_f = NULL;

// other vars
int ret;

// structure for c2encap data
c2encap c2_voice;
c2encap c2_begin, c2_end;

// "audio in" posix thread
pthread_t thr_keypress;

// init data
stereo=-1;
global.transmit=0;

// We need at least 3 arguments: IP-address, udpport and samplerate
if (argc < 4) {
	fprintf(stderr,"Error: at least 3 arguments needed. \n");
	fprintf(stderr,"Usage: %s <ip-addr> <udp port> <samplerate> [ <audiodevice> [exact] ] \n",argv[0]);
	fprintf(stderr,"Note: allowed audio samplerate are 8000, 44100 or 48000 samples/second.\n");
	fprintf(stderr,"Note: use device \"\" to get list of devices.\n");
	exit(-1);
}; // end if

ipaddrtxtin=argv[1];
udpport=atoi(argv[2]);
samplerate=atoi(argv[3]);


// if 1st argument exists, use it as capture device
if (argc >= 5) {
	portaudiodevice = argv[4];

	// is there the "exact" statement?
	if (argc >= 6) {
		if (!strcmp(argv[5],"exact")) {
			exact=1;
		} else {
			fprintf(stderr,"Error: parameter \"exact\" expected. Got %s. Ignoring! \n",argv[5]);
		}; // end else - if
	}; // end if
} else {
	// no argument given
	portaudiodevice = NULL;
}; // end else - if



// create network structure
if ((udpport < 0) || (udpport > 65535)) {
	fprintf(stderr,"Error: UDPport number must be between 0 and 65535! \n");
	exit(-1);
}; // end if


if ((IPV4ONLY) && (IPV6ONLY)) {
	fprintf(stderr,"Error: internal configuration error: ipv4only and ipv6only are mutually exclusive! \n");
	exit(-1);
}; // end if


// sample rates below 8Ksamples/sec or above 48Ksamples/sec do not make sence
if (samplerate == 8000) {
	numSample = 320;
} else if (samplerate == 44100) {
	numSample = 1764;
} else if (samplerate == 48000) {
	numSample = 1920;
} else {
	fprintf(stderr,"Error: audio samplerate should be 8000, 44100 or 48000 samples/sec! \n");
	exit(-1);
}; // end if


// DO DNS query for ipaddress
hint=malloc(sizeof(struct addrinfo));

if (!hint) {
	fprintf(stderr,"Error: could not allocate memory for hint!\n");
	exit(-1);
}; // end if

// clear hint
memset(hint,0,sizeof(hint));

hint->ai_socktype = SOCK_DGRAM;

// resolve hostname, use function "getaddrinfo"
// set address family of hint if ipv4only or ipv6only
if (IPV4ONLY) {
	hint->ai_family = AF_INET;
} else if (IPV6ONLY) {
	hint->ai_family = AF_INET6;
} else {
	hint->ai_family = AF_UNSPEC;
}; // end else - elsif - if

// do DNS-query, use getaddrinfo for both ipv4 and ipv6 support
ret=getaddrinfo(ipaddrtxtin, NULL, hint, &info);

if (ret < 0) {
	fprintf(stderr,"Error: resolving hostname %s failed: (%s)\n",ipaddrtxtin,gai_strerror(ret));
	exit(-1);
}; // end if


udp_family=info->ai_family;

// open UDP socket + set udp port
if (udp_family == AF_INET) {
	udpsd=socket(AF_INET,SOCK_DGRAM,0);
	
	// getaddrinfo returns pointer to generic "struct sockaddr" structure.
	// 		Cast to "struct sockaddr_in" to be able to fill in destination port
	udp_aiaddr_in=(struct sockaddr_in *)info->ai_addr;
	udp_aiaddr_in->sin_port=htons((unsigned short int) udpport);

	// set pointer to be used for "sendto" ipv4 structure
	// sendto uses generic "struct sockaddr" just like the information
	// 		returned from getaddrinfo, so no casting needed here
	sendto_aiaddr=info->ai_addr;
	sendto_sizeaiaddr=sizeof(struct sockaddr);

	// get textual version of returned ip-address
	inet_ntop(AF_INET,&udp_aiaddr_in->sin_addr,ipaddrtxt,INET6_ADDRSTRLEN);
	
} else if (udp_family == AF_INET6) {
	udpsd=socket(AF_INET6,SOCK_DGRAM,0);

	// getaddrinfo returns pointer to generic "struct sockaddr" structure.
	// 		Cast to "struct sockaddr_in6" to be able to fill in destination port
	udp_aiaddr_in6=(struct sockaddr_in6 *)info->ai_addr;
	udp_aiaddr_in6->sin6_port=htons((unsigned short int) udpport);

	// set pointer to be used for "sendto" ipv4 structure
	// sendto uses generic "struct sockaddr" just like the information
	// 		returned from getaddrinfo, so no casting needed here
	sendto_aiaddr=info->ai_addr;
	sendto_sizeaiaddr=sizeof(struct sockaddr_in6);

	// get textual version of returned ip-address
	inet_ntop(AF_INET6,&udp_aiaddr_in6->sin6_addr,ipaddrtxt,INET6_ADDRSTRLEN);
	
} else {
	fprintf(stderr,"Error: DNS query for %s returned an unknown network-family: %d \n",ipaddrtxtin,udp_family);
	exit(-1);
}; // end if



// getaddrinfo can return multiple results, we only use the first one
// give warning is more then one result found.
// Data is returned in info as a linked list
// If the "next" pointer is not NULL, there is more then one
// element in the chain

if (info->ai_next != NULL) {
	fprintf(stderr,"Warning. getaddrinfo returned multiple entries. Using %s\n",ipaddrtxt);
}; // end if


if (udpsd < 0) {
	fprintf(stderr,"Error: could not create socket for UDP! \n");
	exit(-1);
}; // end if

// init c2encap structures
memcpy(c2_begin.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_begin.header[3]=C2ENCAP_MARK_BEGIN;
memcpy(c2_begin.c2data.c2data_text3,"BEG",3);

memcpy(c2_end.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_end.header[3]=C2ENCAP_MARK_END;
memcpy(c2_end.c2data.c2data_text3,"END",3);

memcpy(c2_voice.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_voice.header[3]=C2ENCAP_DATA_VOICE1400;



// PORTAUDIO STUFF

fprintf(stderr,"INITIALISING PORTAUDIO    (this can take some time, please ignore any errors below) .... \n");
// open portaudio device
pa_ret=Pa_Initialize();
fprintf(stderr,".... DONE\n");

if (pa_ret != paNoError) {
	Pa_Terminate();
	fprintf(stderr,"Error: Could not initialise Portaudio: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
	exit(-1);
}; // end if

if (portaudiodevice == NULL) {
	// portaudio device = NULL -> use portaudio "get default input device"
	inputParameters.device = Pa_GetDefaultInputDevice();

	if (inputParameters.device == paNoDevice) {
		fprintf(stderr,"Error: no portaudio default input device!\n");
		exit(-1);
	}; // end if

	if (inputParameters.device >= Pa_GetDeviceCount()) {
		fprintf(stderr,"Internal Error: portaudio \"GetDefaultInputDevice\" returns device number %d while possible devices go from 0 to %d \n,",inputParameters.device, (Pa_GetDeviceCount() -1) );
		exit(-1);
	}; // end if


	// check if device supports samplerate:
	inputParameters.sampleFormat = paInt16;
	inputParameters.suggestedLatency = 0; // not used in Pa_IsFormatSupported
	inputParameters.hostApiSpecificStreamInfo = NULL;

	devinfo = Pa_GetDeviceInfo (inputParameters.device);

   maxnumchannel_input = devinfo->maxInputChannels;
	printf("Audio device = %d (%s %s)\n",inputParameters.device,Pa_GetHostApiInfo(devinfo->hostApi)->name,devinfo->name);

	if (maxnumchannel_input >= 1) {
		// first check if samplerate is supported in mono
		inputParameters.channelCount = 1;
		pa_ret = Pa_IsFormatSupported(NULL,&inputParameters,(double) samplerate);

		if (pa_ret == paFormatIsSupported) {
			printf("Samplerate %d supported in mono.\n",samplerate);
			stereo=0;
		} else {
			// try again using stereo
			inputParameters.channelCount = 2;

			if (maxnumchannel_input >= 2) {
				pa_ret = Pa_IsFormatSupported(NULL,&inputParameters,(double) samplerate);

				if (pa_ret == paFormatIsSupported) {
					printf("Samplerate %d supported in stereo.\n",samplerate);
					stereo=1;
				} else {
					printf("Error: Samplerate %d not supported in mono or stereo!\n",samplerate);
					exit(-1);
				}; // end if
			} else {
				// stereo not supported on this device
				printf("Error: Samplerate %d not supported in mono. Stereo not supported on this device!\n",samplerate);
				exit(-1);
			}; // end if
		}; // end else - if
	} else {
		printf("Error: input not supported on this device!\n");
		exit(-1);
	}; // end if
	
	printf("\n");
	fflush(stdout);


} else {
	// CLI option "device" contains text, look throu list of all devices if there are
	// devices that match that name and support the particular requested samplingrate
	int loop;
	int numdevice;

	int numdevicefound=0;
	int devicenr=0;
	int devicestereo=0;



	// init some vars
	numdevice=Pa_GetDeviceCount();

	inputParameters.sampleFormat = paInt16;
	inputParameters.suggestedLatency = 0; // not used in Pa_IsFormatSupported
	inputParameters.hostApiSpecificStreamInfo = NULL;

	for (loop=0; loop<numdevice;loop++) {
		int devnamematch=0;

		// get name of device
		devinfo = Pa_GetDeviceInfo (loop);

		// only do check if searchstring is smaller or equal is size of device name
		if (strlen(devinfo->name) >= strlen(portaudiodevice)) {
			int numcheck;
			int devnamesize;
			int loop;
			char *p;

			// init pointer to beginning of string
			p=(char *)devinfo->name;
			devnamesize = strlen(portaudiodevice);

			if (exact) {
				// exact match, only check once: at the beginning
				numcheck=1;
			} else {
				numcheck=strlen(p) - strlen(portaudiodevice) +1;
			}; // end if

			// loop until text found or end-of-string
			for (loop=0; (loop<numcheck && devnamematch == 0); loop++) {
				if (strncmp(portaudiodevice,p,devnamesize) ==0) {
					devnamematch=1;
				}; // end if

				// move up pointer
				p++;
			};
		}; // end if

		if (devnamematch) {
			printf("Audio device: %d (API: %s ,NAME: %s)\n",loop,Pa_GetHostApiInfo(devinfo->hostApi)->name,devinfo->name);

   		maxnumchannel_input = devinfo->maxInputChannels;

			if (maxnumchannel_input >= 1) {
				// next step: check if this device supports the particular requested samplerate
				inputParameters.device = loop;

				inputParameters.channelCount = 1;
				pa_ret = Pa_IsFormatSupported(NULL,&inputParameters,(double) samplerate);

				if (pa_ret == paFormatIsSupported) {
					printf("Samplerate %d supported in mono.\n",samplerate);
					numdevicefound++;
					devicenr=loop;
					devicestereo=0;
				} else {
					if (maxnumchannel_input >= 2) {
						inputParameters.channelCount = 2;
						pa_ret = Pa_IsFormatSupported(NULL,&inputParameters,(double) samplerate);

						if (pa_ret == paFormatIsSupported) {
							printf("Samplerate %d supported in stereo.\n",samplerate);
							numdevicefound++;
							devicenr=loop;
							devicestereo=1;
						} else {
							printf("Error: Samplerate %d not supported in mono or stereo.\n",samplerate);
						}; // end else - if
					} else {
						// stereo not supported on this device
						printf("Error: Samplerate %d not supported in mono. Stereo not supported on this device!\n",samplerate);
					}; // end if
				}; // end else - if
			} else {
				printf("Error: Input not supported on device.\n");
			}; // end if

			printf("\n");
			fflush(stdout);
		};// end if
	}; // end for

	// did we find any device
	if (numdevicefound == 0) {
		fprintf(stderr,"Error: did not find any audio-device supporting that audio samplerate\n");
		fprintf(stderr,"       Try again with other samplerate of devicename \"\" to get list of all devices\n");
		exit(-1);
	} else if (numdevicefound > 1) {
		fprintf(stderr,"Error: Found multiple devices matching devicename supporting that audio samplerate\n");
		fprintf(stderr,"       Try again with a more strict devicename or use \"exact\" clause!\n");
		exit(-1);
	} else {
		// OK, we have exactly one device: copy its parameters
		inputParameters.device=devicenr;
		stereo=devicestereo;

		if (devicestereo) {
			inputParameters.channelCount = 2;
		} else {
			inputParameters.channelCount = 1;
		}; // end else - if

		// get name info from device
		devinfo = Pa_GetDeviceInfo (inputParameters.device);

		fprintf(stderr,"Selected Audio device = (API: %s ,NAME: %s)\n",Pa_GetHostApiInfo(devinfo->hostApi)->name,devinfo->name);
	};
}; // end else - if

// set other parameters of inputParameters structure
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;

// configure portaudio global data
if (samplerate == 8000) {
	numSample = 320;
} else if (samplerate == 44100) {
	numSample = 1764;
} else if (samplerate == 48000) {
	numSample = 1920;
} else {
	fprintf(stderr,"Error: invalid value for samplerate in funct_audioout: %d !\n",samplerate);
	exit(-1);
}; // end if


// configure portaudio global data
if (stereo) {
	numBytes = (numSample << 2);
} else {
	numBytes = (numSample << 1); 
}; // end if

// create memory for audiobuffer
audiobuffer = malloc(numBytes); // allow memory for buffer 0
if (!audiobuffer) {
	// memory could not be allocated
	fprintf(stderr,"Error: could not allocate memory for portaudio buffer 0!\n");
	exit(-1);
}; // end if


// some network debug info
fprintf(stderr,"Sending CODEC2 DV stream to ip-address %s udp port %d\n",ipaddrtxt,udpport);


// open PortAudio stream
// do not start stream yet, will be done further down
pa_ret = Pa_OpenStream (
	&stream,
	&inputParameters,
	NULL, // output Parameters, not used here 
	samplerate, // sample rate
	numSample, // frames per buffer: 40 ms @ 8000 samples/sec
	paClipOff, // we won't output out of range samples,
					// so don't bother clipping them
	NULL, // no callback function, syncronous read
	&global // parameters passed to callback function (not used here)
);

if (pa_ret != paNoError) {
	Pa_Terminate();
	fprintf(stderr,"Error in Pa_OpenStream: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
	exit(-1);
}; // end if

// init codec2
mode = CODEC2_MODE_1400;
codec2 = codec2_create (mode);

nc2byte = (codec2_bits_per_frame(codec2) + 7) >> 3; // ">>3" is same as "/8"

if (nc2byte != 7) {
	fprintf(stderr,"Error: number of bytes for codec2 frames should be 7. We got %d \n",nc2byte);
}; // end if

if (codec2_samples_per_frame(codec2) != 320) {
	fprintf(stderr,"Error: number of samples for codec2 frames should be 320. We got %d \n",codec2_samples_per_frame(codec2));
}; // end if

c2_buff = (unsigned char *)&c2_voice.c2data.c2data_data7;


// allocate audiobuffer
if (stereo) {
	buffersize= numSample << 2; // = number of samples  * 4 (stereo and 16 bit/sample)
} else {
	// mono
	buffersize= numSample << 1; // = number of samples * 2 (16 bit/sample)
}; // end else - if
audiobuffer=malloc(buffersize);

if (!audiobuffer) {
	fprintf(stderr,"Error: malloc audiobuffer: %s",strerror(errno));
	exit(-1);
}; // end if


// init samplerate conversion
if (samplerate != 8000) {

// allocate memory for audio sample buffers (only needed when audio rate conversion is used)
	inaudiobuffer_f=malloc(numSample * sizeof(float));
	if (!inaudiobuffer_f) {
		fprintf(stderr,"Error in malloc for inaudiobuffer_f! \n");
		exit(-1);
	}; // end if

	outaudiobuffer_f=malloc(320 * sizeof(float)); // output buffer is 320 samples (40 ms @ 8000 samples/sec)
	if (!outaudiobuffer_f) {
		fprintf(stderr,"Error in malloc for outaudiobuffer_f! \n");
		exit(-1);
	}; // end if

	src = src_new(SRC_SINC_FASTEST,1,&src_error);

	if (!src) {
		fprintf(stderr,"src_new failed! \n");
		exit(-1);
	}; // end if

	src_data.data_in = inaudiobuffer_f;
	src_data.data_out = outaudiobuffer_f;
	src_data.input_frames = numSample;
	src_data.output_frames = 320; // 40 ms @ 8000 samples / sec
	src_data.end_of_input = 0; // no further data, every 40 ms frame is concidered to be a seperate unit

	if (samplerate == 48000) {
		src_data.src_ratio = (float) 8000/48000;
	} else {
		src_data.src_ratio = (float) 8000/44100;
	}; // end else - if
}; // end if


// start thread to read detect keypress (used to switch transmitting)
pthread_create (&thr_keypress, NULL, funct_keypress, (void *) &global);


// Start stream
pa_ret=Pa_StartStream(stream);

if (pa_ret != paNoError) {
	Pa_Terminate();
	fprintf(stderr,"Error in Pa_StartStream: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
	exit(-1);
}; // end if


// init some vars;
oldstate=0;


while (( pa_ret = Pa_IsStreamActive (stream)) == 1) {
// get audio

	pa_ret = Pa_ReadStream(stream, audiobuffer, numSample);

	if (pa_ret != paNoError) {
		Pa_Terminate();
		fprintf(stderr,"Error in Pa_ReadStream: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
		exit(-1);
	}; // end if


	// get state from subthread
	state=global.transmit;

	if (state) {
		// State = 1: write audio

		// first check old state, if we go from oldstate=0 to state=1, this is
		// the beginning of a new stream; so send start packe
		if (oldstate == 0) {
			// start "start" marker
			// fwrite((void *) &c2_begin,C2ENCAP_SIZE_MARK,1,stdout);
			// fflush(stdout);

			// send start 3 times, just to be sure
			sendto(udpsd,&c2_begin,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);
			sendto(udpsd,&c2_begin,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);
			sendto(udpsd,&c2_begin,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);

//			putc('B',stderr);
		}


		// if stereo, only use left channel
		if (stereo) {
			int loop;

			int16_t *p1, *p2;

			// start at 2th element (in stereo format); which is 3th (in mono format)
			p1=&audiobuffer[1];
			p2=&audiobuffer[2];
	
			for (loop=1; loop < numSample; loop++) {
				*p1=*p2;
				p1++; p2 += 2;
			}; // end for
		}; // end if


		// if not 8000 samples / second: convert
		if (samplerate != 8000) {
fprintf(stderr,"2!!! \n");
			if (!inaudiobuffer_f) {
				fprintf(stderr,"Internal Error: inaudiobuffer_f not initialised \n");
				exit(-1);
			}; // end if

			if (!outaudiobuffer_f) {
				fprintf(stderr,"Internal Error: outaudiobuffer_f not initialised \n");
				exit(-1);
			}; // end if

			// convert int16 to float
			src_short_to_float_array(audiobuffer,inaudiobuffer_f,numSample);

			// convert
			ret=src_process(src,&src_data);

			if (ret) {
				fprintf(stderr,"Warning: samplerate conversion error %d (%s)\n",ret,src_strerror(ret));
			}; // end if

			// some error checking
			if (src_data.output_frames_gen != 320) {
				fprintf(stderr,"Warning: number of frames generated by samplerateconvert should be %d, got %ld. \n",numSample,src_data.output_frames_gen);
			}; // end if

			// convert back from float to int
			src_float_to_short_array(outaudiobuffer_f,audiobuffer,320); // 40 ms @ 8000 samples/sec = 320 samples

fprintf(stderr,"3!!! \n");
		}; // end if

		// do codec2 encoding
		codec2_encode(codec2, c2_buff, audiobuffer);

		//fwrite((void *)&c2_voice,C2ENCAP_SIZE_VOICE1400,1,stdout);
		//fflush(stdout);

		sendto(udpsd,&c2_voice,C2ENCAP_SIZE_VOICE1400,0,sendto_aiaddr, sendto_sizeaiaddr);

//		putc('T',stderr);
	} else {
		// state = 0, do not send
		// however, if we go from "oldstate = 1 - > state = 0", this is
		// the end of a stream

		if (oldstate) {
			// send "end" marker
			//fwrite((void *)&c2_end,C2ENCAP_SIZE_MARK,1,stdout);
			//fflush(stdout);

			// send end 3 times, just to be sure
			sendto(udpsd,&c2_end,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);
			sendto(udpsd,&c2_end,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);
			sendto(udpsd,&c2_end,C2ENCAP_SIZE_MARK,0,sendto_aiaddr, sendto_sizeaiaddr);

//			putc('E',stderr);
		}; // end if 
	}; // end else - if

	oldstate=state;

	
}; // end while
// dropped out of endless loop. Should not happen

if (pa_ret < 0) {
	Pa_Terminate();
	fprintf(stderr,"Error in Pa_isStreamActive: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
	exit(-1);
}; // end if

fprintf(stderr,"Error: audiocap dropped out of audiocapturing loop. Should not happen!\n");

pa_ret=Pa_CloseStream(stream);

if (pa_ret != paNoError) {
	Pa_Terminate();
	fprintf(stderr,"Error in Pa_CloseStream: %s(%d) \n",Pa_GetErrorText(pa_ret),pa_ret);
	exit(-1);
}; // end if

// Done!!!

Pa_Terminate();

exit(0);


}; // end main applicion
Example #11
0
int main(int argc, char *argv[]) {
    FILE                      *fin, *fout, *ftxt;
    short                     *speech_out;
    short                     *demod_in;
    struct freedv             *freedv;
    int                        nin, nout, frame = 0;
    struct my_callback_state   my_cb_state;
    struct MODEM_STATS         stats;
    int                        mode;
    int                        sync;
    int                        total_bits;
    int                        total_bit_errors;
    float                      snr_est;
    int                        n_speech_samples;
    int                        n_max_modem_samples;
    float                      clock_offset;
    int                        use_codecrx;
    struct CODEC2             *c2 = NULL;
    int                        i;


    if (argc < 4) {
	printf("usage: %s 1600|700|700B|2400A|2400B|800XA InputModemSpeechFile OutputSpeechRawFile [--test_frames] [--codecrx]\n", argv[0]);
	printf("e.g    %s 1600 hts1a_fdmdv.raw hts1a_out.raw txtLogFile\n", argv[0]);
	exit(1);
    }

    mode = -1;
    if (!strcmp(argv[1],"1600"))
        mode = FREEDV_MODE_1600;
    if (!strcmp(argv[1],"700"))
        mode = FREEDV_MODE_700;
    if (!strcmp(argv[1],"700B"))
        mode = FREEDV_MODE_700B;
    if (!strcmp(argv[1],"2400A"))
        mode = FREEDV_MODE_2400A;
    if (!strcmp(argv[1],"2400B"))
        mode = FREEDV_MODE_2400B;
    if (!strcmp(argv[1],"800XA"))
        mode = FREEDV_MODE_800XA;
    assert(mode != -1);

    if (strcmp(argv[2], "-")  == 0) fin = stdin;
    else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
	fprintf(stderr, "Error opening input raw modem sample file: %s: %s.\n",
         argv[2], strerror(errno));
	exit(1);
    }

    if (strcmp(argv[3], "-") == 0) fout = stdout;
    else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
	fprintf(stderr, "Error opening output speech sample file: %s: %s.\n",
         argv[3], strerror(errno));
	exit(1);
    }

    freedv = freedv_open(mode);
    assert(freedv != NULL);

    use_codecrx = 0;

    if (argc > 4) {
        for (i = 4; i < argc; i++) {
            if (strcmp(argv[i], "--testframes") == 0) {
                freedv_set_test_frames(freedv, 1);
            }
            if (strcmp(argv[i], "--codecrx") == 0) {
                int c2_mode;

                if (mode == FREEDV_MODE_700)  {
		    c2_mode = CODEC2_MODE_700;
		} else if ((mode == FREEDV_MODE_700B)|| (mode == FREEDV_MODE_800XA)) {
                    c2_mode = CODEC2_MODE_700B;
                } else {
                    c2_mode = CODEC2_MODE_1300;
                }
                use_codecrx = 1;

                c2 = codec2_create(c2_mode);
                assert(c2 != NULL);
            }
        }
    }
    freedv_set_snr_squelch_thresh(freedv, -100.0);
    freedv_set_squelch_en(freedv, 1);

    n_speech_samples = freedv_get_n_speech_samples(freedv);
    n_max_modem_samples = freedv_get_n_max_modem_samples(freedv);
    speech_out = (short*)malloc(sizeof(short)*n_speech_samples);
    assert(speech_out != NULL);
    demod_in = (short*)malloc(sizeof(short)*n_max_modem_samples);
    assert(demod_in != NULL);

    ftxt = fopen("freedv_rx_log.txt","wt");
    assert(ftxt != NULL);
    my_cb_state.ftxt = ftxt;
    freedv_set_callback_txt(freedv, &my_put_next_rx_char, NULL, &my_cb_state);
    freedv_set_callback_protocol(freedv, &my_put_next_rx_proto, NULL, &my_cb_state);
    freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state);

    /* Note we need to work out how many samples demod needs on each
       call (nin).  This is used to adjust for differences in the tx and rx
       sample clock frequencies.  Note also the number of output
       speech samples is time varying (nout). */

    nin = freedv_nin(freedv);
    while(fread(demod_in, sizeof(short), nin, fin) == nin) {
        frame++;

        if (use_codecrx == 0) {
            /* Use the freedv_api to do everything: speech decoding, demodulating */
            nout = freedv_rx(freedv, speech_out, demod_in);
        } else {
            int bits_per_codec_frame = codec2_bits_per_frame(c2);
            int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8;
            int codec_frames = freedv_get_n_codec_bits(freedv) / bits_per_codec_frame;
            int samples_per_frame = codec2_samples_per_frame(c2);
            unsigned char encoded[bytes_per_codec_frame * codec_frames];

            /* Use the freedv_api to demodulate only */
            nout = freedv_codecrx(freedv, encoded, demod_in);

            /* deccode the speech ourself (or send it to elsewhere, e.g. network) */
            if (nout) {
                unsigned char *enc_frame = encoded;
		short *speech_frame = speech_out;
		
		nout = 0;
	        for (i = 0; i < codec_frames; i++) {
		    codec2_decode(c2, speech_frame, enc_frame);
		    enc_frame += bytes_per_codec_frame;
		    speech_frame += samples_per_frame;
		    nout += samples_per_frame;
		}
	    }
        }

        nin = freedv_nin(freedv);

        fwrite(speech_out, sizeof(short), nout, fout);
        freedv_get_modem_stats(freedv, &sync, &snr_est);
        freedv_get_modem_extended_stats(freedv,&stats);
        total_bit_errors = freedv_get_total_bit_errors(freedv);
        clock_offset = stats.clock_offset;

        /* log some side info to the txt file */

        if (ftxt != NULL) {
            fprintf(ftxt, "frame: %d  demod sync: %d  nin:%d demod snr: %3.2f dB  bit errors: %d clock_offset: %f\n",
                    frame, sync, nin, snr_est, total_bit_errors, clock_offset);
        }

	/* if this is in a pipeline, we probably don't want the usual
           buffering to occur */

        if (fout == stdout) fflush(stdout);
        if (fin == stdin) fflush(stdin);
    }

    if (freedv_get_test_frames(freedv)) {
        total_bits = freedv_get_total_bits(freedv);
        total_bit_errors = freedv_get_total_bit_errors(freedv);
        fprintf(stderr, "bits: %d errors: %d BER: %3.2f\n", total_bits, total_bit_errors, (float)total_bit_errors/total_bits);
    }

    free(speech_out);
    free(demod_in);
    freedv_close(freedv);
    fclose(fin);
    fclose(fout);

    return 0;
}
Example #12
0
int main(int argc, char *argv[])
{
    int            mode;
    void          *codec2;
    FILE          *fin;
    FILE          *fout;
    FILE          *fber = NULL;
    short         *buf;
    unsigned char *bits;
    float         *softdec_bits;
    int            nsam, nbit, nbyte, i, byte, frames, bits_proc, bit_errors, error_mode;
    int            nstart_bit, nend_bit, bit_rate;
    int            state, next_state;
    float          ber, r, burst_length, burst_period, burst_timer, ber_est;
    unsigned char  mask;
    int            natural, dump, softdec, bit, ret;

    char* opt_string = "h:";
    struct option long_options[] = {
        { "ber", required_argument, NULL, 0 },
        { "startbit", required_argument, NULL, 0 },
        { "endbit", required_argument, NULL, 0 },
        { "berfile", required_argument, NULL, 0 },
        { "natural", no_argument, &natural, 1 },
        { "softdec", no_argument, &softdec, 1 },
        #ifdef DUMP
        { "dump", required_argument, &dump, 1 },
        #endif
        { "help", no_argument, NULL, 'h' },
        { NULL, no_argument, NULL, 0 }
    };
    int num_opts=sizeof(long_options)/sizeof(struct option);
 
    if (argc < 4)
        print_help(long_options, num_opts, argv);
    
    if (strcmp(argv[1],"3200") == 0)
	mode = CODEC2_MODE_3200;
    else if (strcmp(argv[1],"2400") == 0)
	mode = CODEC2_MODE_2400;
    else if (strcmp(argv[1],"1600") == 0)
	mode = CODEC2_MODE_1600;
    else if (strcmp(argv[1],"1400") == 0)
	mode = CODEC2_MODE_1400;
    else if (strcmp(argv[1],"1300") == 0)
	mode = CODEC2_MODE_1300;
    else if (strcmp(argv[1],"1200") == 0)
	mode = CODEC2_MODE_1200;
    else if (strcmp(argv[1],"700") == 0)
	mode = CODEC2_MODE_700;
    else {
	fprintf(stderr, "Error in mode: %s.  Must be 3200, 2400, 1600, 1400, 1300, 1200, or 700\n", argv[1]);
	exit(1);
    }
    bit_rate = atoi(argv[1]);

    if (strcmp(argv[2], "-")  == 0) fin = stdin;
    else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
	fprintf(stderr, "Error opening input bit file: %s: %s.\n",
         argv[2], strerror(errno));
	exit(1);
    }

    if (strcmp(argv[3], "-") == 0) fout = stdout;
    else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
	fprintf(stderr, "Error opening output speech file: %s: %s.\n",
         argv[3], strerror(errno));
	exit(1);
    }

    error_mode = NONE;
    ber = 0.0;
    burst_length = burst_period = 0.0;
    burst_timer = 0.0;
    dump = natural = softdec = 0;

    codec2 = codec2_create(mode);
    nsam = codec2_samples_per_frame(codec2);
    nbit = codec2_bits_per_frame(codec2);
    buf = (short*)malloc(nsam*sizeof(short));
    nbyte = (nbit + 7) / 8;
    bits = (unsigned char*)malloc(nbyte*sizeof(char));
    softdec_bits = (float*)malloc(nbit*sizeof(float));
    frames = bit_errors = bits_proc = 0;
    nstart_bit = 0;
    nend_bit = nbit-1;

    while(1) {
        int option_index = 0;
        int opt = getopt_long(argc, argv, opt_string, 
                    long_options, &option_index);
        if (opt == -1)
            break;

        switch (opt) {
        case 0:
            if(strcmp(long_options[option_index].name, "ber") == 0) {
                ber = atof(optarg);
                error_mode = UNIFORM;
            } else if(strcmp(long_options[option_index].name, "startbit") == 0) {
	        nstart_bit = atoi(optarg);
            } else if(strcmp(long_options[option_index].name, "endbit") == 0) {
	        nend_bit = atoi(optarg);
             } else if(strcmp(long_options[option_index].name, "berfile") == 0) {
	        if ((fber = fopen(optarg,"wt")) == NULL) {
	            fprintf(stderr, "Error opening BER file: %s %s.\n",
                            optarg, strerror(errno));
                    exit(1);
                }
            
            } 
            #ifdef DUMP
            else if(strcmp(long_options[option_index].name, "dump") == 0) {
                if (dump) 
	            dump_on(optarg);
            }
            #endif
            break;

        case 'h':
            print_help(long_options, num_opts, argv);
            break;

        default:
            /* This will never be reached */
            break;
        }
    }
    assert(nend_bit <= nbit);
    codec2_set_natural_or_gray(codec2, !natural);
    //printf("%d %d\n", nstart_bit, nend_bit);
 
    //fprintf(stderr, "softdec: %d natural: %d\n", softdec, natural);
    if (softdec)
        ret = (fread(softdec_bits, sizeof(float), nbit, fin) == (size_t)nbit);
    else
        ret = (fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte);
      
    while(ret) {
	frames++;

        // apply bit errors, MSB of byte 0 is bit 0 in frame, only works in packed mode
        
	if ((error_mode == UNIFORM) || (error_mode == UNIFORM_RANGE)) {
            assert(softdec == 0);
	    for(i=nstart_bit; i<nend_bit+1; i++) {
		r = (float)rand()/RAND_MAX;
		if (r < ber) {
		    byte = i/8;
		    //printf("nbyte %d nbit %d i %d byte %d bits[%d] 0x%0x ", nbyte, nbit, i, byte, byte, bits[byte]);
		    mask = 1 << (7 - i + byte*8);
                    bits[byte] ^= mask;
		    //printf("shift: %d mask: 0x%0x bits[%d] 0x%0x\n", 7 - i + byte*8, mask, byte, bits[byte] );
		    bit_errors++;
 		}
                bits_proc++;
	    }
	}

	if (error_mode == TWO_STATE) {
            assert(softdec == 0);
            burst_timer += (float)nbit/bit_rate;
            fprintf(stderr, "burst_timer: %f  state: %d\n", burst_timer, state);

            next_state = state;
            switch(state) {
            case 0:

                /* clear channel state - no bit errors */

                if (burst_timer > (burst_period - burst_length))
                    next_state = 1;
                break;

            case 1:
                
                /* burst error state - 50% bit error rate */

                for(i=nstart_bit; i<nend_bit+1; i++) {
                    r = (float)rand()/RAND_MAX;
                    if (r < 0.5) {
                        byte = i/8;
                        bits[byte] ^= 1 << (7 - i + byte*8);
                        bit_errors++;
                    }
                    bits_proc++;
		}

                if (burst_timer > burst_period) {
                    burst_timer = 0.0;
                    next_state = 0;
                }
                break;

	    }
               
            state = next_state;
        }

        if (fber != NULL) {
            if (fread(&ber_est, sizeof(float), 1, fber) != 1) {
                fprintf(stderr, "ran out of BER estimates!\n");
                exit(1);
            }
            //fprintf(stderr, "ber_est: %f\n", ber_est);
        }
        else
            ber_est = 0.0;
            
        if (softdec) {
            /* pack bits, MSB received first  */

            bit = 7; byte = 0;
            memset(bits, 0, nbyte);
            for(i=0; i<nbit; i++) {
                bits[byte] |= ((softdec_bits[i] < 0.0) << bit);
                bit--;
                if (bit < 0) {
                    bit = 7;
                    byte++;
                }
            }
            codec2_set_softdec(codec2, softdec_bits);
        }

	codec2_decode_ber(codec2, buf, bits, ber_est);
 	fwrite(buf, sizeof(short), nsam, fout);

	//if this is in a pipeline, we probably don't want the usual
        //buffering to occur

        if (fout == stdout) fflush(stdout);
        if (fin == stdin) fflush(stdin);         

        if (softdec)
            ret = (fread(softdec_bits, sizeof(float), nbit, fin) == (size_t)nbit);
        else
            ret = (fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte);
    }

    if (error_mode)
	fprintf(stderr, "actual BER: %1.3f\n", (float)bit_errors/bits_proc);

    codec2_destroy(codec2);

    free(buf);
    free(bits);
    free(softdec_bits);
    fclose(fin);
    fclose(fout);

    return 0;
}
Example #13
0
void per_frame_rx_processing(short  output_buf[], /* output buf of decoded speech samples          */
                             int   *n_output_buf, /* how many samples currently in output_buf[]    */
                             int    codec_bits[], /* current frame of bits for decoder             */
                             short  input_buf[],  /* input buf of modem samples input to demod     */ 
                             int   *n_input_buf   /* how many samples currently in input_buf[]     */
                             )
{
    int    sync_bit;
    COMP  rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME];
    int    rx_bits[FDMDV_BITS_PER_FRAME];
    unsigned char  packed_bits[BYTES_PER_CODEC_FRAME];
    float  rx_spec[FDMDV_NSPEC];
    int    i, nin_prev, bit, byte;
    int    next_state;

    assert(*n_input_buf <= (2*FDMDV_NOM_SAMPLES_PER_FRAME));

    /*
      This while loop will run the demod 0, 1 (nominal) or 2 times:

      0: when tx sample clock runs faster than rx, occasionally we
         will run out of samples

      1: normal, run decoder once, every 2nd frame output a frame of
         speech samples to D/A

      2: when tx sample clock runs slower than rx, occasionally we will
         have enough samples to run demod twice.

      With a +/- 10 Hz sample clock difference at FS=8000Hz (+/- 1250
      ppm), case 0 or 1 occured about once every 30 seconds.  This is
      no problem for the decoded audio.
    */

    while(*n_input_buf >= g_nin) {

        // demod per frame processing

        for(i=0; i<g_nin; i++) {
            rx_fdm[i].real = (float)input_buf[i]/FDMDV_SCALE;
            rx_fdm[i].imag = 0.0;
        }
        nin_prev = g_nin;
        fdmdv_demod(fdmdv, rx_bits, &sync_bit, rx_fdm, &g_nin);
        *n_input_buf -= nin_prev;
        assert(*n_input_buf >= 0);

        // shift input buffer

        for(i=0; i<*n_input_buf; i++)
            input_buf[i] = input_buf[i+nin_prev];

        // compute rx spectrum & get demod stats, and update GUI plot data

        fdmdv_get_rx_spectrum(fdmdv, rx_spec, rx_fdm, nin_prev);

        // Average rx spectrum data using a simple IIR low pass filter
        for(i = 0; i < FDMDV_NSPEC; i++) 
        {
            g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
        }

        fdmdv_get_demod_stats(fdmdv, &stats);
        jni_update_stats(&stats, g_avmag);
        count++;

        /* 
           State machine to:

           + Mute decoded audio when out of sync.  The demod is synced
             when we are using the fine freq estimate and SNR is above
             a thresh.

           + Decode codec bits only if we have a 0,1 sync bit
             sequence.  Collects two frames of demod bits to decode
             one frame of codec bits.
        */

        next_state = g_state;
        switch (g_state) {
        case 0:
            /* mute output audio when out of sync */

            if (*n_output_buf < 2*codec2_samples_per_frame(codec2) - N8) {
                for(i=0; i<N8; i++)
                    output_buf[*n_output_buf + i] = 0;
                *n_output_buf += N8;
            }
            if (!(*n_output_buf <= (2*codec2_samples_per_frame(codec2)))) {
                LOGE("*n_output_buf <= (2*codec2_samples_per_frame(codec2))");
            }

            if ((stats.fest_coarse_fine == 1))// && (stats.snr_est > 3.0))
                next_state = 1;

            break;
        case 1:
            if (sync_bit == 0) {
                next_state = 2;

                /* first half of frame of codec bits */

                memcpy(codec_bits, rx_bits, FDMDV_BITS_PER_FRAME*sizeof(int));
            }
            else
                next_state = 1;

            if (stats.fest_coarse_fine == 0)
                next_state = 0;

            break;
        case 2:
            next_state = 1;

            if (stats.fest_coarse_fine == 0)
                next_state = 0;

            if (sync_bit == 1) {
                /* second half of frame of codec bits */

                memcpy(&codec_bits[FDMDV_BITS_PER_FRAME], rx_bits,
                        FDMDV_BITS_PER_FRAME*sizeof(int));

                // extract data bit

                int data_flag_index = codec2_get_spare_bit_index(codec2);
                assert(data_flag_index != -1); // not supported for all rates

                short abit = codec_bits[data_flag_index];
                char  ascii_out;

                int n_ascii = varicode_decode(&g_varicode_dec_states,
                        &ascii_out, &abit, 1, 1);
                assert((n_ascii == 0) || (n_ascii == 1));
                if (n_ascii) {
                    short ashort = ascii_out;
                    LOGD("%c", ashort);
                }

                // reconstruct missing bit we steal for data bit and decode
                // speech
                codec2_rebuild_spare_bit(codec2, codec_bits);

                /* pack bits, MSB received first  */

                bit = 7; byte = 0;
                memset(packed_bits, 0, BYTES_PER_CODEC_FRAME);
                for(i=0; i<BITS_PER_CODEC_FRAME; i++) {
                    packed_bits[byte] |= (codec_bits[i] << bit);
                    bit--;
                    if (bit < 0) {
                        bit = 7;
                        byte++;
                    }
                }
                assert(byte == BYTES_PER_CODEC_FRAME);

                /* add decoded speech to end of output buffer */

                if (*n_output_buf <= codec2_samples_per_frame(codec2)) {
                    codec2_decode(codec2, &output_buf[*n_output_buf], packed_bits);
                    *n_output_buf += codec2_samples_per_frame(codec2);
                }
                assert(*n_output_buf <= (2*codec2_samples_per_frame(codec2)));

            }
            break;
        }
        if (!!g_state != !!next_state) {
            jni_update_sync(g_state == 0);
        }
        g_state = next_state;
    }
}
Example #14
0
int main (int argc, char ** argv) {

// vars for networking
int udpport;
struct sockaddr_in localsa4;
struct sockaddr_in6 localsa6;
struct sockaddr * receivefromsa = NULL; // structure used for sendto
socklen_t receivefromsa_size=0; // size of structed used for sendto
unsigned char *udpbuffer;
int udpsock;
int udpsize;


// vars for audio
int16_t *inaudiobuffer; // tempory audio buffer used when audio sampling is needed
float *inaudiobuffer_f = NULL; // used for audio samplerate conversion
float *outaudiobuffer_f = NULL; // used for audio samplerate conversion

// for SAMPLE RATE CONVERSION
SRC_STATE *src=NULL;
SRC_DATA src_data;
int src_error;

// vars for codec2
void *codec2;
int mode, nc2byte;

// other vars
int ret;
int new_ptr_audio_write;
int state;

// structure for c2encap data
c2encap c2_voice;
c2encap c2_begin, c2_end;

uint8_t *c2encap_type;
uint8_t *c2encap_begindata;

// "audio out" posix thread
pthread_t thr_audioout;

// init data
global.stereo=-1;
global.ptr_audio_write=1;
global.ptr_audio_read=0;
global.exact=0;

// We need at least 2 arguments: udpport and samplerate
if (argc < 3) {
	fprintf(stderr,"Error: at least 2 arguments needed. \n");
	fprintf(stderr,"Usage: %s <udp port> <samplerate> [ <audiodevice> [exact] ] \n",argv[0]);
	fprintf(stderr,"Note: allowed audio samplerate are 8000, 44100 or 48000 samples/second.\n");
	fprintf(stderr,"Note: use device \"\" to get list of devices.\n");
	exit(-1);
}; // end if

udpport=atoi(argv[1]);
global.rate=atoi(argv[2]);


// if 1st argument exists, use it as capture device
if (argc >= 4) {
	global.pa_device = argv[3];

	// is there the "exact" statement?
	if (argc >= 5) {
		if (!strcmp(argv[4],"exact")) {
			global.exact=1;
		} else {
			fprintf(stderr,"Error: parameter \"exact\" expected. Got %s. Ignoring! \n",argv[4]);
		}; // end else - if
	}; // end if
} else {
	// no argument given; use default
	global.pa_device = NULL;
}; // end else - if


// sample rates below 8Ksamples/sec or above 48Ksamples/sec do not make sence
if ((global.rate != 8000) &&  (global.rate != 44100) && (global.rate != 48000)) {
	fprintf(stderr,"Error: audio samplerate should be 8000, 44100 or 48000 samples/sec! \n");
	exit(-1);
}; // end if



// create network structure
if ((udpport < 0) || (udpport > 65535)) {
	fprintf(stderr,"Error: UDPport number must be between 0 and 65535! \n");
	exit(-1);
}; // end if


if ((IPV4ONLY) && (IPV6ONLY)) {
	fprintf(stderr,"Error: internal configuration error: ipv4only and ipv6only are mutually exclusive! \n");
	exit(-1);
}; // end if


// initialise UDP buffer
udpbuffer=malloc(1500); // we can receive up to 1500 octets

if (!udpbuffer) {
	fprintf(stderr,"Error: could not allocate memory for udpbuffer!\n");
	exit(-1);
}; // end if

// set pointers for c2encap type and c2encap begin-of-data
c2encap_type = (uint8_t*) &udpbuffer[3];
c2encap_begindata = (uint8_t*) &udpbuffer[4]; 

// open inbound UDP socket and bind to socket
if (IPV4ONLY) {
	udpsock=socket(AF_INET,SOCK_DGRAM,0);

	localsa4.sin_family=AF_INET;
	localsa4.sin_port=udpport;
	memset(&localsa4.sin_addr,0,sizeof(struct in_addr)); // address = "::" (all 0) -> we listen

	receivefromsa=(struct sockaddr *) &localsa4;

	ret=bind(udpsock, receivefromsa, sizeof(localsa4)); 

} else {
	// IPV6 socket can handle both ipv4 and ipv6
	udpsock=socket(AF_INET6,SOCK_DGRAM,0);

	// if ipv6 only, set option
	if (IPV6ONLY) {
		int yes=1;

		// make socket ipv6-only.
		ret=setsockopt(udpsock,IPPROTO_IPV6, IPV6_V6ONLY, (char *)&yes,sizeof(int));
		if (ret == -1) {
			fprintf(stderr,"Error: IPV6ONLY option set but could not make socket ipv6 only: %d (%s)! \n",errno,strerror(errno));
			return(-1);
		}; // end if
	}; // end if

	localsa6.sin6_family=AF_INET6;
	localsa6.sin6_port=htons(udpport);
	localsa6.sin6_flowinfo=0; // flows not used
	localsa6.sin6_scope_id=0; // we listen on all interfaces
	memset(&localsa6.sin6_addr,0,sizeof(struct in6_addr)); // address = "::" (all 0) -> we listen

	receivefromsa=(struct sockaddr *)&localsa6;

	ret=bind(udpsock, receivefromsa, sizeof(localsa6)); 

}; // end else - elsif - if

if (ret < 0) {
	fprintf(stderr,"Error: could not bind network-address to socket: %d (%s) \n",errno,strerror(errno));
	exit(-1);
}; // end if

// start audio out thread
pthread_create (&thr_audioout, NULL, funct_audioout, (void *) &global);


// init c2encap structures
memcpy(c2_begin.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_begin.header[3]=C2ENCAP_MARK_BEGIN;
memcpy(c2_begin.c2data.c2data_text3,"BEG",3);

memcpy(c2_end.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_end.header[3]=C2ENCAP_MARK_END;
memcpy(c2_end.c2data.c2data_text3,"END",3);

memcpy(c2_voice.header,C2ENCAP_HEAD,sizeof(C2ENCAP_HEAD));
c2_voice.header[3]=C2ENCAP_DATA_VOICE1400;

// in the mean time, do some other things while the audio-process initialises
// init codec2
mode = CODEC2_MODE_1400;
codec2 = codec2_create (mode);

nc2byte = (codec2_bits_per_frame(codec2) + 7) >> 3; // ">>3" is same as "/8"

if (nc2byte != 7) {
	fprintf(stderr,"Error: number of bytes for codec2 frames should be 7. We got %d \n",nc2byte);
}; // end if

if (codec2_samples_per_frame(codec2) != 320) {
	fprintf(stderr,"Error: number of samples for codec2 frames should be 320. We got %d \n",codec2_samples_per_frame(codec2));
}; // end if

// wait for thread audio to initialise 
while (!global.audioready) {
	// sleep 5 ms
	usleep(5000);
}; // end while

// done. Just to be sure, check "stereo" setting, should be "0" or "1"
if ((global.stereo != 0) && (global.stereo != 1)) {
	fprintf(stderr,"Internal error: stereo flag not set correctly by audioout subthread! Should not happen! Exiting. \n");
	exit(-1);
}; // end if


if (global.rate != 8000) {
// allocate memory for audio sample buffers (only needed when audio rate conversion is used)
	inaudiobuffer=malloc(320 * sizeof(int16_t));
	if (!inaudiobuffer) {
		fprintf(stderr,"Error in malloc for inaudiobuffer! \n");
		exit(-1);
	}; // end if

	inaudiobuffer_f=malloc(320 * sizeof(float));
	if (!inaudiobuffer_f) {
		fprintf(stderr,"Error in malloc for inaudiobuffer_f! \n");
		exit(-1);
	}; // end if

	outaudiobuffer_f=malloc(global.numSample * sizeof(float));
	if (!outaudiobuffer_f) {
		fprintf(stderr,"Error in malloc for outaudiobuffer_f! \n");
		exit(-1);
	}; // end if

	// init samplerate conversion
	src = src_new(SRC_SINC_FASTEST, 1, &src_error);

	if (!src) {
		fprintf(stderr,"src_new failed! \n");
		exit(-1);
	}; // end if

	src_data.data_in = inaudiobuffer_f;
	src_data.data_out = outaudiobuffer_f;
	src_data.input_frames = 320; // 40ms @ 8000 samples/sec
	src_data.output_frames = global.numSample;
	src_data.end_of_input = 0; // no further data, every 40 ms is processed on itself

	if (global.rate == 48000) {
		src_data.src_ratio = (float) 48000/8000;
	} else {
		src_data.src_ratio = (float) 44100/8000;
	}; // end if
}; // end if



// init state
state=0; // state 0 = wait for start

while (FOREVER ) {
	// wait for UDP packets

	// read until read or error, but ignore "EINTR" errors
	while (FOREVER) {
		udpsize = recvfrom(udpsock, udpbuffer, 1500, 0, receivefromsa, &receivefromsa_size);

		if (udpsize > 0) {
			// break out if really packet received;
			break;
		}; // end if

		// break out when not error EINTR
		if (errno != EINTR) {
			break;
		}; // end if
	}; // end while (read valid UDP packet)

	if (udpsize < 0) {
		// error: print message, wait 1/4 of a second and retry
		fprintf(stderr,"Error receiving UDP packets: %d (%s) \n",errno, strerror(errno));
		usleep(250000);
		continue;
	}; // end if


	if (udpsize < 4) {
		// should be at least 4 octets: to small, ignore it
		fprintf(stderr,"Error: received UDP packet to small (size = %d). Ignoring! \n",udpsize);
		continue;
	}; // end if


	// check beginning of frame, it should contain the c2enc signature
	if (memcmp(udpbuffer,C2ENCAP_HEAD,3)) {
		// signature does not match, ignore packet
		continue;
	}; // end  if
	
	// check size + content
	// we know the udp packet is at least 4 octets, so check 4th char for type
	if (*c2encap_type == C2ENCAP_MARK_BEGIN) {
		if (udpsize < C2ENCAP_SIZE_MARK ) {
			fprintf(stderr,"Error: received C2ENCAP BEGIN MARKER with to small size: %d octets! Ignoring\n",udpsize);
			continue;
		} else if (udpsize > C2ENCAP_SIZE_MARK) {
			fprintf(stderr,"Warning: received C2ENCAP BEGIN MARKER with to large size: %d octets! Ignoring extra data\n",udpsize);
		};

		// check content
		if (memcmp(c2encap_begindata,"BEG",3)) {
			fprintf(stderr,"Error: RECEIVED C2ENCAP BEGIN MARKER WITH INCORRECT TEXT: 0X%02X 0X%02X 0X%02X. Ignoring frame!\n",udpbuffer[4],udpbuffer[5],udpbuffer[6]);
			continue;
		}; // end if
	} else if (*c2encap_type == C2ENCAP_MARK_END) {
		if (udpsize < C2ENCAP_SIZE_MARK ) {
			fprintf(stderr,"Error: received C2ENCAP END MARKER with to small size: %d octets! Ignoring\n",udpsize);
			continue;
		} else if (udpsize > C2ENCAP_SIZE_MARK) {
			fprintf(stderr,"Warning: received C2ENCAP END MARKER with to large size: %d octets! Ignoring extra data\n",udpsize);
		};

		// check content
		if (memcmp(c2encap_begindata,"END",3)) {
			fprintf(stderr,"Error: RECEIVED C2ENCAP BEGIN MARKER WITH INCORRECT TEXT: 0X%02X 0X%02X 0X%02X. Ignoring frame!\n",udpbuffer[4],udpbuffer[5],udpbuffer[6]);
			continue;
		}; // end if
	} else if (*c2encap_type == C2ENCAP_DATA_VOICE1200) {
		if (udpsize < C2ENCAP_SIZE_VOICE1200 ) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE1200 with to small size: %d octets! Ignoring\n",udpsize);
			continue;
		} else if (udpsize > C2ENCAP_SIZE_VOICE1200) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE1200 with to large size: %d octets! Ignoring extra data\n",udpsize);
		};

	} else if (*c2encap_type == C2ENCAP_DATA_VOICE1400) {
		if (udpsize < C2ENCAP_SIZE_VOICE1400 ) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE1400 with to small size: %d octets! Ignoring\n",udpsize);
			continue;
		} else if (udpsize > C2ENCAP_SIZE_VOICE1400) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE1400 with to large size: %d octets! Ignoring extra data\n",udpsize);
		};
	} else if (*c2encap_type == C2ENCAP_DATA_VOICE2400) {
		if (udpsize < C2ENCAP_SIZE_VOICE2400 ) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE2400 with to small size: %d octets! Ignoring\n",udpsize);
			continue;
		} else if (udpsize > C2ENCAP_SIZE_VOICE2400) {
			fprintf(stderr,"Warning: received C2ENCAP VOICE2400 with to large size: %d octets! Ignoring extra data\n",udpsize);
		};
	} else {
		fprintf(stderr,"Warning: received packet with unknown type of C2ENCAP type: 0X%02X. Ignoring!\n",*c2encap_type);
		continue;
	}; // end if


	// processing from here on depends on state
	if (state == 0) {
		// state 0, waiting for start data

		if (*c2encap_type == C2ENCAP_MARK_BEGIN) {
			// received start, go to state 1
			state=1;
			continue;
		} else {
			fprintf(stderr,"Warning: received packet of type 0X%02X in state 0. Ignoring packet! \n",*c2encap_type);
			continue;
		}; // end if
	} else if (state == 1) {
		// state 1: receiving voice data, until we receive a "end" marker
		if (*c2encap_type == C2ENCAP_MARK_END) {
			// end received. Go back to state 0
			state=0;
			continue;
		} else if (*c2encap_type != C2ENCAP_DATA_VOICE1400) {
			fprintf(stderr,"Warning: received packet of type 0X%02X in state 1. Ignoring packet! \n",*c2encap_type);
			continue;
		} else {
			// voice 1400 data packet. Decode and play out

			// first check if there is place to store the result
			new_ptr_audio_write = global.ptr_audio_write+1;
			if (new_ptr_audio_write >= NUMBUFF) {
				// wrap around at NUMBUFF
				new_ptr_audio_write=0;
			}; // end if

			if (new_ptr_audio_write == global.ptr_audio_read) {
				// oeps. No buffers available to write data
				fputc('B',stderr);
			} else {
//				fputc('Q',stderr);


				// decode codec2 frame
  				codec2_decode(codec2, global.audiobuffer[new_ptr_audio_write],c2encap_begindata);
				

				// if not samplerate 8000, do rate conversion
				if (global.rate != 8000) {
					// convert int16 to float
					if (!inaudiobuffer_f) {
						fprintf(stderr,"Internal error: inaudiobuffer_f not initialised! \n");
						exit(-1);
					}; // "end if

					if (!outaudiobuffer_f) {
						fprintf(stderr,"Internal error: outaudiobuffer_f not initialised! \n");
						exit(-1);
					}; // "end if


					src_short_to_float_array(global.audiobuffer[new_ptr_audio_write],inaudiobuffer_f,320);

					// do conversion
					ret=src_process(src,&src_data);

					if (ret) {
						fprintf(stderr,"Warning: samplerate conversion error %d (%s)\n",ret,src_strerror(ret));
					}; // end if

					// some error checking
					if (src_data.output_frames_gen != global.numSample) {
						fprintf(stderr,"Warning: number of frames generated by samplerateconvert should be %d, got %ld. \n",global.numSample,src_data.output_frames_gen);
					}; // end if

					// convert back from float to int, and store immediatly in ringbuffer
					src_float_to_short_array(outaudiobuffer_f,global.audiobuffer[new_ptr_audio_write],global.numSample );
				}; // end if (samplerate != 8000)


				// make stereo (duplicate channels) if needed
				if (global.stereo) {
					int loop;
					int16_t *p1, *p2;

					int lastsample_m, lastsample_s;

					lastsample_m = global.numSample - 1;
					lastsample_s = global.numSample*2 - 1;

					// codec2_decode returns a buffer of 16-bit samples, MONO
					// so duplicate all samples, start with last sample, move down to sample "1" (not 0);
					p1=&global.audiobuffer[new_ptr_audio_write][lastsample_s]; // last sample of buffer (320 samples stereo = 640 samples mono)
					p2=&global.audiobuffer[new_ptr_audio_write][lastsample_m]; // last sample of buffer (mono)

					for (loop=0; loop < lastsample_m; loop++) {
						*p1 = *p2; p1--; // copy 1st octet, move down "write" pointer
						*p1 = *p2; p1--; p2--; // copy 2nd time, move down both pointers
					}; // end if

					// last sample, just copy (no need anymore to move pointers)
					*p1 = *p2;
				}; // end if

				// move up pointer in global vars
				global.ptr_audio_write=new_ptr_audio_write;
			}; // end if

		}; // end if
	} else {
		fprintf(stderr,"Internal Error: unknow state %d in audioplay main loop. Should not happen. Exiting!!!\n",state);
		exit(-1);
	}; // end if

}; // end while

fprintf(stderr,"Internal Error: audioplay main application drops out of endless loop. Should not happen! \n");
exit(-1);

}; // end main application
void per_frame_rx_processing(short  output_buf[], /* output buf of decoded speech samples          */
                             int   *n_output_buf, /* how many samples currently in output_buf[]    */
                             int    codec_bits[], /* current frame of bits for decoder             */
                             short  input_buf[],  /* input buf of modem samples input to demod     */ 
                             int   *n_input_buf   /* how many samples currently in input_buf[]     */
                             )
{
    int    sync_bit;
    COMP   rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME];
    int    rx_bits[FDMDV_BITS_PER_FRAME];
    unsigned char  packed_bits[BYTES_PER_CODEC_FRAME];
    int    i, nin_prev, bit, byte;
    int    next_state;

    if (!(*n_input_buf <= (2*FDMDV_NOM_SAMPLES_PER_FRAME))) {
        fprintf(stderr, "Assert: *n_input_buf <= (2*FDMDV_NOM_SAMPLES_PER_FRAME)\n");
    }
   
    /*
      This while loop will run the demod 0, 1 (nominal) or 2 times:

      0: when tx sample clock runs faster than rx, occasionally we
         will run out of samples

      1: normal, run decoder once, every 2nd frame output a frame of
         speech samples to D/A

      2: when tx sample clock runs slower than rx, occasionally we will
         have enough samples to run demod twice.

      With a +/- 10 Hz sample clock difference at FS=8000Hz (+/- 1250
      ppm), case 0 or 1 occured about once every 30 seconds.  This is
      no problem for the decoded audio.
    */

    while(*n_input_buf >= g_nin) {

        // demod per frame processing

        for(i=0; i<g_nin; i++) {
            rx_fdm[i].real = (float)input_buf[i]/FDMDV_SCALE;
            rx_fdm[i].imag = 0.0;
        }

        nin_prev = g_nin;
        fdmdv_demod(fdmdv, rx_bits, &sync_bit, rx_fdm, &g_nin);
        *n_input_buf -= nin_prev;
        if (!(*n_input_buf >= 0)) {
            fprintf(stderr, "Assert: *n_input_buf >= 0\n");
        }

        // shift input buffer

        for(i=0; i<*n_input_buf; i++)
            input_buf[i] = input_buf[i+nin_prev];

#if 0
        // compute rx spectrum & get demod stats, and update GUI plot data

        fdmdv_get_rx_spectrum(fdmdv, rx_spec, rx_fdm, nin_prev);
#endif
        fdmdv_get_demod_stats(fdmdv, &stats);

        /* 
           State machine to:

           + Mute decoded audio when out of sync.  The demod is synced
             when we are using the fine freq estimate and SNR is above
             a thresh.

           + Decode codec bits only if we have a 0,1 sync bit
             sequence.  Collects two frames of demod bits to decode
             one frame of codec bits.
        */

        next_state = g_state;
        switch (g_state) {
        case 0:
            /* mute output audio when out of sync */

            if (*n_output_buf < 2*codec2_samples_per_frame(codec2) - N8) {
                for(i=0; i<N8; i++)
                    output_buf[*n_output_buf + i] = 0;
                *n_output_buf += N8;
            }
            if (!(*n_output_buf <= (2*codec2_samples_per_frame(codec2)))) {
                fprintf(stderr, "Assert: *n_output_buf <= (2*codec2_samples_per_frame(codec2))\n");
            }

            if ((stats.fest_coarse_fine == 1) && (stats.snr_est > 3.0))
                next_state = 1;

            break;
        case 1:
            if (sync_bit == 0) {
                next_state = 2;

                /* first half of frame of codec bits */

                memcpy(codec_bits, rx_bits, FDMDV_BITS_PER_FRAME*sizeof(int));
            }
            else
                next_state = 1;

            if (stats.fest_coarse_fine == 0)
                next_state = 0;

            break;
        case 2:
            next_state = 1;

            if (stats.fest_coarse_fine == 0)
                next_state = 0;

            if (sync_bit == 1) {
                /* second half of frame of codec bits */

                memcpy(&codec_bits[FDMDV_BITS_PER_FRAME], rx_bits, FDMDV_BITS_PER_FRAME*sizeof(int));

                // reconstruct missing bit we steal for data bit and decode speech

                codec2_rebuild_spare_bit(codec2, codec_bits);

                /* pack bits, MSB received first  */

                bit = 7; byte = 0;
                memset(packed_bits, 0, BYTES_PER_CODEC_FRAME);
                for(i=0; i<BITS_PER_CODEC_FRAME; i++) {
                    packed_bits[byte] |= (codec_bits[i] << bit);
                    bit--;
                    if (bit < 0) {
                        bit = 7;
                        byte++;
                    }
                }
                if (!(byte == BYTES_PER_CODEC_FRAME)) {
                    fprintf(stderr, "Assert: byte == BYTES_PER_CODEC_FRAME\n");
                }

                /* add decoded speech to end of output buffer */

                if (*n_output_buf <= codec2_samples_per_frame(codec2)) {
                    codec2_decode(codec2, &output_buf[*n_output_buf], packed_bits);
                    *n_output_buf += codec2_samples_per_frame(codec2);
                }
                if (!(*n_output_buf <= (2*codec2_samples_per_frame(codec2)))) {
                    fprintf(stderr, "Assert: *n_output_buf <= (2*codec2_samples_per_frame(codec2))\n");
                }

            }
            break;
        }
        g_state = next_state;
    }
}
Example #16
0
  case 1600:
    mode = CODEC2_MODE_1600;
    break;
  case 1400:
    mode = CODEC2_MODE_1400;
    break;
  case 1300:
    mode = CODEC2_MODE_1300;
    break;
  case 1200:
    mode = CODEC2_MODE_1200;
    break;
  }
  struct CODEC2 *c2=codec2_create(mode);
  int bits = codec2_bits_per_frame(c2);
  int samples = codec2_samples_per_frame(c2);
  return (jlong)c2;
}

JNIEXPORT void JNICALL Java_org_servalproject_audio_Codec2_release(JNIEnv *env, jobject this, jlong ptr)
{
  struct CODEC2 *c2=(struct CODEC2*)ptr;
  codec2_destroy(c2);
}

JNIEXPORT jint JNICALL Java_org_servalproject_audio_Codec2_encode(JNIEnv *env, jobject this, jlong ptr, jint data_size, jbyteArray in, jbyteArray out)
{
  struct CODEC2 *c2=(struct CODEC2*)ptr;
  int input_block_size = codec2_samples_per_frame(c2)*2;
  int output_block_size = (codec2_bits_per_frame(c2)+7)/8;
Example #17
0
int main(int argc, char *argv[])
{
    int            mode;
    void          *codec2;
    FILE          *fin;
    FILE          *fout;
    FILE          *fber = NULL;
    short         *buf;
    unsigned char *bits, *prev_bits;
    int            nsam, nbit, nbyte, i, byte, frames, bits_proc, bit_errors, error_mode;
    int            nstart_bit, nend_bit, bit_rate;
    int            state, next_state;
    float          ber, r, burst_length, burst_period, burst_timer, ber_est;
    unsigned char  mask;

    if ((argc != 4) && (argc != 5) && (argc != 6) && (argc != 7)) {
	printf("basic usage.................: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile\n");
	printf("uniform errors usage........: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile uniformBER startBit endBit\n");
	printf("uniform error on range usage: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile uniformBER\n");
	printf("demod BER estimate..........: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile BERfile\n");
	printf("two state fading usage......: c2dec 3200|2400|1600|1400|1300|1200 InputBitFile OutputRawSpeechFile burstLength burstPeriod\n");
	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw\n");
	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw 0.9\n");
	printf("e.g    c2dec 1400 hts1a.c2 hts1a_1400.raw 0.99 0.9\n");
	exit(1);
    }

    if (strcmp(argv[1],"3200") == 0)
	mode = CODEC2_MODE_3200;
    else if (strcmp(argv[1],"2400") == 0)
	mode = CODEC2_MODE_2400;
    else if (strcmp(argv[1],"1600") == 0)
	mode = CODEC2_MODE_1600;
    else if (strcmp(argv[1],"1400") == 0)
	mode = CODEC2_MODE_1400;
    else if (strcmp(argv[1],"1300") == 0)
	mode = CODEC2_MODE_1300;
    else if (strcmp(argv[1],"1200") == 0)
	mode = CODEC2_MODE_1200;
    else {
	fprintf(stderr, "Error in mode: %s.  Must be 3200, 2400, 1600, 1400, 1300 or 1200\n", argv[1]);
	exit(1);
    }
    bit_rate = atoi(argv[1]);

    if (strcmp(argv[2], "-")  == 0) fin = stdin;
    else if ( (fin = fopen(argv[2],"rb")) == NULL ) {
	fprintf(stderr, "Error opening input bit file: %s: %s.\n",
         argv[2], strerror(errno));
	exit(1);
    }

    if (strcmp(argv[3], "-") == 0) fout = stdout;
    else if ( (fout = fopen(argv[3],"wb")) == NULL ) {
	fprintf(stderr, "Error opening output speech file: %s: %s.\n",
         argv[3], strerror(errno));
	exit(1);
    }

    error_mode = NONE;
    ber = 0.0;
    burst_length = burst_period = 0.0;
    burst_timer = 0.0;

    codec2 = codec2_create(mode);
    nsam = codec2_samples_per_frame(codec2);
    nbit = codec2_bits_per_frame(codec2);
    buf = (short*)malloc(nsam*sizeof(short));
    nbyte = (nbit + 7) / 8;
    bits = (unsigned char*)malloc(nbyte*sizeof(char));
    prev_bits = (unsigned char*)malloc(nbyte*sizeof(char));
    frames = bit_errors = bits_proc = 0;
    nstart_bit = 0;
    nend_bit = nbit-1;

    if (argc == 5) {
        /* see if 4th argument is a valid file name */
        if ( (fber = fopen(argv[4],"rb")) == NULL ) {
            /* otherwise it must be BER value for uniform errors */
            ber = atof(argv[4]);
	    error_mode = UNIFORM;
        }
    }

    if (argc == 6) {
        error_mode = TWO_STATE;
	burst_length = atof(argv[4]);
	burst_period = atof(argv[5]);
	nstart_bit = 0;
	nend_bit = 2;
        state = 0;
    }
    
    if (argc == 7) {
        error_mode = UNIFORM_RANGE;
	ber = atof(argv[4]);
	nstart_bit = atoi(argv[5]);
	nend_bit = atoi(argv[6]);
        fprintf(stderr, "ber: %f nstart_bit: %d nend_bit: %d\n", ber, nstart_bit, nend_bit);
        state = 0;
    }

    assert(nend_bit <= nbit);

    while(fread(bits, sizeof(char), nbyte, fin) == (size_t)nbyte) {
	frames++;

        // apply bit errors, MSB of byte 0 is bit 0 in frame */
        
	if ((error_mode == UNIFORM) || (error_mode == UNIFORM_RANGE)) {
	    for(i=nstart_bit; i<nend_bit+1; i++) {
		r = (float)rand()/RAND_MAX;
		if (r < ber) {
		    byte = i/8;
		    //printf("nbyte %d nbit %d i %d byte %d bits[%d] 0x%0x ", nbyte, nbit, i, byte, byte, bits[byte]);
		    mask = 1 << (7 - i + byte*8);
                    bits[byte] ^= mask;
		    //printf("shift: %d mask: 0x%0x bits[%d] 0x%0x\n", 7 - i + byte*8, mask, byte, bits[byte] );
		    bit_errors++;
 		}
                bits_proc++;
	    }
	}

	if (error_mode == TWO_STATE) {
            burst_timer += (float)nbit/bit_rate;
            fprintf(stderr, "burst_timer: %f  state: %d\n", burst_timer, state);

            next_state = state;
            switch(state) {
            case 0:

                /* clear channel state - no bit errors */

                if (burst_timer > (burst_period - burst_length))
                    next_state = 1;
                break;

            case 1:
                
                /* burst error state - 50% bit error rate */

                for(i=nstart_bit; i<nend_bit+1; i++) {
                    r = (float)rand()/RAND_MAX;
                    if (r < 0.5) {
                        byte = i/8;
                        bits[byte] ^= 1 << (7 - i + byte*8);
                        bit_errors++;
                    }
                    bits_proc++;
		}

                if (burst_timer > burst_period) {
                    burst_timer = 0.0;
                    next_state = 0;
                }
                break;

	    }
               
            state = next_state;
        }

        if (fber != NULL) {
            if (fread(&ber_est, sizeof(float), 1, fber) != 1) {
                fprintf(stderr, "ran out of BER estimates!\n");
                exit(1);
            }
            //fprintf(stderr, "ber_est: %f\n", ber_est);
        }
        else
            ber_est = 0.0;

        /* frame repeat logic */
        if (ber_est > 0.15) {
            //memcpy(bits, prev_bits, nbyte);
            // fprintf(stderr, "repeat\n");
        }
            
	codec2_decode(codec2, buf, bits, ber_est);
 	fwrite(buf, sizeof(short), nsam, fout);
	//if this is in a pipeline, we probably don't want the usual
        //buffering to occur
        if (fout == stdout) fflush(stdout);
        if (fin == stdin) fflush(stdin);         

        memcpy(prev_bits, bits, nbyte);
    }

    if (error_mode)
	fprintf(stderr, "actual BER: %1.3f\n", (float)bit_errors/bits_proc);

    codec2_destroy(codec2);

    free(buf);
    free(bits);
    fclose(fin);
    fclose(fout);

    return 0;
}