Fax: technical details¶
This is the technical companion to Fax, the plain-English overview. Start there; this page keeps the full detail: the code's names, the Recommendations' clauses, the numbers and the test lists.
Terms used on this page:
- DTE: the fax program on the computer, which talks to the modem.
- T.30: the fax protocol itself (the frames DIS, DCS, CFR, MCF and so on, sent on V.21 at 300 bit/s), with the pages on a faster modulation.
- ECM: T.30's error correction mode (T.30 Annex A, T.4 Annex A).
- T.85: the JBIG (T.82) coding of fax pages, with ECM only.
- T.42: colour and grey-scale fax pages in JPEG (T.81) of CIELAB samples (T.4 Annex E), with ECM only.
- T.38: fax over IP, as IFP packets carried in UDPTL.
Fax (class 1)¶
fax_class1.cpp implements the T.31 class 1 commands on top of the
modulations in fax_modems.cpp:
| Command | What it does |
|---|---|
+FTH=3 / +FRH=3 |
Send or receive V.21 channel 2 HDLC frames: flags, bit stuffing, CRC-16, <DLE> shielding, OK or ERROR for each received frame |
+FTM= / +FRM= |
Send or receive on a fast modulation: 24, 48 (V.27ter); 72, 96 (V.29); 73, 74, 97, 98, 121, 122, 145, 146 (V.17; each even code is the short train) |
+FTS= / +FRS= |
Send silence for, or wait for silence of, n × 10 ms |
The start of a call¶
- The answering side sends CED (2100 Hz for 3 s) and then starts
+FTH=3by itself. - The calling side sends CNG (0.5 s of 1100 Hz every 3.5 s) while it
waits, and starts
+FRH=3when the answer tone is heard.
Characters from the DTE¶
Any character from the DTE other than XON and XOFF stops +FRH, +FRM
and +FRS with OK, even before their CONNECT (T.31 8.3.2, 8.3.4,
8.3.6). efax, for example, aborts a +FRH that has waited too long by
sending CAN. While a class 1 command runs, the DTE's characters belong to
the engine (as data, or as that abort character). They are read as
commands again only after the command's result.
The DTE's data for +FTH and +FTM is read one character at a time, and
nothing is read past <DLE><ETX>:
- A frame that follows in the same write waits until the current one has gone out.
- Whatever follows the last frame or the
+FTMdata (the next command) is left for the command interpreter, which runs it after theOK. - In
+FTH, an empty frame (<DLE><ETX>alone) ends the transmission withOK(8.3.5/T.31). A frame of one octet goes out as it is.
core/test/scripts/fax_dte.txt tries all three; it runs in core_equiv
as CoreScript.FaxDteUntilsCome.
The receivers¶
The receivers find the training by matching the received phase steps against the known sequence. The V.29 and V.27ter training sequences repeat every 127 symbols, so the end of the alternations before them tells the receiver which repetition it is receiving.
A V.17 short train continues from the equalizer of the last long train at the same rate.
V.17 after a short train¶
After a short train, the original library and spandsp go straight on to the scrambled ones (segment 4), without the 64-symbol bridge that follows a long train. This transmitter does the same, with its trellis encoder in the state from which the original library starts segment 4 (the original receiver expects that state).
After a short train, this transmitter's segment 4 is 240 symbols (100 ms; the original library sends 144). After a long train it is the standard 48 symbols. After the data, 80 symbols of ones follow. Both lengths are for the original library's receiver, which processes in 20 ms frames: depending on where its frames fall, it starts the data before it has converged and ends it early, and the extra ones cover both.
The receiver takes a short train with or without the bridge; the first symbols after the training tell which. During a bridge it decides on the nearest training point instead of following the known sequence. The Agere modem's bridge is not that sequence, and following the wrong points wound the carrier loop up to a frequency offset of some 3 Hz, which spoiled the first seconds of data.
A known quirk of the original receiver at 12000 bit/s¶
At 12000 bit/s after a short train, the original library's receiver now and then decides an outer corner of the constellation as the point 8 away in its subset (a coordinate of 7 comes out as -1). That is one wrong bit on the line, and three after the descrambler.
Our signal is the same every time. Whether and where the error happens depends only on where the receiver's 20 ms frames fall on the long training and on the short one. It happens in three of the four alignments, about once a page.
- Sending the data 1.4 dB lower clears all four alignments, but 0.5 dB lower loses the TCF instead.
- Sending TEP before the training (the original library sends 200 ms of it) clears two of the three.
So the transmitter keeps V.17's levels and sends no TEP.
V.27ter and the receive level¶
V.27ter also leads the data with 100 ms of ones (the original library sends some 60 ms). With the standard's 8 symbols, the original receiver lost the start of a page now and then.
In data mode the V.17 receiver corrects a clear error in the data's power (6 % or more, averaged over some 500 symbols), because the original library's data constellation comes about 1.4 dB below its training.
Tests against spandsp¶
ctest -L spandsp (with libspandsp-dev installed) feeds spandsp's V.17
transmitter and T.4 encoder, as Asterisk's SendFAX uses them, into
these receivers.
Class 1 over T.38¶
FAX_t38_start() (dsplibs.h) moves the engine from the audio to T.38,
also in the middle of a call (dmodemd's call switches to it). The DTE
sees the same commands and results. The line's signals become IFP
packets (dsp/t38.h), sent at the time the signals would take;
FAX_process() is still called with samples to keep that time, but its
audio is silence. A transmission in progress starts over on T.38 with
whatever has not been sent yet. FAX_t38_stop() goes back to the audio.
| Command | On T.38 |
|---|---|
+FTH=3 |
The V.21 preamble's indicator, then a second's worth of flags' time, then each of the DTE's frames as it comes. Frames are paced at 300 bit/s in packets of at most seven octets, each ended by hdlc-fcs-OK (hdlc-fcs-OK-sig-end for the final frame). Accepting a frame that is not the final one is the CONNECT for the next, as on the audio. 100 ms after the final frame (or an empty one): no-signal and OK |
+FTM= |
The modulation's indicator and its training's time, then the DTE's octets at the modulation's rate, bit-reversed the T.38 way, t4-non-ecm-sig-end after the last, and no-signal 60 ms later. If the data starts with two HDLC flags, it is the DTE's own HDLC (in ECM, fax software frames the ECM blocks itself). The frames are then taken out of the bits and sent as HDLC data, each ended by hdlc-fcs-OK (or hdlc-fcs-BAD if the DTE's FCS was wrong), with hdlc-sig-end at the end |
+FRH=3 |
CONNECT at the V.21 preamble (or at its first data). Each frame goes to the DTE with an FCS computed here (deliberately spoilt, with ERROR, for an hdlc-fcs-BAD). NO CARRIER when the signal ends without a frame |
+FRM= |
CONNECT at the first data of a fast modulation. T.4 data goes to the DTE in the DTE's bit order. HDLC frames (ECM) are rebuilt as an HDLC bit stream (flags first, zeros stuffed, the FCS, two closing flags at the end). NO CARRIER at the sig-end or no-signal |
+FRS= |
Silence is "no signal" on T.38. CED is its indicator after 200 ms of no-signal. No CNG is sent (as with the T.30 machine below) |
Tests:
class1_t38_test(labelquick) has a DTE of its own go through T.30 with these commands against our T.30 machine over T.38, with the packets' timing. It covers sending and receiving, with and without ECM, both packet versions, and a switch to T.38 after a while on the audio. TheClass1T38Packetscases check the packets' fields and times.frontend/asterisk/test/efax.shruns efax on dmodemd against Asterisk's fax over T.38 (dmodemd'sSIP_T38; see Using dmodemd).
Class 1.0: V.34 half-duplex¶
With +FCLASS=1.0 and +F34= (maxp not 0), the core calls FAX_v34()
(dsplibs.h) right after FAX_create() (not on T.38, nor after adaptive
answer's own answer tone): the engine's line is a V.34 half-duplex
modem (v34_hdx_create(), V.34) with the primary
channel between minp and maxp (v34_hdx_rates()), V.8 first (CM
calling, ANSam answering, no CNG). Once its control channel is up the
engine writes +F34:<p>,1 to the tty and gives CONNECT; from then on
the DTE's data is T.31's V.34 data mode (Annex B), as HylaFAX speaks it:
- frames each to
<DLE><ETX>both ways (the DTE's without an FCS, the engine's with theirs),<DLE>doubled,<DLE><SUB>two of them; the DTE's go out on the control channel with flags between them; <DLE><0x6B>from the source DTE: once its control channel frames are out the modem turns to the primary channel (v34_hdx_primary()); the DTE's frames that follow (the ECM block, no RCP needed) go on it,<DLE><0x6D>after the last;- to the DTE at either end:
<DLE><0x6B><DLE><0x6F+p>when the primary channel is up, the frames it carries,<DLE><0x6D><DLE><0x6E>when the control channel (1200 bit/s) is up again (also the first time); <DLE><EOT>from the DTE drops the modem:OK. The line going drops it too:<DLE><EOT>to the DTE andNO CARRIER. Rate renegotiation and control channel retrains are not asked for.
Without V.8 at the other end the engine is class 1 again: calling, the
answerer's V.21 flags (or V.8's failure) drop the modem and +FRH=3's
CONNECT and frames follow; answering, the ANSam was the CED and
CONNECT comes for the DTE's +FTH=3 frames.
class1_v34_test (ctest's quick) has a DTE of its own go through
T.30 Annex F with it, sending (to 33600, and capped with maxp 6) and
receiving, against our T.30 machine on V.34 through G.711 with a little
noise, and with a machine without V.34 calling and answering.
Fax (class 2 and 2.0)¶
fax_class2.cpp implements T.32's class 2.0, and the older class 2 that
fax programs know (the EIA/TIA-592 draft, SP-2388). Its entry points are
FAX2_* in dsplibs.h. It is part of the T.30 library, so a program
built without that library has no +FCLASS=2.
The modem runs the T.30 machine described below, with the class 2 engine
as its host (t30_config's host). The engine paces the machine.
Sending:
- After the DIS (
T30_EV_DIS), the machine waits for+FDT, then sends the DCS with+FIS's session parameters (t30_session(),t30_resume()). - For each page, it waits until the DTE's page has come and been
decoded (
next_page()returns 2 until then). - It waits for
+FET's post-page command (post_page()). - It reports the CFR (
T30_EV_TRAINED) and each MCF (T30_EV_PAGE_SENT).
Receiving: the machine runs as it would on its own. The engine keeps
what came in, the session (T30_EV_TRAINED) and the pages with their
post-page commands (T30_EV_POST), for ATA's results and for each
+FDR.
Page data: the DTE's pages are MH with EOLs, in +FBO's bit order.
They are decoded into a bitmap and coded again for the line, with the
scan line fill, MR on receipt, and ECM either way. So the DTE never has
to frame ECM.
Polling:
- An answerer with
+FLP=1(t30_config'spolled) sets DIS bit 9. A DTC (with the CIG before it) then makes it the sender, as a caller is after the DIS. - A caller whose remote offers a document polls with
+FDR(t30_poll()): it sends CIG and DTC instead of the DCS, and then it is the receiver. - The frames' X bit stays the caller's.
T.38: t30_set_t38() moves the machine to T.38 (or back) at any
point of the call. Whatever was going out is sent again from its start
on the new path, as FAX_t38_start() does for class 1.
V.34 fax (T.30 Annex F): a +FIS bit rate (br) above 5 (16800 to
33600 bit/s) together with ECM offers V.34 half-duplex (t30_config's
v34, t30_v34()). V.8 carries the call function: a caller sends, or
polls when +FSP=1 was set before it dialled (v34_poll). +FIS: and
+FCS: report the V.34 rate as br 6 to 13.
Tests (in core_test):
Classes/CoreFax2.TwoPages/*sends two pages between two modems in class 2.0, class 2, class 2.0 with ECM and the other bit order, on T.38 from the start and from the DIS on, and on V.34, with the bitmaps compared.Core.Fax2Pollpolls a page, andFax2PollV34does the same on V.34.Core.Fax2Abortends a call with+FKS.
Fax machine (T.30)¶
t30.cpp is a group 3 fax machine on these modulations. It is used by
libdmodem's fax and the PBX modules' fax applications. The calling
machine sends a document and the answering one receives it.
Error correction mode¶
Both machines offer ECM by default (DIS and DCS bit 27), with frames of 256 octets:
- The page goes as its MH coding (or T.85, below), in blocks of up to 256 HDLC frames (FCD) on the fast modulation, with three RCP frames after each block.
- A PPS follows on V.21, with the page and block counters.
- The receiver answers MCF, or PPR with a map of the frames to send again.
- After four PPRs for one block, the sender sends CTC (and gets CTR) and carries on.
The sender answers RNR with RR, and the receiver answers RR, CTC and EOR as T.30 says.
The receiver ends a block at its RCP. The V.17 short training of the next block starts from the receiver's state at the end of this block, and the V.21 PPS after it would spoil that state.
T.85 (JBIG) pages¶
With ECM the DIS also offers T.85 (bits 78 and 79: any stripe height
L0), its octets carried to the tenth with the extension bits. A sender
whose remote offers bit 78 sets it in its DCS and sends each page as a
T.85 bi-level image entity (BIE) instead of MH; t30_config's
no_t85 keeps a machine to MH and MR, and t30_status's t85 says
which the call has.
jbig.cpp is the coder (T.82 as T.85 profiles it: one layer, one
bit-plane, sequential stripes):
- Sending: stripes of 128 lines (T.85's basic L0, so DCS bit 79 is 0), the three-line template with the AT pixel in its default place (MX 0), typical prediction (TPBON), and the page's height in the header (no NEWLEN). The BIE's octets go into the ECM frames as they are: T.85 sends it least significant bit first, as ECM sends octets.
- Receiving: a DCS with bit 78, or with bit 79 alone (as spandsp sends T.85 with another L0), means T.85. The frames' octets are kept until the page ends (they came with good FCSs, so there are no bad rows to look for block by block), then decoded and scaled or centred to 1728 pels. The decoder takes what T.85 lets a sender use: any L0, the two-line template (LRLTWO), typical prediction, AT moves (ATMOVE, a lag up to MX and 127, its line counted from the top of the stripe that follows), an unknown height (YD of all ones) ended by NEWLEN, COMMENT segments, SDRST, and ABORT. A BIE that ends early or is cut by ABORT keeps the lines decoded; one that is not T.85 (more layers or planes, deterministic prediction) loses the page. A page is at most 32768 lines.
The QM coder follows T.82's flow diagrams, with the carry-free branch of FINALWRITES writing BUFFER, not BUFFER + 1 as Figure 30 shows. Each stripe's coded data drops its trailing 0x00 octets, which the decoder reads past the end anyway.
jbig_test checks the coder against T.82 clause 7: the 256-pixel
arithmetic coder sequence of 7.1 (its 25 coded octets, and decoded
back), and the 1960 by 1951 artificial image of 7.2.1 in its three
sequential codings (no TP with 1951-line stripes, the same with the
two-line template, and TP with 128-line stripes and an AT move to lag 8
at stripe 9), whose stripe coded data, stripe data entities and BIE
match Table 29's byte counts exactly. It also round-trips fax-like
pages, and decodes a BIE with YD of all ones, a comment and NEWLEN, one
cut short, one capped in lines, and random data.
T.42 (JPEG) colour and grey-scale pages¶
With ECM the DIS also offers JPEG (bit 68), in full colour (69), and
takes colour without subsampling (73); t30_config's no_colour turns
that off, and t30_status's jpeg says what a call sends (1 grey, 2
colour).
- Pages: a
T4Pagemay carry colour:comps3 (sRGB) or 1 (grey) and its 8-bit samples inpix, withbitsa dithered copy (an 8x8 ordered dither of the lightness) for whatever takes only black and white: the line without JPEG, class 2's DTE, MH TIFF readers.TiffInreads uncompressed 8-bit grey or RGB pages that way, scaled to 1728 pels at 200 pels an inch;TiffOutwrites such a page uncompressed (RGB, or grey with black zero) at 200 pels an inch. - Sending: a page with colour goes in JPEG when the remote offers bit 68 (and 15, 200 by 200): in colour if it offers 69, else its lightness alone. The DCS sets 68, 69 for colour, 70 (the tables are T.81's K.3 to K.6) and 15. A page without colour goes as before, so a document that mixes them sends EOM between the two kinds, and a new DCS (as for a change of resolution).
- Receiving: a DCS with bit 68 (69: colour) means JPEG. The frames are kept to the page's end as for T.85, decoded, turned from CIELAB to sRGB, scaled or centred to 1728 pels, and dithered. A JPEG cut short keeps its lines so far, with 1 row counted bad.
jpeg.cpp is the coder:
- Encoder: what T.4 E.6.2 lists: SOI, the G3FAX APP1 (version 1994, 200 pels an inch), DQT (K.1 and K.2 at quality 75), DHT (K.3 to K.6), SOF0, one interleaved scan (four L* blocks, then a* and b, for 4:1:1 with a and b* averaged over 2x2, T.4 E.6.3), EOI. Optionally DRI with RSTn, and DNL for an image whose length is not known at the start.
- Decoder: any baseline or extended (SOF1) 8-bit Huffman sequential frame of 1 or 3 components: sampling factors up to 4, one scan or several, 8 or 16-bit quantisation tables, restarts, DNL (Y 0 in the frame header), APPn and COM skipped, the octets after EOI ignored (T.4's padding of the last frame). Progressive, lossless and arithmetic-coded frames are refused.
- CIELAB: T.4 E.6.4's defaults: D50, L = L* x 255/100, a = a* x 255/170 + 128, b = b* x 255/200 + 96, from sRGB through XYZ with the Bradford-adapted sRGB matrix.
- The JPEG's octets go into the ECM frames as they are, as spandsp does.
jpeg_test checks the encoder's markers (and that each Huffman table
is a whole code of T.81's symbols), round trips of grey and colour
pictures (with 4:1:1 and without, odd sizes, restarts and DNL giving
the same pels), damaged and cut-short data, and the CIELAB conversions
(white is 255/128/96). Outside the tests, the encoder's JPEGs were
decoded by libjpeg (through Python's Pillow) at 50 dB, and libjpeg's
(with optimised tables, restarts, 4:2:0) decoded here within 52 to 68
dB of libjpeg's own decoding. fax_test's T30Colour.SendsColourPages
sends a colour page, a black and white one and a grey one between two
machines (JPEG colour, T.85, JPEG grey: 42 and 51 dB), and again to a
receiver with no_colour (all dithered, the same bits).
spandsp 0.0.6 is built without T.85 (SPANDSP_SUPPORT_T85 is off in
its configure), so spandsp_test's calls stay in MH or MR. FreeSWITCH's
spandsp (3.x) has it: its fax test (frontend/freeswitch/test/fax.sh)
sends and receives T.85 pages with AT moves (MX 127), VLENGTH and the
L0 option.
T.43 (lossless JBIG) colour and grey-scale pages¶
With colour on, the DIS also offers T.43 (bit 36, which T.30 allows
only with 68) and takes plane-interleaved data (37); t30_config's
no_t43 leaves T.43 out (JPEG only), and t30_status's t43 says
what a call sends (1 grey, 2 colour).
- Sending: a page with colour goes in T.43 when the remote offers bits 68, 36 and 15 and the page has few colours: in colour (the remote offers 69, the page is RGB) when it has at most 4096, as a palette (image type 16: the colours in T.42's 8-bit CIELAB, the most frequent first, indices of as few bits as hold them); in grey otherwise when its grey levels (or its colours' luma) are at most 16, as 8-bit L* (type 32). Other pages go in JPEG as before. The DCS sets 36 (69 for colour; 68 0, 37 0: stripes interleaved) and 15; a change between T.43, JPEG and black and white sends EOM. On the test's bar chart (five colours, 1728 by 400) T.43 takes 199 octets, JPEG 25809; on its four-level grey chart 300 against 11882.
- Receiving: a DCS with 36 (and not 68) means T.43; the frames are kept to the page's end, decoded (at most 4800 lines), turned to sRGB and handed on as a JPEG page is. Every image type is taken: one bit a colour (RGB, CMY, CMYK: the primaries, black over anything), palettes of 8 or 12-bit tables, grey and colour of 1 to 12 bits a component (12 bits rounded to 8, fewer stretched), and either interleave. The gamut and illuminant entries (G3FAX1, G3FAX2) are skipped: the defaults are assumed, as for JPEG.
t43.cpp is the format (T.43 clause 7): the magic number ff a8, the
G3FAX0 entry (version 1997, resolution, JBIG, image type, bits a
component), G3FAX3 for a palette (ff e3, a 4-octet length), the ECIH,
one BIE of all the bit-planes, then ff a9. Grey and colour samples are
Gray coded (7.3.1), so a small change of a sample changes one plane.
The planes go L's first (from its most significant bit), then a's and
b*'s; a palette index from its most significant; red, green, blue (or
cyan, magenta, yellow, black) for one bit a colour.
jbig.cpp codes the planes: one BIE of P planes (at most 36), each
with its own probabilities, typical prediction and AT pixel, in the
order T.82 Table 11 gives for one layer. T.43 sends ILEAVE and SMID
(stripe interleave, the basic one: a stripe of each plane in turn, L0
128) and accepts ILEAVE alone (plane interleave: each plane whole). An
ATMOVE moves the AT pixel of the next stripe's plane. T.85's single
plane is the same code with P 1.
t43_test checks the header against T.43's examples (G3FAX0 and
G3FAX3's lengths, the palette's table ID and count), Gray code against
Table 6 (the planes of 0 to 15), round trips of every image type and
number of bits in both interleaves and with short stripes, the colours
each type gives, cut-short and damaged data, and JBIG's six stripe
orders (and the two T.82 forbids). fax_test's
T30Colour.SendsChartsLossless sends a colour chart, a black and white
page and a grey chart between two machines: in T.43 the colour chart
comes back within 1 level of each sample (T.42's CIELAB rounding) and
the grey one the same; to a receiver with no_t43 they go in JPEG
(worst errors 83 and 36 levels, at the edges).
spandsp's T.43 (FreeSWITCH's 3.x) has its encoder compiled out and mod_spandsp does not offer it, so there is no T.43 machine to call outside these tests.
T.44 (mixed raster content) pages¶
With colour on, the DIS also offers T.44's mode 1 (bits 92 to 94 as 1,
0, 0, which T.30 allows only with 68) and stripes as long as the page
(95); no_mrc leaves it out, and t30_status's mrc says what a call
sends (1 grey, 2 colour). An MRC page is a mask (bi-level, at the
page's 200 pels an inch) that picks, pel by pel, between a background
and a foreground: each a JPEG or a T.43 image at its own resolution
and place, or one colour. Text over a picture keeps its edges sharp in
the mask while the picture goes in JPEG at half the resolution.
- Sending: a colour or grey page goes in T.44 when the remote offers mode 1 (and 68 and 15) and the page has text or lines on it: dark pels with a light one within 3 pels make the mask, and at least 0.1 % of the page must be mask (a page of few colours still goes in T.43, one without text in JPEG). Each stripe of 256 lines is one of: the mask alone (the foreground and background each one colour: black text on white), the mask with a background JPEG at 100 pels an inch (the pels under the mask filled from their neighbours), with a foreground JPEG at 100 too when the text has more than one colour, or a background JPEG alone at 200 when the stripe has no text. The mask goes in T.85 if the remote offers 78, else in MH. The DCS sets 92, 68 (69 for colour), 70, 78 if the mask is T.85, and the extension bits up to 92. On the test's page of text over a picture (1728 by 600 in colour) the call takes 63 s against 275 s in JPEG, and the page comes back at 42.6 dB against 29.6 dB, its text's edges within 1.7 levels against 7.5; with the mask in MH it takes 96 s.
- Receiving: a DCS with any of 92 to 94 means T.44; the page is decoded at its end (at most 4800 lines) and handed on as a JPEG page is, in grey when every layer and colour is grey. Mode 1 is taken whole: masks in MH, MR, MMR or T.85, layers in JPEG or T.43 at any resolution that divides the mask's, their offsets, stripes of one, two or three layers, the 4-octet lengths, and the optional segments (skipped: the gamut and illuminant are the defaults). Modes 2 and up (whose start of stripe differs) and JBIG2 are not.
t44.cpp is the format (T.44 clause 9): ff d8 and the start of page
(ff ed, "MRC" 0, version 2, mode 1, the coders, the mask's resolution,
the width), ff d9, then each stripe's start (ff ed, "MRC" 1, the layers
in it, the two colours in T.42's CIELAB octets, the offsets, the
height, the mask's length) and its layers in the order mask,
background, foreground; ff d9 ff d9 ends the page. The background and
foreground end themselves (a JPEG at its EOI, a T.43 BCIE at ff a9),
so jpeg_decode() and t43_decode() say how many octets they took.
t44_test checks the start of page's octets, round trips of text over
a picture in colour and grey with either mask (the colour page 63 KB
against 302 KB in JPEG, the grey 16 KB against 281 KB), each kind of
stripe (black text on white comes back exact), a page written by hand
(an optional segment; a background JPEG at 100 pels an inch at an
offset over its colour; an MMR mask over a T.43 foreground; a stripe of
only a foreground) and cut-short and damaged pages. fax_test's
T30Colour.SendsMrcPages sends a colour and a grey page of text over
a picture between two machines, with the mask in T.85 and in MH, and
to a receiver without T.44 (JPEG).
Binary files (T.434)¶
A document may carry binary files between its pages: a T4Page whose
file holds a T.434 BINARY-DATA message (t434_encode() makes one of
a BftFile: its name, MIME type, modification time and octets). With
t30_config's bft and ECM, the DIS offers BFT (bit 53), and the DCS
of a file sets 53 (and 27); a change between files and pages sends EOM.
The message goes as one ECM page (T.30 V.4 case a), in blocks as a
page's coded data does, its last frame short (T.4 B.6: no pad octets),
then PPS-MPS, -EOM or -EOP. The receiver keeps a file's octets across
pages (case b, another sender's) and hands each whole message to
page_received() as a page with file (several in a page: case c);
t434_decode() has the files back. t30_status's bft says a file is
going, files counts them (they are not in pages) and
files_left_out counts those the sender left out because the remote
has no BFT or no ECM (a document of only those ends with
T30_ERR_INCOMPATIBLE). An FDM from the receiver (it won't take the
file as it is) ends the call: we have no other form of the file to
send. A received name is the remote's: take only its last component
before using it as a path.
t434.cpp is the message in BER (X.690): [APPLICATION 23] holding a
SEQUENCE of attributes for each file; we send protocol-version [28]
(version 3), filename [0], date-and-time-of-last-modification [5],
filesize [13], mime-media-type [32] (a high tag number) and
data-file-content [30] as an OCTET STRING, and take those in any order
with definite or indefinite lengths, strings in pieces, content as
EXTERNAL, and skip every other attribute.
t434_test checks a small file's octets, a round trip with every
attribute (lengths of three octets), a message as other coders write
it, the length as the octets come, and cut-short and damaged messages.
fax_test's T30Bft.SendsFiles sends a page, a file of 37 octets, one
of 100000 (two blocks) and a page, to a receiver that takes files and
to one that doesn't (both pages still go); T30Bft.NeedsEcm a file
without ECM; t38_test's T38Pair.SendsFiles files over T.38 with
bursts of lost packets (the frames asked for again).
Without ECM¶
The receiver answers each post-page command (MPS, EOM, EOP) with MCF or RTN.
When the sender misses the MCF, it sends the command again after T4 (3 s). If no page training has arrived since (the fast receiver never found one), the receiver treats the command as a repeat and answers MCF again, as spandsp's receiver does. Answering RTN there would make the sender send again a page the receiver already has.
V.34 half-duplex (T.30 Annex F)¶
With t30_config's v34 (t30_v34()), the machine uses the half-duplex
V.34 modem (V.34's details),
which has the line from the start of the call:
- ANSam takes the place of CED, and V.8's CM that of CNG. The CM carries the call function: T.30 transmit, or receive when the caller polls.
- The T.30 frames go on V.34's control channel at 1200 bit/s, with flags between them.
- The DIS has bit 6 (V.8) set. The DCS gives no rate (bits 11 to 14 are 0), and there is no TCF: the receiver answers the DCS with CFR.
- ECM is the only mode. Each block goes on the primary channel
(
v34_hdx_primary()), its frames after a few flags, and the PPS follows on the control channel once that is back. - A remote without V.8 gets V.21 and the usual fax modulations. An answerer whose ANSam draws no CM within 5 s sends its DIS on V.21, and a caller that hears a DIS on V.21 while V.8 is still waiting drops the V.34 modem.
- V.8 fixes which side sends on the primary channel, so a poll that V.8
did not announce (
t30_poll()with us as the source) is refused.
t30_v34_test runs two machines on V.34 back to back through G.711
(two pages at 31200 bit/s), and one machine with V.34 against one
without it, both ways round (they fall back to V.17).
Tests¶
fax_test'sRates/T30Pair.*cases put two machines back to back, at each rate from 14400 down to 2400, with ECM (in T.85, and once in MH:14400_ecm_mh), and with ECM on a noisy line. At 19 dB, ECM sends a few frames again and the page comes out right; without ECM, some two thousand rows came out damaged. The two test pages take 88 s at 14400 bit/s with ECM in T.85, 175 s in MH.spandsp_test'sCalls/T30Spandsp.*cases (labelspandsp) run one machine against spandsp's fax machine in both directions, with and without ECM, and with line hits.fax_test'sMcf/T30Lost.*cases lose the receiver's MCF to an EOM, an MPS and the last page's EOP.
DSP_T30_LOSE=<fcf in hex>[:<n>] sends the nth message (the first by
default) whose last frame has that type as silence, as if lost on the
line, keeping its timing (8c is MCF).
T.38¶
With t30_config.t38 set, the same machine is a T.38 terminal. It sends
and receives IFP packets (dsp/t38.cpp, in Annex A's encoding) instead
of the modulations.
A transmission¶
Each transmission is:
- A no-signal indicator, then 75 ms.
- The modulation's indicator, then its training's time (for the V.21 preamble, a second of flags; for ECM, 200 ms of flags too).
- The data, paced as the modulation would carry it:
- HDLC frames without their FCS (seven octets a packet on V.21, as
T.38 7.5 has it), each ended by
hdlc-fcs-OKand the last byhdlc-fcs-OK-sig-end; - T.4 data (the TCF's zeros, and the page's bits), ended by
t4-non-ecm-sig-end. - 100 ms (HDLC) or 60 ms (T.4), then no-signal.
The octets carry the line's bits with the first bit in the top bit (7.1.2): the other way round from the frames as T.30 writes them.
CED is its indicator after 200 ms of no-signal. The calling side sends no CNG. The call has moved to T.38 because it is already known to be a fax call, and a gateway that plays CNG holds back what follows until it hears the other machine's V.21, which may be a DIS that has already gone by.
What comes in is taken the same way: a sig-end field or a no-signal
indicator marks the end of the carrier. t30_t38_time() tells the
machine how much time has gone by; the timers are the same as on audio.
Packet encodings and UDPTL¶
The IFP packets use the encoding of either:
- the 1998 ASN.1 (T38FaxVersion 0): field types in four bits, with a field without data leaving the low half of its octet to the next; or
- the 2002 ASN.1 (versions 1 to 3),
as spandsp and Asterisk have them. In our packets a field without data always goes last, so both versions read the same.
UDPTL numbers the packets and repeats the previous ones in each packet (redundancy). On receipt, lost packets are recovered from the next packet's redundancy, in their order, and a repeated packet is taken only once. A packet that uses FEC instead of redundancy is read for its primary packet only.
Tests¶
t38_testcovers the encodings (T38Ifp.*, including Appendix V's DIS), UDPTL with packets lost, late and repeated (T38Udptl.*), and two machines over T.38 (Nets/T38Pair.*): versions 0 to 3, 14400 to 4800 bit/s, with and without ECM, every fifth packet lost, bursts longer than the redundancy can cover, and a relay that renumbers the packets.spandsp_test'sCalls/T38Spandsp.*cases run ours against spandsp's T.38 terminal in both directions.- Class 1 over T.38 (dmodemd's) is covered in Fax (class 1).