long opus_create(const char* format_parameters, const char** format_parameters_out, amci_codec_fmt_info_t** format_description) { opus_state_t* codec_inst; int error; unsigned int maxbandwidth = _OPUS_RATE; int useinbandfec = _OPUS_INBAND_FEC_; int stereo = 0; if (format_parameters) { DBG("OPUS params: >>%s<<.\n", format_parameters); decode_format_parameters(format_parameters, &maxbandwidth, &useinbandfec, &stereo); } codec_inst = (opus_state_t*)malloc(sizeof(opus_state_t)); if (!codec_inst) return -1; DBG("OPUS: creating encoder with maxbandwidth=%u, stereo=%s, useinbandfec=%s\n", maxbandwidth, stereo?"true":"false", useinbandfec?"true":"false"); codec_inst->opus_enc = opus_encoder_create(_OPUS_RATE,1,_OPUS_APPLICATION_,&error); if (error) { DBG("OPUS: error %d while creating encoder state.\n", error); return -1; } opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_FORCE_CHANNELS(stereo ? 2:1)); unsigned int opus_set_bw = _OPUS_RATE; if (maxbandwidth <= 8000) { opus_set_bw = OPUS_BANDWIDTH_NARROWBAND; } else if (maxbandwidth <= 12000) { opus_set_bw = OPUS_BANDWIDTH_MEDIUMBAND; } else if (maxbandwidth <= 16000) { opus_set_bw = OPUS_BANDWIDTH_WIDEBAND; } else if (maxbandwidth <= 24000) { opus_set_bw = OPUS_BANDWIDTH_SUPERWIDEBAND; } else { opus_set_bw = OPUS_BANDWIDTH_FULLBAND; } opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_MAX_BANDWIDTH(opus_set_bw)); opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_PACKET_LOSS_PERC(_OPUS_PKT_LOSS_PCT_)); opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_COMPLEXITY(_OPUS_COMPLEXITY_)); opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_INBAND_FEC(useinbandfec ? 1:0)); opus_encoder_ctl(codec_inst->opus_enc, OPUS_SET_DTX(_OPUS_DTX_)); codec_inst->opus_dec = opus_decoder_create(_OPUS_RATE,1,&error); if (error) { DBG("OPUS: error %d while creating decoder state.\n", error); opus_encoder_destroy(codec_inst->opus_enc); return -1; } *format_description = opus_fmt_description; return (long)codec_inst; }
static int alloc(struct aucodec_st **stp, struct aucodec *ac, struct aucodec_prm *encp, struct aucodec_prm *decp, const char *fmtp) { struct aucodec_st *st; const uint32_t srate = aucodec_srate(ac); const uint8_t ch = aucodec_ch(ac); uint32_t ptime = DEFAULT_PTIME; int use_inbandfec; int use_dtx; int err = 0; int opuserr; (void)decp; (void)fmtp; st = mem_zalloc(sizeof(*st), destructor); if (!st) return ENOMEM; if (encp && encp->ptime) ptime = encp->ptime; st->ac = mem_ref(ac); st->frame_size = srate * ptime / 1000; st->fsize = 2 * st->frame_size * ch; /* Encoder */ st->enc = opus_encoder_create(srate, ch, opus.app, &opuserr); if (!st->enc) { err = ENOMEM; goto out; } use_inbandfec = 1; use_dtx = 1; opus_encoder_ctl(st->enc, OPUS_SET_BITRATE(opus.bitrate)); opus_encoder_ctl(st->enc, OPUS_SET_BANDWIDTH(opus.bandwidth)); opus_encoder_ctl(st->enc, OPUS_SET_VBR(opus.vbr)); opus_encoder_ctl(st->enc, OPUS_SET_COMPLEXITY(opus.complex)); opus_encoder_ctl(st->enc, OPUS_SET_INBAND_FEC(use_inbandfec)); opus_encoder_ctl(st->enc, OPUS_SET_DTX(use_dtx)); /* Decoder */ st->dec = opus_decoder_create(srate, ch, &opuserr); if (!st->dec) { err = ENOMEM; goto out; } out: if (err) mem_deref(st); else *stp = st; return err; }
virtual bool OnChangedOptions() { if (m_encoder == NULL) return false; opus_encoder_ctl(m_encoder, OPUS_SET_INBAND_FEC(m_useInBandFEC)); opus_encoder_ctl(m_encoder, OPUS_SET_DTX(m_useDTX)); opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(m_bitRate)); return true; }
bool OpusEncode::SetFEC(bool enable) { assert(m_encoder); if(!m_encoder) return false; int value = enable; int err = opus_encoder_ctl(m_encoder, OPUS_SET_INBAND_FEC(value)); assert(err == 0); return err == 0; }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_audio_opus_Opus_encoder_1set_1inband_1fec (JNIEnv *env, jclass clazz, jlong encoder, jint inbandFEC) { opus_int32 x = inbandFEC; return opus_encoder_ctl( (OpusEncoder *) (intptr_t) encoder, OPUS_SET_INBAND_FEC(x)); }
static int ms_opus_enc_set_inbandfec(MSFilter *f) { OpusEncData *d = (OpusEncData *)f->data; int error; if (d->state) { error = opus_encoder_ctl(d->state, OPUS_SET_INBAND_FEC(d->useinbandfec)); if (error != OPUS_OK) { ms_error("could not set inband FEC to opus encoder: %s", opus_strerror(error)); } } return 0; }
OpusEncoder *create_audio_encoder(Logger *log, int32_t bit_rate, int32_t sampling_rate, int32_t channel_count) { int status = OPUS_OK; OpusEncoder *rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_VOIP, &status); if (status != OPUS_OK) { LOGGER_ERROR(log, "Error while starting audio encoder: %s", opus_strerror(status)); return NULL; } status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate)); if (status != OPUS_OK) { LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status)); goto FAILURE; } /* Enable in-band forward error correction in codec */ status = opus_encoder_ctl(rc, OPUS_SET_INBAND_FEC(1)); if (status != OPUS_OK) { LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status)); goto FAILURE; } /* Make codec resistant to up to 10% packet loss * NOTE This could also be adjusted on the fly, rather than hard-coded, * with feedback from the receiving client. */ status = opus_encoder_ctl(rc, OPUS_SET_PACKET_LOSS_PERC(10)); if (status != OPUS_OK) { LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status)); goto FAILURE; } /* Set algorithm to the highest complexity, maximizing compression */ status = opus_encoder_ctl(rc, OPUS_SET_COMPLEXITY(10)); if (status != OPUS_OK) { LOGGER_ERROR(log, "Error while setting encoder ctl: %s", opus_strerror(status)); goto FAILURE; } return rc; FAILURE: opus_encoder_destroy(rc); return NULL; }
static gboolean gst_opus_enc_setup (GstOpusEnc * enc) { int error = OPUS_OK; #ifndef GST_DISABLE_DEBUG GST_DEBUG_OBJECT (enc, "setup: %d Hz, %d channels, %d stereo streams, family %d", enc->sample_rate, enc->n_channels, enc->n_stereo_streams, enc->channel_mapping_family); GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams", enc->n_channels, enc->n_stereo_streams); gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, "Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping); gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug, "Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping); #endif enc->state = opus_multistream_encoder_create (enc->sample_rate, enc->n_channels, enc->n_channels - enc->n_stereo_streams, enc->n_stereo_streams, enc->encoding_channel_mapping, enc->audio_or_voip ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error); if (!enc->state || error != OPUS_OK) goto encoder_creation_failed; opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR_CONSTRAINT (enc->constrained_vbr), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_COMPLEXITY (enc->complexity), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_INBAND_FEC (enc->inband_fec), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0); opus_multistream_encoder_ctl (enc->state, OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0); GST_LOG_OBJECT (enc, "we have frame size %d", enc->frame_size); return TRUE; encoder_creation_failed: GST_ERROR_OBJECT (enc, "Encoder creation failed"); return FALSE; }
bool FVoiceEncoderOpus::Init(int32 InSampleRate, int32 InNumChannels) { UE_LOG(LogVoiceEncode, Display, TEXT("EncoderVersion: %s"), ANSI_TO_TCHAR(opus_get_version_string())); SampleRate = InSampleRate; NumChannels = InNumChannels; // 20ms frame sizes are a good choice for most applications (1000ms / 20ms = 50) FrameSize = SampleRate / NUM_OPUS_FRAMES_PER_SEC; //MaxFrameSize = FrameSize * MAX_OPUS_FRAMES; int32 EncError = 0; #if USE_UE4_MEM_ALLOC int32 EncSize = opus_encoder_get_size(NumChannels); Encoder = (OpusEncoder*)FMemory::Malloc(EncSize); EncError = opus_encoder_init(Encoder, SampleRate, NumChannels, OPUS_APPLICATION_VOIP); #else Encoder = opus_encoder_create(SampleRate, NumChannels, OPUS_APPLICATION_VOIP, &EncError); #endif if (EncError != OPUS_OK) { UE_LOG(LogVoiceEncode, Warning, TEXT("Failed to init Opus Encoder: %s"), ANSI_TO_TCHAR(opus_strerror(EncError))); Destroy(); } // Turn on variable bit rate encoding int32 UseVbr = 1; opus_encoder_ctl(Encoder, OPUS_SET_VBR(UseVbr)); // Turn off constrained VBR int32 UseCVbr = 0; opus_encoder_ctl(Encoder, OPUS_SET_VBR_CONSTRAINT(UseCVbr)); // Complexity (1-10) int32 Complexity = 1; opus_encoder_ctl(Encoder, OPUS_SET_COMPLEXITY(Complexity)); // Forward error correction int32 InbandFEC = 0; opus_encoder_ctl(Encoder, OPUS_SET_INBAND_FEC(InbandFEC)); #if DEBUG_OPUS DebugEncoderInfo(Encoder); #endif // DEBUG_OPUS return EncError == OPUS_OK; }
/* Helper methods */ static int opus_encoder_construct(struct ast_trans_pvt *pvt, int sampling_rate) { struct opus_coder_pvt *opvt = pvt->pvt; int error = 0; if (!valid_sampling_rate(sampling_rate)) { return -1; } opvt->sampling_rate = sampling_rate; opvt->multiplier = 48000/sampling_rate; opvt->fec = USE_FEC; opvt->opus = opus_encoder_create(sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if (error != OPUS_OK) { ast_log(LOG_ERROR, "Error creating the Opus encoder: %s\n", opus_strerror(error)); return -1; } if (sampling_rate == 8000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else if (sampling_rate == 12000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); } else if (sampling_rate == 16000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); } else if (sampling_rate == 24000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); } else if (sampling_rate == 48000) { opus_encoder_ctl(opvt->opus, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } opus_encoder_ctl(opvt->opus, OPUS_SET_INBAND_FEC(opvt->fec)); opvt->framesize = sampling_rate/50; opvt->id = ast_atomic_fetchadd_int(&usage.encoder_id, 1) + 1; ast_atomic_fetchadd_int(&usage.encoders, +1); ast_debug(3, "Created encoder #%d (%d -> opus)\n", opvt->id, sampling_rate); return 0; }
/* * Modify codec settings. */ static pj_status_t codec_modify( pjmedia_codec *codec, const pjmedia_codec_param *attr ) { struct opus_data *opus_data = (struct opus_data *)codec->codec_data; pj_mutex_lock (opus_data->mutex); TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__)); /* Set bitrate */ opus_data->cfg.bit_rate = attr->info.avg_bps; opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps)); /* Set VAD */ opus_encoder_ctl(opus_data->enc, OPUS_SET_DTX(attr->setting.vad ? 1 : 0)); /* Set PLC */ opus_encoder_ctl(opus_data->enc, OPUS_SET_INBAND_FEC(attr->setting.plc ? 1 : 0)); pj_mutex_unlock (opus_data->mutex); return PJ_SUCCESS; }
/** * OPUS init */ static void opus_init () { int err; pcm_length = FRAME_SIZE * CHANNELS * sizeof (float); pcm_buffer = pa_xmalloc (pcm_length); opus_data = GNUNET_malloc (MAX_PAYLOAD_BYTES); enc = opus_encoder_create (SAMPLING_RATE, CHANNELS, CONV_OPUS_APP_TYPE, &err); opus_encoder_ctl (enc, OPUS_SET_PACKET_LOSS_PERC (CONV_OPUS_PACKET_LOSS_PERCENTAGE)); opus_encoder_ctl (enc, OPUS_SET_COMPLEXITY (CONV_OPUS_ENCODING_COMPLEXITY)); opus_encoder_ctl (enc, OPUS_SET_INBAND_FEC (CONV_OPUS_INBAND_FEC)); opus_encoder_ctl (enc, OPUS_SET_SIGNAL (CONV_OPUS_SIGNAL)); }
/* * Open codec. */ static pj_status_t codec_open( pjmedia_codec *codec, pjmedia_codec_param *attr ) { struct opus_data *opus_data = (struct opus_data *)codec->codec_data; int idx, err; PJ_ASSERT_RETURN(codec && attr && opus_data, PJ_EINVAL); pj_mutex_lock (opus_data->mutex); TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__)); opus_data->cfg.sample_rate = attr->info.clock_rate; opus_data->cfg.channel_cnt = attr->info.channel_cnt; opus_data->ptime = attr->info.frm_ptime; /* Allocate memory used by the codec */ if (!opus_data->enc) { /* Allocate memory for max 2 channels */ opus_data->enc = pj_pool_zalloc(opus_data->pool, opus_encoder_get_size(2)); } if (!opus_data->dec) { /* Allocate memory for max 2 channels */ opus_data->dec = pj_pool_zalloc(opus_data->pool, opus_decoder_get_size(2)); } if (!opus_data->enc_packer) { opus_data->enc_packer = pj_pool_zalloc(opus_data->pool, opus_repacketizer_get_size()); } if (!opus_data->dec_packer) { opus_data->dec_packer = pj_pool_zalloc(opus_data->pool, opus_repacketizer_get_size()); } if (!opus_data->enc || !opus_data->dec || !opus_data->enc_packer || !opus_data->dec_packer) { PJ_LOG(2, (THIS_FILE, "Unable to allocate memory for the codec")); pj_mutex_unlock (opus_data->mutex); return PJ_ENOMEM; } /* Check max average bit rate */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE); if (idx >= 0) { unsigned rate; rate = (unsigned)pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); if (rate < attr->info.avg_bps) attr->info.avg_bps = rate; } /* Check plc */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_INBAND_FEC, PJ_FALSE); if (idx >= 0) { unsigned plc; plc = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); attr->setting.plc = plc > 0? PJ_TRUE: PJ_FALSE; } /* Check vad */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_DTX, PJ_FALSE); if (idx >= 0) { unsigned vad; vad = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); attr->setting.vad = vad > 0? PJ_TRUE: PJ_FALSE; } /* Check cbr */ idx = find_fmtp(&attr->setting.enc_fmtp, &STR_CBR, PJ_FALSE); if (idx >= 0) { unsigned cbr; cbr = (unsigned) pj_strtoul(&attr->setting.enc_fmtp.param[idx].val); opus_data->cfg.cbr = cbr > 0? PJ_TRUE: PJ_FALSE; } /* Check max average bit rate */ idx = find_fmtp(&attr->setting.dec_fmtp, &STR_MAX_BIT_RATE, PJ_FALSE); if (idx >= 0) { unsigned rate; rate = (unsigned) pj_strtoul(&attr->setting.dec_fmtp.param[idx].val); if (rate < attr->info.avg_bps) attr->info.avg_bps = rate; } TRACE_((THIS_FILE, "%s:%d: sample_rate: %u", __FUNCTION__, __LINE__, opus_data->cfg.sample_rate)); /* Initialize encoder */ err = opus_encoder_init(opus_data->enc, opus_data->cfg.sample_rate, attr->info.channel_cnt, OPUS_APPLICATION_VOIP); if (err != OPUS_OK) { PJ_LOG(2, (THIS_FILE, "Unable to create encoder")); return PJMEDIA_CODEC_EFAILED; } /* Set signal type */ opus_encoder_ctl(opus_data->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); /* Set bitrate */ opus_encoder_ctl(opus_data->enc, OPUS_SET_BITRATE(attr->info.avg_bps)); /* Set VAD */ opus_encoder_ctl(opus_data->enc, OPUS_SET_DTX(attr->setting.vad ? 1 : 0)); /* Set PLC */ opus_encoder_ctl(opus_data->enc, OPUS_SET_INBAND_FEC(attr->setting.plc ? 1 : 0)); /* Set bandwidth */ opus_encoder_ctl(opus_data->enc, OPUS_SET_MAX_BANDWIDTH(get_opus_bw_constant( opus_data->cfg.sample_rate))); /* Set expected packet loss */ opus_encoder_ctl(opus_data->enc, OPUS_SET_PACKET_LOSS_PERC(opus_data->cfg.packet_loss)); /* Set complexity */ opus_encoder_ctl(opus_data->enc, OPUS_SET_COMPLEXITY(opus_data->cfg.complexity)); /* Set constant bit rate */ opus_encoder_ctl(opus_data->enc, OPUS_SET_VBR(opus_data->cfg.cbr ? 0 : 1)); PJ_LOG(5, (THIS_FILE, "Initialize Opus encoder, sample rate: %d, " "avg bitrate: %d, vad: %d, plc: %d, pkt loss: %d, " "complexity: %d, constant bit rate: %d", opus_data->cfg.sample_rate, attr->info.avg_bps, attr->setting.vad?1:0, attr->setting.plc?1:0, opus_data->cfg.packet_loss, opus_data->cfg.complexity, opus_data->cfg.cbr?1:0)); /* Initialize decoder */ err = opus_decoder_init (opus_data->dec, opus_data->cfg.sample_rate, attr->info.channel_cnt); if (err != OPUS_OK) { PJ_LOG(2, (THIS_FILE, "Unable to initialize decoder")); return PJMEDIA_CODEC_EFAILED; } /* Initialize temporary decode frames used for FEC */ opus_data->dec_frame[0].type = PJMEDIA_FRAME_TYPE_NONE; opus_data->dec_frame[0].buf = pj_pool_zalloc(opus_data->pool, (opus_data->cfg.sample_rate / 1000) * 60 * attr->info.channel_cnt * 2 /* bytes per sample */); opus_data->dec_frame[1].type = PJMEDIA_FRAME_TYPE_NONE; opus_data->dec_frame[1].buf = pj_pool_zalloc(opus_data->pool, (opus_data->cfg.sample_rate / 1000) * 60 * attr->info.channel_cnt * 2 /* bytes per sample */); opus_data->dec_frame_index = -1; /* Initialize the repacketizers */ opus_repacketizer_init(opus_data->enc_packer); opus_repacketizer_init(opus_data->dec_packer); pj_mutex_unlock (opus_data->mutex); return PJ_SUCCESS; }
/* * Open codec. */ static pj_status_t opus_codec_open(pjmedia_codec *codec, pjmedia_codec_param *attr) { pj_status_t status; struct opus_private *opus; int id, ret = 0; unsigned i; int structSizeBytes; int tmpFmtpVal = 0; unsigned max_nsamples; const pj_str_t STR_FMTP_USE_INBAND_FEC = {"useinbandfec", 12}; const pj_str_t STR_FMTP_MAX_AVERAGE_BITRATE = {"maxaveragebitrate", 17}; const pj_str_t STR_FMTP_MAX_CODED_AUDIO_BANDWIDTH = {"maxplaybackrate", 15}; const pj_str_t STR_FMTP_USE_DTX = {"usedtx", 6}; opus = (struct opus_private *)codec->codec_data; pj_assert(opus != NULL); pj_assert(opus->enc_ready == PJ_FALSE && opus->dec_ready == PJ_FALSE); PJ_LOG(4, (THIS_FILE, "Clock rate is %d ", attr->info.clock_rate)); opus->externalFs = attr->info.clock_rate; /* Create Encoder */ structSizeBytes = opus_encoder_get_size(attr->info.channel_cnt); opus->psEnc = pj_pool_zalloc(opus->pool, structSizeBytes); ret = opus_encoder_init(opus->psEnc, opus->externalFs, attr->info.channel_cnt, OPUS_APPLICATION_VOIP); if (ret) { PJ_LOG(1, (THIS_FILE, "Unable to init encoder : %d", ret)); return PJ_EINVAL; } /* * Set Encoder parameters * TODO : have it configurable */ opus_encoder_ctl(opus->psEnc, OPUS_SET_COMPLEXITY(2)); opus_encoder_ctl(opus->psEnc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); /* Apply fmtp params to Encoder */ for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) { if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_USE_INBAND_FEC) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); opus_encoder_ctl(opus->psEnc, OPUS_SET_INBAND_FEC(tmpFmtpVal)); break; } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_MAX_AVERAGE_BITRATE) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); if (tmpFmtpVal >= 6000 && tmpFmtpVal <= 510000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_BITRATE(tmpFmtpVal)); } } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_MAX_CODED_AUDIO_BANDWIDTH) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); if (tmpFmtpVal <= 8000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else if (tmpFmtpVal <= 12000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); } else if (tmpFmtpVal <= 16000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); } else if (tmpFmtpVal <= 24000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); } else if (tmpFmtpVal <= 48000) { opus_encoder_ctl(opus->psEnc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } } else if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_FMTP_USE_DTX) == 0) { tmpFmtpVal = (int)(pj_strtoul(&attr->setting.enc_fmtp.param[i].val)); opus_encoder_ctl(opus->psEnc, OPUS_SET_DTX(tmpFmtpVal)); } } opus->enc_ready = PJ_TRUE; /* Decoder buffer */ opus->pcm_bytes_per_sample = attr->info.pcm_bits_per_sample / 8; max_nsamples = 120 * OPUS_CLOCK_RATE / 1000; /* 120ms is max frame time */ opus->dec_buf_max_size = max_nsamples * opus->pcm_bytes_per_sample; opus->dec_buf = pj_pool_alloc(opus->pool, opus->dec_buf_max_size); /* Create decoder */ structSizeBytes = opus_decoder_get_size(attr->info.channel_cnt); opus->psDec = pj_pool_zalloc(opus->pool, structSizeBytes); ret = opus_decoder_init(opus->psDec, opus->externalFs, attr->info.channel_cnt); if (ret) { PJ_LOG(1, (THIS_FILE, "Unable to init decoder : %d", ret)); return PJ_EINVAL; } opus->dec_ready = PJ_TRUE; return PJ_SUCCESS; }
int opus_encode_update(struct auenc_state **aesp, const struct aucodec *ac, struct auenc_param *param, const char *fmtp) { struct auenc_state *aes; struct opus_param prm, conf_prm; opus_int32 fch, vbr; const struct aucodec *auc = ac; (void)param; if (!aesp || !ac || !ac->ch) return EINVAL; debug("opus: encoder fmtp (%s)\n", fmtp); /* Save the incoming OPUS parameters from SDP offer */ if (str_isset(fmtp)) { opus_mirror_params(fmtp); } aes = *aesp; if (!aes) { const opus_int32 complex = 10; int opuserr; aes = mem_zalloc(sizeof(*aes), destructor); if (!aes) return ENOMEM; aes->ch = ac->ch; aes->enc = opus_encoder_create(ac->srate, ac->ch, /* this has big impact on cpu */ OPUS_APPLICATION_AUDIO, &opuserr); if (!aes->enc) { warning("opus: encoder create: %s\n", opus_strerror(opuserr)); mem_deref(aes); return ENOMEM; } (void)opus_encoder_ctl(aes->enc, OPUS_SET_COMPLEXITY(complex)); *aesp = aes; } prm.srate = 48000; prm.bitrate = OPUS_AUTO; prm.stereo = 1; prm.cbr = 0; prm.inband_fec = 0; prm.dtx = 0; opus_decode_fmtp(&prm, fmtp); conf_prm.bitrate = OPUS_AUTO; opus_decode_fmtp(&conf_prm, auc->fmtp); if ((prm.bitrate == OPUS_AUTO) || ((conf_prm.bitrate != OPUS_AUTO) && (conf_prm.bitrate < prm.bitrate))) prm.bitrate = conf_prm.bitrate; fch = prm.stereo ? OPUS_AUTO : 1; vbr = prm.cbr ? 0 : 1; (void)opus_encoder_ctl(aes->enc, OPUS_SET_MAX_BANDWIDTH(srate2bw(prm.srate))); (void)opus_encoder_ctl(aes->enc, OPUS_SET_BITRATE(prm.bitrate)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_FORCE_CHANNELS(fch)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_VBR(vbr)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_INBAND_FEC(prm.inband_fec)); (void)opus_encoder_ctl(aes->enc, OPUS_SET_DTX(prm.dtx)); #if 0 { opus_int32 bw, complex; (void)opus_encoder_ctl(aes->enc, OPUS_GET_MAX_BANDWIDTH(&bw)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_BITRATE(&prm.bitrate)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_FORCE_CHANNELS(&fch)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_VBR(&vbr)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_INBAND_FEC(&prm.inband_fec)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_DTX(&prm.dtx)); (void)opus_encoder_ctl(aes->enc, OPUS_GET_COMPLEXITY(&complex)); debug("opus: encode bw=%s bitrate=%i fch=%s " "vbr=%i fec=%i dtx=%i complex=%i\n", bwname(bw), prm.bitrate, chname(fch), vbr, prm.inband_fec, prm.dtx, complex); } #endif return 0; }
static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { struct opus_context *context = NULL; int encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); int decoding = (flags & SWITCH_CODEC_FLAG_DECODE); switch_codec_fmtp_t codec_fmtp; opus_codec_settings_t opus_codec_settings = { 0 }; if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) { return SWITCH_STATUS_FALSE; } context->enc_frame_size = codec->implementation->actual_samples_per_second * (codec->implementation->microseconds_per_packet / 1000) / 1000; memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); codec_fmtp.private_info = &opus_codec_settings; switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); /* Verify if the local or remote configuration are lowering maxaveragebitrate and/or maxplaybackrate */ if ( opus_prefs.maxaveragebitrate && (opus_prefs.maxaveragebitrate < opus_codec_settings.maxaveragebitrate || !opus_codec_settings.maxaveragebitrate) ) { opus_codec_settings.maxaveragebitrate = opus_prefs.maxaveragebitrate; } if ( opus_prefs.maxplaybackrate && (opus_prefs.maxplaybackrate < opus_codec_settings.maxplaybackrate || !opus_codec_settings.maxplaybackrate) ) { opus_codec_settings.maxplaybackrate = opus_prefs.maxplaybackrate; } codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); if (encoding) { /* come up with a way to specify these */ int bitrate_bps = OPUS_AUTO; int use_vbr = opus_prefs.use_vbr; int complexity = opus_prefs.complexity; int err; int samplerate = opus_codec_settings.samplerate ? opus_codec_settings.samplerate : codec->implementation->actual_samples_per_second; context->encoder_object = opus_encoder_create(samplerate, codec->implementation->number_of_channels, codec->implementation->number_of_channels == 1 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err)); return SWITCH_STATUS_GENERR; } /* Setting documented in "RTP Payload Format for Opus Speech and Audio Codec" draft-spittka-payload-rtp-opus-03 */ if( opus_codec_settings.maxaveragebitrate ) { /* Remote codec settings found in SDP "fmtp", we accept to tune the Encoder */ opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(opus_codec_settings.maxaveragebitrate)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate based on maxaveragebitrate found in SDP [%dbps]\n", opus_codec_settings.maxaveragebitrate); } else { /* Default codec settings used, may have been modified by SDP "samplerate" */ opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); if (codec->implementation->actual_samples_per_second == 8000) { opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else { opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate to local settings [%dbps]\n", bitrate_bps); } /* Another setting from "RTP Payload Format for Opus Speech and Audio Codec" */ if ( opus_codec_settings.maxplaybackrate ) { if (opus_codec_settings.maxplaybackrate == 8000) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */ opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); } else if (opus_codec_settings.maxplaybackrate == 12000) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */ opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); } else if (opus_codec_settings.maxplaybackrate == 16000) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */ opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); } else if (opus_codec_settings.maxplaybackrate == 24000) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */ opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); } else if (opus_codec_settings.maxplaybackrate == 48000) { /* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */ opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bandwidth based on maxplaybackrate found in SDP [%dHz]\n", opus_codec_settings.maxplaybackrate); } if (use_vbr) { opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr)); } if (complexity) { opus_encoder_ctl(context->encoder_object, OPUS_SET_COMPLEXITY(complexity)); } if (opus_codec_settings.useinbandfec) { opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(opus_codec_settings.useinbandfec)); } if (opus_codec_settings.usedtx) { opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(opus_codec_settings.usedtx)); } } if (decoding) { int err; context->decoder_object = opus_decoder_create(codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create decoder: %s\n", opus_strerror(err)); if (context->encoder_object) { opus_encoder_destroy(context->encoder_object); context->encoder_object = NULL; } return SWITCH_STATUS_GENERR; } } codec->private_info = context; return SWITCH_STATUS_SUCCESS; }
static void ms_opus_enc_process(MSFilter *f) { OpusEncData *d = (OpusEncData *)f->data; OpusRepacketizer *repacketizer = NULL; mblk_t *om = NULL; int packet_size, pcm_buffer_size; int max_frame_byte_size, ptime = 20; int frame_count = 0, frame_size = 0; opus_int32 total_length = 0; uint8_t *repacketizer_frame_buffer[MAX_INPUT_FRAMES]; int i; ms_filter_lock(f); ptime = d->ptime; packet_size = d->samplerate * ptime / 1000; /* in samples */ ms_filter_unlock(f); switch (ptime) { case 10: frame_size = d->samplerate * 10 / 1000; frame_count = 1; break; case 20: frame_size = d->samplerate * 20 / 1000; frame_count = 1; break; case 40: frame_size = d->samplerate * 40 / 1000; frame_count = 1; break; case 60: frame_size = d->samplerate * 60 / 1000; frame_count = 1; break; case 80: frame_size = d->samplerate * 40 / 1000; frame_count = 2; break; case 100: frame_size = d->samplerate * 20 / 1000; frame_count = 5; break; case 120: frame_size = d->samplerate * 60 / 1000; frame_count = 2; break; default: frame_size = d->samplerate * 20 / 1000; frame_count = 1; } max_frame_byte_size = MAX_BYTES_PER_MS * ptime/frame_count; pcm_buffer_size = d->channels * frame_size * SIGNAL_SAMPLE_SIZE; if (pcm_buffer_size > d->pcmbufsize){ if (d->pcmbuffer) ms_free(d->pcmbuffer); d->pcmbuffer = ms_malloc(pcm_buffer_size); d->pcmbufsize = pcm_buffer_size; } for (i=0; i<MAX_INPUT_FRAMES; i++) { repacketizer_frame_buffer[i]=NULL; } ms_bufferizer_put_from_queue(d->bufferizer, f->inputs[0]); while (ms_bufferizer_get_avail(d->bufferizer) >= (d->channels * packet_size * SIGNAL_SAMPLE_SIZE)) { opus_int32 ret = 0; if (frame_count == 1) { /* One Opus frame, not using the repacketizer */ om = allocb(max_frame_byte_size, 0); ms_bufferizer_read(d->bufferizer, d->pcmbuffer, frame_size * SIGNAL_SAMPLE_SIZE * d->channels); ret = opus_encode(d->state, (opus_int16 *)d->pcmbuffer, frame_size, om->b_wptr, max_frame_byte_size); if (ret < 0) { freemsg(om); om=NULL; ms_error("Opus encoder error: %s", opus_strerror(ret)); break; } else { total_length = ret; om->b_wptr += total_length; } } else if(frame_count > 1) { /* We have multiple Opus frames we will use the opus repacketizer */ repacketizer = opus_repacketizer_create(); opus_repacketizer_init(repacketizer); /* Do not include FEC/LBRR in any frame after the first one since it will be sent with the previous one */ ret = opus_encoder_ctl(d->state, OPUS_SET_INBAND_FEC(0)); if (ret != OPUS_OK) { ms_error("could not set inband FEC to opus encoder: %s", opus_strerror(ret)); } for (i=0; i<frame_count; i++) { if(frame_count == i+1){ /* if configured, reactivate FEC on the last frame to tell the encoder he should restart saving LBRR frames */ ret = opus_encoder_ctl(d->state, OPUS_SET_INBAND_FEC(d->useinbandfec)); if (ret != OPUS_OK) { ms_error("could not set inband FEC to opus encoder: %s", opus_strerror(ret)); } } if (!repacketizer_frame_buffer[i]) repacketizer_frame_buffer[i] = ms_malloc(max_frame_byte_size); /* the repacketizer need the pointer to packet to remain valid, so we shall have a buffer for each coded frame */ ms_bufferizer_read(d->bufferizer, d->pcmbuffer, frame_size * SIGNAL_SAMPLE_SIZE * d->channels); ret = opus_encode(d->state, (opus_int16 *)d->pcmbuffer, frame_size, repacketizer_frame_buffer[i], max_frame_byte_size); if (ret < 0) { ms_error("Opus encoder error: %s", opus_strerror(ret)); break; } else if (ret > 0) { int err = opus_repacketizer_cat(repacketizer, repacketizer_frame_buffer[i], ret); /* add the encoded frame into the current packet */ if (err != OPUS_OK) { ms_error("Opus repacketizer error: %s", opus_strerror(err)); break; } total_length += ret; } } om = allocb(total_length + frame_count + 1, 0); /* opus repacketizer API: allocate at least number of frame + size of all data added before */ ret = opus_repacketizer_out(repacketizer, om->b_wptr, total_length+frame_count); if(ret < 0){ freemsg(om); om=NULL; ms_error("Opus repacketizer out error: %s", opus_strerror(ret)); } else { om->b_wptr += ret; } opus_repacketizer_destroy(repacketizer); for (i=0; i<frame_count; i++) { if (repacketizer_frame_buffer[i] != NULL) { ms_free(repacketizer_frame_buffer[i]); } } } if(om) { /* we have an encoded output message */ mblk_set_timestamp_info(om, d->ts); ms_bufferizer_fill_current_metas(d->bufferizer, om); ms_queue_put(f->outputs[0], om); d->ts += packet_size*48000/d->samplerate; /* RFC payload RTP opus 03 - section 4: RTP timestamp multiplier : WARNING works only with sr at 48000 */ total_length = 0; } } }
static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings) { struct opus_context *context = NULL; int encoding = (flags & SWITCH_CODEC_FLAG_ENCODE); int decoding = (flags & SWITCH_CODEC_FLAG_DECODE); if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) { return SWITCH_STATUS_FALSE; } context->frame_size = codec->implementation->samples_per_packet; if (encoding) { /* come up with a way to specify these */ int bitrate_bps = codec->implementation->bits_per_second; int use_vbr = 1; int complexity = 10; int use_inbandfec = 1; int use_dtx = 1; int bandwidth = OPUS_BANDWIDTH_FULLBAND; int err; context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels, OPUS_APPLICATION_VOIP, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err)); return SWITCH_STATUS_GENERR; } opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(bandwidth)); opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr)); opus_encoder_ctl(context->encoder_object, OPUS_SET_COMPLEXITY(complexity)); opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(use_inbandfec)); opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(use_dtx)); } if (decoding) { int err; context->decoder_object = opus_decoder_create(codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create decoder: %s\n", opus_strerror(err)); if (context->encoder_object) { opus_encoder_destroy(context->encoder_object); context->encoder_object = NULL; } return SWITCH_STATUS_GENERR; } } codec->private_info = context; return SWITCH_STATUS_SUCCESS; }