speex_codec.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 826 行 · 第 1/2 页
C
826 行
/* $Id: speex_codec.c 974 2007-02-19 01:13:53Z bennylp $ *//* * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjmedia-codec/speex.h>#include <pjmedia/codec.h>#include <pjmedia/errno.h>#include <pjmedia/endpoint.h>#include <pjmedia/port.h>#include <speex/speex.h>#include <pj/assert.h>#include <pj/log.h>#include <pj/pool.h>#include <pj/string.h>#include <pj/os.h>/* * Only build this file if PJMEDIA_HAS_SPEEX_CODEC != 0 */#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0#define THIS_FILE "speex_codec.c"#define DEFAULT_QUALITY 10#define DEFAULT_COMPLEXITY 10/* Prototypes for Speex factory */static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory, const pjmedia_codec_info *id );static pj_status_t spx_default_attr( pjmedia_codec_factory *factory, const pjmedia_codec_info *id, pjmedia_codec_param *attr );static pj_status_t spx_enum_codecs( pjmedia_codec_factory *factory, unsigned *count, pjmedia_codec_info codecs[]);static pj_status_t spx_alloc_codec( pjmedia_codec_factory *factory, const pjmedia_codec_info *id, pjmedia_codec **p_codec);static pj_status_t spx_dealloc_codec( pjmedia_codec_factory *factory, pjmedia_codec *codec );/* Prototypes for Speex implementation. */static pj_status_t spx_codec_init( pjmedia_codec *codec, pj_pool_t *pool );static pj_status_t spx_codec_open( pjmedia_codec *codec, pjmedia_codec_param *attr );static pj_status_t spx_codec_close( pjmedia_codec *codec );static pj_status_t spx_codec_modify(pjmedia_codec *codec, const pjmedia_codec_param *attr );static pj_status_t spx_codec_parse( pjmedia_codec *codec, void *pkt, pj_size_t pkt_size, const pj_timestamp *ts, unsigned *frame_cnt, pjmedia_frame frames[]);static pj_status_t spx_codec_encode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output);static pj_status_t spx_codec_decode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output);static pj_status_t spx_codec_recover(pjmedia_codec *codec, unsigned output_buf_len, struct pjmedia_frame *output);/* Definition for Speex codec operations. */static pjmedia_codec_op spx_op = { &spx_codec_init, &spx_codec_open, &spx_codec_close, &spx_codec_modify, &spx_codec_parse, &spx_codec_encode, &spx_codec_decode, &spx_codec_recover};/* Definition for Speex codec factory operations. */static pjmedia_codec_factory_op spx_factory_op ={ &spx_test_alloc, &spx_default_attr, &spx_enum_codecs, &spx_alloc_codec, &spx_dealloc_codec};/* Index to Speex parameter. */enum{ PARAM_NB, /* Index for narrowband parameter. */ PARAM_WB, /* Index for wideband parameter. */ PARAM_UWB, /* Index for ultra-wideband parameter */};/* Speex default parameter */struct speex_param{ int enabled; /* Is this mode enabled? */ const SpeexMode *mode; /* Speex mode. */ int pt; /* Payload type. */ unsigned clock_rate; /* Default sampling rate to be used.*/ int quality; /* Default encoder quality. */ int complexity; /* Default encoder complexity. */ int samples_per_frame; /* Samples per frame. */ int framesize; /* Frame size for current mode. */ int bitrate; /* Bit rate for current mode. */};/* Speex factory */static struct spx_factory{ pjmedia_codec_factory base; pjmedia_endpt *endpt; pj_pool_t *pool; pj_mutex_t *mutex; pjmedia_codec codec_list; struct speex_param speex_param[3];} spx_factory;/* Speex codec private data. */struct spx_private{ int param_id; /**< Index to speex param. */ void *enc; /**< Encoder state. */ SpeexBits enc_bits; /**< Encoder bits. */ void *dec; /**< Decoder state. */ SpeexBits dec_bits; /**< Decoder bits. */};/* * Get codec bitrate and frame size. */static pj_status_t get_speex_info( struct speex_param *p ){ void *state; int tmp; /* Create temporary encoder */ state = speex_encoder_init(p->mode); if (!state) return PJMEDIA_CODEC_EFAILED; /* Set the quality */ if (p->quality != -1) speex_encoder_ctl(state, SPEEX_SET_QUALITY, &p->quality); /* Sampling rate. */ speex_encoder_ctl(state, SPEEX_SET_SAMPLING_RATE, &p->clock_rate); /* VAD off to have max bitrate */ tmp = 0; speex_encoder_ctl(state, SPEEX_SET_VAD, &tmp); /* Complexity. */ if (p->complexity != -1) speex_encoder_ctl(state, SPEEX_SET_COMPLEXITY, &p->complexity); /* Now get the frame size */ speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &p->samples_per_frame); /* Now get the the averate bitrate */ speex_encoder_ctl(state, SPEEX_GET_BITRATE, &p->bitrate); /* Calculate framesize. */ p->framesize = p->bitrate * 20 / 1000; /* Destroy encoder. */ speex_encoder_destroy(state); return PJ_SUCCESS;}/* * Initialize and register Speex codec factory to pjmedia endpoint. */PJ_DEF(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt, unsigned options, int quality, int complexity ){ pjmedia_codec_mgr *codec_mgr; unsigned i; pj_status_t status; if (spx_factory.pool != NULL) { /* Already initialized. */ return PJ_SUCCESS; } /* Get defaults */ if (quality <= 0) quality = DEFAULT_QUALITY; if (complexity <= 0) complexity = DEFAULT_COMPLEXITY; /* Create Speex codec factory. */ spx_factory.base.op = &spx_factory_op; spx_factory.base.factory_data = NULL; spx_factory.endpt = endpt; spx_factory.pool = pjmedia_endpt_create_pool(endpt, "speex", 4000, 4000); if (!spx_factory.pool) return PJ_ENOMEM; pj_list_init(&spx_factory.codec_list); /* Create mutex. */ status = pj_mutex_create_simple(spx_factory.pool, "speex", &spx_factory.mutex); if (status != PJ_SUCCESS) goto on_error; /* Initialize default Speex parameter. */ spx_factory.speex_param[PARAM_NB].enabled = ((options & PJMEDIA_SPEEX_NO_NB) == 0); spx_factory.speex_param[PARAM_NB].pt = PJMEDIA_RTP_PT_SPEEX_NB; spx_factory.speex_param[PARAM_NB].mode = &speex_nb_mode; spx_factory.speex_param[PARAM_NB].clock_rate = 8000; spx_factory.speex_param[PARAM_NB].quality = quality; spx_factory.speex_param[PARAM_NB].complexity = complexity; spx_factory.speex_param[PARAM_WB].enabled = ((options & PJMEDIA_SPEEX_NO_WB) == 0); spx_factory.speex_param[PARAM_WB].pt = PJMEDIA_RTP_PT_SPEEX_WB; spx_factory.speex_param[PARAM_WB].mode = &speex_wb_mode; spx_factory.speex_param[PARAM_WB].clock_rate = 16000; spx_factory.speex_param[PARAM_WB].quality = quality; spx_factory.speex_param[PARAM_WB].complexity = complexity; spx_factory.speex_param[PARAM_UWB].enabled = ((options & PJMEDIA_SPEEX_NO_UWB) == 0); spx_factory.speex_param[PARAM_UWB].pt = PJMEDIA_RTP_PT_SPEEX_UWB; spx_factory.speex_param[PARAM_UWB].mode = &speex_uwb_mode; spx_factory.speex_param[PARAM_UWB].clock_rate = 32000; spx_factory.speex_param[PARAM_UWB].quality = quality; spx_factory.speex_param[PARAM_UWB].complexity = complexity; /* Somehow quality <=4 is broken in linux. */ if (quality <= 4 && quality >= 0) { PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb")); spx_factory.speex_param[PARAM_UWB].quality = 5; } /* Get codec framesize and avg bitrate for each mode. */ for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) { status = get_speex_info(&spx_factory.speex_param[i]); } /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); if (!codec_mgr) { status = PJ_EINVALIDOP; goto on_error; } /* Register codec factory to endpoint. */ status = pjmedia_codec_mgr_register_factory(codec_mgr, &spx_factory.base); if (status != PJ_SUCCESS) goto on_error; /* Done. */ return PJ_SUCCESS;on_error: pj_pool_release(spx_factory.pool); spx_factory.pool = NULL; return status;}/* * Initialize with default settings. */PJ_DEF(pj_status_t) pjmedia_codec_speex_init_default(pjmedia_endpt *endpt){ return pjmedia_codec_speex_init(endpt, 0, -1, -1);}/* * Unregister Speex codec factory from pjmedia endpoint and deinitialize * the Speex codec library. */PJ_DEF(pj_status_t) pjmedia_codec_speex_deinit(void){ pjmedia_codec_mgr *codec_mgr; pj_status_t status; if (spx_factory.pool == NULL) { /* Already deinitialized */ return PJ_SUCCESS; } pj_mutex_lock(spx_factory.mutex); /* We don't want to deinit if there's outstanding codec. */ /* This is silly, as we'll always have codec in the list if we ever allocate a codec! A better behavior maybe is to deallocate all codecs in the list. if (!pj_list_empty(&spx_factory.codec_list)) { pj_mutex_unlock(spx_factory.mutex); return PJ_EBUSY; } */ /* Get the codec manager. */ codec_mgr = pjmedia_endpt_get_codec_mgr(spx_factory.endpt); if (!codec_mgr) { pj_pool_release(spx_factory.pool); spx_factory.pool = NULL; return PJ_EINVALIDOP; } /* Unregister Speex codec factory. */ status = pjmedia_codec_mgr_unregister_factory(codec_mgr, &spx_factory.base); /* Destroy mutex. */ pj_mutex_destroy(spx_factory.mutex); /* Destroy pool. */ pj_pool_release(spx_factory.pool); spx_factory.pool = NULL; return status;}/* * Check if factory can allocate the specified codec. */static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory, const pjmedia_codec_info *info ){ const pj_str_t speex_tag = { "speex", 5}; unsigned i; PJ_UNUSED_ARG(factory); /* Type MUST be audio. */ if (info->type != PJMEDIA_TYPE_AUDIO) return PJMEDIA_CODEC_EUNSUP; /* Check encoding name. */ if (pj_stricmp(&info->encoding_name, &speex_tag) != 0) return PJMEDIA_CODEC_EUNSUP; /* Check clock-rate */ for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) { if (info->clock_rate == spx_factory.speex_param[i].clock_rate) { /* Okay, let's Speex! */ return PJ_SUCCESS; } } /* Unsupported, or mode is disabled. */ return PJMEDIA_CODEC_EUNSUP;}/* * Generate default attribute. */static pj_status_t spx_default_attr (pjmedia_codec_factory *factory, const pjmedia_codec_info *id, pjmedia_codec_param *attr ){ PJ_ASSERT_RETURN(factory==&spx_factory.base, PJ_EINVAL); pj_bzero(attr, sizeof(pjmedia_codec_param)); attr->info.pt = (pj_uint8_t)id->pt; attr->info.channel_cnt = 1; if (id->clock_rate <= 8000) { attr->info.clock_rate = spx_factory.speex_param[PARAM_NB].clock_rate; attr->info.avg_bps = spx_factory.speex_param[PARAM_NB].bitrate; } else if (id->clock_rate <= 16000) { attr->info.clock_rate = spx_factory.speex_param[PARAM_WB].clock_rate; attr->info.avg_bps = spx_factory.speex_param[PARAM_WB].bitrate; } else { /* Wow.. somebody is doing ultra-wideband. Cool...! */ attr->info.clock_rate = spx_factory.speex_param[PARAM_UWB].clock_rate; attr->info.avg_bps = spx_factory.speex_param[PARAM_UWB].bitrate; } attr->info.pcm_bits_per_sample = 16; attr->info.frm_ptime = 20; attr->info.pt = (pj_uint8_t)id->pt;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?