2018-12-25 11:09:41 -08:00
|
|
|
#ifndef ALC_BACKENDS_BASE_H
|
|
|
|
#define ALC_BACKENDS_BASE_H
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2018-11-22 14:32:48 -08:00
|
|
|
#include <chrono>
|
2021-04-26 07:56:00 -07:00
|
|
|
#include <cstdarg>
|
2019-07-29 19:59:48 -07:00
|
|
|
#include <memory>
|
2021-04-26 07:56:00 -07:00
|
|
|
#include <ratio>
|
2019-07-29 19:59:48 -07:00
|
|
|
#include <string>
|
|
|
|
|
2019-09-15 09:50:28 -07:00
|
|
|
#include "albyte.h"
|
2021-04-26 07:56:00 -07:00
|
|
|
#include "core/device.h"
|
2020-12-21 18:00:43 -08:00
|
|
|
#include "core/except.h"
|
2018-12-25 11:09:41 -08:00
|
|
|
|
|
|
|
|
2020-12-17 03:06:52 -08:00
|
|
|
using uint = unsigned int;
|
|
|
|
|
2018-11-15 03:49:59 -08:00
|
|
|
struct ClockLatency {
|
2018-11-22 14:32:48 -08:00
|
|
|
std::chrono::nanoseconds ClockTime;
|
|
|
|
std::chrono::nanoseconds Latency;
|
2018-11-15 03:49:59 -08:00
|
|
|
};
|
2016-05-28 00:43:14 -07:00
|
|
|
|
2018-12-28 22:56:20 -08:00
|
|
|
struct BackendBase {
|
2020-12-17 21:07:53 -08:00
|
|
|
virtual void open(const char *name) = 0;
|
2016-05-28 00:43:14 -07:00
|
|
|
|
2019-09-15 09:50:28 -07:00
|
|
|
virtual bool reset();
|
2020-04-28 19:25:58 -07:00
|
|
|
virtual void start() = 0;
|
2018-12-28 22:56:20 -08:00
|
|
|
virtual void stop() = 0;
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2020-12-17 03:06:52 -08:00
|
|
|
virtual void captureSamples(al::byte *buffer, uint samples);
|
|
|
|
virtual uint availableSamples();
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2018-12-28 22:56:20 -08:00
|
|
|
virtual ClockLatency getClockLatency();
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2021-04-24 09:03:14 -07:00
|
|
|
DeviceBase *const mDevice;
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2021-04-24 09:03:14 -07:00
|
|
|
BackendBase(DeviceBase *device) noexcept : mDevice{device} { }
|
2020-03-30 00:07:35 -07:00
|
|
|
virtual ~BackendBase() = default;
|
2020-06-12 11:58:41 -07:00
|
|
|
|
|
|
|
protected:
|
|
|
|
/** Sets the default channel order used by most non-WaveFormatEx-based APIs. */
|
|
|
|
void setDefaultChannelOrder();
|
|
|
|
/** Sets the default channel order used by WaveFormatEx. */
|
|
|
|
void setDefaultWFXChannelOrder();
|
2020-06-15 18:50:59 -07:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
/** Sets the channel order given the WaveFormatEx mask. */
|
2020-12-17 21:07:53 -08:00
|
|
|
void setChannelOrderFromWFXMask(uint chanmask);
|
2020-06-15 18:50:59 -07:00
|
|
|
#endif
|
2013-10-27 16:37:40 -07:00
|
|
|
};
|
2018-12-29 02:16:16 -08:00
|
|
|
using BackendPtr = std::unique_ptr<BackendBase>;
|
2013-10-27 16:37:40 -07:00
|
|
|
|
2018-12-29 01:38:26 -08:00
|
|
|
enum class BackendType {
|
|
|
|
Playback,
|
2018-12-29 02:21:53 -08:00
|
|
|
Capture
|
2018-11-15 02:36:05 -08:00
|
|
|
};
|
2013-10-28 07:27:35 -07:00
|
|
|
|
|
|
|
|
2020-03-30 16:06:34 -07:00
|
|
|
/* Helper to get the current clock time from the device's ClockBase, and
|
|
|
|
* SamplesDone converted from the sample rate.
|
|
|
|
*/
|
2021-04-24 09:03:14 -07:00
|
|
|
inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device)
|
2020-03-30 16:06:34 -07:00
|
|
|
{
|
|
|
|
using std::chrono::seconds;
|
|
|
|
using std::chrono::nanoseconds;
|
|
|
|
|
|
|
|
auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
|
|
|
|
return device->ClockBase + ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Helper to get the device latency from the backend, including any fixed
|
|
|
|
* latency from post-processing.
|
|
|
|
*/
|
2021-04-24 09:03:14 -07:00
|
|
|
inline ClockLatency GetClockLatency(DeviceBase *device)
|
2020-03-30 16:06:34 -07:00
|
|
|
{
|
|
|
|
BackendBase *backend{device->Backend.get()};
|
|
|
|
ClockLatency ret{backend->getClockLatency()};
|
|
|
|
ret.Latency += device->FixedLatency;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-15 19:15:14 -08:00
|
|
|
struct BackendFactory {
|
|
|
|
virtual bool init() = 0;
|
|
|
|
|
2018-12-29 01:38:26 -08:00
|
|
|
virtual bool querySupport(BackendType type) = 0;
|
2018-11-15 19:15:14 -08:00
|
|
|
|
2020-03-30 16:00:02 -07:00
|
|
|
virtual std::string probe(BackendType type) = 0;
|
2018-11-15 19:15:14 -08:00
|
|
|
|
2021-04-24 09:03:14 -07:00
|
|
|
virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0;
|
2019-09-15 10:22:56 -07:00
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~BackendFactory() = default;
|
2018-11-15 19:15:14 -08:00
|
|
|
};
|
|
|
|
|
2020-04-10 15:11:40 -07:00
|
|
|
namespace al {
|
|
|
|
|
2020-12-17 21:07:53 -08:00
|
|
|
enum class backend_error {
|
|
|
|
NoDevice,
|
|
|
|
DeviceError,
|
|
|
|
OutOfMemory
|
|
|
|
};
|
|
|
|
|
2020-04-10 15:11:40 -07:00
|
|
|
class backend_exception final : public base_exception {
|
2020-12-17 21:07:53 -08:00
|
|
|
backend_error mErrorCode;
|
2020-12-17 16:46:21 -08:00
|
|
|
|
2020-04-10 15:11:40 -07:00
|
|
|
public:
|
2021-03-12 03:14:29 -08:00
|
|
|
#ifdef __USE_MINGW_ANSI_STDIO
|
|
|
|
[[gnu::format(gnu_printf, 3, 4)]]
|
|
|
|
#else
|
2020-04-10 15:11:40 -07:00
|
|
|
[[gnu::format(printf, 3, 4)]]
|
2021-03-12 03:14:29 -08:00
|
|
|
#endif
|
2020-12-17 21:07:53 -08:00
|
|
|
backend_exception(backend_error code, const char *msg, ...) : mErrorCode{code}
|
2020-04-10 15:11:40 -07:00
|
|
|
{
|
|
|
|
std::va_list args;
|
|
|
|
va_start(args, msg);
|
|
|
|
setMessage(msg, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
2020-12-17 21:07:53 -08:00
|
|
|
backend_error errorCode() const noexcept { return mErrorCode; }
|
2020-04-10 15:11:40 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace al
|
|
|
|
|
2018-12-25 11:09:41 -08:00
|
|
|
#endif /* ALC_BACKENDS_BASE_H */
|