isac_enc.c 7.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 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
17
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 19 20
 */

#include "isacfix.h"
21
#include "signal_processing_library.h"
22

23
#include "isac_constants.h"
24

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


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

typedef struct _isac_encoder_struct_t isac_encoder_struct_t;

40 41

static void filter_init ( MSFilter *f ) {
42 43 44
	ISACFIX_MainStruct* isac_mainstruct = NULL;
	struct _isac_encoder_struct_t *obj = NULL;
	int instance_size;
45
	int16_t ret;
46

47 48
	f->data = ms_new0(isac_encoder_struct_t, 1);
	obj = (isac_encoder_struct_t*)f->data;
49 50


51 52 53 54 55
	ret = WebRtcIsacfix_AssignSize( &instance_size );
	if( ret ) {
		ms_error("WebRtcIsacfix_AssignSize returned size %d", instance_size);
	}
	isac_mainstruct = ms_malloc0(instance_size);
56

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

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

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


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

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

static void filter_preprocess ( MSFilter *f ) {
}

static void filter_process ( MSFilter *f ) {
85
	isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;
86

87 88
	mblk_t *im;
	mblk_t *om=NULL;
89 90 91
#if defined (_MSC_VER)
	uint8_t* input_buf = NULL;
#else
92
	u_int8_t* input_buf = NULL;
93
#endif
94
	int16_t ret;
95
	static int out_count = 0;
96

97 98 99 100
	// 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 );
	}
101

102 103 104
	// 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 ){
105

106 107 108
		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);
109

110
		ret = WebRtcIsacfix_Encode(obj->isac,
111 112
								   (const int16_t*)input_buf,
								   (uint8_t*)om->b_wptr);
113

114
		if( ret < 0) {
115

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

119 120 121 122 123
		} else if( ret == 0 ) {
			// Encode() buffered the input, not yet able to produce a packet, continue feeding it
			// 160 samples per-call
			obj->ts += ISAC_SAMPLES_PER_ENCODE;
			freeb(om);
124

125
		} else {
126

127 128 129 130 131
			// a new packet has been encoded, send it
			obj->ts += ISAC_SAMPLES_PER_ENCODE;
			om->b_wptr += ret;
			out_count++;
			//            ms_message("packet %d out, samples %d", out_count, obj->ts);
132

133 134
			mblk_set_timestamp_info( om, obj->ts );
			ms_queue_put(f->outputs[0], om);
135

136 137
			om = NULL;
		}
138

139
	}
140

141 142 143
	if( input_buf ){
		ms_free(input_buf);
	}
144 145 146 147 148 149 150
}

static void filter_postprocess ( MSFilter *f ) {

}

static void filter_uninit ( MSFilter *f ) {
151 152 153 154 155
	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;
156 157 158 159 160 161
}


/*filter specific method*/

static int filter_get_sample_rate ( MSFilter *f, void *arg ) {
162 163
	*(int*)arg = ISAC_SAMPLE_RATE;
	return 0;
164 165 166 167
}

#ifdef MS_AUDIO_ENCODER_SET_PTIME
static int filter_get_ptime(MSFilter *f, void *arg){
168 169 170
	isac_encoder_struct_t* obj= ( isac_encoder_struct_t* ) f->data;
	*(int*)arg=obj->ptime;
	return 0;
171 172 173
}

static int filter_set_ptime(MSFilter *f, void *arg){
174 175
	int asked = *(int*)arg;
	isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;
176

177 178 179 180 181 182
	// iSAC handles only 30 or 60ms ptime
	if( asked != 30 && asked != 60 ){
		// use the closest
		asked = (asked > 45)? 60 : 30;
		ms_warning("iSAC doesn't handle %dms ptime, choosing closest: %dms", *(int*)arg, asked);
	}
183

184
	obj->ptime = asked;
185

186
	return 0;
187
}
188 189
#endif

190
static int filter_set_bitrate ( MSFilter *f, void *arg ) {
191 192
	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
	int wanted_bitrate = *(int*)arg;
193

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

198
		wanted_bitrate = ISAC_BITRATE_MAX;
199

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

204
		wanted_bitrate = ISAC_BITRATE_MIN;
205

206
	}
207

208
	return WebRtcIsacfix_SetMaxRate(obj->isac, wanted_bitrate);
209 210 211
}

static int filter_get_bitrate ( MSFilter *f, void *arg ) {
212 213 214
	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
	*(int*)arg = (int)WebRtcIsacfix_GetUplinkBw(obj->isac);
	return 0;
215 216 217
}

static MSFilterMethod filter_methods[]= {
218 219 220 221 222 223 224 225
	{ 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                   }
226 227 228
};


229 230 231 232 233 234 235 236 237

#define MS_ISAC_ENC_NAME        "MSiSACEnc"
#define MS_ISAC_ENC_DESCRIPTION "iSAC audio encoder filter."
#define MS_ISAC_ENC_CATEGORY    MS_FILTER_ENCODER
#define MS_ISAC_ENC_ENC_FMT     "iSAC"
#define MS_ISAC_ENC_NINPUTS     1
#define MS_ISAC_ENC_NOUTPUTS    1
#define MS_ISAC_ENC_FLAGS       0

238 239
#ifdef _MSC_VER

240 241 242 243 244 245 246 247
MSFilterDesc ms_isac_enc_desc = {
	MS_FILTER_PLUGIN_ID,
	MS_ISAC_ENC_NAME,
	MS_ISAC_ENC_DESCRIPTION,
	MS_ISAC_ENC_CATEGORY,
	MS_ISAC_ENC_ENC_FMT,
	MS_ISAC_ENC_NINPUTS,
	MS_ISAC_ENC_NOUTPUTS,
248 249 250 251 252 253
	filter_init,
	filter_preprocess,
	filter_process,
	filter_postprocess,
	filter_uninit,
	filter_methods,
254
	MS_ISAC_ENC_FLAGS
255 256 257 258 259
};

#else

MSFilterDesc ms_isac_enc_desc = {
260 261 262 263 264 265 266 267 268 269 270 271 272 273
	.id = MS_FILTER_PLUGIN_ID,
	.name = MS_ISAC_ENC_NAME,
	.text = MS_ISAC_ENC_DESCRIPTION,
	.category = MS_ISAC_ENC_CATEGORY,
	.enc_fmt = MS_ISAC_ENC_ENC_FMT,
	.ninputs = MS_ISAC_ENC_NINPUTS,
	.noutputs = MS_ISAC_ENC_NOUTPUTS,
	.init = filter_init,
	.preprocess = filter_preprocess,
	.process = filter_process,
	.postprocess = filter_postprocess,
	.uninit = filter_uninit,
	.methods = filter_methods,
	.flags = MS_ISAC_ENC_FLAGS
274 275 276 277 278
};

#endif

MS_FILTER_DESC_EXPORT ( ms_isac_enc_desc )