11 #define WIN32_LEAN_AND_MEAN
16 #include "core/logging.h"
17 #include "aloptional.h"
21 #include "core/devformat.h"
24 bool BackendBase::reset()
25 { throw al::backend_exception
{al::backend_error::DeviceError
, "Invalid BackendBase call"}; }
27 void BackendBase::captureSamples(al::byte
*, uint
)
30 uint
BackendBase::availableSamples()
33 ClockLatency
BackendBase::getClockLatency()
39 refcount
= mDevice
->waitForMix();
40 ret
.ClockTime
= GetDeviceClockTime(mDevice
);
41 std::atomic_thread_fence(std::memory_order_acquire
);
42 } while(refcount
!= ReadRef(mDevice
->MixCount
));
44 /* NOTE: The device will generally have about all but one periods filled at
45 * any given time during playback. Without a more accurate measurement from
46 * the output, this is an okay approximation.
48 ret
.Latency
= std::max(std::chrono::seconds
{mDevice
->BufferSize
-mDevice
->UpdateSize
},
49 std::chrono::seconds::zero());
50 ret
.Latency
/= mDevice
->Frequency
;
55 void BackendBase::setDefaultWFXChannelOrder()
57 mDevice
->RealOut
.ChannelIndex
.fill(INVALID_CHANNEL_INDEX
);
59 switch(mDevice
->FmtChans
)
62 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 0;
65 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
66 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
69 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
70 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
71 mDevice
->RealOut
.ChannelIndex
[BackLeft
] = 2;
72 mDevice
->RealOut
.ChannelIndex
[BackRight
] = 3;
75 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
76 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
77 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 2;
78 mDevice
->RealOut
.ChannelIndex
[LFE
] = 3;
79 mDevice
->RealOut
.ChannelIndex
[SideLeft
] = 4;
80 mDevice
->RealOut
.ChannelIndex
[SideRight
] = 5;
83 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
84 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
85 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 2;
86 mDevice
->RealOut
.ChannelIndex
[LFE
] = 3;
87 mDevice
->RealOut
.ChannelIndex
[BackCenter
] = 4;
88 mDevice
->RealOut
.ChannelIndex
[SideLeft
] = 5;
89 mDevice
->RealOut
.ChannelIndex
[SideRight
] = 6;
92 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
93 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
94 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 2;
95 mDevice
->RealOut
.ChannelIndex
[LFE
] = 3;
96 mDevice
->RealOut
.ChannelIndex
[BackLeft
] = 4;
97 mDevice
->RealOut
.ChannelIndex
[BackRight
] = 5;
98 mDevice
->RealOut
.ChannelIndex
[SideLeft
] = 6;
99 mDevice
->RealOut
.ChannelIndex
[SideRight
] = 7;
106 void BackendBase::setDefaultChannelOrder()
108 mDevice
->RealOut
.ChannelIndex
.fill(INVALID_CHANNEL_INDEX
);
110 switch(mDevice
->FmtChans
)
113 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
114 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
115 mDevice
->RealOut
.ChannelIndex
[SideLeft
] = 2;
116 mDevice
->RealOut
.ChannelIndex
[SideRight
] = 3;
117 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 4;
118 mDevice
->RealOut
.ChannelIndex
[LFE
] = 5;
121 mDevice
->RealOut
.ChannelIndex
[FrontLeft
] = 0;
122 mDevice
->RealOut
.ChannelIndex
[FrontRight
] = 1;
123 mDevice
->RealOut
.ChannelIndex
[BackLeft
] = 2;
124 mDevice
->RealOut
.ChannelIndex
[BackRight
] = 3;
125 mDevice
->RealOut
.ChannelIndex
[FrontCenter
] = 4;
126 mDevice
->RealOut
.ChannelIndex
[LFE
] = 5;
127 mDevice
->RealOut
.ChannelIndex
[SideLeft
] = 6;
128 mDevice
->RealOut
.ChannelIndex
[SideRight
] = 7;
131 /* Same as WFX order */
137 setDefaultWFXChannelOrder();
143 void BackendBase::setChannelOrderFromWFXMask(uint chanmask
)
145 static constexpr uint x51
{SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_FRONT_CENTER
146 | SPEAKER_LOW_FREQUENCY
| SPEAKER_SIDE_LEFT
| SPEAKER_SIDE_RIGHT
};
147 static constexpr uint x51rear
{SPEAKER_FRONT_LEFT
| SPEAKER_FRONT_RIGHT
| SPEAKER_FRONT_CENTER
148 | SPEAKER_LOW_FREQUENCY
| SPEAKER_BACK_LEFT
| SPEAKER_BACK_RIGHT
};
149 /* Swap a 5.1 mask using the back channels for one with the sides. */
150 if(chanmask
== x51rear
) chanmask
= x51
;
152 auto get_channel
= [](const DWORD chanbit
) noexcept
-> al::optional
<Channel
>
156 case SPEAKER_FRONT_LEFT
: return al::make_optional(FrontLeft
);
157 case SPEAKER_FRONT_RIGHT
: return al::make_optional(FrontRight
);
158 case SPEAKER_FRONT_CENTER
: return al::make_optional(FrontCenter
);
159 case SPEAKER_LOW_FREQUENCY
: return al::make_optional(LFE
);
160 case SPEAKER_BACK_LEFT
: return al::make_optional(BackLeft
);
161 case SPEAKER_BACK_RIGHT
: return al::make_optional(BackRight
);
162 case SPEAKER_FRONT_LEFT_OF_CENTER
: break;
163 case SPEAKER_FRONT_RIGHT_OF_CENTER
: break;
164 case SPEAKER_BACK_CENTER
: return al::make_optional(BackCenter
);
165 case SPEAKER_SIDE_LEFT
: return al::make_optional(SideLeft
);
166 case SPEAKER_SIDE_RIGHT
: return al::make_optional(SideRight
);
167 case SPEAKER_TOP_CENTER
: return al::make_optional(TopCenter
);
168 case SPEAKER_TOP_FRONT_LEFT
: return al::make_optional(TopFrontLeft
);
169 case SPEAKER_TOP_FRONT_CENTER
: return al::make_optional(TopFrontCenter
);
170 case SPEAKER_TOP_FRONT_RIGHT
: return al::make_optional(TopFrontRight
);
171 case SPEAKER_TOP_BACK_LEFT
: return al::make_optional(TopBackLeft
);
172 case SPEAKER_TOP_BACK_CENTER
: return al::make_optional(TopBackCenter
);
173 case SPEAKER_TOP_BACK_RIGHT
: return al::make_optional(TopBackRight
);
175 WARN("Unhandled WFX channel bit 0x%lx\n", chanbit
);
179 const uint numchans
{mDevice
->channelsFromFmt()};
183 const int bit
{al::countr_zero(chanmask
)};
184 const uint mask
{1u << bit
};
187 if(auto label
= get_channel(mask
))
189 mDevice
->RealOut
.ChannelIndex
[*label
] = idx
;
190 if(++idx
== numchans
) break;