/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* header includes */ #include "typedefs.h" #include "stdio.h" #include "webrtc_neteq.h" #include "webrtc_neteq_internal.h" #include "webrtc_neteq_help_macros.h" #include "neteq_error_codes.h" // for the API test #include "NETEQTEST_RTPpacket.h" #include "NETEQTEST_NetEQClass.h" #include "NETEQTEST_CodecClass.h" #include #include #include #include #include #ifdef WIN32 #include #include #endif #ifdef WEBRTC_LINUX #include #include #include #endif //#include "vld.h" //#define NETEQ_DELAY_LOGGING //#define DUMMY_SLAVE_CHANNEL #ifdef NETEQ_DELAY_LOGGING #include "delay_logging.h" #define DUMMY_SLAVE_CHANNEL // do not use a slave channel, only generate zeros instead #endif /************************/ /* Define payload types */ /************************/ // Payload types are defined in the textfile ptypes.txt, and can be changed after compilation. /*********************/ /* Misc. definitions */ /*********************/ #define TIME_STEP 1 #define FIRSTLINELEN 40 #define MAX_NETEQ_BUFFERSIZE 170000 //100000 #define CHECK_ZERO(a) {int errCode = a; char tempErrName[WEBRTC_NETEQ_MAX_ERROR_NAME]; if((errCode)!=0){errCode = WebRtcNetEQ_GetErrorCode(inst); WebRtcNetEQ_GetErrorName(errCode, tempErrName, WEBRTC_NETEQ_MAX_ERROR_NAME); printf("\n %s \n line: %d \n error at %s\n Error Code = %d\n",__FILE__,__LINE__,#a, errCode); exit(0);}} #define CHECK_NOT_NULL(a) if((a)==NULL){printf("\n %s \n line: %d \nerror at %s\n",__FILE__,__LINE__,#a );return(-1);} //#define PLAY_CLEAN // ignore arrival times and let the packets arrive according to RTP timestamps #define HDR_SIZE 8 // rtpplay packet header size in bytes //#define JUNK_DATA // scramble the payloads to test error resilience //#define ZERO_TS_START #ifdef JUNK_DATA #define SEED_FILE "randseed.txt" #endif #ifdef WIN32 #define MY_MAX_DRIVE _MAX_DRIVE #define MY_MAX_PATH _MAX_PATH #define MY_MAX_FNAME _MAX_FNAME #define MY_MAX_EXT _MAX_EXT #else #if defined(WEBRTC_LINUX) #include //#define MY_MAX_DRIVE 17 // arbitary number #define MY_MAX_PATH PATH_MAX //#define MY_MAX_FNAME NAME_MAX //#define MY_MAX_EXT 17 // arbitary number #endif #endif /************/ /* Typedefs */ /************/ typedef struct { enum WebRtcNetEQDecoder codec; enum stereoModes stereo; NETEQTEST_Decoder * decoder[2]; int fs; } decoderStruct; /*************************/ /* Function declarations */ /*************************/ void stereoInterleave(WebRtc_Word16 *data, WebRtc_Word16 totalLen); int getNextRecoutTime(FILE *fp, WebRtc_UWord32 *nextTime); void getNextExtraDelay(FILE *fp, WebRtc_UWord32 *t, int *d); bool splitStereo(NETEQTEST_RTPpacket& rtp, NETEQTEST_RTPpacket& rtpSlave, const WebRtc_Word16 *stereoPtype, const enum stereoModes *stereoMode, int noOfStereoCodecs, const WebRtc_Word16 *cngPtype, int noOfCngCodecs, bool *isStereo); void parsePtypeFile(FILE *ptypeFile, std::map* decoders); int populateUsedCodec(std::map* decoders, enum WebRtcNetEQDecoder *usedCodec); void createAndInsertDecoders (NETEQTEST_NetEQClass *neteq, std::map* decoders, int channelNumber); void free_coders(std::map & decoders); int doAPItest(); bool changeStereoMode(NETEQTEST_RTPpacket & rtp, std::map & decoders, enum stereoModes *stereoMode); /********************/ /* Global variables */ /********************/ WebRtc_Word16 NetEqPacketBuffer[MAX_NETEQ_BUFFERSIZE>>1]; WebRtc_Word16 NetEqPacketBufferSlave[MAX_NETEQ_BUFFERSIZE>>1]; FILE *in_file; FILE *out_file; #ifdef NETEQ_DELAY_LOGGING extern "C" { FILE *delay_fid2; /* file pointer */ WebRtc_UWord32 tot_received_packets=0; } #endif #ifdef DEF_BUILD_DATE extern char BUILD_DATE; #endif WebRtc_UWord32 writtenSamples = 0; WebRtc_UWord32 simClock=0; int main(int argc, char* argv[]) { std::vector NetEQvector; NETEQTEST_RTPpacket rtp; char version[20]; char firstline[FIRSTLINELEN]; NETEQTEST_RTPpacket slaveRtp; //bool switchMS = false; //bool duplicatePayload = false; enum WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd-1]; int noOfCodecs; int ok; WebRtc_Word16 out_data[640*2]; WebRtc_Word16 outLen, writeLen; int fs = 8000; WebRtcNetEQ_RTCPStat RTCPstat; #ifdef WIN32 char outdrive[MY_MAX_DRIVE]; char outpath[MY_MAX_PATH]; char outfile[MY_MAX_FNAME]; char outext[MY_MAX_EXT]; #endif char outfilename[MY_MAX_PATH]; #ifdef NETEQ_DELAY_LOGGING float clock_float; int temp_var; #endif #ifdef JUNK_DATA FILE *seedfile; #endif FILE *recoutTimes = NULL; FILE *extraDelays = NULL; WebRtcNetEQPlayoutMode streamingMode = kPlayoutOn; bool preParseRTP = false; bool rtpOnly = false; int packetLen = 0; int packetCount = 0; std::map decoders; /* get the version string */ WebRtcNetEQ_GetVersion(version); printf("\n\nNetEq version: %s\n", version); #ifdef DEF_BUILD_DATE printf("Build time: %s\n", __BUILD_DATE); #endif /* check number of parameters */ if ((argc < 3) #ifdef WIN32 // implicit output file name possible for windows && (argc < 2) #endif ) { /* print help text and exit */ printf("Test program for NetEQ.\n"); printf("The program reads an RTP stream from file and inserts it into NetEQ.\n"); printf("The format of the RTP stream file should be the same as for rtpplay,\n"); printf("and can be obtained e.g., from Ethereal by using\n"); printf("Statistics -> RTP -> Show All Streams -> [select a stream] -> Save As\n\n"); printf("Usage:\n\n"); #ifdef WIN32 printf("%s RTPfile [outfile] [-options]\n", argv[0]); #else printf("%s RTPfile outfile [-options]\n", argv[0]); #endif printf("where:\n"); printf("RTPfile : RTP stream input file\n\n"); printf("outfile : PCM speech output file\n"); printf(" Output file name is derived from RTP file name if omitted\n\n"); printf("-options are optional switches:\n"); printf("\t-recout datfile : supply recout times\n"); printf("\t-extradelay datfile : supply extra delay settings and timing\n"); printf("\t-streaming : engage streaming mode\n"); printf("\t-fax : engage fax mode\n"); printf("\t-preparsertp : use RecIn with pre-parsed RTP\n"); printf("\t-rtponly packLenBytes : input file consists of constant size RTP packets without RTPplay headers\n"); //printf("\t-switchms : switch from mono to stereo (copy channel) after 10 seconds\n"); //printf("\t-duplicate : use two instances with identical input (2-channel mono)\n"); return(0); } if (strcmp(argv[1], "-apitest")==0) { // do API test and then return ok=doAPItest(); if (ok==0) printf("API test successful!\n"); else printf("API test failed!\n"); return(ok); } in_file=fopen(argv[1],"rb"); CHECK_NOT_NULL(in_file); printf("Input file: %s\n",argv[1]); int argIx = 2; // index of next argument from command line if ( argc >= 3 && argv[2][0] != '-' ) { // output name given on command line strcpy(outfilename, argv[2]); argIx++; } else { // derive output name from input name #ifdef WIN32 _splitpath(argv[1],outdrive,outpath,outfile,outext); _makepath(outfilename,outdrive,outpath,outfile,"pcm"); #else fprintf(stderr,"Output file name must be specified.\n"); return(-1); #endif } out_file=fopen(outfilename,"wb"); if (out_file==NULL) { fprintf(stderr,"Could not open file %s for writing\n", outfilename); return(-1); } printf("Output file: %s\n\n",outfilename); // Parse for more arguments, all beginning with '-' while( argIx < argc ) { if (argv[argIx][0] != '-') { fprintf(stderr,"Unknown input argument %s\n", argv[argIx]); return(-1); } if( strcmp(argv[argIx], "-recout") == 0 ) { argIx++; recoutTimes = fopen(argv[argIx], "rb"); CHECK_NOT_NULL(recoutTimes); argIx++; } else if( strcmp(argv[argIx], "-extradelay") == 0 ) { argIx++; extraDelays = fopen(argv[argIx], "rb"); CHECK_NOT_NULL(extraDelays); argIx++; } else if( strcmp(argv[argIx], "-streaming") == 0 ) { argIx++; streamingMode = kPlayoutStreaming; } else if( strcmp(argv[argIx], "-fax") == 0 ) { argIx++; streamingMode = kPlayoutFax; } else if( strcmp(argv[argIx], "-preparsertp") == 0 ) { argIx++; preParseRTP = true; } else if( strcmp(argv[argIx], "-rtponly") == 0 ) { argIx++; rtpOnly = true; packetLen = atoi(argv[argIx]); argIx++; if (packetLen <= 0) { printf("Wrong packet size used with argument -rtponly.\n"); exit(1); } } //else if( strcmp(argv[argIx], "-switchms") == 0 ) { // argIx++; // switchMS = true; //} //else if( strcmp(argv[argIx], "-duplicate") == 0 ) { // argIx++; // duplicatePayload = true; //} else { fprintf(stderr,"Unknown input argument %s\n", argv[argIx]); return(-1); } } #ifdef NETEQ_DELAY_LOGGING char delayfile[MY_MAX_PATH]; #ifdef WIN32 _splitpath(outfilename,outdrive,outpath,outfile,outext); _makepath(delayfile,outdrive,outpath,outfile,"d"); #else sprintf(delayfile, "%s.d", outfilename); #endif delay_fid2 = fopen(delayfile,"wb"); fprintf(delay_fid2, "#!NetEQ_Delay_Logging%s\n", NETEQ_DELAY_LOGGING_VERSION_STRING); #endif char ptypesfile[MY_MAX_PATH]; #ifdef WIN32 _splitpath(argv[0],outdrive,outpath,outfile,outext); _makepath(ptypesfile,outdrive,outpath,"ptypes","txt"); #else // TODO(hlundin): Include path to ptypes, as for WIN32 above. strcpy(ptypesfile, "ptypes.txt"); #endif FILE *ptypeFile = fopen(ptypesfile,"rt"); CHECK_NOT_NULL(ptypeFile); parsePtypeFile(ptypeFile, &decoders); fclose(ptypeFile); noOfCodecs = populateUsedCodec(&decoders, usedCodec); /* read RTP file header */ if (!rtpOnly) { fgets(firstline, FIRSTLINELEN, in_file); if(strncmp(firstline,"#!rtpplay",9) == 0) { if(strncmp(firstline,"#!rtpplay1.0",12) != 0){ printf("ERROR: wrong rtpplay version, must be 1.0\n"); exit(0); } } else if (strncmp(firstline,"#!RTPencode",11) == 0) { if(strncmp(firstline,"#!RTPencode1.0",14) != 0){ printf("ERROR: wrong RTPencode version, must be 1.0\n"); exit(0); } } else { printf("ERROR: wrong file format of input file\n"); exit(0); } WebRtc_UWord32 start_sec; WebRtc_UWord32 start_usec; WebRtc_UWord32 source; WebRtc_UWord16 port; WebRtc_UWord16 padding; fread(&start_sec, 4, 1, in_file); start_sec=ntohl(start_sec); fread(&start_usec, 4, 1, in_file); start_usec=ntohl(start_usec); fread(&source, 4, 1, in_file); source=ntohl(source); fread(&port, 2, 1, in_file); port=ntohs(port); fread(&padding, 2, 1, in_file); padding=ntohs(padding); } /* check payload type for first speech packet */ long tempFilePos = ftell(in_file); enum stereoModes stereoMode = stereoModeMono; if (!rtpOnly) { while (rtp.readFromFile(in_file) >= 0) { if (decoders.count(rtp.payloadType()) > 0 && decoders[rtp.payloadType()].codec != kDecoderRED && decoders[rtp.payloadType()].codec != kDecoderAVT && decoders[rtp.payloadType()].codec != kDecoderCNG ) { stereoMode = decoders[rtp.payloadType()].stereo; fs = decoders[rtp.payloadType()].fs; break; } } } else { while (rtp.readFixedFromFile(in_file, packetLen) >= 0) { if (decoders.count(rtp.payloadType()) > 0 && decoders[rtp.payloadType()].codec != kDecoderRED && decoders[rtp.payloadType()].codec != kDecoderAVT && decoders[rtp.payloadType()].codec != kDecoderCNG ) { stereoMode = decoders[rtp.payloadType()].stereo; fs = decoders[rtp.payloadType()].fs; break; } } } fseek(in_file, tempFilePos, SEEK_SET /* from beginning */); /* block some payload types */ //rtp.blockPT(72); //rtp.blockPT(23); /* read first packet */ if (!rtpOnly) { rtp.readFromFile(in_file); } else { rtp.readFixedFromFile(in_file, packetLen); rtp.setTime((1000 * rtp.timeStamp()) / fs); } if (!rtp) { printf("\nWarning: RTP file is empty\n\n"); } /* Initialize NetEQ instances */ int numInst = 1; if (stereoMode > stereoModeMono) { numInst = 2; } for (int i = 0; i < numInst; i++) { // create memory, allocate, initialize, and allocate packet buffer memory NetEQvector.push_back (new NETEQTEST_NetEQClass(usedCodec, noOfCodecs, static_cast(fs), kTCPLargeJitter)); createAndInsertDecoders (NetEQvector[i], &decoders, i /* channel */); WebRtcNetEQ_SetAVTPlayout(NetEQvector[i]->instance(),1); // enable DTMF playout WebRtcNetEQ_SetPlayoutMode(NetEQvector[i]->instance(), streamingMode); NetEQvector[i]->usePreparseRTP(preParseRTP); if (numInst > 1) { // we are using master/slave mode if (i == 0) { // first instance is master NetEQvector[i]->isMaster(); } else { // all other are slaves NetEQvector[i]->isSlave(); } } } #ifdef ZERO_TS_START WebRtc_UWord32 firstTS = rtp.timeStamp(); rtp.setTimeStamp(0); #else WebRtc_UWord32 firstTS = 0; #endif // check stereo mode if (stereoMode > stereoModeMono) { if(rtp.splitStereo(slaveRtp, stereoMode)) { printf("Error in splitStereo\n"); } } #ifdef PLAY_CLEAN WebRtc_UWord32 prevTS = rtp.timeStamp(); WebRtc_UWord32 currTS, prev_time; #endif #ifdef JUNK_DATA unsigned int random_seed = (unsigned int) /*1196764538; */time(NULL); srand(random_seed); if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) { fprintf(stderr, "Error: Could not open file %s\n", SEED_FILE); } else { fprintf(seedfile, "%u\n", random_seed); fclose(seedfile); } #endif WebRtc_UWord32 nextRecoutTime; int lastRecout = getNextRecoutTime(recoutTimes, &nextRecoutTime); // does nothing if recoutTimes == NULL if (recoutTimes) simClock = (rtp.time() < nextRecoutTime ? rtp.time(): nextRecoutTime); else simClock = rtp.time(); // start immediately with first packet WebRtc_UWord32 start_clock = simClock; WebRtc_UWord32 nextExtraDelayTime; int extraDelay = -1; getNextExtraDelay(extraDelays, &nextExtraDelayTime, &extraDelay); void *msInfo; msInfo = malloc(WebRtcNetEQ_GetMasterSlaveInfoSize()); if(msInfo == NULL) return(-1); while(rtp.dataLen() >= 0 || (recoutTimes && !lastRecout)) { // printf("simClock = %Lu\n", simClock); #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_CLOCK; clock_float = (float) simClock; fwrite(&temp_var,sizeof(int),1,delay_fid2); fwrite(&clock_float, sizeof(float),1,delay_fid2); #endif /* time to set extra delay */ if (extraDelay > -1 && simClock >= nextExtraDelayTime) { // set extra delay for all instances for (int i = 0; i < numInst; i++) { WebRtcNetEQ_SetExtraDelay(NetEQvector[i]->instance(), extraDelay); } getNextExtraDelay(extraDelays, &nextExtraDelayTime, &extraDelay); } /* check if time to receive */ while (simClock >= rtp.time() && rtp.dataLen() >= 0) { if (rtp.dataLen() > 0) { // insert main packet NetEQvector[0]->recIn(rtp); if (stereoMode > stereoModeMono && slaveRtp.dataLen() > 0) { // insert slave packet NetEQvector[1]->recIn(slaveRtp); } } /* get next packet */ #ifdef PLAY_CLEAN prev_time = rtp.time(); #endif if (!rtpOnly) { rtp.readFromFile(in_file); } else { rtp.readFixedFromFile(in_file, packetLen); rtp.setTime((1000 * rtp.timeStamp()) / fs); } if (rtp.dataLen() >= 0) { rtp.setTimeStamp(rtp.timeStamp() - firstTS); } packetCount++; if (changeStereoMode(rtp, decoders, &stereoMode)) { printf("Warning: stereo mode changed\n"); } if (stereoMode > stereoModeMono) { if(rtp.splitStereo(slaveRtp, stereoMode)) { printf("Error in splitStereo\n"); } } #ifdef PLAY_CLEAN currTS = rtp.timeStamp(); rtp.setTime(prev_time + (currTS-prevTS)/(fs/1000)); prevTS = currTS; #endif } /* check if time to RecOut */ if ( (!recoutTimes && (simClock%10)==0) // recout times not given from file || ( recoutTimes && (simClock >= nextRecoutTime) ) ) // recout times given from file { if (stereoMode > stereoModeMono) { // stereo WebRtc_Word16 tempLen; tempLen = NetEQvector[0]->recOut( out_data, msInfo ); // master outLen = NetEQvector[1]->recOut( &out_data[tempLen], msInfo ); // slave assert(tempLen == outLen); writeLen = outLen * 2; stereoInterleave(out_data, writeLen); } else { // mono outLen = NetEQvector[0]->recOut( out_data ); writeLen = outLen; } // write to file fwrite(out_data,writeLen,2,out_file); writtenSamples += writeLen; lastRecout = getNextRecoutTime(recoutTimes, &nextRecoutTime); // does nothing if recoutTimes == NULL /* ask for statistics */ WebRtcNetEQ_NetworkStatistics inCallStats; WebRtcNetEQ_GetNetworkStatistics(NetEQvector[0]->instance(), &inCallStats); } /* increase time */ simClock+=TIME_STEP; } fclose(in_file); fclose(out_file); #ifdef NETEQ_DELAY_LOGGING temp_var = NETEQ_DELAY_LOGGING_SIGNAL_EOF; fwrite(&temp_var,sizeof(int),1,delay_fid2); fwrite(&tot_received_packets,sizeof(WebRtc_UWord32),1,delay_fid2); fprintf(delay_fid2,"End of file\n"); fclose(delay_fid2); #endif WebRtcNetEQ_GetRTCPStats(NetEQvector[0]->instance(), &RTCPstat); printf("RTCP statistics:\n"); printf(" cum_lost : %d\n", (int) RTCPstat.cum_lost); printf(" ext_max : %d\n", (int) RTCPstat.ext_max); printf(" fraction_lost : %d (%f%%)\n", RTCPstat.fraction_lost, (float)(100.0*RTCPstat.fraction_lost/256.0)); printf(" jitter : %d\n", (int) RTCPstat.jitter); WebRtcNetEQ_JitterStatistics jitterStats; WebRtcNetEQ_GetJitterStatistics(NetEQvector[0]->instance(), &jitterStats); printf("\nPost-call statistics:\n"); printf(" Call duration ms : %lu\n", simClock-start_clock); printf(" Expand (voice) ms : %lu \t(%.2f%%)\n", jitterStats.interpolatedVoiceMs, (float) 100.0 * jitterStats.interpolatedVoiceMs/(simClock-start_clock)); printf(" Expand (silence) ms : %lu \t(%.2f%%)\n", jitterStats.interpolatedSilentMs, (float) 100.0 * jitterStats.interpolatedSilentMs/(simClock-start_clock)); printf(" Accelerate ms : %lu \t(%.2f%%)\n", jitterStats.accelerateMs, (float) 100.0 * jitterStats.accelerateMs/(simClock-start_clock)); printf(" Flushed ms : %lu \t(%.2f%%)\n", jitterStats.flushedMs, (float) 100.0 * jitterStats.flushedMs/(simClock-start_clock)); printf(" JB avg size ms : %lu\n", jitterStats.jbAvgSize); printf(" JB max size ms : %lu\n", jitterStats.jbMaxSize); printf(" Max inter-arrival ms: %lu\n", jitterStats.longestIATms); printf("\nComplexity estimates (including sub-components):\n"); printf(" RecIn complexity : %.2f MCPS\n", NetEQvector[0]->getRecInTime() / ((float) 1000*(simClock-start_clock))); printf(" RecOut complexity : %.2f MCPS\n", NetEQvector[0]->getRecOutTime() / ((float) 1000*(simClock-start_clock))); free_coders(decoders); //free_coders(0 /* first channel */); // if (stereoMode > stereoModeMono) { // free_coders(1 /* second channel */); // } free(msInfo); for (std::vector::iterator it = NetEQvector.begin(); it < NetEQvector.end(); delete *it++); printf("\nSimulation done!\n"); #ifdef JUNK_DATA if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) { fprintf(stderr, "Error: Could not open file %s\n", SEED_FILE); } else { fprintf(seedfile, "ok\n\n"); fclose(seedfile); } #endif // Log complexity to file /* FILE *statfile; statfile = fopen("complexity.txt","at"); fprintf(statfile,"%.4f, %.4f\n", (float) totTime_RecIn.QuadPart / ((float) 1000*(simClock-start_clock)), (float) totTime_RecOut.QuadPart / ((float) 1000*(simClock-start_clock))); fclose(statfile);*/ return(0); } /****************/ /* Subfunctions */ /****************/ bool splitStereo(NETEQTEST_RTPpacket& rtp, NETEQTEST_RTPpacket& rtpSlave, const WebRtc_Word16 *stereoPtype, const enum stereoModes *stereoMode, int noOfStereoCodecs, const WebRtc_Word16 *cngPtype, int noOfCngCodecs, bool *isStereo) { // init //bool isStereo = false; enum stereoModes tempStereoMode = stereoModeMono; bool isCng = false; // check payload length if (rtp.dataLen() <= 0) { //*isStereo = false; // don't change return(*isStereo); } // check payload type WebRtc_Word16 ptype = rtp.payloadType(); // is this a cng payload? for (int k = 0; k < noOfCngCodecs; k++) { if (ptype == cngPtype[k]) { // do not change stereo state isCng = true; tempStereoMode = stereoModeFrame; } } if (!isCng) { *isStereo = false; // is this payload type a stereo codec? which type? for (int k = 0; k < noOfStereoCodecs; k++) { if (ptype == stereoPtype[k]) { tempStereoMode = stereoMode[k]; *isStereo = true; break; // exit for loop } } } if (*isStereo) { // split the payload if stereo if(rtp.splitStereo(rtpSlave, tempStereoMode)) { printf("Error in splitStereo\n"); } } return(*isStereo); } void stereoInterleave(WebRtc_Word16 *data, WebRtc_Word16 totalLen) { int k; for(k = totalLen/2; k < totalLen; k++) { WebRtc_Word16 temp = data[k]; memmove(&data[2*k - totalLen + 2], &data[2*k - totalLen + 1], (totalLen - k -1) * sizeof(WebRtc_Word16)); data[2*k - totalLen + 1] = temp; } } int getNextRecoutTime(FILE *fp, WebRtc_UWord32 *nextTime) { float tempTime; if (!fp) { return -1; } if (fread(&tempTime, sizeof(float), 1, fp) != 0) { // not end of file *nextTime = (WebRtc_UWord32) tempTime; return 0; } *nextTime = 0; fclose(fp); return 1; } void getNextExtraDelay(FILE *fp, WebRtc_UWord32 *t, int *d) { float temp[2]; if(!fp) { *d = -1; return; } if (fread(&temp, sizeof(float), 2, fp) != 0) { // not end of file *t = (WebRtc_UWord32) temp[0]; *d = (int) temp[1]; return; } *d = -1; fclose(fp); return; } void parsePtypeFile(FILE *ptypeFile, std::map* decoders) { int n, pt; char codec[100]; decoderStruct tempDecoder; // read first line n = fscanf(ptypeFile, "%s %i\n", codec, &pt); while (n==2) { memset(&tempDecoder, 0, sizeof(decoderStruct)); tempDecoder.stereo = stereoModeMono; if( pt >= 0 // < 0 disables this codec && isalpha(codec[0]) ) // and is a letter { /* check for stereo */ int L = strlen(codec); bool isStereo = false; if (codec[L-1] == '*') { // stereo codec isStereo = true; // remove '*' codec[L-1] = '\0'; } #ifdef CODEC_G711 if(strcmp(codec, "pcmu") == 0) { tempDecoder.codec = kDecoderPCMu; tempDecoder.fs = 8000; } else if(strcmp(codec, "pcma") == 0) { tempDecoder.codec = kDecoderPCMa; tempDecoder.fs = 8000; } #endif #ifdef CODEC_IPCMU else if(strcmp(codec, "eg711u") == 0) { tempDecoder.codec = kDecoderEG711u; tempDecoder.fs = 8000; } #endif #ifdef CODEC_IPCMA else if(strcmp(codec, "eg711a") == 0) { tempDecoder.codec = kDecoderEG711a; tempDecoder.fs = 8000; } #endif #ifdef CODEC_ILBC else if(strcmp(codec, "ilbc") == 0) { tempDecoder.codec = kDecoderILBC; tempDecoder.fs = 8000; } #endif #ifdef CODEC_ISAC else if(strcmp(codec, "isac") == 0) { tempDecoder.codec = kDecoderISAC; tempDecoder.fs = 16000; } #endif #ifdef CODEC_ISACLC else if(strcmp(codec, "isaclc") == 0) { tempDecoder.codec = NETEQ_CODEC_ISACLC; tempDecoder.fs = 16000; } #endif #ifdef CODEC_ISAC_SWB else if(strcmp(codec, "isacswb") == 0) { tempDecoder.codec = kDecoderISACswb; tempDecoder.fs = 32000; } #endif #ifdef CODEC_IPCMWB else if(strcmp(codec, "ipcmwb") == 0) { tempDecoder.codec = kDecoderIPCMwb; tempDecoder.fs = 16000; } #endif #ifdef CODEC_G722 else if(strcmp(codec, "g722") == 0) { tempDecoder.codec = kDecoderG722; tempDecoder.fs = 16000; } #endif #ifdef CODEC_G722_1_16 else if(strcmp(codec, "g722_1_16") == 0) { tempDecoder.codec = kDecoderG722_1_16; tempDecoder.fs = 16000; } #endif #ifdef CODEC_G722_1_24 else if(strcmp(codec, "g722_1_24") == 0) { tempDecoder.codec = kDecoderG722_1_24; tempDecoder.fs = 16000; } #endif #ifdef CODEC_G722_1_32 else if(strcmp(codec, "g722_1_32") == 0) { tempDecoder.codec = kDecoderG722_1_32; tempDecoder.fs = 16000; } #endif #ifdef CODEC_G722_1C_24 else if(strcmp(codec, "g722_1c_24") == 0) { tempDecoder.codec = kDecoderG722_1C_24; tempDecoder.fs = 32000; } #endif #ifdef CODEC_G722_1C_32 else if(strcmp(codec, "g722_1c_32") == 0) { tempDecoder.codec = kDecoderG722_1C_32; tempDecoder.fs = 32000; } #endif #ifdef CODEC_G722_1C_48 else if(strcmp(codec, "g722_1c_48") == 0) { tempDecoder.codec = kDecoderG722_1C_48; tempDecoder.fs = 32000; } #endif #ifdef CODEC_G723 else if(strcmp(codec, "g723") == 0) { tempDecoder.codec = NETEQ_CODEC_G723; tempDecoder.fs = 8000; } #endif #ifdef CODEC_G726 else if(strcmp(codec, "g726_16") == 0) { tempDecoder.codec = kDecoderG726_16; tempDecoder.fs = 8000; } else if(strcmp(codec, "g726_24") == 0) { tempDecoder.codec = kDecoderG726_24; tempDecoder.fs = 8000; } else if(strcmp(codec, "g726_32") == 0) { tempDecoder.codec = kDecoderG726_32; tempDecoder.fs = 8000; } else if(strcmp(codec, "g726_40") == 0) { tempDecoder.codec = kDecoderG726_40; tempDecoder.fs = 8000; } #endif #ifdef CODEC_G729 else if(strcmp(codec, "g729") == 0) { tempDecoder.codec = kDecoderG729; tempDecoder.fs = 8000; } #endif #ifdef CODEC_G729D else if(strcmp(codec, "g729d") == 0) { tempDecoder.codec = NETEQ_CODEC_G729D; tempDecoder.fs = 8000; } #endif #ifdef CODEC_G729_1 else if(strcmp(codec, "g729_1") == 0) { tempDecoder.codec = kDecoderG729_1; tempDecoder.fs = 16000; } #endif #ifdef CODEC_GSMFR else if(strcmp(codec, "gsmfr") == 0) { tempDecoder.codec = kDecoderGSMFR; tempDecoder.fs = 8000; } #endif #ifdef CODEC_GSMEFR else if(strcmp(codec, "gsmefr") == 0) { tempDecoder.codec = NETEQ_CODEC_GSMEFR; tempDecoder.fs = 8000; } #endif #ifdef CODEC_AMR else if(strcmp(codec, "amr") == 0) { tempDecoder.codec = kDecoderAMR; tempDecoder.fs = 8000; } #endif #ifdef CODEC_AMRWB else if(strcmp(codec, "amrwb") == 0) { tempDecoder.codec = kDecoderAMRWB; tempDecoder.fs = 16000; } #endif #ifdef CODEC_DVI4 else if(strcmp(codec, "dvi4") == 0) { tempDecoder.codec = NETEQ_CODEC_DVI4; tempDecoder.fs = 8000; } #endif #ifdef CODEC_SPEEX_8 else if(strcmp(codec, "speex8") == 0) { tempDecoder.codec = kDecoderSPEEX_8; tempDecoder.fs = 8000; } #endif #ifdef CODEC_SPEEX_16 else if(strcmp(codec, "speex16") == 0) { tempDecoder.codec = kDecoderSPEEX_16; tempDecoder.fs = 16000; } #endif #ifdef CODEC_SILK_NB else if(strcmp(codec, "silk8") == 0) { tempDecoder.codec = NETEQ_CODEC_SILK_8; tempDecoder.fs = 8000; } #endif #ifdef CODEC_SILK_WB else if(strcmp(codec, "silk12") == 0) { tempDecoder.codec = NETEQ_CODEC_SILK_12; tempDecoder.fs = 16000; } else if(strcmp(codec, "silk16") == 0) { tempDecoder.codec = NETEQ_CODEC_SILK_16; tempDecoder.fs = 16000; } #endif #ifdef CODEC_SILK_SWB else if(strcmp(codec, "silk24") == 0) { tempDecoder.codec = NETEQ_CODEC_SILK_24; tempDecoder.fs = 32000; } #endif #ifdef CODEC_MELPE else if(strcmp(codec, "melpe") == 0) { tempDecoder.codec = NETEQ_CODEC_MELPE; tempDecoder.fs = 8000; } #endif #ifdef CODEC_PCM16B else if(strcmp(codec, "pcm16b") == 0) { tempDecoder.codec = kDecoderPCM16B; tempDecoder.fs = 8000; } #endif #ifdef CODEC_PCM16B_WB else if(strcmp(codec, "pcm16b_wb") == 0) { tempDecoder.codec = kDecoderPCM16Bwb; tempDecoder.fs = 16000; } #endif #ifdef CODEC_PCM16B_32KHZ else if(strcmp(codec, "pcm16b_swb32khz") == 0) { tempDecoder.codec = kDecoderPCM16Bswb32kHz; tempDecoder.fs = 32000; } #endif #ifdef CODEC_PCM16B_48KHZ else if(strcmp(codec, "pcm16b_swb48khz") == 0) { tempDecoder.codec = kDecoderPCM16Bswb48kHz; tempDecoder.fs = 48000; } #endif #ifdef CODEC_CNGCODEC8 else if(strcmp(codec, "cn") == 0) { tempDecoder.codec = kDecoderCNG; tempDecoder.fs = 8000; } #endif #ifdef CODEC_CNGCODEC16 else if(strcmp(codec, "cn_wb") == 0) { tempDecoder.codec = kDecoderCNG; tempDecoder.fs = 16000; } #endif #ifdef CODEC_CNGCODEC32 else if(strcmp(codec, "cn_swb32") == 0) { tempDecoder.codec = kDecoderCNG; tempDecoder.fs = 32000; } #endif #ifdef CODEC_CNGCODEC48 else if(strcmp(codec, "cn_swb48") == 0) { tempDecoder.codec = kDecoderCNG; tempDecoder.fs = 48000; } #endif #ifdef CODEC_ATEVENT_DECODE else if(strcmp(codec, "avt") == 0) { tempDecoder.codec = kDecoderAVT; tempDecoder.fs = 8000; } #endif #ifdef CODEC_RED else if(strcmp(codec, "red") == 0) { tempDecoder.codec = kDecoderRED; tempDecoder.fs = 8000; } #endif else if(isalpha(codec[0])) { printf("Unsupported codec %s\n", codec); // read next line and continue while loop n = fscanf(ptypeFile, "%s %i\n", codec, &pt); continue; } else { // name is not recognized, and does not start with a letter // hence, it is commented out // read next line and continue while loop n = fscanf(ptypeFile, "%s %i\n", codec, &pt); continue; } // handle stereo if (tempDecoder.codec == kDecoderCNG) { // always set stereo mode for CNG, even if it is not marked at stereo tempDecoder.stereo = stereoModeFrame; } else if(isStereo) { switch(tempDecoder.codec) { // sample based codecs case kDecoderPCMu: case kDecoderPCMa: case kDecoderG722: { // 1 octet per sample tempDecoder.stereo = stereoModeSample1; break; } case kDecoderPCM16B: case kDecoderPCM16Bwb: case kDecoderPCM16Bswb32kHz: case kDecoderPCM16Bswb48kHz: { // 2 octets per sample tempDecoder.stereo = stereoModeSample2; break; } // fixed-rate frame codecs // case kDecoderG729: // case NETEQ_CODEC_G729D: // case NETEQ_CODEC_G729E: // case kDecoderG722_1_16: // case kDecoderG722_1_24: // case kDecoderG722_1_32: // case kDecoderG722_1C_24: // case kDecoderG722_1C_32: // case kDecoderG722_1C_48: // case NETEQ_CODEC_MELPE: // { // tempDecoder.stereo = stereoModeFrame; // break; // } default: { printf("Cannot use codec %s as stereo codec\n", codec); exit(0); } } } if (pt > 127) { printf("Payload type must be less than 128\n"); exit(0); } // insert into codecs map (*decoders)[static_cast(pt)] = tempDecoder; } n = fscanf(ptypeFile, "%s %i\n", codec, &pt); } // end while } bool changeStereoMode(NETEQTEST_RTPpacket & rtp, std::map & decoders, enum stereoModes *stereoMode) { if (decoders.count(rtp.payloadType()) > 0 && decoders[rtp.payloadType()].codec != kDecoderRED && decoders[rtp.payloadType()].codec != kDecoderAVT && decoders[rtp.payloadType()].codec != kDecoderCNG ) { if (decoders[rtp.payloadType()].stereo != *stereoMode) { *stereoMode = decoders[rtp.payloadType()].stereo; return true; // stereo mode did change } } return false; // stereo mode did not change } int populateUsedCodec(std::map* decoders, enum WebRtcNetEQDecoder *usedCodec) { int numCodecs = 0; std::map::iterator it; it = decoders->begin(); for (int i = 0; i < static_cast(decoders->size()); i++, it++) { usedCodec[numCodecs] = (*it).second.codec; numCodecs++; } return numCodecs; } void createAndInsertDecoders (NETEQTEST_NetEQClass *neteq, std::map* decoders, int channelNumber) { std::map::iterator it; for (it = decoders->begin(); it != decoders->end(); it++) { if (channelNumber == 0 || ((*it).second.stereo > stereoModeMono )) { // create decoder instance WebRtc_UWord8 pt = static_cast( (*it).first ); NETEQTEST_Decoder **dec = &((*it).second.decoder[channelNumber]); enum WebRtcNetEQDecoder type = (*it).second.codec; switch (type) { #ifdef CODEC_G711 case kDecoderPCMu: *dec = new decoder_PCMU( pt ); break; case kDecoderPCMa: *dec = new decoder_PCMA( pt ); break; #endif #ifdef CODEC_IPCMU case kDecoderEG711u: *dec = new decoder_IPCMU( pt ); break; #endif #ifdef CODEC_IPCMA case kDecoderEG711a: *dec = new decoder_IPCMA( pt ); break; #endif #ifdef CODEC_IPCMWB case kDecoderIPCMwb: *dec = new decoder_IPCMWB( pt ); break; #endif #ifdef CODEC_ILBC case kDecoderILBC: *dec = new decoder_ILBC( pt ); break; #endif #ifdef CODEC_ISAC case kDecoderISAC: *dec = new decoder_iSAC( pt ); break; #endif #ifdef CODEC_ISAC_SWB case kDecoderISACswb: *dec = new decoder_iSACSWB( pt ); break; #endif #ifdef CODEC_G729 case kDecoderG729: *dec = new decoder_G729( pt ); break; case NETEQ_CODEC_G729D: printf("Error: G729D not supported\n"); break; #endif #ifdef CODEC_G729E case NETEQ_CODEC_G729E: *dec = new decoder_G729E( pt ); break; #endif #ifdef CODEC_G729_1 case kDecoderG729_1: *dec = new decoder_G729_1( pt ); break; #endif #ifdef CODEC_G723 case NETEQ_CODEC_G723: *dec = new decoder_G723( pt ); break; #endif #ifdef CODEC_PCM16B case kDecoderPCM16B: *dec = new decoder_PCM16B_NB( pt ); break; #endif #ifdef CODEC_PCM16B_WB case kDecoderPCM16Bwb: *dec = new decoder_PCM16B_WB( pt ); break; #endif #ifdef CODEC_PCM16B_32KHZ case kDecoderPCM16Bswb32kHz: *dec = new decoder_PCM16B_SWB32( pt ); break; #endif #ifdef CODEC_PCM16B_48KHZ case kDecoderPCM16Bswb48kHz: *dec = new decoder_PCM16B_SWB48( pt ); break; #endif #ifdef CODEC_DVI4 case NETEQ_CODEC_DVI4: *dec = new decoder_DVI4( pt ); break; #endif #ifdef CODEC_G722 case kDecoderG722: *dec = new decoder_G722( pt ); break; #endif #ifdef CODEC_G722_1_16 case kDecoderG722_1_16: *dec = new decoder_G722_1_16( pt ); break; #endif #ifdef CODEC_G722_1_24 case kDecoderG722_1_24: *dec = new decoder_G722_1_24( pt ); break; #endif #ifdef CODEC_G722_1_32 case kDecoderG722_1_32: *dec = new decoder_G722_1_32( pt ); break; #endif #ifdef CODEC_G722_1C_24 case kDecoderG722_1C_24: *dec = new decoder_G722_1C_24( pt ); break; #endif #ifdef CODEC_G722_1C_32 case kDecoderG722_1C_32: *dec = new decoder_G722_1C_32( pt ); break; #endif #ifdef CODEC_G722_1C_48 case kDecoderG722_1C_48: *dec = new decoder_G722_1C_48( pt ); break; #endif #ifdef CODEC_AMR case kDecoderAMR: *dec = new decoder_AMR( pt ); break; #endif #ifdef CODEC_AMRWB case kDecoderAMRWB: *dec = new decoder_AMRWB( pt ); break; #endif #ifdef CODEC_GSMFR case kDecoderGSMFR: *dec = new decoder_GSMFR( pt ); break; #endif #ifdef CODEC_GSMEFR case NETEQ_CODEC_GSMEFR: *dec = new decoder_GSMEFR( pt ); break; #endif #ifdef CODEC_G726 case kDecoderG726_16: *dec = new decoder_G726_16( pt ); break; case kDecoderG726_24: *dec = new decoder_G726_24( pt ); break; case kDecoderG726_32: *dec = new decoder_G726_32( pt ); break; case kDecoderG726_40: *dec = new decoder_G726_40( pt ); break; #endif #ifdef CODEC_MELPE case NETEQ_CODEC_MELPE: #if (_MSC_VER >= 1400) && !defined(_WIN64) // only for Visual 2005 or later, and not for x64 *dec = new decoder_MELPE( pt ); #endif break; #endif #ifdef CODEC_SPEEX_8 case kDecoderSPEEX_8: *dec = new decoder_SPEEX( pt, 8000 ); break; #endif #ifdef CODEC_SPEEX_16 case kDecoderSPEEX_16: *dec = new decoder_SPEEX( pt, 16000 ); break; #endif #ifdef CODEC_RED case kDecoderRED: *dec = new decoder_RED( pt ); break; #endif #ifdef CODEC_ATEVENT_DECODE case kDecoderAVT: *dec = new decoder_AVT( pt ); break; #endif #if (defined(CODEC_CNGCODEC8) || defined(CODEC_CNGCODEC16) || \ defined(CODEC_CNGCODEC32) || defined(CODEC_CNGCODEC48)) case kDecoderCNG: *dec = new decoder_CNG( pt, static_cast((*it).second.fs) ); break; #endif #ifdef CODEC_ISACLC case NETEQ_CODEC_ISACLC: *dec = new decoder_iSACLC( pt ); break; #endif #ifdef CODEC_SILK_NB case NETEQ_CODEC_SILK_8: #if (_MSC_VER >= 1400) && !defined(_WIN64) // only for Visual 2005 or later, and not for x64 *dec = new decoder_SILK8( pt ); #endif break; #endif #ifdef CODEC_SILK_WB case NETEQ_CODEC_SILK_12: #if (_MSC_VER >= 1400) && !defined(_WIN64) // only for Visual 2005 or later, and not for x64 *dec = new decoder_SILK12( pt ); #endif break; #endif #ifdef CODEC_SILK_WB case NETEQ_CODEC_SILK_16: #if (_MSC_VER >= 1400) && !defined(_WIN64) // only for Visual 2005 or later, and not for x64 *dec = new decoder_SILK16( pt ); #endif break; #endif #ifdef CODEC_SILK_SWB case NETEQ_CODEC_SILK_24: #if (_MSC_VER >= 1400) && !defined(_WIN64) // only for Visual 2005 or later, and not for x64 *dec = new decoder_SILK24( pt ); #endif break; #endif default: printf("Unknown codec type encountered in createAndInsertDecoders\n"); exit(0); } // insert into codec DB if (*dec) { (*dec)->loadToNetEQ(*neteq); } } } } void free_coders(std::map & decoders) { std::map::iterator it; for (it = decoders.begin(); it != decoders.end(); it++) { if ((*it).second.decoder[0]) { delete (*it).second.decoder[0]; } if ((*it).second.decoder[1]) { delete (*it).second.decoder[1]; } } } #include "pcm16b.h" #include "g711_interface.h" #include "isac.h" int doAPItest() { char version[20]; void *inst; enum WebRtcNetEQDecoder usedCodec; int NetEqBufferMaxPackets, BufferSizeInBytes; WebRtcNetEQ_CodecDef codecInst; WebRtcNetEQ_RTCPStat RTCPstat; WebRtc_UWord32 timestamp; int memorySize; int ok; printf("API-test:\n"); /* get the version string */ WebRtcNetEQ_GetVersion(version); printf("NetEq version: %s\n\n", version); /* test that API functions return -1 if instance is NULL */ #define CHECK_MINUS_ONE(x) {int errCode = x; if((errCode)!=-1){printf("\n API test failed at line %d: %s. Function did not return -1 as expected\n",__LINE__,#x); return(-1);}} //#define RESET_ERROR(x) ((MainInst_t*) x)->ErrorCode = 0; inst = NULL; CHECK_MINUS_ONE(WebRtcNetEQ_GetErrorCode(inst)) CHECK_MINUS_ONE(WebRtcNetEQ_Assign(&inst, NULL)) // printf("WARNING: Test of WebRtcNetEQ_Assign() is disabled due to a bug.\n"); usedCodec=kDecoderPCMu; CHECK_MINUS_ONE(WebRtcNetEQ_GetRecommendedBufferSize(inst, &usedCodec, 1, kTCPLargeJitter, &NetEqBufferMaxPackets, &BufferSizeInBytes)) CHECK_MINUS_ONE(WebRtcNetEQ_AssignBuffer(inst, NetEqBufferMaxPackets, NetEqPacketBuffer, BufferSizeInBytes)) CHECK_MINUS_ONE(WebRtcNetEQ_Init(inst, 8000)) CHECK_MINUS_ONE(WebRtcNetEQ_SetAVTPlayout(inst, 0)) CHECK_MINUS_ONE(WebRtcNetEQ_SetExtraDelay(inst, 17)) CHECK_MINUS_ONE(WebRtcNetEQ_SetPlayoutMode(inst, kPlayoutOn)) CHECK_MINUS_ONE(WebRtcNetEQ_CodecDbReset(inst)) CHECK_MINUS_ONE(WebRtcNetEQ_CodecDbAdd(inst, &codecInst)) CHECK_MINUS_ONE(WebRtcNetEQ_CodecDbRemove(inst, usedCodec)) WebRtc_Word16 temp1, temp2; CHECK_MINUS_ONE(WebRtcNetEQ_CodecDbGetSizeInfo(inst, &temp1, &temp2)) CHECK_MINUS_ONE(WebRtcNetEQ_CodecDbGetCodecInfo(inst, 0, &usedCodec)) CHECK_MINUS_ONE(WebRtcNetEQ_RecIn(inst, &temp1, 17, 4711)) CHECK_MINUS_ONE(WebRtcNetEQ_RecOut(inst, &temp1, &temp2)) CHECK_MINUS_ONE(WebRtcNetEQ_GetRTCPStats(inst, &RTCPstat)); // error here!!! CHECK_MINUS_ONE(WebRtcNetEQ_GetSpeechTimeStamp(inst, ×tamp)) WebRtcNetEQOutputType temptype; CHECK_MINUS_ONE(WebRtcNetEQ_GetSpeechOutputType(inst, &temptype)) WebRtc_UWord8 tempFlags; WebRtc_UWord16 utemp1, utemp2; CHECK_MINUS_ONE(WebRtcNetEQ_VQmonRecOutStatistics(inst, &utemp1, &utemp2, &tempFlags)) CHECK_MINUS_ONE(WebRtcNetEQ_VQmonGetRxStatistics(inst, &utemp1, &utemp2)) WebRtcNetEQ_AssignSize(&memorySize); CHECK_ZERO(WebRtcNetEQ_Assign(&inst, malloc(memorySize))) /* init with wrong sample frequency */ CHECK_MINUS_ONE(WebRtcNetEQ_Init(inst, 17)) /* init with correct fs */ CHECK_ZERO(WebRtcNetEQ_Init(inst, 8000)) /* GetRecommendedBufferSize with wrong codec */ usedCodec=kDecoderReservedStart; ok = WebRtcNetEQ_GetRecommendedBufferSize(inst, &usedCodec, 1, kTCPLargeJitter , &NetEqBufferMaxPackets, &BufferSizeInBytes); if((ok!=-1) || ((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_UNKNOWN_CODEC))){ printf("WebRtcNetEQ_GetRecommendedBufferSize() did not return proper error code for wrong codec.\n"); printf("return value = %d; error code = %d\n", ok, WebRtcNetEQ_GetErrorCode(inst)); } //RESET_ERROR(inst) /* GetRecommendedBufferSize with wrong network type */ usedCodec = kDecoderPCMu; ok=WebRtcNetEQ_GetRecommendedBufferSize(inst, &usedCodec, 1, (enum WebRtcNetEQNetworkType) 4711 , &NetEqBufferMaxPackets, &BufferSizeInBytes); if ((ok!=-1) || ((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-FAULTY_NETWORK_TYPE))) { printf("WebRtcNetEQ_GetRecommendedBufferSize() did not return proper error code for wrong network type.\n"); printf("return value = %d; error code = %d\n", ok, WebRtcNetEQ_GetErrorCode(inst)); //RESET_ERROR(inst) } CHECK_ZERO(WebRtcNetEQ_GetRecommendedBufferSize(inst, &usedCodec, 1, kTCPLargeJitter , &NetEqBufferMaxPackets, &BufferSizeInBytes)) /* try to do RecIn before assigning the packet buffer */ /* makeRTPheader(rtp_data, NETEQ_CODEC_AVT_PT, 17,4711, 1235412312); makeDTMFpayload(&rtp_data[12], 1, 1, 10, 100); ok = WebRtcNetEQ_RecIn(inst, (short *) rtp_data, 12+4, 4711); printf("return value = %d; error code = %d\n", ok, WebRtcNetEQ_GetErrorCode(inst));*/ /* check all limits of WebRtcNetEQ_AssignBuffer */ ok=WebRtcNetEQ_AssignBuffer(inst, NetEqBufferMaxPackets, NetEqPacketBuffer, 149<<1); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-PBUFFER_INIT_ERROR))) { printf("WebRtcNetEQ_AssignBuffer() did not return proper error code for wrong sizeinbytes\n"); } ok=WebRtcNetEQ_AssignBuffer(inst, NetEqBufferMaxPackets, NULL, BufferSizeInBytes); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-PBUFFER_INIT_ERROR))) { printf("WebRtcNetEQ_AssignBuffer() did not return proper error code for NULL memory pointer\n"); } ok=WebRtcNetEQ_AssignBuffer(inst, 1, NetEqPacketBuffer, BufferSizeInBytes); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-PBUFFER_INIT_ERROR))) { printf("WebRtcNetEQ_AssignBuffer() did not return proper error code for wrong MaxNoOfPackets\n"); } ok=WebRtcNetEQ_AssignBuffer(inst, 601, NetEqPacketBuffer, BufferSizeInBytes); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-PBUFFER_INIT_ERROR))) { printf("WebRtcNetEQ_AssignBuffer() did not return proper error code for wrong MaxNoOfPackets\n"); } /* do correct assignbuffer */ CHECK_ZERO(WebRtcNetEQ_AssignBuffer(inst, NetEqBufferMaxPackets, NetEqPacketBuffer, BufferSizeInBytes)) ok=WebRtcNetEQ_SetExtraDelay(inst, -1); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-FAULTY_DELAYVALUE))) { printf("WebRtcNetEQ_SetExtraDelay() did not return proper error code for too small delay\n"); } ok=WebRtcNetEQ_SetExtraDelay(inst, 1001); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-FAULTY_DELAYVALUE))) { printf("WebRtcNetEQ_SetExtraDelay() did not return proper error code for too large delay\n"); } ok=WebRtcNetEQ_SetPlayoutMode(inst,(enum WebRtcNetEQPlayoutMode) 4711); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-FAULTY_PLAYOUTMODE))) { printf("WebRtcNetEQ_SetPlayoutMode() did not return proper error code for wrong mode\n"); } /* number of codecs should return zero before adding any codecs */ WebRtcNetEQ_CodecDbGetSizeInfo(inst, &temp1, &temp2); if(temp1!=0) printf("WebRtcNetEQ_CodecDbGetSizeInfo() return non-zero number of codecs in DB before adding any codecs\n"); /* get info from empty database */ ok=WebRtcNetEQ_CodecDbGetCodecInfo(inst, 17, &usedCodec); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_NOT_EXIST1))) { printf("WebRtcNetEQ_CodecDbGetCodecInfo() did not return proper error code for out-of-range entry number\n"); } /* remove codec from empty database */ ok=WebRtcNetEQ_CodecDbRemove(inst,kDecoderPCMa); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_NOT_EXIST4))) { printf("WebRtcNetEQ_CodecDbRemove() did not return proper error code when removing codec that has not been added\n"); } /* add codec with unsupported fs */ #ifdef CODEC_PCM16B #ifndef NETEQ_48KHZ_WIDEBAND SET_CODEC_PAR(codecInst,kDecoderPCM16Bswb48kHz,77,NULL,48000); SET_PCM16B_SWB48_FUNCTIONS(codecInst); ok=WebRtcNetEQ_CodecDbAdd(inst, &codecInst); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_UNSUPPORTED_FS))) { printf("WebRtcNetEQ_CodecDbAdd() did not return proper error code when adding codec with unsupported sample freq\n"); } #else printf("Could not test adding codec with unsupported sample frequency since NetEQ is compiled with 48kHz support.\n"); #endif #else printf("Could not test adding codec with unsupported sample frequency since NetEQ is compiled without PCM16B support.\n"); #endif /* add two codecs with identical payload types */ SET_CODEC_PAR(codecInst,kDecoderPCMa,17,NULL,8000); SET_PCMA_FUNCTIONS(codecInst); CHECK_ZERO(WebRtcNetEQ_CodecDbAdd(inst, &codecInst)) SET_CODEC_PAR(codecInst,kDecoderPCMu,17,NULL,8000); SET_PCMU_FUNCTIONS(codecInst); ok=WebRtcNetEQ_CodecDbAdd(inst, &codecInst); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_PAYLOAD_TAKEN))) { printf("WebRtcNetEQ_CodecDbAdd() did not return proper error code when adding two codecs with identical payload types\n"); } /* try adding several payload types for CNG codecs */ SET_CODEC_PAR(codecInst,kDecoderCNG,105,NULL,16000); SET_CNG_FUNCTIONS(codecInst); CHECK_ZERO(WebRtcNetEQ_CodecDbAdd(inst, &codecInst)) SET_CODEC_PAR(codecInst,kDecoderCNG,13,NULL,8000); SET_CNG_FUNCTIONS(codecInst); CHECK_ZERO(WebRtcNetEQ_CodecDbAdd(inst, &codecInst)) /* try adding a speech codec over a CNG codec */ SET_CODEC_PAR(codecInst,kDecoderISAC,105,NULL,16000); /* same as WB CNG above */ SET_ISAC_FUNCTIONS(codecInst); ok=WebRtcNetEQ_CodecDbAdd(inst, &codecInst); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_PAYLOAD_TAKEN))) { printf("WebRtcNetEQ_CodecDbAdd() did not return proper error code when adding a speech codec over a CNG codec\n"); } /* try adding a CNG codec over a speech codec */ SET_CODEC_PAR(codecInst,kDecoderCNG,17,NULL,32000); /* same as PCMU above */ SET_CNG_FUNCTIONS(codecInst); ok=WebRtcNetEQ_CodecDbAdd(inst, &codecInst); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_PAYLOAD_TAKEN))) { printf("WebRtcNetEQ_CodecDbAdd() did not return proper error code when adding a speech codec over a CNG codec\n"); } /* remove codec out of range */ ok=WebRtcNetEQ_CodecDbRemove(inst,kDecoderReservedStart); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_UNSUPPORTED_CODEC))) { printf("WebRtcNetEQ_CodecDbRemove() did not return proper error code when removing codec that is out of range\n"); } ok=WebRtcNetEQ_CodecDbRemove(inst,kDecoderReservedEnd); if((ok!=-1)||((ok==-1)&&(WebRtcNetEQ_GetErrorCode(inst)!=-CODEC_DB_UNSUPPORTED_CODEC))) { printf("WebRtcNetEQ_CodecDbRemove() did not return proper error code when removing codec that is out of range\n"); } /*SET_CODEC_PAR(codecInst,kDecoderEG711a,NETEQ_CODEC_EG711A_PT,NetEqiPCMAState,8000); SET_IPCMA_FUNCTIONS(codecInst); CHECK_ZERO(WebRtcNetEQ_CodecDbAdd(inst, &codecInst)) */ free(inst); return(0); }