Avoid a stateful unique_ptr deleter
[openal-soft.git] / alc / backends / base.cpp
blobcd1b76bab3bfbde22d2cfe1c568f208e71ea1582
2 #include "config.h"
4 #include "base.h"
6 #include <algorithm>
7 #include <array>
8 #include <atomic>
10 #ifdef _WIN32
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #include <mmreg.h>
15 #include "albit.h"
16 #include "core/logging.h"
17 #include "aloptional.h"
18 #endif
20 #include "atomic.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)
28 { }
30 uint BackendBase::availableSamples()
31 { return 0; }
33 ClockLatency BackendBase::getClockLatency()
35 ClockLatency ret;
37 uint refcount;
38 do {
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;
52 return ret;
55 void BackendBase::setDefaultWFXChannelOrder()
57 mDevice->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX);
59 switch(mDevice->FmtChans)
61 case DevFmtMono:
62 mDevice->RealOut.ChannelIndex[FrontCenter] = 0;
63 break;
64 case DevFmtStereo:
65 mDevice->RealOut.ChannelIndex[FrontLeft] = 0;
66 mDevice->RealOut.ChannelIndex[FrontRight] = 1;
67 break;
68 case DevFmtQuad:
69 mDevice->RealOut.ChannelIndex[FrontLeft] = 0;
70 mDevice->RealOut.ChannelIndex[FrontRight] = 1;
71 mDevice->RealOut.ChannelIndex[BackLeft] = 2;
72 mDevice->RealOut.ChannelIndex[BackRight] = 3;
73 break;
74 case DevFmtX51:
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;
81 break;
82 case DevFmtX61:
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;
90 break;
91 case DevFmtX71:
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;
100 break;
101 case DevFmtAmbi3D:
102 break;
106 void BackendBase::setDefaultChannelOrder()
108 mDevice->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX);
110 switch(mDevice->FmtChans)
112 case DevFmtX51:
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;
119 return;
120 case DevFmtX71:
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;
129 return;
131 /* Same as WFX order */
132 case DevFmtMono:
133 case DevFmtStereo:
134 case DevFmtQuad:
135 case DevFmtX61:
136 case DevFmtAmbi3D:
137 setDefaultWFXChannelOrder();
138 break;
142 #ifdef _WIN32
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>
154 switch(chanbit)
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);
176 return al::nullopt;
179 const uint numchans{mDevice->channelsFromFmt()};
180 uint idx{0};
181 while(chanmask)
183 const int bit{al::countr_zero(chanmask)};
184 const uint mask{1u << bit};
185 chanmask &= ~mask;
187 if(auto label = get_channel(mask))
189 mDevice->RealOut.ChannelIndex[*label] = idx;
190 if(++idx == numchans) break;
194 #endif