isac_enc.c 7.29 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
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 45
	ISACFIX_MainStruct* isac_mainstruct = NULL;
	struct _isac_encoder_struct_t *obj = NULL;
	int instance_size;
	WebRtc_Word16 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 89 90 91
	mblk_t *im;
	mblk_t *om=NULL;
	u_int8_t* input_buf = NULL;
	WebRtc_Word16 ret;
	static int out_count = 0;
92

93 94 95 96
	// 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 );
	}
97

98 99 100
	// 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 ){
101

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

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

110
		if( ret < 0) {
111

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

115 116 117 118 119
		} 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);
120

121
		} else {
122

123 124 125 126 127
			// 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);
128

129 130
			mblk_set_timestamp_info( om, obj->ts );
			ms_queue_put(f->outputs[0], om);
131

132 133
			om = NULL;
		}
134

135
	}
136

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

static void filter_postprocess ( MSFilter *f ) {

}

static void filter_uninit ( MSFilter *f ) {
147 148 149 150 151
	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;
152 153 154 155 156 157
}


/*filter specific method*/

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

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

static int filter_set_ptime(MSFilter *f, void *arg){
170 171
	int asked = *(int*)arg;
	isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;
172

173 174 175 176 177 178
	// 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);
	}
179

180
	obj->ptime = asked;
181

182
	return 0;
183
}
184 185
#endif

186
static int filter_set_bitrate ( MSFilter *f, void *arg ) {
187 188
	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
	int wanted_bitrate = *(int*)arg;
189

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

194
		wanted_bitrate = ISAC_BITRATE_MAX;
195

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

200
		wanted_bitrate = ISAC_BITRATE_MIN;
201

202
	}
203

204
	return WebRtcIsacfix_SetMaxRate(obj->isac, wanted_bitrate);
205 206 207
}

static int filter_get_bitrate ( MSFilter *f, void *arg ) {
208 209 210
	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
	*(int*)arg = (int)WebRtcIsacfix_GetUplinkBw(obj->isac);
	return 0;
211 212 213
}

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


#ifdef _MSC_VER

MSFilterDesc ms_isac_enc_desc= {
228 229 230 231 232 233 234 235 236 237 238 239 240 241
	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
242 243 244 245 246
};

#else

MSFilterDesc ms_isac_enc_desc = {
247 248 249 250 251 252 253 254 255 256 257 258 259
	.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
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
};

#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() {
279 280
	char isac_version[64];
	isac_version[0] = 0;
281

282 283
	WebRtcSpl_Init();
	WebRtcIsacfix_version(isac_version);
284

285 286
	ms_filter_register ( &ms_isac_enc_desc );
	ms_filter_register ( &ms_isac_dec_desc );
287

288
	ms_message ( " libmsisac " VERSION " plugin loaded, iSAC codec version %s", isac_version );
289 290 291
}