feat(audio): custom surround-params - #2424
Conversation
fd72e35 to
ce8b027
Compare
|
Do we want this to work with 11+ channels eventually? If so, using |
|
@kentyman23 In that case, Moonlight core lib needs to changed. And of course webOS needs that support too. |
ce8b027 to
9fe580b
Compare
| if (!session.surround_params.empty()) { | ||
| // If we have our own surround parameters, advertise them twice first | ||
| ss << "a=fmtp:97 surround-params="sv << session.surround_params << std::endl; | ||
| ss << "a=fmtp:97 surround-params="sv << session.surround_params << std::endl; |
There was a problem hiding this comment.
What's the purpose of advertising them twice?
There was a problem hiding this comment.
The first surround-params will be applied to NormalQualityOpusConfig, and the second one goes to HighQualityOpusConfig. I think advertising them twice first will make sure both configs having the desired mapping.
|
Hi, will ac3 encoding be functional on moonlight-android and moonlight-qt? (provided that development is done I suppose) |
|
@moi952 Hi, this PR won't enable AC3 codec, it only rearranges sound channel mapping. May I ask why you are interested in AC3 codec? As far as I know, all existing clients handles OPUS better. |
Thank you for your answer. Too bad, I don't know OPUS but I guess it's PCM? I tried different sound input/output settings on my TV but it doesn't work. For example for Windows if I connect my PC to my TV, it does not offer me more than 2 channels in the sound output configuration. |
|
@moi952 That may have something to do with the TV, and yes while Sunshine transfers audio to Moonlight using OPUS, it will eventually become PCM. Let's discuss in the channel you're in on discord. |
|
@mariotaku could you rebase your PR? |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2424 +/- ##
=========================================
+ Coverage 7.01% 7.98% +0.97%
=========================================
Files 88 88
Lines 17987 18036 +49
Branches 8579 8596 +17
=========================================
+ Hits 1261 1441 +180
- Misses 14019 15827 +1808
+ Partials 2707 768 -1939
Flags with carried forward coverage won't be shown. Click here to find out more.
|
0511af3 to
ca24752
Compare
da82fa2 to
4e2d4ff
Compare
|
@mariotaku are you happy with this PR and tests? |
Yes, I'd like to get it merged :) |
The PulseAudio backend built the capture stream's channel map from the Opus channel mapping. That mapping is applied by the multistream encoder in audio.cpp and undone by the client when it decodes, so the two cancel out. Using it as the capture channel map makes PulseAudio reorder the samples as well, and that second reordering is never undone. It is invisible with the built-in mappings, which are all identities, so it went unnoticed until custom surround-params arrived in LizardByte#2424. A client that requests its own mapping gets permuted channels: the webOS Moonlight client asks for 0,1,4,5,2,3 and ends up with centre on rear left, rear left on centre, LFE on rear right and rear right on the subwoofer. Capture in the canonical layout instead, which is what the WASAPI and macOS backends already do by ignoring the mapping argument entirely. Since map_stereo, map_surround51 and map_surround71 are all the identity over speaker_e, the canonical position of channel i is position_mapping[i], so the map is now filled directly from the channel index. Clients that do not send surroundParams are unaffected: the resulting pa_channel_map is identical to the current one for every layout in stream_configs. No other Moonlight client sends surroundParams today; android, ios, qt, embedded and tizen send only the standard surroundAudioInfo. Also give position_mapping an explicit speaker::MAX_SPEAKERS bound and reject out-of-range channel counts, so the parallel-array relationship with speaker_e is enforced by the compiler rather than by the callers. Refs: mariotaku/moonlight-tv#575
The PulseAudio backend built the capture stream's channel map from the Opus channel mapping. That mapping is applied by the multistream encoder in audio.cpp and undone by the client when it decodes, so the two cancel out. Using it as the capture channel map makes PulseAudio reorder the samples as well, and that second reordering is never undone. It is invisible with the built-in mappings, which are all identities, so it went unnoticed until custom surround-params arrived in LizardByte#2424. A client that requests its own mapping gets permuted channels: the webOS Moonlight client asks for 0,1,4,5,2,3 and ends up with centre on rear left, rear left on centre, LFE on rear right and rear right on the subwoofer. Capture in the canonical layout instead, which is what the WASAPI and macOS backends already do by ignoring the mapping argument entirely. Since map_stereo, map_surround51 and map_surround71 are all the identity over speaker_e, the canonical position of channel i is position_mapping[i], so the map is now filled directly from the channel index. Clients that do not send surroundParams are unaffected: the resulting pa_channel_map is identical to the current one for every layout in stream_configs. No other Moonlight client sends surroundParams today; android, ios, qt, embedded and tizen send only the standard surroundAudioInfo. Also give position_mapping an explicit speaker::MAX_SPEAKERS bound and reject out-of-range channel counts, so the parallel-array relationship with speaker_e is enforced by the compiler rather than by the callers. Refs: mariotaku/moonlight-tv#575 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The PulseAudio backend built the capture stream's channel map from the Opus channel mapping. That mapping is applied by the multistream encoder in audio.cpp and undone by the client when it decodes, so the two cancel out. Using it as the capture channel map makes PulseAudio reorder the samples as well, and that second reordering is never undone. It is invisible with the built-in mappings, which are all identities, so it went unnoticed until custom surround-params arrived in LizardByte#2424. A client that requests its own mapping gets permuted channels: the webOS Moonlight client asks for 0,1,4,5,2,3 and ends up with centre on rear left, rear left on centre, LFE on rear right and rear right on the subwoofer. Capture in the canonical layout instead, which is what the WASAPI and macOS backends already do by ignoring the mapping argument entirely. Since map_stereo, map_surround51 and map_surround71 are all the identity over speaker_e, the canonical position of channel i is position_mapping[i], so the map is now filled directly from the channel index. Clients that do not send surroundParams are unaffected: the resulting pa_channel_map is identical to the current one for every layout in stream_configs. No other Moonlight client sends surroundParams today; android, ios, qt, embedded and tizen send only the standard surroundAudioInfo. Also give position_mapping an explicit speaker::MAX_SPEAKERS bound and reject out-of-range channel counts, so the parallel-array relationship with speaker_e is enforced by the compiler rather than by the callers. Refs: mariotaku/moonlight-tv#575 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The PulseAudio backend built the capture stream's channel map from the Opus channel mapping. That mapping is applied by the multistream encoder in audio.cpp and undone by the client when it decodes, so the two cancel out. Using it as the capture channel map makes PulseAudio reorder the samples as well, and that second reordering is never undone. It is invisible with the built-in mappings, which are all identities, so it went unnoticed until custom surround-params arrived in LizardByte#2424. A client that requests its own mapping gets permuted channels: the webOS Moonlight client asks for 0,1,4,5,2,3 and ends up with centre on rear left, rear left on centre, LFE on rear right and rear right on the subwoofer. Capture in the canonical layout instead, which is what the WASAPI and macOS backends already do by ignoring the mapping argument entirely. Since map_stereo, map_surround51 and map_surround71 are all the identity over speaker_e, the canonical position of channel i is position_mapping[i], so the map is now filled directly from the channel index. Clients that do not send surroundParams are unaffected: the resulting pa_channel_map is identical to the current one for every layout in stream_configs. No other Moonlight client sends surroundParams today; android, ios, qt, embedded and tizen send only the standard surroundAudioInfo. The map construction moves into fill_canonical_channel_map() so it can be tested without a running PulseAudio server, and position_mapping becomes a std::array bounded by speaker::MAX_SPEAKERS so the parallel-array relationship with speaker_e is enforced by the compiler. Out-of-range channel counts are now rejected rather than read past the end. Refs: mariotaku/moonlight-tv#575 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Description
This PR is made for improving webOS client support. On webOS 5.0 and above, if surround channel configuration is done properly, it can re-encode OPUS stream on-the-fly & send it to surround sound system through eARC/Optical.
Currently, webOS only handles 6-channels, 4 streams & 2 coupled streams configuration, and the channel must be ordered as
[0, 1, 4, 5, 2, 3]which Sunshine doesn't have. It won't accept stream header either, which makes this PR necessary.With this PR, if
surroundParamsis specified (formatted likesurround-params=in RTSP handshake, e.g.642014523) in HTTP launch request, it will be applied, and during RTSP handshake, our custom surround-paramsa=fmtp:97 surround-params=642014523will be advertised twice first, followed by the original ones.Screenshot
Not applicable
Issues Fixed or Closed
Type of Change
.github/...)Checklist
Branch Updates
LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.