Members
(static, constant) TRANSCODE_CAUSE_H264_CEILING_HEIGHT
The 1080p hardware ceiling ItemPostPlaybackInfo clamps h264 to, independently of any setting. Renamed from TRANSCODE_CAUSE_DEFAULT_MAX_HEIGHT when the resolution predicate stopped treating 1080 as a cap the user could not beat: this is now the ONLY thing 1080 means in this file, and the old name claimed the other one.
- Default Value
- 1080
(static, constant) TRANSCODE_CAUSE_STEREO_CAPPED_CODECS
Codecs whose decode path JellyRock caps at 2 channels when the user turns "Decode Multichannel Audio" off. Mirrors stereoOutputCodecs in deviceCapabilities.bs getCodecProfiles() — and the list is the reason this predicate needs the source CODEC and not just its channel count: an EAC3 5.1 source hitting AudioChannelsNotSupported was not capped by us, because EAC3 is not on this list.
- Default Value
- aac,flac,alac,pcm,lpcm,wav,opus,vorbis
Methods
(static) causedByBitrateLimit(ctx, settings) → {boolean}
Mirrors GetBitRateLimit() in deviceCapabilities.bs — and mirrors it through the SAME mediaNumber coercion, deliberately. That function emits the user's value only when the limit is enabled and the stored value reads as a positive number; otherwise it falls through to Roku's per-codec HARDWARE ceilings, which are not the user's doing and must not be reported as such. If the two ever disagree about what counts as a usable limit, this module would name a setting that did not constrain anything.
The last conjunct — the source actually exceeding the limit — is what turns "the setting is on" into "the setting is why". A 5 Mbps stream under a 20 Mbps cap transcoded for some other reason entirely.
| Name | Type | Description |
|---|---|---|
ctx | object | |
settings | object |
- Type:
- boolean
(static) causedByForceTranscodeAnamorphic(ctx, settings) → {boolean}
Mirrors getAnamorphicCondition() in deviceCapabilities.bs, which emits its condition ONLY when this setting is on — so the setting being off means the constraint was never sent and something else produced the reason. The source being anamorphic is the second half: the condition cannot bind on a stream it does not describe.
| Name | Type | Description |
|---|---|---|
ctx | object | |
settings | object |
- Type:
- boolean
(static) causedByMultichannelDecodeOff(ctx, settings) → {boolean}
Mirrors the 2-channel cap in getCodecProfiles() (deviceCapabilities.bs), which applies when playbackDecodeMultichannelAudio is FALSE — note the inversion; the setting reads as "let the Roku decode it", so turning it OFF is what adds a constraint.
The cap only touches TRANSCODE_CAUSE_STEREO_CAPPED_CODECS, so the source codec has to be on that list. This is the predicate most likely to be got wrong by reading the setting name alone: a 5.1 EAC3 source that transcodes for channels was capped by the device's real capabilities, not by this setting.
| Name | Type | Description |
|---|---|---|
ctx | object | |
settings | object |
- Type:
- boolean
(static) causedByPreserveDovi(ctx, settings) → {boolean}
Mirrors the DoVi container-profile injection in ItemPostPlaybackInfo (source/api/items.bs). Every conjunct there is reproduced here, because each one is a way the constraint is NOT injected and therefore a way this reason belongs to someone else:
- the setting off, or the caller bypassing it on a buffer-overflow retry
- a device that cannot do DoVi (the injection is skipped entirely)
- a server below apiVersion 2, where VideoRangeType does not exist
- a non-mkv container, or an AV1 stream, both explicitly exempted there
| Name | Type | Description |
|---|---|---|
ctx | object | |
settings | object |
- Type:
- boolean
(static) causedByResolutionCap(ctx, settings) → {boolean}
Mirrors getResolutionConditions() in deviceCapabilities.bs, where two of the three branches produce a cap that is NOT the user's choice: "off" -> no conditions at all "auto" -> the device's own height; following the TV is not a choice Any NUMERIC value is the user actively giving something up, and is attributable whenever the source actually exceeds it and the device could have done better.
This used to carry a third exemption — cap >= 1080 -> collapses to the default every device gets — which mirrored a REGRESSION rather than a design. Until jellyrock#866, getResolutionConditions compared the user's height against its own 1080 failure-fallback, so "4k" and "8k" silently became a 1080 cap and there was genuinely nothing to attribute. Now the chosen height is honoured, so a 1080 cap on a 4K device IS the user's doing — auto would have given them 2160 — and staying silent about it would be the false negative this module tries to avoid. The deviceMaxHeight <= cap guard below already expresses "the setting is moot" correctly, which is why removing the exemption needed no replacement for it.
The h264 exclusion is the ambiguity guard. ItemPostPlaybackInfo caps h264 at the 1080p hardware ceiling independently of any setting, so a 4K h264 source would transcode with this setting at its default. Two candidate causes, no way to tell them apart from the reason code, so we claim neither.
| Name | Type | Description |
|---|---|---|
ctx | object | |
settings | object |
- Type:
- boolean
(static) transcodeCauseSettingKey(reason, ctx) → {string}
The JellyRock setting that provably caused a transcode reason, as the translationKey of that setting's title.
Returning the setting's OWN title key — the one settings.json already carries — rather than a bespoke phrase is deliberate: the report then names the setting exactly as the Settings screen spells it, which is where the user has to go next. It also means this feature adds one translation string in total instead of a parallel vocabulary that can drift out of sync with the settings UI.
| Name | Type | Description |
|---|---|---|
reason | string | a Jellyfin TranscodeReason code, verbatim |
ctx | object | see transcodeCauseContext() for the shape and why each field is needed |
- a translationKey, or "" when no setting can be proven responsible
- Type:
- string