diff options
Diffstat (limited to 'alc')
-rw-r--r-- | alc/backends/pipewire.cpp | 69 | ||||
-rw-r--r-- | alc/backends/pulseaudio.cpp | 96 |
2 files changed, 60 insertions, 105 deletions
diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index ae6c81f8..efcbb8b4 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -244,13 +244,13 @@ template<uint32_t T> using Pod_t = typename PodInfo<T>::Type; template<uint32_t T> -al::span<Pod_t<T>> get_array_span(const spa_pod *pod) +al::span<const Pod_t<T>> get_array_span(const spa_pod *pod) { uint32_t nvals; if(void *v{spa_pod_get_array(pod, &nvals)}) { if(get_array_value_type(pod) == T) - return {static_cast<Pod_t<T>*>(v), nvals}; + return {static_cast<const Pod_t<T>*>(v), nvals}; } return {}; } @@ -504,6 +504,7 @@ struct DeviceNode { uint32_t mId{}; NodeType mType{}; bool mIsHeadphones{}; + bool mIs51Rear{}; uint mSampleRate{}; DevFmtChannels mChannels{InvalidChannelConfig}; @@ -594,7 +595,7 @@ const spa_audio_channel MonoMap[]{ * to or a superset of map1). */ template<size_t N> -bool MatchChannelMap(const al::span<uint32_t> map0, const spa_audio_channel (&map1)[N]) +bool MatchChannelMap(const al::span<const uint32_t> map0, const spa_audio_channel (&map1)[N]) { if(map0.size() < N) return false; @@ -685,41 +686,46 @@ void DeviceNode::parseSampleRate(const spa_pod *value) noexcept void DeviceNode::parsePositions(const spa_pod *value) noexcept { + mIs51Rear = false; + const auto chanmap = get_array_span<SPA_TYPE_Id>(value); if(chanmap.empty()) return; - /* TODO: Does 5.1(rear) need to be tracked, or will PipeWire do the right - * thing and re-route the Side-labelled Surround channels to Rear-labelled - * Surround? - */ if(MatchChannelMap(chanmap, X71Map)) mChannels = DevFmtX71; else if(MatchChannelMap(chanmap, X61Map)) mChannels = DevFmtX61; - else if(MatchChannelMap(chanmap, X51Map) || MatchChannelMap(chanmap, X51RearMap)) + else if(MatchChannelMap(chanmap, X51Map)) + mChannels = DevFmtX51; + else if(MatchChannelMap(chanmap, X51RearMap)) + { mChannels = DevFmtX51; + mIs51Rear = true; + } else if(MatchChannelMap(chanmap, QuadMap)) mChannels = DevFmtQuad; else if(MatchChannelMap(chanmap, StereoMap)) mChannels = DevFmtStereo; else mChannels = DevFmtMono; - TRACE("Device ID %u got %zu position%s for %s\n", mId, chanmap.size(), - (chanmap.size()==1)?"":"s", DevFmtChannelsString(mChannels)); + TRACE("Device ID %u got %zu position%s for %s%s\n", mId, chanmap.size(), + (chanmap.size()==1)?"":"s", DevFmtChannelsString(mChannels), mIs51Rear?"(rear)":""); } void DeviceNode::parseChannelCount(const spa_pod *value) noexcept { + mIs51Rear = false; + /* As a fallback with just a channel count, just assume mono or stereo. */ - if(auto chans = get_value<SPA_TYPE_Int>(value)) - { - if(*chans >= 2) - mChannels = DevFmtStereo; - else if(*chans >= 1) - mChannels = DevFmtMono; - TRACE("Device ID %u got %d channel%s for %s\n", mId, *chans, (*chans==1)?"":"s", - DevFmtChannelsString(mChannels)); - } + const auto chancount = get_value<SPA_TYPE_Int>(value); + if(!chancount) return; + + if(*chancount >= 2) + mChannels = DevFmtStereo; + else if(*chancount >= 1) + mChannels = DevFmtMono; + TRACE("Device ID %u got %d channel%s for %s\n", mId, *chancount, (*chancount==1)?"":"s", + DevFmtChannelsString(mChannels)); } @@ -1137,7 +1143,7 @@ void EventManager::coreCallback(uint32_t id, int seq) enum use_f32p_e : bool { UseDevType=false, ForceF32Planar=true }; -spa_audio_info_raw make_spa_info(DeviceBase *device, use_f32p_e use_f32p) +spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e use_f32p) { spa_audio_info_raw info{}; if(use_f32p) @@ -1164,7 +1170,10 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, use_f32p_e use_f32p) case DevFmtMono: map = MonoMap; break; case DevFmtStereo: map = StereoMap; break; case DevFmtQuad: map = QuadMap; break; - case DevFmtX51: map = X51Map; break; + case DevFmtX51: + if(is51rear) map = X51RearMap; + else map = X51Map; + break; case DevFmtX61: map = X61Map; break; case DevFmtX71: map = X71Map; break; case DevFmtAmbi3D: @@ -1386,6 +1395,7 @@ bool PipeWirePlayback::reset() /* If connecting to a specific device, update various device parameters to * match its format. */ + bool is51rear{false}; mDevice->Flags.reset(DirectEar); if(mTargetId != PwIdAny) { @@ -1410,12 +1420,13 @@ bool PipeWirePlayback::reset() mDevice->FmtChans = match->mChannels; if(match->mChannels == DevFmtStereo && match->mIsHeadphones) mDevice->Flags.set(DirectEar); + is51rear = match->mIs51Rear; } } /* Force planar 32-bit float output for playback. This is what PipeWire * handles internally, and it's easier for us too. */ - spa_audio_info_raw info{make_spa_info(mDevice, ForceF32Planar)}; + spa_audio_info_raw info{make_spa_info(mDevice, is51rear, ForceF32Planar)}; /* TODO: How to tell what an appropriate size is? Examples just use this * magic value. @@ -1775,7 +1786,19 @@ void PipeWireCapture::open(const char *name) mDevice->DeviceName = pwireInput; - spa_audio_info_raw info{make_spa_info(mDevice, UseDevType)}; + bool is51rear{false}; + if(mTargetId != PwIdAny) + { + EventWatcherLockGuard _{gEventHandler}; + auto&& devlist = DeviceNode::GetList(); + + auto match_id = [targetid=mTargetId](const DeviceNode &n) -> bool + { return targetid == n.mId; }; + auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_id); + if(match != devlist.cend()) + is51rear = match->mIs51Rear; + } + spa_audio_info_raw info{make_spa_info(mDevice, is51rear, UseDevType)}; constexpr uint32_t pod_buffer_size{1024}; auto pod_buffer = std::make_unique<al::byte[]>(pod_buffer_size); diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 84d9351a..67e00234 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -236,78 +236,6 @@ constexpr pa_channel_map MonoChanMap{ } }; -al::optional<Channel> ChannelFromPulse(pa_channel_position_t chan) -{ - switch(chan) - { - case PA_CHANNEL_POSITION_INVALID: break; - case PA_CHANNEL_POSITION_MONO: return al::make_optional(FrontCenter); - case PA_CHANNEL_POSITION_FRONT_LEFT: return al::make_optional(FrontLeft); - case PA_CHANNEL_POSITION_FRONT_RIGHT: return al::make_optional(FrontRight); - case PA_CHANNEL_POSITION_FRONT_CENTER: return al::make_optional(FrontCenter); - case PA_CHANNEL_POSITION_REAR_CENTER: return al::make_optional(BackCenter); - case PA_CHANNEL_POSITION_REAR_LEFT: return al::make_optional(BackLeft); - case PA_CHANNEL_POSITION_REAR_RIGHT: return al::make_optional(BackRight); - case PA_CHANNEL_POSITION_LFE: return al::make_optional(LFE); - case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: break; - case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: break; - case PA_CHANNEL_POSITION_SIDE_LEFT: return al::make_optional(SideLeft); - case PA_CHANNEL_POSITION_SIDE_RIGHT: return al::make_optional(SideRight); - case PA_CHANNEL_POSITION_AUX0: break; - case PA_CHANNEL_POSITION_AUX1: break; - case PA_CHANNEL_POSITION_AUX2: break; - case PA_CHANNEL_POSITION_AUX3: break; - case PA_CHANNEL_POSITION_AUX4: break; - case PA_CHANNEL_POSITION_AUX5: break; - case PA_CHANNEL_POSITION_AUX6: break; - case PA_CHANNEL_POSITION_AUX7: break; - case PA_CHANNEL_POSITION_AUX8: break; - case PA_CHANNEL_POSITION_AUX9: break; - case PA_CHANNEL_POSITION_AUX10: break; - case PA_CHANNEL_POSITION_AUX11: break; - case PA_CHANNEL_POSITION_AUX12: break; - case PA_CHANNEL_POSITION_AUX13: break; - case PA_CHANNEL_POSITION_AUX14: break; - case PA_CHANNEL_POSITION_AUX15: break; - case PA_CHANNEL_POSITION_AUX16: break; - case PA_CHANNEL_POSITION_AUX17: break; - case PA_CHANNEL_POSITION_AUX18: break; - case PA_CHANNEL_POSITION_AUX19: break; - case PA_CHANNEL_POSITION_AUX20: break; - case PA_CHANNEL_POSITION_AUX21: break; - case PA_CHANNEL_POSITION_AUX22: break; - case PA_CHANNEL_POSITION_AUX23: break; - case PA_CHANNEL_POSITION_AUX24: break; - case PA_CHANNEL_POSITION_AUX25: break; - case PA_CHANNEL_POSITION_AUX26: break; - case PA_CHANNEL_POSITION_AUX27: break; - case PA_CHANNEL_POSITION_AUX28: break; - case PA_CHANNEL_POSITION_AUX29: break; - case PA_CHANNEL_POSITION_AUX30: break; - case PA_CHANNEL_POSITION_AUX31: break; - case PA_CHANNEL_POSITION_TOP_CENTER: return al::make_optional(TopCenter); - case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft); - case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight); - case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter); - case PA_CHANNEL_POSITION_TOP_REAR_LEFT: return al::make_optional(TopBackLeft); - case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return al::make_optional(TopBackRight); - case PA_CHANNEL_POSITION_TOP_REAR_CENTER: return al::make_optional(TopBackCenter); - case PA_CHANNEL_POSITION_MAX: break; - } - WARN("Unexpected channel enum %d (%s)\n", chan, pa_channel_position_to_string(chan)); - return al::nullopt; -} - -void SetChannelOrderFromMap(DeviceBase *device, const pa_channel_map &chanmap) -{ - device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX); - for(uint i{0};i < chanmap.channels;++i) - { - if(auto label = ChannelFromPulse(chanmap.map[i])) - device->RealOut.ChannelIndex[*label] = i; - } -} - /* *grumble* Don't use enums for bitflags. */ constexpr inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs) @@ -708,6 +636,7 @@ struct PulsePlayback final : public BackendBase { al::optional<std::string> mDeviceName{al::nullopt}; + bool mIs51Rear{false}; pa_buffer_attr mAttr; pa_sample_spec mSpec; @@ -780,15 +709,16 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int struct ChannelMap { DevFmtChannels fmt; pa_channel_map map; + bool is_51rear; }; static constexpr std::array<ChannelMap,7> chanmaps{{ - { DevFmtX71, X71ChanMap }, - { DevFmtX61, X61ChanMap }, - { DevFmtX51, X51ChanMap }, - { DevFmtX51, X51RearChanMap }, - { DevFmtQuad, QuadChanMap }, - { DevFmtStereo, StereoChanMap }, - { DevFmtMono, MonoChanMap } + { DevFmtX71, X71ChanMap, false }, + { DevFmtX61, X61ChanMap, false }, + { DevFmtX51, X51ChanMap, false }, + { DevFmtX51, X51RearChanMap, true }, + { DevFmtQuad, QuadChanMap, false }, + { DevFmtStereo, StereoChanMap, false }, + { DevFmtMono, MonoChanMap, false } }}; if(eol) @@ -805,9 +735,11 @@ void PulsePlayback::sinkInfoCallback(pa_context*, const pa_sink_info *info, int { if(!mDevice->Flags.test(ChannelsRequest)) mDevice->FmtChans = chaniter->fmt; + mIs51Rear = chaniter->is_51rear; } else { + mIs51Rear = false; char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{}; pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); WARN("Failed to find format for channel map:\n %s\n", chanmap_str); @@ -955,7 +887,7 @@ bool PulsePlayback::reset() chanmap = QuadChanMap; break; case DevFmtX51: - chanmap = X51ChanMap; + chanmap = (mIs51Rear ? X51RearChanMap : X51ChanMap); break; case DevFmtX61: chanmap = X61ChanMap; @@ -964,7 +896,7 @@ bool PulsePlayback::reset() chanmap = X71ChanMap; break; } - SetChannelOrderFromMap(mDevice, chanmap); + setDefaultWFXChannelOrder(); switch(mDevice->FmtType) { @@ -1245,7 +1177,7 @@ void PulseCapture::open(const char *name) throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; } - SetChannelOrderFromMap(mDevice, chanmap); + setDefaultWFXChannelOrder(); switch(mDevice->FmtType) { |