1 /*
2  isac_enc.c
3  Copyright (C) 2013 Belledonne Communications, Grenoble, France
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  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 #include "mediastreamer2/msfilter.h"
26 #include "mediastreamer2/mscodecutils.h"
27 
28 
29 /*filter common method*/
30 struct _isac_encoder_struct_t {
31 	ISACFIX_MainStruct* isac;
32 	MSBufferizer *bufferizer;
33 	unsigned int ptime;
34 	unsigned int bitrate;
35 	unsigned int ts;
36 };
37 
38 typedef struct _isac_encoder_struct_t isac_encoder_struct_t;
39 
40 
filter_init(MSFilter * f)41 static void filter_init ( MSFilter *f ) {
42 	ISACFIX_MainStruct* isac_mainstruct = NULL;
43 	struct _isac_encoder_struct_t *obj = NULL;
44 	int instance_size;
45 	int16_t ret;
46 
47 	f->data = ms_new0(isac_encoder_struct_t, 1);
48 	obj = (isac_encoder_struct_t*)f->data;
49 
50 
51 	ret = WebRtcIsacfix_AssignSize( &instance_size );
52 	if( ret ) {
53 		ms_error("WebRtcIsacfix_AssignSize returned size %d", instance_size);
54 	}
55 	isac_mainstruct = ms_malloc0(instance_size);
56 
57 	ret = WebRtcIsacfix_Assign(&obj->isac, isac_mainstruct);
58 	if( ret ) {
59 		ms_error("WebRtcIsacfix_Create failed (%d)", ret);
60 	}
61 
62 	// TODO: AUTO or USER coding mode?
63 	ret = WebRtcIsacfix_EncoderInit(obj->isac, CODING_USERDEFINED);
64 	if( ret ) {
65 		ms_error("WebRtcIsacfix_EncoderInit failed (%d)",  WebRtcIsacfix_GetErrorCode(obj->isac));
66 	}
67 
68 	obj->ptime   = 30; // iSAC allows 30 or 60ms per packet
69 	obj->bitrate = ISAC_BITRATE_MAX;
70 
71 
72 	ret = WebRtcIsacfix_Control(obj->isac, obj->bitrate, obj->ptime);
73 	if( ret ) {
74 		ms_error("WebRtcIsacfix_Control failed: %d", WebRtcIsacfix_GetErrorCode(obj->isac));
75 	}
76 
77 	obj->bufferizer = ms_bufferizer_new();
78 	obj->ts = 0;
79 }
80 
filter_preprocess(MSFilter * f)81 static void filter_preprocess ( MSFilter *f ) {
82 }
83 
filter_process(MSFilter * f)84 static void filter_process ( MSFilter *f ) {
85 	isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;
86 
87 	mblk_t *im;
88 	mblk_t *om=NULL;
89 #if defined (_MSC_VER)
90 	uint8_t* input_buf = NULL;
91 #else
92 	u_int8_t* input_buf = NULL;
93 #endif
94 	int16_t ret;
95 	static int out_count = 0;
96 
97 	// get the input data and put it into our buffered input
98 	while( (im = ms_queue_get( f->inputs[0] ) ) != NULL ) {
99 		ms_bufferizer_put( obj->bufferizer, im );
100 	}
101 
102 	// feed the encoder with 160 16bit samples, until it has reached enough data
103 	// to produce a packet
104 	while( ms_bufferizer_get_avail(obj->bufferizer) > ISAC_SAMPLES_PER_ENCODE*2 ){
105 
106 		om = allocb( WebRtcIsacfix_GetNewFrameLen(obj->isac), 0 );
107 		if(!input_buf) input_buf = ms_malloc( ISAC_SAMPLES_PER_ENCODE*2 );
108 		ms_bufferizer_read(obj->bufferizer, input_buf, ISAC_SAMPLES_PER_ENCODE*2);
109 
110 		ret = WebRtcIsacfix_Encode(obj->isac,
111 								   (const int16_t*)input_buf,
112 								   (uint8_t*)om->b_wptr);
113 
114 		if( ret < 0) {
115 
116 			ms_error( "WebRtcIsacfix_Encode error: %d", WebRtcIsacfix_GetErrorCode(obj->isac) );
117 			freeb(om);
118 
119 		} else if( ret == 0 ) {
120 			// Encode() buffered the input, not yet able to produce a packet, continue feeding it
121 			// 160 samples per-call
122 			obj->ts += ISAC_SAMPLES_PER_ENCODE;
123 			freeb(om);
124 
125 		} else {
126 
127 			// a new packet has been encoded, send it
128 			obj->ts += ISAC_SAMPLES_PER_ENCODE;
129 			om->b_wptr += ret;
130 			out_count++;
131 			//            ms_message("packet %d out, samples %d", out_count, obj->ts);
132 
133 			mblk_set_timestamp_info( om, obj->ts );
134 			ms_queue_put(f->outputs[0], om);
135 
136 			om = NULL;
137 		}
138 
139 	}
140 
141 	if( input_buf ){
142 		ms_free(input_buf);
143 	}
144 }
145 
filter_postprocess(MSFilter * f)146 static void filter_postprocess ( MSFilter *f ) {
147 
148 }
149 
filter_uninit(MSFilter * f)150 static void filter_uninit ( MSFilter *f ) {
151 	struct _isac_encoder_struct_t *encoder = (struct _isac_encoder_struct_t*)f->data;
152 	ms_free(encoder->isac);
153 	ms_bufferizer_destroy(encoder->bufferizer);
154 	ms_free(encoder);
155 	f->data = 0;
156 }
157 
158 
159 /*filter specific method*/
160 
filter_get_sample_rate(MSFilter * f,void * arg)161 static int filter_get_sample_rate ( MSFilter *f, void *arg ) {
162 	*(int*)arg = ISAC_SAMPLE_RATE;
163 	return 0;
164 }
165 
166 #ifdef MS_AUDIO_ENCODER_SET_PTIME
filter_get_ptime(MSFilter * f,void * arg)167 static int filter_get_ptime(MSFilter *f, void *arg){
168 	isac_encoder_struct_t* obj= ( isac_encoder_struct_t* ) f->data;
169 	*(int*)arg=obj->ptime;
170 	return 0;
171 }
172 
filter_set_ptime(MSFilter * f,void * arg)173 static int filter_set_ptime(MSFilter *f, void *arg){
174 	int asked = *(int*)arg;
175 	isac_encoder_struct_t* obj = (isac_encoder_struct_t*)f->data;
176 
177 	// iSAC handles only 30 or 60ms ptime
178 	if( asked != 30 && asked != 60 ){
179 		// use the closest
180 		asked = (asked > 45)? 60 : 30;
181 		ms_warning("iSAC doesn't handle %dms ptime, choosing closest: %dms", *(int*)arg, asked);
182 	}
183 
184 	obj->ptime = asked;
185 
186 	return 0;
187 }
188 #endif
189 
filter_set_bitrate(MSFilter * f,void * arg)190 static int filter_set_bitrate ( MSFilter *f, void *arg ) {
191 	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
192 	int wanted_bitrate = *(int*)arg;
193 
194 	if( wanted_bitrate > ISAC_BITRATE_MAX ) {
195 		ms_warning("iSAC doesn't handle bitrate > %d (wanted: %d)",
196 				   ISAC_BITRATE_MAX, wanted_bitrate );
197 
198 		wanted_bitrate = ISAC_BITRATE_MAX;
199 
200 	} else if( wanted_bitrate < ISAC_BITRATE_MIN) {
201 		ms_warning("iSAC doesn't handle bitrate < %d (wanted: %d)",
202 				   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 
filter_get_bitrate(MSFilter * f,void * arg)211 static int filter_get_bitrate ( MSFilter *f, void *arg ) {
212 	isac_encoder_struct_t *obj = (isac_encoder_struct_t*)f->data;
213 	*(int*)arg = (int)WebRtcIsacfix_GetUplinkBw(obj->isac);
214 	return 0;
215 }
216 
217 static MSFilterMethod filter_methods[]= {
218 	{ MS_FILTER_GET_SAMPLE_RATE,  filter_get_sample_rate },
219 	{ MS_FILTER_SET_BITRATE,      filter_set_bitrate     },
220 	{ MS_FILTER_GET_BITRATE,      filter_get_bitrate     },
221 #ifdef MS_AUDIO_ENCODER_SET_PTIME
222 	{ MS_AUDIO_ENCODER_SET_PTIME, filter_set_ptime       },
223 	{ MS_AUDIO_ENCODER_GET_PTIME, filter_get_ptime       },
224 #endif
225 	{ 0,                          NULL                   }
226 };
227 
228 
229 
230 #define MS_ISAC_ENC_NAME        "MSiSACEnc"
231 #define MS_ISAC_ENC_DESCRIPTION "iSAC audio encoder filter."
232 #define MS_ISAC_ENC_CATEGORY    MS_FILTER_ENCODER
233 #define MS_ISAC_ENC_ENC_FMT     "iSAC"
234 #define MS_ISAC_ENC_NINPUTS     1
235 #define MS_ISAC_ENC_NOUTPUTS    1
236 #define MS_ISAC_ENC_FLAGS       0
237 
238 #ifdef _MSC_VER
239 
240 MSFilterDesc ms_isac_enc_desc = {
241 	MS_FILTER_PLUGIN_ID,
242 	MS_ISAC_ENC_NAME,
243 	MS_ISAC_ENC_DESCRIPTION,
244 	MS_ISAC_ENC_CATEGORY,
245 	MS_ISAC_ENC_ENC_FMT,
246 	MS_ISAC_ENC_NINPUTS,
247 	MS_ISAC_ENC_NOUTPUTS,
248 	filter_init,
249 	filter_preprocess,
250 	filter_process,
251 	filter_postprocess,
252 	filter_uninit,
253 	filter_methods,
254 	MS_ISAC_ENC_FLAGS
255 };
256 
257 #else
258 
259 MSFilterDesc ms_isac_enc_desc = {
260 	.id = MS_FILTER_PLUGIN_ID,
261 	.name = MS_ISAC_ENC_NAME,
262 	.text = MS_ISAC_ENC_DESCRIPTION,
263 	.category = MS_ISAC_ENC_CATEGORY,
264 	.enc_fmt = MS_ISAC_ENC_ENC_FMT,
265 	.ninputs = MS_ISAC_ENC_NINPUTS,
266 	.noutputs = MS_ISAC_ENC_NOUTPUTS,
267 	.init = filter_init,
268 	.preprocess = filter_preprocess,
269 	.process = filter_process,
270 	.postprocess = filter_postprocess,
271 	.uninit = filter_uninit,
272 	.methods = filter_methods,
273 	.flags = MS_ISAC_ENC_FLAGS
274 };
275 
276 #endif
277 
278 MS_FILTER_DESC_EXPORT ( ms_isac_enc_desc )
279