Exemple #1
0
/*------------------------------------------------------------------------------
 *  Write data to the encoder
 *----------------------------------------------------------------------------*/
unsigned int
FaacEncoder :: write (  const void    * buf,
                        unsigned int    len )           throw ( Exception )
{
    if ( !isOpen() || len == 0 ) {
        return 0;
    }

    unsigned int    channels         = getInChannel();
    unsigned int    bitsPerSample    = getInBitsPerSample();
    unsigned int    sampleSize       = (bitsPerSample / 8) * channels;
    unsigned char * b                = (unsigned char*) buf;
    unsigned int    processed        = len - (len % sampleSize);
    unsigned int    nSamples         = processed / sampleSize;
    unsigned char * faacBuf          = new unsigned char[maxOutputBytes];
    int             samples          = (int) nSamples * channels;
    int             processedSamples = 0;



    if ( converter ) {
        unsigned int         converted;
#ifdef HAVE_SRC_LIB
        src_short_to_float_array ((short *) b, (float *) converterData.data_in, samples);
        converterData.input_frames   = nSamples;
        converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
        int srcError = src_process (converter, &converterData);
        if (srcError)
             throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
        converted = converterData.output_frames_gen;
#else
        int         inCount  = nSamples;
        short int     * shortBuffer  = new short int[samples];
        int         outCount = (int) (inCount * resampleRatio);
        Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
        converted = converter->resample( inCount,
                                         outCount+1,
                                         shortBuffer,
                                         &resampledOffset[resampledOffsetSize*channels]);
        delete[] shortBuffer;
#endif
        resampledOffsetSize += converted;

        // encode samples (if enough)
        while(resampledOffsetSize - processedSamples >= inputSamples/channels) {
            int outputBytes;
#ifdef HAVE_SRC_LIB
            short *shortData = new short[inputSamples];
            src_float_to_short_array(resampledOffset + (processedSamples * channels),
                                     shortData, inputSamples) ;
            outputBytes = faacEncEncode(encoderHandle,
                                       (int32_t*) shortData,
                                        inputSamples,
                                        faacBuf,
                                        maxOutputBytes);
            delete [] shortData;
#else
            outputBytes = faacEncEncode(encoderHandle,
                                       (int32_t*) &resampledOffset[processedSamples*channels],
                                        inputSamples,
                                        faacBuf,
                                        maxOutputBytes);
#endif
            getSink()->write(faacBuf, outputBytes);
            processedSamples+=inputSamples/channels;
        }

        if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
            resampledOffsetSize -= processedSamples;
            //move least part of resampled data to beginning
            if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
                resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
                                                    resampledOffsetSize*channels*sizeof(float));
#else
                resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
                                                    resampledOffsetSize*sampleSize);
#endif
        }
    } else {
        while (processedSamples < samples) {
            int     outputBytes;
            int     inSamples = samples - processedSamples < (int) inputSamples
                              ? samples - processedSamples
                              : inputSamples;

            outputBytes = faacEncEncode(encoderHandle,
                                       (int32_t*) (b + processedSamples/sampleSize),
                                        inSamples,
                                        faacBuf,
                                        maxOutputBytes);
            getSink()->write(faacBuf, outputBytes);

            processedSamples += inSamples;
        }
    }

    delete[] faacBuf;

    return samples * sampleSize;
}
Exemple #2
0
RawFile::RawFile(const std::string& name, sfl::AudioCodec *codec, unsigned int sampleRate)
    : AudioFile(name), audioCodec_(codec)
{
    if (filepath_.empty())
        throw AudioFileException("Unable to open audio file: filename is empty");

    std::fstream file;
    file.open(filepath_.c_str(), std::fstream::in);

    if (!file.is_open())
        throw AudioFileException("Unable to open audio file");

    file.seekg(0, std::ios::end);
    size_t length = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<char> fileBuffer(length);
    file.read(&fileBuffer[0], length);
    file.close();

    const unsigned int frameSize = audioCodec_->getFrameSize();
    const unsigned int bitrate   = audioCodec_->getBitRate() * 1000 / 8;
    const unsigned int audioRate = audioCodec_->getClockRate();
    const unsigned int encFrameSize = frameSize * bitrate / audioRate;
    const unsigned int decodedSize = length * (frameSize / encFrameSize);

    SFLDataFormat *monoBuffer = new SFLDataFormat[decodedSize];
    SFLDataFormat *bufpos = monoBuffer;
    unsigned char *filepos = reinterpret_cast<unsigned char *>(&fileBuffer[0]);
    size_ = decodedSize;

    while (length >= encFrameSize) {
        bufpos += audioCodec_->decode(bufpos, filepos, encFrameSize);
        filepos += encFrameSize;
        length -= encFrameSize;
    }

    if (sampleRate == audioRate)
        buffer_ = monoBuffer;
    else {
        double factord = (double) sampleRate / audioRate;
        float* floatBufferIn = new float[size_];
        int    sizeOut  = ceil(factord * size_);
        src_short_to_float_array(monoBuffer, floatBufferIn, size_);
        delete [] monoBuffer;
        delete [] buffer_;
        buffer_ = new SFLDataFormat[sizeOut];

        SRC_DATA src_data;
        src_data.data_in = floatBufferIn;
        src_data.input_frames = size_;
        src_data.output_frames = sizeOut;
        src_data.src_ratio = factord;

        float* floatBufferOut = new float[sizeOut];
        src_data.data_out = floatBufferOut;

        src_simple(&src_data, SRC_SINC_BEST_QUALITY, 1);
        src_float_to_short_array(floatBufferOut, buffer_, src_data.output_frames_gen);

        delete [] floatBufferOut;
        delete [] floatBufferIn;
        size_ = src_data.output_frames_gen;
    }
}
Exemple #3
0
static int resample(unsigned char *input, int /*input_avail*/, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate)
{
    int *psrc = (int*)input;
    int *pdest = (int*)output;
    int i = 0, j = 0;

#ifdef USE_SPEEX
    spx_uint32_t in_len, out_len;
    if(Resample == RESAMPLER_SPEEX)
    {
        if(spx_state == NULL)
        {
            spx_state = speex_resampler_init(2, oldsamplerate, newsamplerate, ResampleQuality,  &error);
            if(spx_state == NULL)
            {
                memset(output, 0, output_needed);
                return 0;
            }
        }
        speex_resampler_set_rate(spx_state, oldsamplerate, newsamplerate);
        in_len = input_avail / 4;
        out_len = output_needed / 4;

        if ((error = speex_resampler_process_interleaved_int(spx_state, (const spx_int16_t *)input, &in_len, (spx_int16_t *)output, &out_len)))
        {
            memset(output, 0, output_needed);
            return input_avail;  // number of bytes consumed
        }
        return in_len * 4;
    }
#endif
#ifdef USE_SRC
    if(Resample == RESAMPLER_SRC)
    {
        // the high quality resampler needs more input than the samplerate ratio would indicate to work properly
        if (input_avail > output_needed * 3 / 2)
            input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time
        if (_src_len < input_avail*2 && input_avail > 0)
        {
            if(_src) free(_src);
            _src_len = input_avail*2;
            _src = malloc(_src_len);
        }
        if (_dest_len < output_needed*2 && output_needed > 0)
        {
            if(_dest) free(_dest);
            _dest_len = output_needed*2;
            _dest = malloc(_dest_len);
        }
        memset(_src,0,_src_len);
        memset(_dest,0,_dest_len);
        if(src_state == NULL)
        {
            src_state = src_new (ResampleQuality, 2, &error);
            if(src_state == NULL)
            {
                memset(output, 0, output_needed);
                return 0;
            }
        }
        src_short_to_float_array ((short *) input, _src, input_avail/2);
        src_data.end_of_input = 0;
        src_data.data_in = _src;
        src_data.input_frames = input_avail/4;
        src_data.src_ratio = (float) newsamplerate / oldsamplerate;
        src_data.data_out = _dest;
        src_data.output_frames = output_needed/4;
        if ((error = src_process (src_state, &src_data)))
        {
            memset(output, 0, output_needed);
            return input_avail;  // number of bytes consumed
        }
        src_float_to_short_array (_dest, (short *) output, output_needed/2);
        return src_data.input_frames_used * 4;
    }
#endif
    // RESAMPLE == TRIVIAL
    if (newsamplerate >= oldsamplerate)
    {
        int sldf = oldsamplerate;
        int const2 = 2*sldf;
        int dldf = newsamplerate;
        int const1 = const2 - 2*dldf;
        int criteria = const2 - dldf;
        for (i = 0; i < output_needed/4; i++)
        {
            pdest[i] = psrc[j];
            if(criteria >= 0)
            {
                ++j;
                criteria += const1;
            }
            else criteria += const2;
        }
        return j * 4; //number of bytes consumed
    }
    // newsamplerate < oldsamplerate, this only happens when speed_factor > 1
    for (i = 0; i < output_needed/4; i++)
    {
        j = i * oldsamplerate / newsamplerate;
        pdest[i] = psrc[j];
    }
    return j * 4; //number of bytes consumed
}
Exemple #4
0
static int resample(Uint8 *input, int input_avail, int oldsamplerate, Uint8 *output, int output_needed, int newsamplerate)
{

#ifdef USE_SRC
    if(Resample == 2)
    {
        // the high quality resampler needs more input than the samplerate ratio would indicate to work properly
        if (input_avail > output_needed * 3 / 2)
            input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time
        if (_src_len < input_avail*2 && input_avail > 0)
        {
            if(_src) free(_src);
            _src_len = input_avail*2;
            _src = malloc(_src_len);
        }
        if (_dest_len < output_needed*2 && output_needed > 0)
        {
            if(_dest) free(_dest);
            _dest_len = output_needed*2;
            _dest = malloc(_dest_len);
        }
        memset(_src,0,_src_len);
        memset(_dest,0,_dest_len);
        if(src_state == NULL)
        {
            src_state = src_new (SRC_SINC_BEST_QUALITY, 2, &error);
            if(src_state == NULL)
            {
                memset(output, 0, output_needed);
                return;
            }
        }
        src_short_to_float_array ((short *) input, _src, input_avail/2);
        src_data.end_of_input = 0;
        src_data.data_in = _src;
        src_data.input_frames = input_avail/4;
        src_data.src_ratio = (float) newsamplerate / oldsamplerate;
        src_data.data_out = _dest;
        src_data.output_frames = output_needed/4;
        if ((error = src_process (src_state, &src_data)))
        {
            memset(output, 0, output_needed);
            return input_avail;  // number of bytes consumed
        }
        src_float_to_short_array (_dest, (short *) output, output_needed/2);
        return src_data.input_frames_used * 4;
    }
#endif
    // RESAMPLE == 1
    int *psrc = (int*)input;
    int *pdest = (int*)output;
    int i;
    int j=0;
    int sldf = oldsamplerate;
    int const2 = 2*sldf;
    int dldf = newsamplerate;
    int const1 = const2 - 2*dldf;
    int criteria = const2 - dldf;
    for(i = 0; i < output_needed; i++)
    {
        pdest[i] = psrc[j];
        if(criteria >= 0)
        {
            ++j;
            criteria += const1;
        }
        else criteria += const2;
    }
    return j * 4; //number of bytes consumed
}
void PulseAudioSource::stream_read_cb (pa_stream *p, size_t nbytes, void *userdata)
{
	PulseAudioSource *src = (PulseAudioSource *) userdata;
	const void* padata = NULL;
	if (src->mQuit)
		return;

	OSDebugOut("stream_read_callback %d bytes\n", nbytes);

	int ret = pf_pa_stream_peek(p, &padata, &nbytes);
	OSDebugOut("pa_stream_peek %zu %s\n", nbytes, pf_pa_strerror(ret));

	if (ret != PA_OK)
		return;

	auto dur = std::chrono::duration_cast<ms>(hrc::now() - src->mLastGetBuffer).count();
	if (src->mPaused || dur > 50000) {
		ret = pf_pa_stream_drop(p);
		if (ret != PA_OK)
			OSDebugOut("pa_stream_drop %s\n", pf_pa_strerror(ret));
		return;
	}

	{
		size_t old_size = src->mQBuffer.size();
		size_t nfloats = nbytes / sizeof(float);
		src->mQBuffer.resize(old_size + nfloats);
		memcpy(&src->mQBuffer[old_size], padata, nbytes);
		//if copy succeeded, drop samples at pulse's side
		ret = pf_pa_stream_drop(p);
		if (ret != PA_OK)
			OSDebugOut("pa_stream_drop %s\n", pf_pa_strerror(ret));
	}

	size_t resampled = static_cast<size_t>(src->mQBuffer.size() * src->mResampleRatio * src->mTimeAdjust);// * src->mSSpec.channels;
	if (resampled == 0)
		resampled = src->mQBuffer.size();

	std::vector<float> rebuf(resampled);

	SRC_DATA data;
	memset(&data, 0, sizeof(SRC_DATA));
	data.data_in = &src->mQBuffer[0];
	data.input_frames = src->mQBuffer.size() / src->mSSpec.channels;
	data.data_out = &rebuf[0];
	data.output_frames = resampled / src->mSSpec.channels;
	data.src_ratio = src->mResampleRatio * src->mTimeAdjust;

	src_process(src->mResampler, &data);

	std::lock_guard<std::mutex> lock(src->mMutex);

	uint32_t len = data.output_frames_gen * src->mSSpec.channels;
	size_t size = src->mResampledBuffer.size();
	if (len > 0)
	{
		//too long, drop samples, caused by saving/loading savestates and random stutters
		int sizeInMS = (((src->mResampledBuffer.size() + len) * 1000 / src->mSSpec.channels) / src->mOutputSamplesPerSec);
		int threshold = src->mBuffering > 25 ? src->mBuffering : 25;
		if (sizeInMS > threshold)
		{
			size = 0;
			src->mResampledBuffer.resize(len);
		}
		else
			src->mResampledBuffer.resize(size + len);
		src_float_to_short_array(&rebuf[0], &(src->mResampledBuffer[size]), len);
	}

//#if _DEBUG
//	if (file && len)
//		fwrite(&(src->mResampledBuffer[size]), sizeof(short), len, file);
//#endif

	auto remSize = data.input_frames_used * src->mSSpec.channels;
	src->mQBuffer.erase(src->mQBuffer.begin(), src->mQBuffer.begin() + remSize);

	OSDebugOut("Resampler: in %d out %d used %d gen %d, rb: %zd, qb: %zd\n",
		data.input_frames, data.output_frames,
		data.input_frames_used, data.output_frames_gen,
		src->mResampledBuffer.size(), src->mQBuffer.size());
}
// 0 -> eof, but still check for data.
// Otherwise, 1.
int decGetData(
	void* data, 
	char* ch_buffer, // Expecting AV_BUFFSIZE bytes.
	int*  data_size)
{
	dec_data* dec = (dec_data*)data;
	int ret;
	int to_read = AV_BUFFSIZE * dec->samplerate / audio_samplerate;
	char* read_buffer;
	int actually_read;

	// Make sure the number is is at least a multiple
	// of channels * 16 bits.
	while(to_read % (audio_channels * sizeof(short)))
		to_read--;

	// Are we changing the samplerate?
	if(to_read == AV_BUFFSIZE)
		read_buffer = ch_buffer;
	else
 		read_buffer = (char*)alloca(to_read);

	if(dec->channels == audio_channels)
	{
		if((actually_read = dec->decoder->read(
			dec->data,
			read_buffer,
			to_read)) == 0)
		{
			*data_size = 0;
			return 0;
		}

		ret = actually_read;
	}
	else if(dec->channels == 1)
	{
		// If we have mono, repeat the data
		// for all channels.
		short* buff = (short*)alloca(to_read / audio_channels);
		int i;
		int m = to_read / sizeof(short) / audio_channels;

 		short* sbuff = (short*)read_buffer;

		if((actually_read = dec->decoder->read(
			dec->data,
			(char*)buff,
			to_read / audio_channels)) == 0)
		{
			*data_size = 0;
			return 0;
		}

		for(i = 0 ; i < m ; i++)
		{
			int j;

			for(j = 0 ; j < audio_channels ; j++)
				sbuff[i * audio_channels + j] = buff[i];
		}

		ret = actually_read * audio_channels;
	}
	else
	{
		LOG(L"I only support from mono to multiple channels!\n");
		*data_size = 0;
		return 0;
	}

	// At this point, we know that the input has audio_channels channels.

	if(dec->samplerate != audio_samplerate)
	{
		SRC_DATA src;
		float* buffer_in = (float*)alloca(ret / sizeof(short) * sizeof(float));
		float buffer_out[AV_BUFFSIZE / sizeof(short)];
		int err;
		
		short* buffer = (short*)read_buffer;

		src_short_to_float_array(
			buffer,
			buffer_in,
			ret / sizeof(short));

		src.data_in  = buffer_in;
		src.data_out = buffer_out;

		src.input_frames  = ret         / sizeof(short) / audio_channels;
		src.output_frames = AV_BUFFSIZE / sizeof(short) / audio_channels;

		src.src_ratio = dec->ratio;
		src.end_of_input = (actually_read != to_read);

		src.input_frames_used = 0;
		src.output_frames_gen = 0;

		if((err = src_process((SRC_STATE*)dec->converter, &src)) != 0)
		{
			LOG(L"libsamplerate: %s\n", src_strerror(err));
			*data_size = 0;
			return 0;
		}

		src_float_to_short_array(
			buffer_out,
			(short*)ch_buffer,
			src.output_frames_gen * audio_channels);

		*data_size = src.output_frames_gen * sizeof(short) * audio_channels;
		return src.output_frames_gen != 0 || src.input_frames_used != 0;
	}
	else
	{
		*data_size = ret;
		return ret;
	}

/*	return dec->decoder->read(
		dec->data,
		ch_buffer,
		AV_BUFFSIZE);*/
}
Exemple #7
0
//this function is called by PortAudio when new audio data arrived
int snd_callback(const void *input,
                 void *output,
                 unsigned long frameCount,
                 const PaStreamCallbackTimeInfo* timeInfo,
                 PaStreamCallbackFlags statusFlags,
                 void *userData)
{
    int samplerate_out;
    bool convert_stream = false;
    bool convert_record = false;


    memcpy(pa_pcm_buf, input, frameCount*cfg.audio.channel*sizeof(short));
    samplerate_out = cfg.audio.samplerate;

    if(dsp->hasToProcessSamples()) {
        dsp->processSamples(pa_pcm_buf);
    }
	
	if (streaming)
	{
        if ((!strcmp(cfg.audio.codec, "opus")) && (cfg.audio.samplerate != 48000))
        {
            convert_stream = true;
            samplerate_out = 48000;
        }

        if (convert_stream == true)
        {
            srconv_stream.end_of_input = 0;
            srconv_stream.src_ratio = (float)samplerate_out/cfg.audio.samplerate;
            srconv_stream.input_frames = frameCount;
            srconv_stream.output_frames = frameCount*cfg.audio.channel * (srconv_stream.src_ratio+1) * sizeof(float);

            src_short_to_float_array((short*)pa_pcm_buf, (float*) srconv_stream.data_in, (int) frameCount*cfg.audio.channel);

            //The actual resample process
            src_process(srconv_state_stream, &srconv_stream);

            src_float_to_short_array(srconv_stream.data_out, (short*)stream_buf, (int) srconv_stream.output_frames_gen*cfg.audio.channel);

            rb_write(&stream_rb, (char*)stream_buf, (int) srconv_stream.output_frames_gen*sizeof(short)*cfg.audio.channel);
        }
        else
            rb_write(&stream_rb, (char*)pa_pcm_buf, (int) frameCount*sizeof(short)*cfg.audio.channel);

		pthread_cond_signal(&stream_cond);
	}

	if(recording)
	{

        if ((!strcmp(cfg.rec.codec, "opus")) && (cfg.audio.samplerate != 48000))
        {
            convert_record = true;
            samplerate_out = 48000;
        }

        if (convert_record == true)
        {
            srconv_record.end_of_input = 0;
            srconv_record.src_ratio = (float)samplerate_out/cfg.audio.samplerate;
            srconv_record.input_frames = frameCount;
            srconv_record.output_frames = frameCount*cfg.audio.channel * (srconv_record.src_ratio+1) * sizeof(float);

            src_short_to_float_array((short*)pa_pcm_buf, (float*) srconv_record.data_in, (int) frameCount*cfg.audio.channel);

            //The actual resample process
            src_process(srconv_state_record, &srconv_record);

            src_float_to_short_array(srconv_record.data_out, (short*)record_buf, (int) srconv_record.output_frames_gen*cfg.audio.channel);

            rb_write(&rec_rb, (char*)record_buf, (int) srconv_record.output_frames_gen*sizeof(short)*cfg.audio.channel);

        }
        else
            rb_write(&rec_rb, (char*)pa_pcm_buf, (int) frameCount*sizeof(short)*cfg.audio.channel);

		pthread_cond_signal(&rec_cond);
	}
    
    //tell vu_update() that there is new audio data
    pa_new_frames = 1;

    return 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
Exemple #9
0
/* Sound data resampling */
static int raw_resample(char *fname, double ratio)
{
	int res = 0;
	FILE *fl;
	struct stat st;
	int in_size;
	short *in_buff, *out_buff;
	long in_frames, out_frames;
	float *inp, *outp;
	SRC_DATA rate_change;

	if ((fl = fopen(fname, "r")) == NULL) {
		ast_log(LOG_ERROR, "eSpeak: Failed to open file for resampling.\n");
		return -1;
	}
	if ((stat(fname, &st) == -1)) {
		ast_log(LOG_ERROR, "eSpeak: Failed to stat file for resampling.\n");
		fclose(fl);
		return -1;
	}
	in_size = st.st_size;
	if ((in_buff = ast_malloc(in_size)) == NULL) {
		fclose(fl);
		return -1;
	}
	if ((fread(in_buff, 1, in_size, fl) != (size_t)in_size)) {
		ast_log(LOG_ERROR, "eSpeak: Failed to read file for resampling.\n");
		fclose(fl);
		res = -1;
		goto CLEAN1;
	}
	fclose(fl);
	in_frames = in_size / 2;

	if ((inp = (float *)(ast_malloc(in_frames * sizeof(float)))) == NULL) {
		res = -1;
		goto CLEAN1;
	}
	src_short_to_float_array(in_buff, inp, in_size/sizeof(short));
	out_frames = (long)((double)in_frames * ratio);
	if ((outp = (float *)(ast_malloc(out_frames * sizeof(float)))) == NULL) {
		res = -1;
		goto CLEAN2;
	}
	rate_change.data_in = inp;
	rate_change.data_out = outp;
	rate_change.input_frames = in_frames;
	rate_change.output_frames = out_frames;
	rate_change.src_ratio = ratio;

	if ((res = src_simple(&rate_change, SRC_SINC_FASTEST, 1)) != 0) {
		ast_log(LOG_ERROR, "eSpeak: Failed to resample sound file '%s': '%s'\n",
				fname, src_strerror(res));
		res = -1;
		goto CLEAN3;
	}

	if ((out_buff = ast_malloc(out_frames*sizeof(float))) == NULL) {
		res = -1;
		goto CLEAN3;
	}
	src_float_to_short_array(rate_change.data_out, out_buff, out_frames);
	if ((fl = fopen(fname, "w+")) != NULL) {
		if ((fwrite(out_buff, 1, 2*out_frames, fl)) != (size_t)(2*out_frames)) {
			ast_log(LOG_ERROR, "eSpeak: Failed to write resampled output file.\n");
			res = -1;
		}
		fclose(fl);
	} else {
		ast_log(LOG_ERROR, "eSpeak: Failed to open output file for resampling.\n");
		res = -1;
	}
	ast_free(out_buff);
CLEAN3:
	ast_free(outp);
CLEAN2:
	ast_free(inp);
CLEAN1:
	ast_free(in_buff);
	return res;
}
Exemple #10
0
/* All and mighty connection handler. */
static void* rsd_thread(void *thread_data)
{
   connection_t conn;
   void *data = NULL;
   wav_header_t w;
   wav_header_t w_orig;
   int resample = 0;
   int rc, written;
   void *buffer = NULL;
#ifdef HAVE_SAMPLERATE
   SRC_STATE *resample_state = NULL;
#else
   resampler_t *resample_state = NULL;
#endif
   float *resample_buffer = NULL;
   resample_cb_state_t cb_data;

   connection_t *temp_conn = thread_data;
   conn.socket = temp_conn->socket;
   conn.ctl_socket = temp_conn->ctl_socket;
   conn.serv_ptr = 0;
   conn.rate_ratio = 1.0;
   conn.identity[0] = '\0';
   free(temp_conn);

   if ( debug )
      log_printf("Connection accepted, awaiting WAV header data ...\n");

   /* Firstly, get the wave header with stream settings. */
   rc = get_wav_header(conn, &w);
   if ( rc == -1 )
   {
      close(conn.socket);
      close(conn.ctl_socket);
      log_printf("Couldn't read WAV header... Disconnecting.\n");
      pthread_exit(NULL);
   }
   memcpy(&w_orig, &w, sizeof(wav_header_t));

   if ( resample_freq > 0 && resample_freq != (int)w.sampleRate )
   {
      w.sampleRate = resample_freq;
      w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16;
      if (w_orig.bitsPerSample == 32)
         w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE;
      else
         w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE;
      resample = 1;
      conn.rate_ratio = (float)w.sampleRate * w.bitsPerSample / ((float)w_orig.sampleRate * w_orig.bitsPerSample);
   }

   if ( debug )
   {
      log_printf("Successfully got WAV header ...\n");
      pheader(&w_orig);
      if ( resample )
      {
         log_printf("Resamples to:\n");
         pheader(&w);
      }
   }

   if ( debug )
      log_printf("Initializing %s ...\n", backend->backend);

   /* Sets up backend */
   if ( backend->init(&data) < 0 )
   {
      log_printf("Failed to initialize %s ...\n", backend->backend);
      goto rsd_exit;
   }

   /* Opens device with settings. */
   if ( backend->open(data, &w) < 0 )
   {
      log_printf("Failed to open audio driver ...\n");
      goto rsd_exit;
   }

   backend_info_t backend_info; 
   memset(&backend_info, 0, sizeof(backend_info));
   backend->get_backend_info(data, &backend_info);
   if ( backend_info.chunk_size == 0 )
   {
      log_printf("Couldn't get backend info ...\n");
      goto rsd_exit;
   }

   if ( backend_info.resample )
   {
      resample = 1;
      w.sampleRate = w.sampleRate * backend_info.ratio;
      conn.rate_ratio = backend_info.ratio;

      w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16;
      if (w_orig.bitsPerSample == 32)
         w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE;
      else
         w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE;
   }

   size_t size = backend_info.chunk_size;
   size_t read_size = size;

   size_t buffer_size = (read_size > size) ? read_size : size;
   buffer = malloc(buffer_size);
   if ( buffer == NULL )
   {
      log_printf("Could not allocate memory for buffer.");
      goto rsd_exit;
   }

   if ( resample )
   {
      resample_buffer = malloc(BYTES_TO_SAMPLES(buffer_size, w.rsd_format) * sizeof(float));
      if ( resample_buffer == NULL )
      {
         log_printf("Could not allocate memory for buffer.");
         goto rsd_exit;
      }

      cb_data.format = w_orig.rsd_format;
      cb_data.data = data;
      cb_data.conn = &conn;
      cb_data.framesize = w_orig.numChannels * rsnd_format_to_bytes(w_orig.rsd_format);

#ifdef HAVE_SAMPLERATE
      int err;
      resample_state = src_callback_new(resample_callback, src_converter, w.numChannels, &err, &cb_data);
#else
      resample_state = resampler_new(resample_callback, (float)w.sampleRate/w_orig.sampleRate, w.numChannels, &cb_data);
#endif
      if ( resample_state == NULL )
      {
         log_printf("Could not initialize resampler.");
         goto rsd_exit;
      }
   }

#define MAX_TCP_BUFSIZ (1 << 14)

   // We only bother with setting buffer size if we're doing TCP.
   if ( rsd_conn_type == RSD_CONN_TCP )
   {
      int flag = 1;
      int bufsiz = backend_info.chunk_size * 32;
      if (bufsiz > MAX_TCP_BUFSIZ)
         bufsiz = MAX_TCP_BUFSIZ;

      setsockopt(conn.socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int));

      if ( conn.ctl_socket )
      {
         setsockopt(conn.ctl_socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int));
         setsockopt(conn.ctl_socket, SOL_SOCKET, SO_SNDBUF, CONST_CAST &bufsiz, sizeof(int));
         setsockopt(conn.ctl_socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int));
      }

      setsockopt(conn.socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int));
   }

   /* Now we can send backend info to client. */
   if ( send_backend_info(conn, &backend_info) < 0 )
   {
      log_printf("Failed to send backend info ...\n");
      goto rsd_exit;
   }

   if ( debug )
      log_printf("Initializing of %s successful ...\n", backend->backend);

   if ( debug )
   {
      if ( resample )
      {
         log_printf("Resampling active. %d Hz --> %d Hz ", (int)w_orig.sampleRate, (int)w.sampleRate);
#ifdef HAVE_SAMPLERATE
         log_printf("(libsamplerate)\n");
#else
         log_printf("(internal quadratic resampler)\n");
#endif
      }
   }

   /* Recieve data, write to sound card. Rinse, repeat :') */
   for(;;)
   {
      if ( strlen(conn.identity) > 0 && verbose )
      {
         log_printf(" :: %s\n", conn.identity);
         conn.identity[0] = '\0';
      }

      if ( resample )
      {
#ifdef HAVE_SAMPLERATE
         rc = src_callback_read(resample_state, (double)w.sampleRate/(double)w_orig.sampleRate, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer);
         if (rsnd_format_to_bytes(w.rsd_format) == 4)
            src_float_to_int_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format));
         else
            src_float_to_short_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format));
#else
         rc = resampler_cb_read(resample_state, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer);
         if (rsnd_format_to_bytes(w.rsd_format) == 4)
            resampler_float_to_s32(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format));
         else
            resampler_float_to_s16(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format));
#endif
      }
      else
         rc = receive_data(data, &conn, buffer, read_size);

      if ( rc <= 0 )
      {
         if ( debug )
            log_printf("Client closed connection.\n");
         goto rsd_exit;
      }

      for ( written = 0; written < (int)size; )
      {
         rc = backend->write(data, (const char*)buffer + written, size - written);
         if ( rc == 0 )
            goto rsd_exit;

         written += rc;
      }
   }

   /* Cleanup */
rsd_exit:
   if ( debug )
      log_printf("Closed connection.\n\n");
#ifdef _WIN32
#undef close
#endif
   backend->close(data);
#ifdef _WIN32
#define close(x) closesocket(x)
#endif
   free(buffer);
   close(conn.socket);
   if (conn.ctl_socket)
      close(conn.ctl_socket);

   if (resample_state)
   {
#ifdef HAVE_SAMPLERATE
      src_delete(resample_state);
#else
      resampler_free(resample_state);
#endif
   }
   free(resample_buffer);
   pthread_exit(NULL);
}