🛠️🐜 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.

118 lines
2.7 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. };
  33. using BackendPtr = std::unique_ptr<BackendBase>;
  34. enum class BackendType {
  35. Playback,
  36. Capture
  37. };
  38. /* Helper to get the current clock time from the device's ClockBase, and
  39. * SamplesDone converted from the sample rate.
  40. */
  41. inline std::chrono::nanoseconds GetDeviceClockTime(DeviceBase *device)
  42. {
  43. using std::chrono::seconds;
  44. using std::chrono::nanoseconds;
  45. auto ns = nanoseconds{seconds{device->SamplesDone}} / device->Frequency;
  46. return device->ClockBase + ns;
  47. }
  48. /* Helper to get the device latency from the backend, including any fixed
  49. * latency from post-processing.
  50. */
  51. inline ClockLatency GetClockLatency(DeviceBase *device, BackendBase *backend)
  52. {
  53. ClockLatency ret{backend->getClockLatency()};
  54. ret.Latency += device->FixedLatency;
  55. return ret;
  56. }
  57. struct BackendFactory {
  58. virtual bool init() = 0;
  59. virtual bool querySupport(BackendType type) = 0;
  60. virtual std::string probe(BackendType type) = 0;
  61. virtual BackendPtr createBackend(DeviceBase *device, BackendType type) = 0;
  62. protected:
  63. virtual ~BackendFactory() = default;
  64. };
  65. namespace al {
  66. enum class backend_error {
  67. NoDevice,
  68. DeviceError,
  69. OutOfMemory
  70. };
  71. class backend_exception final : public base_exception {
  72. backend_error mErrorCode;
  73. public:
  74. #ifdef __USE_MINGW_ANSI_STDIO
  75. [[gnu::format(gnu_printf, 3, 4)]]
  76. #else
  77. [[gnu::format(printf, 3, 4)]]
  78. #endif
  79. backend_exception(backend_error code, const char *msg, ...) : mErrorCode{code}
  80. {
  81. std::va_list args;
  82. va_start(args, msg);
  83. setMessage(msg, args);
  84. va_end(args);
  85. }
  86. backend_error errorCode() const noexcept { return mErrorCode; }
  87. };
  88. } // namespace al
  89. #endif /* ALC_BACKENDS_BASE_H */