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