aboutsummaryrefslogtreecommitdiffstats
path: root/alc
diff options
context:
space:
mode:
Diffstat (limited to 'alc')
-rw-r--r--alc/backends/pipewire.cpp69
-rw-r--r--alc/backends/pulseaudio.cpp96
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)
{