🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
2.8 KiB

  1. #ifndef ALC_BACKENDS_BASE_H
  2. #define ALC_BACKENDS_BASE_H
  3. #include <chrono>
  4. #include <cstdarg>
  5. #include <memory>
  6. #include <ratio>
  7. #include <string>
  8. #include "albyte.h"
  9. #include "core/device.h"
  10. #include "core/except.h"
  11. using uint = unsigned int;
  12. struct ClockLatency {
  13. std::chrono::nanoseconds ClockTime;
  14. std::chrono::nanoseconds Latency;
  15. };
  16. struct BackendBase {
  17. virtual void open(const char *name) = 0;
  18. virtual bool reset();
  19. virtual void start() = 0;
  20. virtual void stop() = 0;
  21. virtual void captureSamples(al::byte *buffer, uint samples);
  22. virtual uint availableSamples();
  23. virtual ClockLatency getClockLatency();
  24. DeviceBase *const mDevice;
  25. BackendBase(DeviceBase *device) noexcept : mDevice{device} { }
  26. virtual ~BackendBase() = default;
  27. protected:
  28. /** Sets the default channel order used by most non-WaveFormatEx-based APIs. */
  29. void setDefaultChannelOrder();
  30. /** Sets the default channel order used by WaveFormatEx. */
  31. void setDefaultWFXChannelOrder();
  32. #ifdef _WIN32
  33. /** Sets the channel order given the WaveFormatEx mask. */
  34. void setChannelOrderFromWFXMask(uint chanmask);
  35. #endif
  36. };
  37. using BackendPtr = std::unique_ptr<BackendBase>;
  38. enum class BackendType {
  39. Playback,
  40. Capture
  41. };
  42. /* Helper to get the current clock time from the device's ClockBase, and
  43. * SamplesDone converted from the sample rate.
  44. */
  45. inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device)
  46. {
  47. using std::chrono::seconds;
  48. using std::chrono::nanoseconds;
  49. auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
  50. return device->ClockBase + ns;
  51. }
  52. /* Helper to get the device latency from the backend, including any fixed
  53. * latency from post-processing.
  54. */
  55. inline ClockLatency GetClockLatency(DeviceBase *device, BackendBase *backend)
  56. {
  57. ClockLatency ret{backend->getClockLatency()};
  58. ret.Latency += device->FixedLatency;
  59. return ret;
  60. }
  61. struct BackendFactory {
  62. virtual bool init() = 0;
  63. virtual bool querySupport(BackendType type) = 0;
  64. virtual std::string probe(BackendType type) = 0;
  65. virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0;
  66. protected:
  67. virtual ~BackendFactory() = default;
  68. };
  69. namespace al {
  70. enum class backend_error {
  71. NoDevice,
  72. DeviceError,
  73. OutOfMemory
  74. };
  75. class backend_exception final : public base_exception {
  76. backend_error mErrorCode;
  77. public:
  78. #ifdef __USE_MINGW_ANSI_STDIO
  79. [[gnu::format(gnu_printf, 3, 4)]]
  80. #else
  81. [[gnu::format(printf, 3, 4)]]
  82. #endif
  83. backend_exception(backend_error code, const char *msg, ...) : mErrorCode{code}
  84. {
  85. std::va_list args;
  86. va_start(args, msg);
  87. setMessage(msg, args);
  88. va_end(args);
  89. }
  90. backend_error errorCode() const noexcept { return mErrorCode; }
  91. };
  92. } // namespace al
  93. #endif /* ALC_BACKENDS_BASE_H */