/* * codec_silk.h - A asterisk translation wrapper for the Skype SILK Codec * * See http://www.asterisk.org for more information about * the Asterisk project. * * See http://developer.skype.com/silk for more information * about the SILK codec, including downloads. * * Copyright (C) 2012 Todd Mortimer * * Todd Mortimer * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. */ #include "asterisk.h" ASTERISK_FILE_VERSION(__FILE__, "$Revision: $") #include "asterisk/translate.h" #include "asterisk/module.h" #include "asterisk/format.h" #include "asterisk/utils.h" #include "asterisk/slin.h" #include "asterisk/silk.h" #include "silk/interface/SKP_Silk_SDK_API.h" #include "ex_silk.h" #include "asterisk/logger.h" #define SILK_FRAME_LENGTH_MS 20 #define SILK_MAX_BYTES_PER_FRAME 1024 /* apparently.. */ #define SILK_MAX_SAMPLES_PER_FRAME 960 #define SILK_MAX_INTERNAL_FRAMES 5 #define SILK_MAX_LBRR_DELAY 2 #define SILK_BUFFER_SIZE_BYTES 5120 /* MAX_BYTES * MAX_FRAMES */ #define SLIN_BUFFER_SIZE_BYTES 9600 /* 100 ms @ 48KHZ * 2 bytes */ SKP_int32 encSizeBytes; SKP_int32 decSizeBytes; /* default values */ SKP_int32 API_sampleRate = 8000; SKP_int32 maxInternalSampleRate = 8000; SKP_int32 packetSize_ms = SILK_FRAME_LENGTH_MS; SKP_int32 packetLossPercentage = 0; SKP_int32 useInBandFEC = 0; SKP_int32 useDTX = 0; SKP_int32 complexity = 2; SKP_int32 bitRate = 10000; /* translator registration indicators */ int silk8_reg = 0, silk12_reg = 0, silk16_reg = 0, silk24_reg = 0; struct silk_coder_pvt { void* psEnc; SKP_SILK_SDK_EncControlStruct encControl; void* psDec; SKP_SILK_SDK_DecControlStruct decControl; int16_t buf[SLIN_BUFFER_SIZE_BYTES / 2]; }; /************ CONSTRUCTORS ************/ static int lintosilk_new(struct ast_trans_pvt *pvt) { SKP_int32 ret; int silk_samplerate = 8000; int slin_samplerate = 8000; struct silk_coder_pvt *coder = pvt->pvt; char format_string[100]; char* pointer = format_string; char* format; struct ast_format format_struct; struct ast_format* format_def = &format_struct; int attr_dtx = 0, attr_fec = 0, attr_pktloss_pct = 0, attr_max_bitrate = 0, attr_samp_rate = 0; /* init the silk encoder */ coder->psEnc = malloc(encSizeBytes); ret = SKP_Silk_SDK_InitEncoder(coder->psEnc, &coder->encControl); if (ret) { ast_log(LOG_WARNING, "SKP_Silk_SDK_InitEncoder returned %d\n", ret); } /* Get the names of the silk codecs */ ast_getformatname_multiple_byid(format_string, sizeof(format_string), AST_FORMAT_SILK); /* The destination sample rate is set explicitly */ ret = ast_format_get_value(&pvt->explicit_dst, SILK_ATTR_KEY_SAMP_RATE, &attr_samp_rate); switch(attr_samp_rate){ case SILK_ATTR_VAL_SAMP_8KHZ: silk_samplerate = 8000; break; case SILK_ATTR_VAL_SAMP_12KHZ: silk_samplerate = 12000; break; case SILK_ATTR_VAL_SAMP_16KHZ: silk_samplerate = 16000; break; case SILK_ATTR_VAL_SAMP_24KHZ: silk_samplerate = 24000; break; } /* get the source rate */ switch(pvt->t->src_format.id){ case AST_FORMAT_SLINEAR: slin_samplerate = 8000; break; case AST_FORMAT_SLINEAR12: slin_samplerate = 12000; break; case AST_FORMAT_SLINEAR16: slin_samplerate = 16000; break; case AST_FORMAT_SLINEAR24: slin_samplerate = 24000; break; default: slin_samplerate = 8000; break; } /* SILK Docs say that internal sampling rate > API Sampling rate is not allowed */ if(slin_samplerate < silk_samplerate){ silk_samplerate = slin_samplerate; } /* set the parameters for the coder */ coder->encControl.API_sampleRate = (SKP_int32)slin_samplerate; /* lin input rate */ coder->encControl.maxInternalSampleRate = (SKP_int32)silk_samplerate; /* silk output rate */ coder->encControl.packetSize = (packetSize_ms * slin_samplerate) / 1000; coder->encControl.complexity = complexity; while ((format = strsep(&pointer, "(|)"))){ if(strlen(format) > 0){ if((format_def = ast_getformatbyname(format, format_def))){ /* now pull out the format attributes */ ret = ast_format_get_value(format_def, SILK_ATTR_KEY_DTX, &attr_dtx); coder->encControl.useDTX = !ret ? (SKP_int32)attr_dtx : useDTX; ret = ast_format_get_value(format_def, SILK_ATTR_KEY_FEC, &attr_fec); coder->encControl.useInBandFEC = !ret ? (SKP_int32)attr_fec : useInBandFEC; ret = ast_format_get_value(format_def, SILK_ATTR_KEY_PACKETLOSS_PERCENTAGE, &attr_pktloss_pct); coder->encControl.packetLossPercentage = !ret ? (SKP_int32)attr_pktloss_pct : packetLossPercentage; ret = ast_format_get_value(format_def, SILK_ATTR_KEY_MAX_BITRATE, &attr_max_bitrate); coder->encControl.bitRate = !ret ? (SKP_int32)attr_max_bitrate : bitRate; break; } } } return 0; } static int new_silktolin(struct ast_trans_pvt *pvt, int samplerate) { SKP_int32 ret; struct silk_coder_pvt *coder = pvt->pvt; /* init the silk decoder */ coder->psDec = malloc(decSizeBytes); coder->decControl.API_sampleRate = (SKP_int32)samplerate; coder->decControl.framesPerPacket = 1; /* reset decoder */ ret = SKP_Silk_SDK_InitDecoder(coder->psDec); if (ret) { ast_log(LOG_WARNING, "SKP_Silk_SDK_InitDecoder returned %d\n", ret); } return 0; } static int silk8tolin_new(struct ast_trans_pvt *pvt) { return new_silktolin(pvt, 8000); } static int silk12tolin_new(struct ast_trans_pvt *pvt) { return new_silktolin(pvt, 12000); } static int silk16tolin_new(struct ast_trans_pvt *pvt) { return new_silktolin(pvt, 16000); } static int silk24tolin_new(struct ast_trans_pvt *pvt) { return new_silktolin(pvt, 24000); } /************ TRANSLATOR FUNCTIONS ************/ /* Just copy in the samples for later encoding */ static int lintosilk_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { struct silk_coder_pvt *coder = pvt->pvt; /* just add the frames to the buffer */ memcpy(coder->buf + pvt->samples, f->data.ptr, f->datalen); pvt->samples += f->samples; return 0; } /* And decode everything we can in the buffer */ static struct ast_frame *lintosilk_frameout(struct ast_trans_pvt *pvt) { struct silk_coder_pvt *coder = pvt->pvt; SKP_int ret = 0; SKP_int16 nBytesOut = 0; int datalen = 0; int samples = 0; int numPackets = 0; struct ast_frame *f; /* we can only work on multiples of a 10 ms sample * and no more than encControl->packetSize. * So we shove in packetSize samples repeatedly until * we are out */ /* We only do stuff if we have more than packetSize */ if (pvt->samples < coder->encControl.packetSize) { return NULL; } while (pvt->samples >= coder->encControl.packetSize) { nBytesOut = SILK_BUFFER_SIZE_BYTES - datalen; ret = SKP_Silk_SDK_Encode(coder->psEnc, &coder->encControl, (SKP_int16*)(coder->buf + samples), coder->encControl.packetSize, (SKP_uint8*)(pvt->outbuf.ui8 + datalen), &nBytesOut); if (ret) { ast_log(LOG_WARNING, "Silk_Encode returned %d\n", ret); } /* nBytesOut now holds the number of bytes encoded */ datalen += nBytesOut; samples += coder->encControl.packetSize; pvt->samples -= coder->encControl.packetSize; if(nBytesOut > 0){ /* if stuff came out, we have encoded a packet */ numPackets++; } } /* Move the remaining buffer stuff down */ if (pvt->samples) { memmove(coder->buf, coder->buf + samples, pvt->samples *2); } if(datalen == 0){ /* we shoved a bunch of samples in, but got no packets * out. We return NULL to the caller, like * if we could not encode anything */ return NULL; } /* we build the frame ourselves because we have an explicit dest */ f = &pvt->f; f->samples = coder->encControl.packetSize * numPackets; f->datalen = datalen; f->frametype = AST_FRAME_VOICE; ast_format_copy(&f->subclass.format, &pvt->explicit_dst); f->mallocd = 0; f->offset = AST_FRIENDLY_OFFSET; f->src = pvt->t->name; f->data.ptr = pvt->outbuf.c; return ast_frisolate(f); } static int silktolin_framein(struct ast_trans_pvt *pvt, struct ast_frame *f) { struct silk_coder_pvt *coder = pvt->pvt; SKP_int ret = 0; SKP_int16 numSamplesOut = 0; SKP_int16 totalSamplesOut = 0; SKP_int16 *dst = (SKP_int16*)pvt->outbuf.i16; SKP_uint8 *src = (SKP_uint8*)f->data.ptr; SKP_int srcBytes = (SKP_int)f->datalen; SKP_int lostFlag = 0; /* assume no loss for now */ int decodeIterations = SILK_MAX_INTERNAL_FRAMES; /* int i = 0; struct ast_frame *nf = NULL; SKP_uint8 FECPayload[SILK_MAX_BYTES_PER_FRAME * SILK_MAX_INTERNAL_FRAMES]; SKP_int16 FECBytes = 0; */ /* If we indicate native PLC in the translator for silktolin * then we may get passed an empty frame (f->datalen = 0), indicating * that we should fill in some PLC data. So when we get f->datalen=0 * we should check to see if we have any next frames (check * f->frame_list.next ?) and look inside them with * SKP_Silk_SDK_search_for_LBRR(). We can search up to 2 frames ahead. * If we find LBRR data, then we should pass that data to the * decoder. If we do not find any LBRR data, then we should * just pass lostFlag=1 to the decoder for normal PLC */ if(srcBytes == 0) { /* Native PLC */ lostFlag = 1; /* search for LBRR data */ /* FIXME: Actually do the lookahead, which I guess will require a jitterbuffer? */ /* if (f->frame_list && f->frame_list.next) { nf = f->frame_list.next; } for(i = 0; i < SILK_MAX_LBRR_DELAY; ++i){ if(nf) { if(nf->datalen) { SKP_Silk_SDK_search_for_LBRR((SKP_uint8*)nf->data.ptr, nf->datalen, i+1, FECPayload, &FECBytes); if(FECBytes > 0){ src = FECPayload; srcBytes = FECBytes; lostFlag = 0; break; } } if (nf->frame_list && nf->frame_list.next) { nf = nf->frame_list.next; } } } */ } if(lostFlag) { /* set the decodeIterations for the do{}while() to be the * number of frames in the last decoded packet */ decodeIterations = coder->decControl.framesPerPacket; ast_log(LOG_NOTICE, "silktolin indicated lost packet - no LBRR"); } do { ret = SKP_Silk_SDK_Decode(coder->psDec, &coder->decControl, lostFlag, src, srcBytes, dst, &numSamplesOut); if(ret) { ast_log(LOG_NOTICE, "SKP_Silk_SDK_Decode returned %d\n", ret); } dst += numSamplesOut; totalSamplesOut += numSamplesOut; /* decrement the number of iterations remaining */ decodeIterations--; /* while we have more data and have not gone too far */ } while (coder->decControl.moreInternalDecoderFrames && decodeIterations > 0); /* okay, we've decoded everything we can */ pvt->samples = totalSamplesOut; pvt->datalen = totalSamplesOut * 2; return 0; } /************ DESTRUCTORS ************/ static void lintosilk_destroy(struct ast_trans_pvt *pvt) { struct silk_coder_pvt *coder = pvt->pvt; free(coder->psEnc); } static void silktolin_destroy(struct ast_trans_pvt *pvt) { struct silk_coder_pvt *coder = pvt->pvt; free(coder->psDec); } /************ TRANSLATOR DEFINITIONS ************/ static struct ast_translator silk8tolin = { .name = "silk8tolin", .newpvt = silk8tolin_new, .framein = silktolin_framein, .destroy = silktolin_destroy, .sample = silk8_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SLIN_BUFFER_SIZE_BYTES / 2, .buf_size = SLIN_BUFFER_SIZE_BYTES, .native_plc = 1 }; static struct ast_translator lintosilk8 = { .name = "lintosilk8", .newpvt = lintosilk_new, .framein = lintosilk_framein, .frameout = lintosilk_frameout, .destroy = lintosilk_destroy, .sample = slin8_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SILK_MAX_SAMPLES_PER_FRAME * SILK_MAX_INTERNAL_FRAMES, .buf_size = SILK_BUFFER_SIZE_BYTES }; static struct ast_translator silk12tolin = { .name = "silk12tolin", .newpvt = silk12tolin_new, .framein = silktolin_framein, .destroy = silktolin_destroy, .sample = silk12_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SLIN_BUFFER_SIZE_BYTES / 2, .buf_size = SLIN_BUFFER_SIZE_BYTES, .native_plc = 1 }; static struct ast_translator lintosilk12 = { .name = "lintosilk12", .newpvt = lintosilk_new, .framein = lintosilk_framein, .frameout = lintosilk_frameout, .destroy = lintosilk_destroy, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SILK_MAX_SAMPLES_PER_FRAME * SILK_MAX_INTERNAL_FRAMES, .buf_size = SILK_BUFFER_SIZE_BYTES }; static struct ast_translator silk16tolin = { .name = "silk16tolin", .newpvt = silk16tolin_new, .framein = silktolin_framein, .destroy = silktolin_destroy, .sample = silk16_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SLIN_BUFFER_SIZE_BYTES / 2, .buf_size = SLIN_BUFFER_SIZE_BYTES, .native_plc = 1 }; static struct ast_translator lintosilk16 = { .name = "lintosilk16", .newpvt = lintosilk_new, .framein = lintosilk_framein, .frameout = lintosilk_frameout, .destroy = lintosilk_destroy, .sample = slin16_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SILK_MAX_SAMPLES_PER_FRAME * SILK_MAX_INTERNAL_FRAMES, .buf_size = SILK_BUFFER_SIZE_BYTES }; static struct ast_translator silk24tolin = { .name = "silk24tolin", .newpvt = silk24tolin_new, .framein = silktolin_framein, .destroy = silktolin_destroy, .sample = silk24_sample, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SLIN_BUFFER_SIZE_BYTES / 2, .buf_size = SLIN_BUFFER_SIZE_BYTES, .native_plc = 1 }; static struct ast_translator lintosilk24 = { .name = "lintosilk24", .newpvt = lintosilk_new, .framein = lintosilk_framein, .frameout = lintosilk_frameout, .destroy = lintosilk_destroy, .desc_size = sizeof(struct silk_coder_pvt), .buffer_samples = SILK_MAX_SAMPLES_PER_FRAME * SILK_MAX_INTERNAL_FRAMES, .buf_size = SILK_BUFFER_SIZE_BYTES }; /************ MODULE LOAD / UNLOAD **************/ static int load_module(void) { SKP_int32 ret = 0;; int res = 0; char format_string[100]; char* format; char* pointer = format_string; struct ast_format format_struct; struct ast_format* format_def = &format_struct; int attr_samp_rate = 0; /* print the skype version */ ast_log(LOG_NOTICE, "SILK Version : %s\n", SKP_Silk_SDK_get_version()); /* get the encoder / decoder sizes */ ret = SKP_Silk_SDK_Get_Encoder_Size(&encSizeBytes); if (ret) { ast_log(LOG_WARNING, "SKP_Silk_SDK_Get_Encoder_size returned %d", ret); } ret = SKP_Silk_SDK_Get_Decoder_Size(&decSizeBytes); if (ret) { ast_log(LOG_WARNING, "SKP_Silk_SDK_Get_Decoder_size returned %d", ret); } /* Finish the setup of the encoders / decoders */ /* silk8 */ ast_format_set(&silk8tolin.src_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END); ast_format_set(&silk8tolin.dst_format, AST_FORMAT_SLINEAR,0); ast_format_set(&lintosilk8.src_format, AST_FORMAT_SLINEAR,0); ast_format_set(&lintosilk8.dst_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_8KHZ, AST_FORMAT_ATTR_END); /* silk12 */ ast_format_set(&silk12tolin.src_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ, AST_FORMAT_ATTR_END); ast_format_set(&silk12tolin.dst_format, AST_FORMAT_SLINEAR12,0); ast_format_set(&lintosilk12.src_format, AST_FORMAT_SLINEAR12,0); ast_format_set(&lintosilk12.dst_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_12KHZ, AST_FORMAT_ATTR_END); /* silk16 */ ast_format_set(&silk16tolin.src_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ, AST_FORMAT_ATTR_END); ast_format_set(&silk16tolin.dst_format, AST_FORMAT_SLINEAR16,0); ast_format_set(&lintosilk16.src_format, AST_FORMAT_SLINEAR16,0); ast_format_set(&lintosilk16.dst_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_16KHZ, AST_FORMAT_ATTR_END); /* silk24 */ ast_format_set(&silk24tolin.src_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ, AST_FORMAT_ATTR_END); ast_format_set(&silk24tolin.dst_format, AST_FORMAT_SLINEAR24,0); ast_format_set(&lintosilk24.src_format, AST_FORMAT_SLINEAR24,0); ast_format_set(&lintosilk24.dst_format, AST_FORMAT_SILK,1, SILK_ATTR_KEY_SAMP_RATE, SILK_ATTR_VAL_SAMP_24KHZ, AST_FORMAT_ATTR_END); /* Get the names of the silk codecs */ ast_getformatname_multiple_byid(format_string, sizeof(format_string), AST_FORMAT_SILK); ast_log(LOG_NOTICE, "Defined silk codecs are: %s\n", format_string); while ((format = strsep(&pointer, "(|)"))){ if(strlen(format) > 0){ if((format_def = ast_getformatbyname(format, format_def))){ /* now pull out the format attributes */ ret = ast_format_get_value(format_def, SILK_ATTR_KEY_SAMP_RATE, &attr_samp_rate); if(!ret) { switch (attr_samp_rate) { case SILK_ATTR_VAL_SAMP_8KHZ: res |= ast_register_translator(&silk8tolin); res |= ast_register_translator(&lintosilk8); silk8_reg = 1; break; case SILK_ATTR_VAL_SAMP_12KHZ: res |= ast_register_translator(&silk12tolin); res |= ast_register_translator(&lintosilk12); silk12_reg = 1; break; case SILK_ATTR_VAL_SAMP_16KHZ: res |= ast_register_translator(&silk16tolin); res |= ast_register_translator(&lintosilk16); silk16_reg = 1; break; case SILK_ATTR_VAL_SAMP_24KHZ: res |= ast_register_translator(&silk24tolin); res |= ast_register_translator(&lintosilk24); silk24_reg = 1; break; } } } } } /* register the encoder / decoder */ if(res){ return AST_MODULE_LOAD_FAILURE; } return AST_MODULE_LOAD_SUCCESS; } static int unload_module(void) { int res = 0; ast_log(LOG_NOTICE, "Silk Coder/Encoder unloading\n"); if(silk8_reg){ res |= ast_unregister_translator(&lintosilk8); res |= ast_unregister_translator(&silk8tolin); } if (silk12_reg){ res |= ast_unregister_translator(&lintosilk12); res |= ast_unregister_translator(&silk12tolin); } if(silk16_reg){ res |= ast_unregister_translator(&lintosilk16); res |= ast_unregister_translator(&silk16tolin); } if(silk24_reg){ res |= ast_unregister_translator(&lintosilk24); res |= ast_unregister_translator(&silk24tolin); } return res; } AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SILK Coder/Decoder");