Skip to content

alwaysAvailableFile and alwaysAvailableTracks are mutually exclusive, making custom offline video impossible for G711 audio #6005

Description

@ftaiolivista

Describe the feature

alwaysAvailableFile and alwaysAvailableTracks are mutually exclusive, making custom offline video impossible for G711 audio

Description

When using the always-available feature, there is no way to combine a custom offline video clip with a G711 audio track. The two configuration mechanisms are mutually exclusive, and G711 is only reachable through the one that forbids custom video.

Steps to reproduce

paths:
  mypath:
    alwaysAvailable: true
    alwaysAvailableFile: "./my-offline.mp4"
    alwaysAvailableTracks:
      - codec: H264
      - codec: G711
        sampleRate: 8000
        channelCount: 1
        muLaw: true

Expected: custom video from the file, G711 silence generated for the audio track.

Actual: the server refuses to start:

'alwaysAvailableFile' and 'alwaysAvailableTracks' cannot be used together

Why there is no workaround

Removing alwaysAvailableTracks and muxing G711 into the MP4 instead does not work either, because G711 is not accepted from a file:

  • checkAlwaysAvailableFile (internal/conf/path.go:154-159) whitelists only AV1, VP9, H265, H264, Opus, MPEG4Audio, LPCM and rejects anything else with unsupported codec %T.
  • mediasFromAlwaysAvailableFile (internal/stream/stream.go:24-114) has no *codecs.G711 case, so such a track would produce no media even if validation passed.

Conversely, removing alwaysAvailableFile gives up the custom video. G711 support exists only as synthetic silence generation in offlineSubStreamTrack.run (internal/stream/offline_sub_stream_track.go:163-190, emitting 0xFF for µ-law / 0xD5 for A-law), and that code is unreachable whenever a file is configured — the file branch short-circuits first, for every track:

// internal/stream/offline_sub_stream_track.go:81
if t.file != "" {
    // open + runFile + return
}
// synthetic audio generation below never runs

offline_sub_stream.go:45 passes the same AlwaysAvailableFile to every track, so the choice is all-or-nothing across the entire stream rather than per-track.

The same split appears in buildOfflineDesc (internal/stream/stream.go:226-243), which is a plain if/else — when a file is set, alwaysAvailableTracks is never consulted.

Impact

This affects any deployment whose live streams carry G711 audio — common with IP cameras and ONVIF/RTSP sources, and in VoIP/intercom setups. Since the offline segment's codecs must match the publisher's for the gapless concatenation the feature is built around, such users cannot substitute AAC or Opus in the offline segment. They are forced to use the built-in "STREAM IS OFFLINE" clip, with no way to show their own branding or message.

Possible solutions

  1. Allow the two options to coexist, treating alwaysAvailableFile as the source for the tracks it provides and alwaysAvailableTracks as the declaration for the rest. This is the most flexible and covers the case above directly.
  2. Per-track file selection, e.g. an optional file field on individual entries of alwaysAvailableTracks, letting video come from an MP4 while audio stays synthetic.

Documentation note

docs/2-features/08-always-available.md presents alwaysAvailableFile and alwaysAvailableTracks in separate examples but never states that they cannot be combined, nor that the supported codec set differs between them — G711 is listed as an available value for alwaysAvailableTracks, which is where users will reasonably expect it to keep working. Worth documenting regardless of which fix is chosen.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions