60db Logo
  • Guides

PCMU versus PCMA: companding errors you can reproduce

PCMU versus PCMA needs explicit law and PCM boundaries. Run known vectors, endian checks, and a bounded reconstruction fixture.

Editorial date
Reading time
25 min
One encoded byte branches into separate PCMU and PCMA reconstruction paths

TL;DR: PCMU and PCMA use different G.711 companding laws, so identical bytes can decode into different signed sample values. Resolve the negotiated law before decoding, declare PCM width and endianness after decoding, and test known vectors plus every possible code byte before investigating recognition quality.


A call connects, payload sizes look correct, and audio sounds harsh. The application assumes that every G.711 byte uses the same decoder. Changing the sample-rate label makes the output sound different but leaves the actual interpretation defect untouched.

Start with the declared law. The SIP troubleshooting guide explains how negotiated media evidence narrows the problem before application tuning. PCMU and PCMA are separate byte mappings, even when their payloads contain the same number of octets.

This guide provides small pure decoders and a bounded reconstruction fixture suite. It does not rank carrier audio, report recognition results, or publish a production media adapter. All signal examples are synthetic, and standards constants are identified as such.

The public ITU-T G.711 recommendation defines the companding standard. A developer asking why one library exposed a mu-law path but not an A-law decoder should distinguish library support from the format itself. That historical question is not evidence about current Jitsi support; the two laws need separate interpretation paths regardless of whether one library happens to expose both.

Table of contents

  1. Name the encoded and linear formats
  2. Resolve the RTP payload mapping
  3. Understand the reconstruction boundary
  4. Run the complete decoder fixture
  5. Compare against an independent implementation
  6. Reproduce common format mistakes
  7. Keep framing separate from conversion
  8. Diagnose with known signals
  9. Retain evidence through deployment
  10. Review a reproducible codec incident
  11. Separate release criteria from audio impressions
  12. Frequently asked questions
  13. Validate the mapping before the model

Name the encoded and linear formats

PCMU names G.711 mu-law audio, while PCMA names G.711 A-law audio. Both map each encoded octet to a reconstructed linear sample under a particular law. The encoded byte is not simply an unsigned linear amplitude that you can shift around zero.

A decoder reconstructs a signed sample value. The application then chooses how to represent that value in memory or in an output byte stream. Signed PCM16, little-endian PCM16 bytes, and a WAV container are related representations, but they are different boundaries with different metadata and validation rules.

For a synthetic sequence containing eight G.711 bytes, decoding produces eight linear samples. Packing those samples as PCM16 produces sixteen sample bytes. That change in byte count does not double the signal duration or sample rate; each reconstructed sample simply uses a wider representation.

Keep units in variable names and interfaces. Encoded octets, decoded samples, PCM sample bytes, and RTP timestamp ticks should not share an ambiguous field called length. An adapter that takes a byte count as a sample count can produce a perfectly repeatable timing error.

The audio chunk-size guide develops this distinction for streaming buffers. A chunk duration calculation requires the actual representation, channel count, and sampling rate. A payload size alone is insufficient when formats change along the path.

Endianness describes how a multi-byte value is ordered. A single G.711 code octet has no two-byte ordering to reverse. Endianness becomes relevant when a reconstructed sample is packed into a multi-byte linear PCM representation or when another container field uses a specified byte order.

The Python struct documentation makes the packing choice explicit. The <h format means a little-endian signed short with a standard size. Writing native-endian samples and assuming every consumer shares the current machine's convention introduces an avoidable portability defect.

Do not call all these representations raw PCM. A reader needs to know whether raw means headerless G.711, headerless signed PCM16, or bytes extracted from a container. Name the representation at every boundary and reject an unsupported declaration rather than attempting to infer it from plausible audio.

Resolve the RTP payload mapping

The public audio profile in RFC 3551 assigns static payload types for PCMU and PCMA under that profile. The familiar mappings are payload type zero for PCMU and payload type eight for PCMA, both with an 8 kHz clock and mono default. These are standards mappings within a context, not a universal parser for every byte stream.

A real adapter must inspect the negotiated session and relevant profile. Dynamic payload mappings, multiple media sections, and renegotiation can change what an observed packet means. A detached payload-type integer without its negotiation history cannot establish the current decoder contract by itself.

The transport comparison guide explains why a WebSocket message contract differs from an RTP session contract. If a provider says a WebSocket field contains base64-encoded mu-law, decoding the base64 yields G.711 bytes. It does not yield linear PCM samples or a WAV file.

Do not decode transport serialization twice. Base64 decoding, RTP header removal, G.711 reconstruction, and PCM packing are separate operations. Skipping one or applying it twice changes the input to the next stage. Trace those transformations with representation labels rather than one generic audio decode event.

Container parsing and payload mapping precede law-specific decoding

Negotiated media can also change during a call. A successful reoffer can alter a codec or destination while buffered data from a previous configuration still exists. The hold and re-INVITE guide explains why the new effective contract needs explicit ownership rather than an in-place global variable update.

Keep old payload context long enough to classify delayed work correctly. A packet that belongs to an older media revision should not be decoded under the current law simply because it arrived later. Your adapter must define the transition and rejection behavior with the protocol stack; the pure decoder below intentionally receives already selected law information.

Sample rate and RTP clock must remain distinct fields when supporting additional codecs. G.722 is the important RFC 3551 counterexample: its audio sampling rate is 16 kHz, while its RTP timestamp clock is 8 kHz. The 8 kHz and wideband ASR guide develops that distinction before rate conversion.

Understand the reconstruction boundary

Companding allocates encoded values nonlinearly across linear amplitudes. The decoder reconstructs one representative amplitude for each code. Multiple original linear inputs can map to the same encoded value. An encode-decode round trip cannot generally preserve every original PCM16 input exactly.

The correct assertion depends on the operation. Decoder compatibility asks whether a particular code reconstructs the expected value under the chosen convention. PCM packing asks whether the reconstructed integer becomes the intended bytes. A speech evaluation asks whether the resulting signal supports recognition and the application task.

For mu-law, the public code vectors FF and 7F reconstruct zero under the decoder below. The two code identities remain distinct even though their reconstructed values match. A canonical encoder may select one representation, so exact code-byte equality is the wrong universal round-trip assertion around zero.

For A-law, D5 reconstructs positive eight and 55 reconstructs negative eight in the signed PCM16 scale used here. Those are near-zero reconstruction levels rather than exact signed integer zero. Calling one arbitrary zero-filled byte buffer silence for both laws can create a large unintended signal under the wrong mapping.

These are format vectors, not measured quality results. Their purpose is to expose sign and mapping errors with inputs small enough to inspect. Do not infer that one law recognizes identifiers better because one reconstruction level is closer to a particular PCM integer.

Assertions distinguish decoder equality from lossy original-PCM reconstruction

The reference below includes a nearest-reconstruction selector to exercise reconstruction equivalence. It is deliberately a slow test helper, not a normative G.711 encoder or a production encoding recommendation. Ties follow its declared first-code policy, which can differ from another encoder's canonical byte choice.

This distinction lets the fixture test a meaningful round trip without publishing an unverified encoder. Decode a valid byte, select a code with the same nearest reconstructed amplitude, and decode again. The reconstructed amplitude should remain equal even when a canonical code identity changes.

If your application needs a real encoder, use a maintained implementation with a known contract. Compare its output with the appropriate public reference and document zero handling, clipping, and input scaling. Do not promote a convenient test selector into a production codec merely because it passes its own reconstruction loop.

Run the complete decoder fixture

The complete standard-library example runs on Python 3.11 and newer. It accepts only explicit PCMU or PCMA law names, validates individual integer code inputs, copies supported byte payloads, reconstructs signed samples, and packs them as little-endian PCM16. It does not parse RTP, decode base64, resample, or establish that metadata is truthful.

The implementation is a small expression of public format rules. The public FFmpeg PCM codec paths provide an independent maintained implementation for comparison. Do not copy a third-party implementation into an article without considering its license; comparison against an installed executable is a different activity.

from dataclasses import dataclass
import struct

LAWS = ("PCMU", "PCMA")


def decode(code, law):
    if law not in LAWS:
        raise ValueError("unsupported law")
    if type(code) is not int or not 0 <= code <= 255:
        raise ValueError("one integer octet required")
    if law == "PCMU":
        u = (~code) & 255
        magnitude = (((u & 15) << 3) + 132) << ((u >> 4) & 7)
        return 132 - magnitude if u & 128 else magnitude - 132
    a = code ^ 0x55
    segment = (a >> 4) & 7
    magnitude = (a & 15) << 4
    if segment == 0:
        magnitude += 8
    else:
        magnitude = (magnitude + 264) << (segment - 1)
    return magnitude if a & 128 else -magnitude


@dataclass(frozen=True)
class Decoded:
    law: str
    codes: bytes
    samples: tuple
    pcm16le: bytes


def decode_payload(payload, law):
    if law not in LAWS:
        raise ValueError("unsupported law")
    if not isinstance(payload, (bytes, bytearray, memoryview)):
        raise ValueError("byte payload required")
    owned = bytes(payload)
    if not owned:
        raise ValueError("empty payload")
    samples = tuple(decode(code, law) for code in owned)
    packed = struct.pack("<" + "h" * len(samples), *samples)
    return Decoded(law, owned, samples, packed)


def unpack_pcm16le(payload):
    if not isinstance(payload, (bytes, bytearray, memoryview)):
        raise ValueError("byte payload required")
    owned = bytes(payload)
    if not owned or len(owned) % 2:
        raise ValueError("empty or partial PCM16")
    return struct.unpack("<" + "h" * (len(owned) // 2), owned)


def nearest_reconstruction(sample, law):
    # Fixture helper only; NOT a normative or efficient encoder.
    if law not in LAWS or type(sample) is not int or not -32768 <= sample <= 32767:
        raise ValueError("supported signed PCM16 sample required")
    return min(range(256), key=lambda code: abs(decode(code, law) - sample))


def expect_error(fn):
    try:
        fn()
    except ValueError:
        return
    raise AssertionError("expected rejection")


def fixtures():
    # Public-format vectors, not measured audio quality.
    assert [decode(c, "PCMU") for c in (0xFF, 0x7F, 0x00, 0x80)] == [0, 0, -32124, 32124]
    assert [decode(c, "PCMA") for c in (0xD5, 0x55, 0x2A, 0xAA)] == [8, -8, -32256, 32256]
    for law in LAWS:
        result = decode_payload(bytes(range(256)), law)
        assert len(result.samples) == 256 and len(result.pcm16le) == 512
        assert unpack_pcm16le(result.pcm16le) == result.samples
        assert all(-32768 <= x <= 32767 for x in result.samples)
        for sample in result.samples:
            assert decode(nearest_reconstruction(sample, law), law) == sample
    assert decode(0xFF, "PCMU") != decode(0xFF, "PCMA")
    assert nearest_reconstruction(0, "PCMU") == 0x7F
    assert decode(0x7F, "PCMU") == decode(0xFF, "PCMU")
    # Synthetic endian and signedness boundaries.
    raw = struct.pack("<h", -300)
    assert unpack_pcm16le(raw) == (-300,)
    assert struct.unpack(">h", raw) != (-300,)
    assert struct.unpack("<H", raw) != (-300,)
    mutable = bytearray([255, 127])
    owned = decode_payload(mutable, "PCMU")
    mutable[0] = 0
    assert owned.codes == bytes([255, 127]) and owned.samples == (0, 0)
    from dataclasses import FrozenInstanceError
    try:
        owned.law = "PCMA"
    except FrozenInstanceError:
        pass
    else:
        raise AssertionError("mutable result")
    for code in (-1, 256, True, 1.5, "1"):
        expect_error(lambda code=code: decode(code, "PCMU"))
    expect_error(lambda: decode(0, "unknown"))
    expect_error(lambda: decode_payload(b"", "PCMA"))
    expect_error(lambda: decode_payload([1, 2], "PCMA"))
    expect_error(lambda: unpack_pcm16le(b"\x00"))
    expect_error(lambda: nearest_reconstruction(32768, "PCMU"))
    expect_error(lambda: nearest_reconstruction(True, "PCMA"))
    print("synthetic G.711 reconstruction fixtures passed")

if __name__ == "__main__":
    fixtures()

The result object owns a byte copy, an immutable sample tuple, and immutable packed bytes. Mutating the caller's bytearray cannot rewrite a previously inspected result. The fixture also checks property rebinding, invalid integer ranges, booleans posing as code integers, unsupported laws, and partial PCM frames.

A frozen result is useful evidence, but it does not establish the source format. The adapter still owns container parsing and payload mapping. If it supplies the wrong law, the decoder will faithfully reconstruct the wrong interpretation. That is why mapping fixtures must accompany these local arithmetic fixtures.

Compare against an independent implementation

Self-consistency tests alone are insufficient. Two functions can agree because they share the same incorrect sign convention or scaling assumption. Compare all possible encoded byte values with a separately maintained implementation, recording the actual executable version and the output format used for comparison.

For each law, create the ordered byte sequence from zero through 255, decode it with the reference implementation, and request signed little-endian PCM16 output. Compare the complete sample sequence with this article's decoder output. There are only 256 possible octet values per law, so the input domain is small enough to cover exhaustively.

The public FFmpeg table-generation source helps identify the maintained law-specific reference context. Pin an installed release for a repeatable check rather than treating a moving repository branch as a permanent binary identity. Preserve the comparison command and hashes in the evaluation report.

The fixture's nearest-reconstruction selector is intentionally not an independent oracle. It calls the same decoder it is testing, so its round trip establishes reconstruction-set consistency only. The separate executable comparison supplies a different implementation boundary. Explain both checks so a passing self-test does not acquire an exaggerated meaning.

Repeat the oracle check when the decoder code, output scaling, or reference version changes. A different reference convention may need explanation rather than an automatic code change. Confirm the public format expectation, signed scaling, and byte order before declaring either side incorrect.

Use the regression testing guide to preserve the exact failing vector if a comparison disagrees. A short reproducible input is more useful than a full call recording when the defect is a deterministic sample mapping. It is also easier to share without exposing caller content.

The new example deliberately avoids audioop. The official Python audioop documentation records its removal in Python 3.13 after deprecation in Python 3.11. An old snippet may still explain a historical API, but a new general-purpose guide should not silently require that removed module.

Reproduce common format mistakes

Wrong-law decoding preserves the number of samples. A length assertion still passes while the reconstructed values differ. Include a fixture whose code maps differently under PCMU and PCMA, then assert that selecting the wrong law produces a different reconstruction. This catches a mapping error that duration checks cannot see.

A signedness mistake happens later. A negative PCM16 value interpreted as unsigned becomes a large positive integer. If the next stage scales that integer as though it were a signed amplitude, the result can be badly distorted. The synthetic negative sample in the fixture makes the interpretation difference visible without a microphone or carrier.

Endianness mistakes also happen at the linear boundary. A known sample packed little-endian and read big-endian becomes a different value even though both readers consume two bytes. Test a value with distinct high and low bytes; a zero-only fixture would conceal the mistake.

Wrong law, wrong endian, and wrong width are separate format failures

Scaling is another independent decision. A library may expose floating-point samples while another exposes signed integers. Record the scale and clipping behavior when converting between them. Multiplying by an assumed maximum without checking the source convention can introduce clipping or unexpectedly quiet output.

Do not repair a mapping problem with gain. Increasing amplitude can make a corrupted signal louder without restoring the intended values. Validate the byte interpretation first, then investigate an actual level problem with a known input and a documented scaling contract.

The audio boundary guide addresses clipping and discontinuities that remain possible after correct decoding. Format correctness and boundary smoothness are separate properties. A codec fixture should not promise that it has tested every streaming segmentation policy.

The speaking-rate timing guide explains why rate labels and duration cannot be adjusted casually. Correct sample amplitudes played at the wrong rate still produce an incorrect signal. Keep sample mapping and time interpretation as separate assertions.

Keep framing separate from conversion

A G.711 decoder consumes codec bytes, not an arbitrary file or network packet. A WAV header passed as codec data becomes unintended samples. An RTP header passed through the same path produces another kind of garbage. Neither error is solved by changing the companding formula.

Parse the enclosing representation first. A container reader must identify the supported encoding and deliver only its sample payload. A transport adapter must identify which bytes belong to media under the negotiated contract. The pure decoder's intentionally small interface makes those responsibilities visible instead of concealing them in one permissive function.

The Python wave documentation describes a reader with a bounded supported WAV contract. Do not assume it can decode every compression format that can appear inside a WAV container. A header carrying an unsupported encoding requires a suitable decoder, not a forced PCM interpretation.

Payload boundaries also differ from sample boundaries and utterance boundaries. Multiple G.711 payloads can form a continuous signal, while a single payload can contain only part of a spoken word. A transport chunk should not automatically become a complete recognizer request or a standalone linguistic segment.

The WebSocket head-of-line diagnosis guide addresses timing stalls that correct decoding cannot remove. Ordered transport can deliver a burst of valid old audio after a stall. Decide whether the application still wants that audio before blaming the codec for conversational delay.

Use explicit input limits at the adapter boundary. The pure payload function copies its input and allocates decoded samples, so an unbounded network payload can create excessive work even when every sample maps correctly. A real adapter should bound message size and scheduling cost according to its own supported interface.

That operational limit belongs outside the mathematical decoder contract. Test the adapter's oversize rejection separately and retain the rejected payload's safe metadata without logging caller audio. Do not imply that a deterministic conversion function supplies transport authentication, flow control, or a complete media security boundary.

Diagnose with known signals

Begin with known code bytes and expected sample values. Those fixtures isolate the companding mapping from microphones, playback devices, network loss, and speech recognition. If the mapping fails locally, adding a live call only adds uncertainty.

Next use synthetic constant sections, sign changes, and bounded tones to inspect the surrounding linear path. Keep the generator configuration and expected sample count. A tone can expose a rate mismatch or a discontinuity, but it cannot tell you whether a caller's name will be recognized correctly.

Synthetic fixture families cover silence, sign, extremes, and wrong-law input

Encoded silence is law-specific. Mu-law includes zero-reconstruction code representations, while A-law near-zero codes reconstruct small values of opposite sign under the convention used here. The safe test names the law and expected decoded output; a buffer filled with the numeric byte zero is not a universal silence generator.

After local fixtures pass, inspect packet completeness and ordering. The burst packet-loss guide separates missing-media patterns from decoder defects. A correct decoder cannot reconstruct a packet that never reached its input without another explicitly supported recovery mechanism.

The FEC and concealment guide explains the separate boundaries for redundancy and estimated replacement audio. Concealed samples can sound plausible while representing uncertainty about missing media. Keep that condition distinct from the exact mapping of received G.711 octets.

Only then evaluate appropriately consented speech. The multilingual benchmark guide provides a cohort method for recognition outcomes. Keep language policy, task labels, source path, and endpoint configuration stable when comparing media conditions. A passing codec fixture is a format requirement, not a recognition benchmark.

Use consequential utterances in the speech corpus, including values that the workflow confirms before action. The confirmation prosody guide helps define that interaction boundary. Correct decoding does not eliminate the need for clarification when a field remains ambiguous.

Retain evidence through deployment

The criteria table uses ✓ to mean the method can establish the named property under its declared input. A ✗ means the method cannot establish that property alone. These marks compare evidence boundaries rather than ranking PCMU against PCMA on perceived quality.

Method Law mapping PCM byte order Transport negotiation Recognition outcome
Known decoder vectors ✓ locally ✗ without packing test ✗ ✗
Exhaustive independent decode comparison ✓ within scale convention ✓ with declared output ✗ ✗
Negotiation trace ✓ as declared ✗ ✓ within captured exchange ✗
Paired consented speech evaluation ✗ without format checks ✗ without format checks ✗ without trace ✓ within task criteria

G.711 reconstruction and PCM packing preserve different properties

Record the media descriptor and implementation version with each evaluation condition. Safe provenance can include law, decoded rate, channel count, output width, byte order, and validator version. The observability guide explains how to connect those facts to a request without copying sensitive audio into routine logs.

Separate conversion timing from overall response timing. The latency benchmark guide provides named endpoints for that measurement. A fast local decode does not establish a fast conversation when transport buffering, ASR, model work, or playback dominates the user-visible path.

Keep configuration stable across an evaluation cohort. The voice consistency guide describes why mixed settings complicate attribution. If the application changes decoder version or media policy midway through a run, split the condition rather than pretending it was one stable experiment.

For an application using 60db Agent, validate the documented audio boundary exposed to your integration. Do not infer a private codec implementation from this reference. The useful output is a reproducible public-format check and a clear account of which adapter supplies the law and transport evidence.

Write a rollback rule around actual failures: a known-vector mismatch, changed output scale, invalid framing, or a negotiated mapping the adapter cannot support. Keep an explicit unsupported disposition. A guessed decoder can produce audible output while destroying the evidence needed to understand why it is wrong.

Review a reproducible codec incident

Imagine a synthetic integration fixture where the negotiated descriptor selects PCMA but the application invokes the PCMU decoder. Both functions produce the same number of reconstructed samples, and both produce a byte stream that fits the downstream PCM16 interface. A request can pass message-length checks while containing the wrong signal.

Keep the smallest failing payload and its descriptor together. The byte sequence alone is not a complete incident fixture because the expected law lives outside those bytes. A useful regression record names the selected media revision, the law passed to the decoder, the expected output convention, and the exact observed mismatch.

The first diagnostic question is whether the mapping was wrong before decoding or whether the decoder implemented the selected mapping incorrectly. A known-vector test distinguishes those cases. If the decoder passes independent vectors for both laws, inspect the adapter that selects a law from the negotiated context instead of rewriting the arithmetic.

Next ask whether the linear output was serialized correctly. A correct signed integer sequence can become wrong bytes through endian or width mistakes. Compare the integer tuple before packing with the output bytes after packing. That split locates the defect without relying on how a playback device happens to interpret the result.

Then inspect timing. The same valid sample sequence can be played at an incorrect rate or delivered after its conversational deadline. The decoder has no knowledge of that deadline. Its success should remain one local result within a larger media disposition, rather than becoming permission to submit every reconstructed buffer whenever it arrives.

For a mid-call transition, retain the identity of the decoder configuration used for each accepted payload. If the selected media revision changes, old work must either finish under its old bounded context or be rejected according to the transition policy. Do not reinterpret an old payload under the latest law solely to avoid keeping a small amount of configuration history.

A good incident report separates deterministic reproduction from operational impact. The local fixture may prove that a specific law mismatch changes reconstructed samples. It does not establish how many calls were affected, whether callers heard the defect, or which tasks failed. Those impact questions require their own observed populations and evidence.

The independent authoring check for this guide ran the complete decoder from the published fence against an installed FFmpeg 9.0.2 executable on November 10, 2026. All 256 input octets for each law matched signed little-endian PCM16 output. This is a local exhaustive decoder comparison, not a speech, carrier, latency, or perceptual-quality measurement.

Keep that result scoped to the exact code and output convention. If you modify the sign handling, scale, or packing, rerun the comparison. If you replace the decoder with a library, run the same complete input domain against that library. Compatibility evidence belongs to a versioned implementation, not to a familiar function name.

Retain input order when preparing the independent comparison. A table containing the same reconstructed values in a different order is still incompatible with the signal. Compare each output position against its corresponding code, and require the expected output length before comparing bytes. A prefix match must not pass when the reference output is truncated.

Preserve the reference process failure separately from a value mismatch. If the executable is unavailable or returns an error, the independent check is unavailable, not successful. The standalone fixture remains useful, but its report should not claim the missing oracle comparison. This distinction prevents a skipped environment-dependent check from being mistaken for positive evidence.

Separate release criteria from audio impressions

A listening check is useful after deterministic format checks pass. It can reveal obvious clipping, repeated segments, or a wrong source selection. It remains sensitive to the listener, playback device, level, and material. Record its purpose rather than using an informal impression as the only evidence that a decoder is correct.

For structural release criteria, require exact known-vector agreement under the declared scale, complete domain agreement with the independent reference, correct PCM packing, and explicit unsupported-input handling. Add adapter-level mapping fixtures for every supported source contract. Each criterion should have a failure disposition that the integration can surface.

For conversational release criteria, use appropriately consented material and the actual application workflow. Measure critical-field interpretation and correction behavior separately from decoder arithmetic. If a caller has to repeat a value, preserve that recovery outcome even when the final task succeeds. A correct codec path is compatible with a recognizer making a linguistic error.

Keep unsupported formats visible. If an endpoint begins sending a new encoding, the safe local outcome is an explicit unsupported contract until the adapter supports it. Guessing a familiar law can produce a full-length stream of wrong samples, which is harder to diagnose than a clear refusal at the representation boundary.

A release report should identify which properties were checked locally and which require an integration environment. Packet negotiation, transport serialization, playback acceptance, and acoustic observation are different boundaries. Do not give a mathematical fixture credit for a device or network observation that never occurred.

When performance matters, benchmark a bounded workload using the actual implementation and runtime. The nearest-reconstruction helper in this article performs a search over code values and is intentionally unsuitable as an efficient encoder. Its correctness-oriented test role does not justify placing it in an unmeasured realtime path.

Finally, preserve the regression inputs independently of caller content. A short synthetic byte vector can demonstrate a mapping defect without retaining a recording. That keeps the reproducible evidence small and makes it easier to review a future decoder replacement against the same public-format contract.


Frequently asked questions

What is the difference between PCMU and PCMA?

They are the mu-law and A-law G.711 mappings. Each encoded octet reconstructs a sample under its selected law, so identical bytes can mean different amplitudes. Resolve the negotiated mapping before decoding. Equal payload size does not establish interchangeable interpretation.

Are both formats linear 8-bit PCM?

No. Their octets represent companded values rather than uniformly spaced unsigned linear amplitudes. The decoder reconstructs a signed linear value. Your application then chooses a representation such as PCM16 bytes, with its own width, scale, and endianness contract.

Does mu-law use a different sample rate from A-law?

The familiar PCMU and PCMA RTP mappings in RFC 3551 both use an 8 kHz clock and mono default. Their difference is the companding law. Other codec mappings require their own metadata, so do not infer every decoded sample rate from one RTP clock field.

Can I reinterpret A-law bytes as mu-law?

You can run that computation, but it produces the wrong reconstruction for the declared source. A law change requires proper decoding and encoding under supported contracts. Relabeling the same bytes does not perform that conversion and can preserve duration while damaging the signal.

Why does a wrong law produce noisy audio?

The decoder assigns different reconstructed amplitudes to the code values. The resulting sequence can differ substantially from the intended signal even though sample count and payload length remain correct. Use known vectors to diagnose the mapping before adjusting gain or model settings.

What does a G.711 code byte represent?

It selects one reconstruction value under a specific companding law. It is not self-describing evidence of the law, sample rate, or channel arrangement. Those facts come from the enclosing format or negotiated contract and must reach the decoder through a validated adapter.

Why does decoded PCM need more bytes?

A code octet becomes one reconstructed sample, which can be represented as a signed PCM16 value using two bytes. Sample count remains unchanged. Keep encoded-byte length and decoded-sample-byte length separate so that duration calculations do not accidentally double.

Does G.711 preserve the exact original PCM?

Generally no, because companding quantizes multiple input amplitudes into fewer encoded representations. A meaningful round-trip test checks declared reconstruction behavior and canonical handling. It should not assert exact equality for every possible original PCM16 input.

Are all zero representations unique?

No. Under the mu-law convention used here, FF and 7F both reconstruct zero. A canonical selector can choose one code, so reconstructed-value equality can hold while code identity changes. Document that equivalence instead of declaring every nonidentical byte round trip a defect.

Why is A-law silence not exact integer zero?

The near-zero A-law code levels reconstruct small signed values under the PCM16 convention used here. D5 and 55 reconstruct opposite signs. Test the declared mapping rather than treating a buffer of arbitrary zero octets as silence for every law.

Does endianness apply to one encoded byte?

A single octet has no multi-byte ordering to reverse. Endianness matters when reconstructed values become multi-byte PCM samples or when a container contains ordered fields. Keep that later packing operation separate from the law-specific reconstruction formula.

Where does endianness matter after decoding?

It matters when a signed sample is serialized into PCM16 bytes and interpreted by the next consumer. Use an explicit format such as little-endian signed PCM16 when that is the required contract. Test a nonzero value with distinct bytes; silence can conceal a swap.

How do signedness mistakes alter output?

Reading a negative signed PCM value as unsigned produces a different integer interpretation. Subsequent scaling can then create severe distortion or clipping. A short synthetic negative sample isolates this failure without requiring a live call or a large speech recording.

Can a WAV header identify raw codec bytes?

A valid supported container header describes its own payload, but arbitrary headerless bytes do not carry that evidence. Parse the actual container and honor its encoding declaration. Do not add a convenient PCM header to compressed bytes and call the result decoded audio.

Should a transport payload include a WAV header?

That depends on the documented interface. Many raw media contracts expect sample bytes without a file header, while file-upload interfaces may require a container. Follow the exact endpoint contract. A header passed as raw audio becomes unintended sample data.

How do I compare a decoder independently?

Decode every possible octet with a separately maintained implementation using the same signed output scale and byte order. Record the executable version and compare complete sample sequences. Self-consistency tests are useful, but they cannot independently establish the correctness of a shared formula.

Why avoid audioop in a new example?

Python removed audioop in version 3.13 after earlier deprecation. Depending on it would silently restrict the runtime or require another compatibility decision. The published fixture uses supported standard-library operations and makes its small public-format decoder explicit.

Does a tone round trip predict ASR accuracy?

No. Synthetic tones can expose conversion and timing properties under controlled inputs. Recognition requires consented speech, labels, endpoint settings, and task-specific criteria. Keep the structural result separate from any transcript or completed-task outcome.

Can a payload-type number be interpreted alone?

Only within the relevant profile and negotiated session context. Static mappings are useful within their specified scope, while dynamic mappings and renegotiation require additional evidence. Preserve the mapping history instead of applying one global decoder based on a detached integer.

Which negative fixtures should block release?

Block the supported path on wrong known vectors, independent-reference mismatches, incorrect endian packing, partial PCM frames, and unsupported law handling. Also test adapter mapping and transition behavior. A passing arithmetic fixture does not excuse an adapter that supplies the wrong media contract.

Validate the mapping before the model

Start with the selected law and a small known byte sequence. Run the complete fixture, compare the full encoded-byte domain with an independent implementation, and verify the output scale and byte order. Preserve any disagreement as a minimal regression.

Then validate the enclosing transport and container adapters, including mid-call changes. Only after those checks pass should you interpret speech-recognition differences or tune application behavior. Format correctness gives those later experiments a trustworthy input boundary.

Keep the decoder's promise narrow. It reconstructs public-format samples from explicitly selected codec bytes. It does not establish caller identity, captured bandwidth, reliable delivery, acoustic audibility, or completed tasks. A clear boundary makes the reference useful when a real system fails.