isac_enc.c 7.72 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 isac_enc.c
 Copyright (C) 2013 Belledonne Communications, Grenoble, France

 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 "isacfix.h"
21
#include "signal_processing_library.h"
22

23 24
#include "constants.h"

25 26 27 28 29
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mscodecutils.h"


/*filter common method*/
30 31 32 33
struct _isac_encoder_struct_t {
    ISACFIX_MainStruct* isac;
    MSBufferizer *bufferizer;
    unsigned int ptime;
34
    unsigned int bitrate;
35 36 37 38 39
    unsigned int totalSize;
};

typedef struct _isac_encoder_struct_t isac_encoder_struct_t;

40 41

static void filter_init ( MSFilter *f ) {
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    ISACFIX_MainStruct* isac_mainstruct = NULL;
    struct _isac_encoder_struct_t *obj = NULL;
    int instance_size;
    WebRtc_Word16 ret;

    f->data = ms_new0(isac_encoder_struct_t, 1);
    obj = (isac_encoder_struct_t*)f->data;


    ret = WebRtcIsacfix_AssignSize( &instance_size );
    if( ret ) {
        ms_error("WebRtcIsacfix_AssignSize returned size %d", instance_size);
    }
    isac_mainstruct = ms_malloc0(instance_size);

    ret = WebRtcIsacfix_Assign(&obj->isac, isac_mainstruct);
    if( ret ) {
        ms_error("WebRtcIsacfix_Create failed (%d)", ret);
    }

    // TODO: AUTO or USER coding mode?
63
    ret = WebRtcIsacfix_EncoderInit(obj->isac, CODING_USERDEFINED);
64
    if( ret ) {
65 66 67 68 69 70 71 72 73 74
        ms_error("WebRtcIsacfix_EncoderInit failed (%d)",  WebRtcIsacfix_GetErrorCode(obj->isac));
    }

    obj->ptime   = 30; // iSAC allows 30 or 60ms per packet
    obj->bitrate = ISAC_BITRATE_MAX;


    ret = WebRtcIsacfix_Control(obj->isac, obj->bitrate, obj->ptime);
    if( ret ) {
        ms_error("WebRtcIsacfix_Control failed: %d", WebRtcIsacfix_GetErrorCode(obj->isac));
75 76 77
    }

    obj->bufferizer = ms_bufferizer_new();
78 79 80 81 82 83
}

static void filter_preprocess ( MSFilter *f ) {
}

static void filter_process ( MSFilter *f ) {
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;

    mblk_t *im;
    mblk_t *om=NULL;
    u_int8_t* input_buf = NULL;
    WebRtc_Word16 ret;

    // get the input data and put it into our buffered input
    while( (im = ms_queue_get( f->inputs[0] ) ) != NULL ) {
        ms_bufferizer_put( obj->bufferizer, im );
    }

    // feed the encoder with 160 16bit samples, until it has reached enough data
    // to produce a packet
    while( ms_bufferizer_get_avail(obj->bufferizer) > ISAC_SAMPLES_PER_ENCODE*2 ){

        om = allocb( WebRtcIsacfix_GetNewFrameLen(obj->isac), 0 );
        if(!input_buf) input_buf = ms_malloc( ISAC_SAMPLES_PER_ENCODE*2 );
        ms_bufferizer_read(obj->bufferizer, input_buf, ISAC_SAMPLES_PER_ENCODE*2);

        ret = WebRtcIsacfix_Encode(obj->isac,
                                   (const WebRtc_Word16*)input_buf,
                                   (WebRtc_Word16*)om->b_wptr);

        if( ret < 0) {

            ms_error( "WebRtcIsacfix_Encode error: %d", WebRtcIsacfix_GetErrorCode(obj->isac) );
            freeb(om);

        } else if( ret == 0 ) {

            // Encode buffered the input, not yet able to produce a packet, continue feeding it
            // 160 samples per-call, if possible
            freeb(om);

        } else {

            // a new packet has been encoded, send it
            obj->totalSize += ret;
            om->b_wptr += ret;
            // ms_message("packet out, size %d", ret);

            mblk_set_timestamp_info( om, obj->totalSize );
            ms_queue_put(f->outputs[0], om);

            om = NULL;
            break;
        }

    }

    if( input_buf ){
        ms_free(input_buf);
    }
138 139 140 141 142 143 144
}

static void filter_postprocess ( MSFilter *f ) {

}

static void filter_uninit ( MSFilter *f ) {
145 146 147 148 149
    struct _isac_encoder_struct_t *encoder = (struct _isac_encoder_struct_t*)f->data;
    ms_free(encoder->isac);
    ms_bufferizer_destroy(encoder->bufferizer);
    ms_free(encoder);
    f->data = 0;
150 151 152 153 154 155
}


/*filter specific method*/

static int filter_get_sample_rate ( MSFilter *f, void *arg ) {
156
    *(int*)arg = ISAC_SAMPLE_RATE;
157 158 159 160 161
    return 0;
}

#ifdef MS_AUDIO_ENCODER_SET_PTIME
static int filter_get_ptime(MSFilter *f, void *arg){
162 163
    isac_encoder_struct_t* obj= ( isac_encoder_struct_t* ) f->data;
    *(int*)arg=obj->ptime;
164 165 166 167
    return 0;
}

static int filter_set_ptime(MSFilter *f, void *arg){
168 169 170 171 172 173 174 175 176 177
    int asked = *(int*)arg;
    isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;

    // iSAC handles only 30 or 60ms ptime
    if( asked != 30 && asked != 60 ){
        // use the closest
        asked = (asked > 45)? 60 : 30;
    }

    obj->ptime = asked;
178 179 180

    return 0;
}
181 182
#endif

183
static int filter_set_bitrate ( MSFilter *f, void *arg ) {
184
    isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    int wanted_bitrate = *(int*)arg;

    if( wanted_bitrate > ISAC_BITRATE_MAX ) {
        ms_warning("iSAC doesn't handle bitrate > %d (wanted: %d)",
                   ISAC_BITRATE_MAX, wanted_bitrate );

        wanted_bitrate = ISAC_BITRATE_MAX;

    } else if( wanted_bitrate < ISAC_BITRATE_MIN) {
        ms_warning("iSAC doesn't handle bitrate < %d (wanted: %d)",
                   ISAC_BITRATE_MIN, wanted_bitrate );

        wanted_bitrate = ISAC_BITRATE_MIN;

    }

    return WebRtcIsacfix_SetMaxRate(obj->isac, wanted_bitrate);
202 203 204
}

static int filter_get_bitrate ( MSFilter *f, void *arg ) {
205 206
    isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
    *(int*)arg = (int)WebRtcIsacfix_GetUplinkBw(obj->isac);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    return 0;
}

static MSFilterMethod filter_methods[]= {
    {MS_FILTER_GET_SAMPLE_RATE,     filter_get_sample_rate },
    {MS_FILTER_SET_BITRATE,         filter_set_bitrate },
    {MS_FILTER_GET_BITRATE,         filter_get_bitrate },
#ifdef MS_AUDIO_ENCODER_SET_PTIME
    {MS_AUDIO_ENCODER_SET_PTIME,    filter_set_ptime },
    {MS_AUDIO_ENCODER_GET_PTIME,    filter_get_ptime },
#endif
    {0, NULL}
};


#ifdef _MSC_VER

MSFilterDesc ms_isac_enc_desc= {
    MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/
    "MSiSACEnc",
    "iSAC audio encoder filter.",
    MS_FILTER_ENCODER,
    "iSAC",
    1, /*number of inputs*/
    1, /*number of outputs*/
    filter_init,
    filter_preprocess,
    filter_process,
    filter_postprocess,
    filter_uninit,
    filter_methods,
    0
};

#else

MSFilterDesc ms_isac_enc_desc = {
    .id=MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/
    .name="MSiSACEnc",
    .text="iSAC audio encoder filter.",
    .category=MS_FILTER_ENCODER,
    .enc_fmt="iSAC",
    .ninputs=1, /*number of inputs*/
    .noutputs=1, /*number of outputs*/
    .init=filter_init,
    .preprocess=filter_preprocess,
    .process=filter_process,
    .postprocess=filter_postprocess,
    .uninit=filter_uninit,
    .methods=filter_methods
};

#endif

MS_FILTER_DESC_EXPORT ( ms_isac_enc_desc )

extern MSFilterDesc ms_isac_dec_desc;

#ifndef VERSION
#define VERSION "debug"
#endif

#ifdef _MSC_VER
#define MS_PLUGIN_DECLARE(type) __declspec(dllexport) type
#else
#define MS_PLUGIN_DECLARE(type) type
#endif

MS_PLUGIN_DECLARE ( void ) libmsisac_init() {
276 277 278
    char isac_version[64];
    isac_version[0] = 0;

279
    WebRtcSpl_Init();
280 281
    WebRtcIsacfix_version(isac_version);

282 283
    ms_filter_register ( &ms_isac_enc_desc );
    ms_filter_register ( &ms_isac_dec_desc );
284 285

    ms_message ( " libmsisac " VERSION " plugin loaded, iSAC codec version %s", isac_version );
286 287 288
}