Add "fast" variants for the bsinc resamplers
[openal-soft.git] / alc / backends / null.cpp
blobb6b115f13c3778f9374d165fa63ebce81488bc4c
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2010 by Chris Robinson
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include "backends/null.h"
25 #include <exception>
26 #include <atomic>
27 #include <chrono>
28 #include <cstdint>
29 #include <cstring>
30 #include <functional>
31 #include <thread>
33 #include "alcmain.h"
34 #include "almalloc.h"
35 #include "alu.h"
36 #include "logging.h"
37 #include "threads.h"
40 namespace {
42 using std::chrono::seconds;
43 using std::chrono::milliseconds;
44 using std::chrono::nanoseconds;
46 constexpr ALCchar nullDevice[] = "No Output";
49 struct NullBackend final : public BackendBase {
50 NullBackend(ALCdevice *device) noexcept : BackendBase{device} { }
52 int mixerProc();
54 ALCenum open(const ALCchar *name) override;
55 bool reset() override;
56 bool start() override;
57 void stop() override;
59 std::atomic<bool> mKillNow{true};
60 std::thread mThread;
62 DEF_NEWDEL(NullBackend)
65 int NullBackend::mixerProc()
67 const milliseconds restTime{mDevice->UpdateSize*1000/mDevice->Frequency / 2};
69 SetRTPriority();
70 althrd_setname(MIXER_THREAD_NAME);
72 int64_t done{0};
73 auto start = std::chrono::steady_clock::now();
74 while(!mKillNow.load(std::memory_order_acquire) &&
75 mDevice->Connected.load(std::memory_order_acquire))
77 auto now = std::chrono::steady_clock::now();
79 /* This converts from nanoseconds to nanosamples, then to samples. */
80 int64_t avail{std::chrono::duration_cast<seconds>((now-start) * mDevice->Frequency).count()};
81 if(avail-done < mDevice->UpdateSize)
83 std::this_thread::sleep_for(restTime);
84 continue;
86 while(avail-done >= mDevice->UpdateSize)
88 lock();
89 aluMixData(mDevice, nullptr, mDevice->UpdateSize);
90 unlock();
91 done += mDevice->UpdateSize;
94 /* For every completed second, increment the start time and reduce the
95 * samples done. This prevents the difference between the start time
96 * and current time from growing too large, while maintaining the
97 * correct number of samples to render.
99 if(done >= mDevice->Frequency)
101 seconds s{done/mDevice->Frequency};
102 start += s;
103 done -= mDevice->Frequency*s.count();
107 return 0;
111 ALCenum NullBackend::open(const ALCchar *name)
113 if(!name)
114 name = nullDevice;
115 else if(strcmp(name, nullDevice) != 0)
116 return ALC_INVALID_VALUE;
118 mDevice->DeviceName = name;
120 return ALC_NO_ERROR;
123 bool NullBackend::reset()
125 SetDefaultWFXChannelOrder(mDevice);
126 return true;
129 bool NullBackend::start()
131 try {
132 mKillNow.store(false, std::memory_order_release);
133 mThread = std::thread{std::mem_fn(&NullBackend::mixerProc), this};
134 return true;
136 catch(std::exception& e) {
137 ERR("Failed to start mixing thread: %s\n", e.what());
139 catch(...) {
141 return false;
144 void NullBackend::stop()
146 if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
147 return;
148 mThread.join();
151 } // namespace
154 bool NullBackendFactory::init()
155 { return true; }
157 bool NullBackendFactory::querySupport(BackendType type)
158 { return (type == BackendType::Playback); }
160 void NullBackendFactory::probe(DevProbe type, std::string *outnames)
162 switch(type)
164 case DevProbe::Playback:
165 /* Includes null char. */
166 outnames->append(nullDevice, sizeof(nullDevice));
167 break;
168 case DevProbe::Capture:
169 break;
173 BackendPtr NullBackendFactory::createBackend(ALCdevice *device, BackendType type)
175 if(type == BackendType::Playback)
176 return BackendPtr{new NullBackend{device}};
177 return nullptr;
180 BackendFactory &NullBackendFactory::getFactory()
182 static NullBackendFactory factory{};
183 return factory;