Skip to content

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=3 by itself.
  • The calling side sends CNG (0.5 s of 1100 Hz every 3.5 s) while it waits, and starts +FRH=3 when 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 +FTM data (the next command) is left for the command interpreter, which runs it after the OK.
  • In +FTH, an empty frame (<DLE><ETX> alone) ends the transmission with OK (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 (label quick) 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. The Class1T38Packets cases check the packets' fields and times.
  • frontend/asterisk/test/efax.sh runs efax on dmodemd against Asterisk's fax over T.38 (dmodemd's SIP_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 and NO 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:

  1. After the DIS (T30_EV_DIS), the machine waits for +FDT, then sends the DCS with +FIS's session parameters (t30_session(), t30_resume()).
  2. For each page, it waits until the DTE's page has come and been decoded (next_page() returns 2 until then).
  3. It waits for +FET's post-page command (post_page()).
  4. 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's polled) 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.Fax2Poll polls a page, and Fax2PollV34 does the same on V.34.
  • Core.Fax2Abort ends 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:

  1. 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.
  2. A PPS follows on V.21, with the page and block counters.
  3. The receiver answers MCF, or PPR with a map of the frames to send again.
  4. 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 T4Page may carry colour: comps 3 (sRGB) or 1 (grey) and its 8-bit samples in pix, with bits a 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. TiffIn reads uncompressed 8-bit grey or RGB pages that way, scaled to 1728 pels at 200 pels an inch; TiffOut writes 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's Rates/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's Calls/T30Spandsp.* cases (label spandsp) run one machine against spandsp's fax machine in both directions, with and without ECM, and with line hits.
  • fax_test's Mcf/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:

  1. A no-signal indicator, then 75 ms.
  2. 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).
  3. The data, paced as the modulation would carry it:
  4. HDLC frames without their FCS (seven octets a packet on V.21, as T.38 7.5 has it), each ended by hdlc-fcs-OK and the last by hdlc-fcs-OK-sig-end;
  5. T.4 data (the TCF's zeros, and the page's bits), ended by t4-non-ecm-sig-end.
  6. 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_test covers 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's Calls/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).