/*------------------------------------------------------------------------------ * 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; }
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; } }
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 }
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);*/ }
//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
/* 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; }
/* 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); }