Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/t38_non_ecm_buffer.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * t38_non_ecm_buffer.c - A rate adapting buffer for T.38 non-ECM image | |
5 * and TCF data | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2005, 2006, 2007, 2008 Steve Underwood | |
10 * | |
11 * All rights reserved. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU Lesser General Public License version 2.1, | |
15 * as published by the Free Software Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU Lesser General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU Lesser General Public | |
23 * License along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 * | |
26 * $Id: t38_non_ecm_buffer.c,v 1.9.4.1 2009/12/19 06:43:28 steveu Exp $ | |
27 */ | |
28 | |
29 /*! \file */ | |
30 | |
31 #if defined(HAVE_CONFIG_H) | |
32 #include "config.h" | |
33 #endif | |
34 | |
35 #include <inttypes.h> | |
36 #include <stdlib.h> | |
37 #include <stdio.h> | |
38 #include <fcntl.h> | |
39 #include <time.h> | |
40 #include <string.h> | |
41 #if defined(HAVE_TGMATH_H) | |
42 #include <tgmath.h> | |
43 #endif | |
44 #if defined(HAVE_MATH_H) | |
45 #include <math.h> | |
46 #endif | |
47 #include "floating_fudge.h" | |
48 #include <assert.h> | |
49 | |
50 #include "spandsp/telephony.h" | |
51 #include "spandsp/logging.h" | |
52 #include "spandsp/queue.h" | |
53 #include "spandsp/dc_restore.h" | |
54 #include "spandsp/bit_operations.h" | |
55 #include "spandsp/async.h" | |
56 #include "spandsp/t38_non_ecm_buffer.h" | |
57 | |
58 #include "spandsp/private/t38_non_ecm_buffer.h" | |
59 | |
60 /* Phases */ | |
61 enum | |
62 { | |
63 TCF_AT_INITIAL_ALL_ONES = 0, | |
64 TCF_AT_ALL_ZEROS = 1, | |
65 IMAGE_WAITING_FOR_FIRST_EOL = 2, | |
66 IMAGE_IN_PROGRESS = 3 | |
67 }; | |
68 | |
69 static void restart_buffer(t38_non_ecm_buffer_state_t *s) | |
70 { | |
71 /* This should be called when draining the buffer is complete, which should | |
72 occur before any fresh data can possibly arrive to begin refilling it. */ | |
73 s->octet = 0xFF; | |
74 s->flow_control_fill_octet = 0xFF; | |
75 s->input_phase = (s->image_data_mode) ? IMAGE_WAITING_FOR_FIRST_EOL : TCF_AT_INITIAL_ALL_ONES; | |
76 s->bit_stream = 0xFFFF; | |
77 s->out_ptr = 0; | |
78 s->in_ptr = 0; | |
79 s->latest_eol_ptr = 0; | |
80 s->data_finished = FALSE; | |
81 } | |
82 /*- End of function --------------------------------------------------------*/ | |
83 | |
84 SPAN_DECLARE_NONSTD(int) t38_non_ecm_buffer_get_bit(void *user_data) | |
85 { | |
86 t38_non_ecm_buffer_state_t *s; | |
87 int bit; | |
88 | |
89 s = (t38_non_ecm_buffer_state_t *) user_data; | |
90 | |
91 if (s->bit_no <= 0) | |
92 { | |
93 /* We need another byte */ | |
94 if (s->out_ptr != s->latest_eol_ptr) | |
95 { | |
96 s->octet = s->data[s->out_ptr]; | |
97 s->out_ptr = (s->out_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
98 } | |
99 else | |
100 { | |
101 if (s->data_finished) | |
102 { | |
103 /* The queue is empty, and we have received the end of data signal. This must | |
104 really be the end to transmission. */ | |
105 restart_buffer(s); | |
106 return SIG_STATUS_END_OF_DATA; | |
107 } | |
108 /* The queue is blocked, but this does not appear to be the end of the data. Idle with | |
109 fill octets, which should be safe at this point. */ | |
110 s->octet = s->flow_control_fill_octet; | |
111 s->flow_control_fill_octets++; | |
112 } | |
113 s->out_octets++; | |
114 s->bit_no = 8; | |
115 } | |
116 s->bit_no--; | |
117 bit = (s->octet >> 7) & 1; | |
118 s->octet <<= 1; | |
119 return bit; | |
120 } | |
121 /*- End of function --------------------------------------------------------*/ | |
122 | |
123 SPAN_DECLARE(void) t38_non_ecm_buffer_push(t38_non_ecm_buffer_state_t *s) | |
124 { | |
125 /* Don't flow control the data any more. Just push out the remainder of the data | |
126 in the buffer as fast as we can, and shut down. */ | |
127 s->latest_eol_ptr = s->in_ptr; | |
128 s->data_finished = TRUE; | |
129 } | |
130 /*- End of function --------------------------------------------------------*/ | |
131 | |
132 SPAN_DECLARE(void) t38_non_ecm_buffer_inject(t38_non_ecm_buffer_state_t *s, const uint8_t *buf, int len) | |
133 { | |
134 int i; | |
135 int upper; | |
136 int lower; | |
137 | |
138 /* TCF consists of: | |
139 - zero or more ones, followed by | |
140 - about 1.5s of zeros | |
141 There may be a little junk at the end, as the modem shuts down. | |
142 | |
143 We can stuff with extra ones in the initial period of all ones, and we can stuff with extra | |
144 zeros once the zeros start. The thing we need to be wary about is the odd zero bit in the | |
145 midst of the ones, due to a bit error. */ | |
146 | |
147 /* Non-ECM image data consists of: | |
148 - zero or more ones, followed by | |
149 - zero or more zeros, followed by | |
150 - an EOL (end of line), which marks the start of the image, followed by | |
151 - a succession of data rows, with an EOL at the end of each, followed by | |
152 - an RTC (return to control) | |
153 There may be a little junk at the end, as the modem shuts down. | |
154 | |
155 An EOL 11 zeros followed by a one in a T.4 1D image or 11 zeros followed by a one followed | |
156 by a one or a zero in a T.4 2D image. An RTC consists of 6 EOLs in succession, with no | |
157 pixel data between them. | |
158 | |
159 We can stuff with ones until we get the first EOL into our buffer, then we can stuff with | |
160 zeros in front of each EOL at any point up the the RTC. We should not pad between the EOLs | |
161 which make up the RTC. Most FAX machines don't care about this, but a few will not recognise | |
162 the RTC if here is padding between the EOLs. | |
163 | |
164 We need to buffer whole rows before we output their beginning, so there is no possibility | |
165 of underflow mid-row. */ | |
166 | |
167 /* FoIP has latency issues, because of the fairly tight timeouts in the T.30 spec. We must | |
168 ensure our buffering does everything needed to avoid underflows, and to meet the minimum | |
169 row length requirements imposed by many mechanical FAX machines. We cannot, however, | |
170 afford to bulk up the data, by sending superfluous bytes. The resulting loop delay could | |
171 provoke an erroneous timeout of the acknowledgement signal. */ | |
172 | |
173 i = 0; | |
174 switch (s->input_phase) | |
175 { | |
176 case TCF_AT_INITIAL_ALL_ONES: | |
177 /* Dump initial 0xFF bytes. We will add enough of our own to makes things flow | |
178 smoothly. If we don't strip these off, we might end up delaying the start of | |
179 forwarding by a substantial amount, as we could end up with a large block of 0xFF | |
180 bytes before the real data begins. This is especially true with PC FAX | |
181 systems. This test is very simplistic, as bit errors could confuse it. */ | |
182 for ( ; i < len; i++) | |
183 { | |
184 if (buf[i] != 0xFF) | |
185 { | |
186 s->input_phase = TCF_AT_ALL_ZEROS; | |
187 s->flow_control_fill_octet = 0x00; | |
188 break; | |
189 } | |
190 } | |
191 /* Fall through */ | |
192 case TCF_AT_ALL_ZEROS: | |
193 for ( ; i < len; i++) | |
194 { | |
195 s->data[s->in_ptr] = buf[i]; | |
196 s->latest_eol_ptr = s->in_ptr; | |
197 /* TODO: We can't buffer overflow, since we wrap around. However, the tail could | |
198 overwrite itself if things fall badly behind. */ | |
199 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
200 s->in_octets++; | |
201 } | |
202 break; | |
203 case IMAGE_WAITING_FOR_FIRST_EOL: | |
204 /* Dump anything up to the first EOL. Let the output side stuff with 0xFF bytes while waiting | |
205 for that first EOL. What occurs before the first EOL is expected to be a period of all ones | |
206 and then a period of all zeros. We really don't care what junk might be there. By definition, | |
207 the image only starts at the first EOL. */ | |
208 for ( ; i < len; i++) | |
209 { | |
210 if (buf[i]) | |
211 { | |
212 /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split | |
213 between two octets. Between those two octets we can insert numerous zero octets | |
214 as a means of flow control. Note that we stuff in blocks of 8 bits, and not at | |
215 the minimal level. */ | |
216 /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 | |
217 trailing zeros */ | |
218 upper = bottom_bit(s->bit_stream | 0x800); | |
219 lower = top_bit(buf[i]); | |
220 if ((upper - lower) > (11 - 8)) | |
221 { | |
222 /* This is an EOL - our first row is beginning. */ | |
223 s->input_phase = IMAGE_IN_PROGRESS; | |
224 /* Start a new row */ | |
225 s->row_bits = lower - 8; | |
226 s->latest_eol_ptr = s->in_ptr; | |
227 s->flow_control_fill_octet = 0x00; | |
228 | |
229 /* If we push out two bytes of zero, and our latest non-zero byte | |
230 we should definitely form a proper EOL to begin things, with a | |
231 few harmless extra zero bits at the front. */ | |
232 s->data[s->in_ptr] = 0x00; | |
233 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
234 s->data[s->in_ptr] = 0x00; | |
235 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
236 s->data[s->in_ptr] = buf[i]; | |
237 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
238 s->in_octets += 3; | |
239 s->bit_stream = (s->bit_stream << 8) | buf[i]; | |
240 i++; | |
241 break; | |
242 } | |
243 } | |
244 s->bit_stream = (s->bit_stream << 8) | buf[i]; | |
245 } | |
246 if (i >= len) | |
247 break; | |
248 /* Fall through */ | |
249 case IMAGE_IN_PROGRESS: | |
250 /* Now we have seen an EOL, we can stuff with zeros just in front of that EOL, or any | |
251 subsequent EOL that does not immediately follow a previous EOL (i.e. a candidate RTC). | |
252 We need to track our way through the image data, allowing the output side to only send | |
253 up to the last EOL. This prevents the possibility of underflow mid-row, where we cannot | |
254 safely stuff anything in the bit stream. */ | |
255 for ( ; i < len; i++) | |
256 { | |
257 if (buf[i]) | |
258 { | |
259 /* There might be an EOL here. Look for at least 11 zeros, followed by a one, split | |
260 between two octets. Between those two octets we can insert numerous zero octets | |
261 as a means of flow control. Note that we stuff in blocks of 8 bits, and not at | |
262 the minimal level. */ | |
263 /* Or'ing with 0x800 here is to avoid zero words looking like they have -1 | |
264 trailing zeros */ | |
265 upper = bottom_bit(s->bit_stream | 0x800); | |
266 lower = top_bit(buf[i]); | |
267 if ((upper - lower) > (11 - 8)) | |
268 { | |
269 /* This is an EOL. */ | |
270 s->row_bits += (8 - lower); | |
271 /* Make sure we don't stretch back to back EOLs, as that could spoil the RTC. | |
272 This is a slightly crude check, as we don't know if we are processing a T.4 1D | |
273 or T.4 2D image. Accepting 12 or 12 bits apart as meaning back to back is fine, | |
274 as no 1D image row could be 1 bit long. */ | |
275 if (s->row_bits < 12 || s->row_bits > 13) | |
276 { | |
277 /* If the row is too short, extend it in chunks of a whole byte. */ | |
278 /* TODO: extend by the precise amount we should, instead of this | |
279 rough approach. */ | |
280 while (s->row_bits < s->min_bits_per_row) | |
281 { | |
282 s->min_row_bits_fill_octets++; | |
283 s->data[s->in_ptr] = 0; | |
284 s->row_bits += 8; | |
285 /* TODO: We can't buffer overflow, since we wrap around. However, | |
286 the tail could overwrite itself if things fall badly behind. */ | |
287 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
288 } | |
289 /* This is now the limit for the output side, before it starts | |
290 stuffing. */ | |
291 s->latest_eol_ptr = s->in_ptr; | |
292 } | |
293 /* Start a new row */ | |
294 s->row_bits = lower - 8; | |
295 s->in_rows++; | |
296 } | |
297 } | |
298 s->bit_stream = (s->bit_stream << 8) | buf[i]; | |
299 s->data[s->in_ptr] = buf[i]; | |
300 s->row_bits += 8; | |
301 /* TODO: We can't buffer overflow, since we wrap around. However, the tail could overwrite | |
302 itself if things fall badly behind. */ | |
303 s->in_ptr = (s->in_ptr + 1) & (T38_NON_ECM_TX_BUF_LEN - 1); | |
304 s->in_octets++; | |
305 } | |
306 break; | |
307 } | |
308 } | |
309 /*- End of function --------------------------------------------------------*/ | |
310 | |
311 SPAN_DECLARE(void) t38_non_ecm_buffer_report_input_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging) | |
312 { | |
313 if (s->in_octets || s->min_row_bits_fill_octets) | |
314 { | |
315 span_log(logging, | |
316 SPAN_LOG_FLOW, | |
317 "%d+%d incoming non-ECM octets, %d rows.\n", | |
318 s->in_octets, | |
319 s->min_row_bits_fill_octets, | |
320 s->in_rows); | |
321 s->in_octets = 0; | |
322 s->in_rows = 0; | |
323 s->min_row_bits_fill_octets = 0; | |
324 } | |
325 } | |
326 /*- End of function --------------------------------------------------------*/ | |
327 | |
328 SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_state_t *s, logging_state_t *logging) | |
329 { | |
330 if (s->out_octets || s->flow_control_fill_octets) | |
331 { | |
332 span_log(logging, | |
333 SPAN_LOG_FLOW, | |
334 "%d+%d outgoing non-ECM octets, %d rows.\n", | |
335 s->out_octets - s->flow_control_fill_octets, | |
336 s->flow_control_fill_octets, | |
337 s->out_rows); | |
338 s->out_octets = 0; | |
339 s->out_rows = 0; | |
340 s->flow_control_fill_octets = 0; | |
341 } | |
342 } | |
343 /*- End of function --------------------------------------------------------*/ | |
344 | |
345 SPAN_DECLARE(void) t38_non_ecm_buffer_set_mode(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) | |
346 { | |
347 s->image_data_mode = mode; | |
348 s->min_bits_per_row = min_bits_per_row; | |
349 } | |
350 /*- End of function --------------------------------------------------------*/ | |
351 | |
352 SPAN_DECLARE(t38_non_ecm_buffer_state_t *) t38_non_ecm_buffer_init(t38_non_ecm_buffer_state_t *s, int mode, int min_bits_per_row) | |
353 { | |
354 if (s == NULL) | |
355 { | |
356 if ((s = (t38_non_ecm_buffer_state_t *) malloc(sizeof(*s))) == NULL) | |
357 return NULL; | |
358 } | |
359 memset(s, 0, sizeof(*s)); | |
360 s->image_data_mode = mode; | |
361 s->min_bits_per_row = min_bits_per_row; | |
362 restart_buffer(s); | |
363 return s; | |
364 } | |
365 /*- End of function --------------------------------------------------------*/ | |
366 | |
367 SPAN_DECLARE(int) t38_non_ecm_buffer_release(t38_non_ecm_buffer_state_t *s) | |
368 { | |
369 return 0; | |
370 } | |
371 /*- End of function --------------------------------------------------------*/ | |
372 | |
373 SPAN_DECLARE(int) t38_non_ecm_buffer_free(t38_non_ecm_buffer_state_t *s) | |
374 { | |
375 if (s) | |
376 free(s); | |
377 return 0; | |
378 } | |
379 /*- End of function --------------------------------------------------------*/ | |
380 /*- End of file ------------------------------------------------------------*/ |