pulseaudio.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #include <pulse/pulseaudio.h>
  2. struct AudioPulseAudio : AudioDriver {
  3. AudioPulseAudio& self = *this;
  4. AudioPulseAudio(Audio& super) : AudioDriver(super) {}
  5. ~AudioPulseAudio() { terminate(); }
  6. auto create() -> bool override {
  7. super.setChannels(2);
  8. super.setFrequency(48000);
  9. super.setLatency(40);
  10. return initialize();
  11. }
  12. auto driver() -> string override { return "PulseAudio"; }
  13. auto ready() -> bool override { return _ready; }
  14. auto hasBlocking() -> bool override { return true; }
  15. auto hasDynamic() -> bool override { return true; }
  16. auto hasFrequencies() -> vector<uint> override {
  17. return {44100, 48000, 96000};
  18. }
  19. auto hasLatencies() -> vector<uint> override {
  20. return {20, 40, 60, 80, 100};
  21. }
  22. auto setBlocking(bool blocking) -> bool override { return true; }
  23. auto setFrequency(uint frequency) -> bool override { return initialize(); }
  24. auto setLatency(uint latency) -> bool override { return initialize(); }
  25. auto level() -> double override {
  26. pa_mainloop_iterate(_mainLoop, 0, nullptr);
  27. auto length = pa_stream_writable_size(_stream);
  28. return (double)(_bufferSize - length) / _bufferSize;
  29. }
  30. auto output(const double samples[]) -> void override {
  31. pa_stream_begin_write(_stream, (void**)&_buffer, &_period);
  32. _buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
  33. _buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
  34. if((++_offset + 1) * pa_frame_size(&_specification) <= _period) return;
  35. while(true) {
  36. pa_mainloop_iterate(_mainLoop, 0, nullptr);
  37. auto length = pa_stream_writable_size(_stream);
  38. if(length >= _offset * pa_frame_size(&_specification)) break;
  39. if(!self.blocking) {
  40. _offset = 0;
  41. return;
  42. }
  43. }
  44. pa_stream_write(_stream, (const void*)_buffer, _offset * pa_frame_size(&_specification), nullptr, 0LL, PA_SEEK_RELATIVE);
  45. _buffer = nullptr;
  46. _offset = 0;
  47. }
  48. private:
  49. auto initialize() -> bool {
  50. terminate();
  51. _mainLoop = pa_mainloop_new();
  52. _context = pa_context_new(pa_mainloop_get_api(_mainLoop), "ruby::pulseAudio");
  53. pa_context_connect(_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
  54. pa_context_state_t contextState;
  55. do {
  56. pa_mainloop_iterate(_mainLoop, 1, nullptr);
  57. contextState = pa_context_get_state(_context);
  58. if(!PA_CONTEXT_IS_GOOD(contextState)) return false;
  59. } while(contextState != PA_CONTEXT_READY);
  60. _specification.format = PA_SAMPLE_S16LE;
  61. _specification.channels = 2;
  62. _specification.rate = self.frequency;
  63. _stream = pa_stream_new(_context, "audio", &_specification, nullptr);
  64. pa_buffer_attr bufferAttributes;
  65. bufferAttributes.maxlength = -1;
  66. bufferAttributes.tlength = pa_usec_to_bytes(self.latency * PA_USEC_PER_MSEC, &_specification);
  67. bufferAttributes.prebuf = -1;
  68. bufferAttributes.minreq = -1;
  69. bufferAttributes.fragsize = -1;
  70. pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE);
  71. pa_stream_connect_playback(_stream, nullptr, &bufferAttributes, flags, nullptr, nullptr);
  72. pa_stream_state_t streamState;
  73. do {
  74. pa_mainloop_iterate(_mainLoop, 1, nullptr);
  75. streamState = pa_stream_get_state(_stream);
  76. if(!PA_STREAM_IS_GOOD(streamState)) return false;
  77. } while(streamState != PA_STREAM_READY);
  78. const pa_buffer_attr* attributes = pa_stream_get_buffer_attr(_stream);
  79. _period = attributes->minreq;
  80. _bufferSize = attributes->tlength;
  81. _offset = 0;
  82. return _ready = true;
  83. }
  84. auto terminate() -> void {
  85. _ready = false;
  86. if(_buffer) {
  87. pa_stream_cancel_write(_stream);
  88. _buffer = nullptr;
  89. }
  90. if(_stream) {
  91. pa_stream_disconnect(_stream);
  92. pa_stream_unref(_stream);
  93. _stream = nullptr;
  94. }
  95. if(_context) {
  96. pa_context_disconnect(_context);
  97. pa_context_unref(_context);
  98. _context = nullptr;
  99. }
  100. if(_mainLoop) {
  101. pa_mainloop_free(_mainLoop);
  102. _mainLoop = nullptr;
  103. }
  104. }
  105. bool _ready = false;
  106. uint32_t* _buffer = nullptr;
  107. size_t _period = 0;
  108. size_t _bufferSize = 0;
  109. uint _offset = 0;
  110. pa_mainloop* _mainLoop = nullptr;
  111. pa_context* _context = nullptr;
  112. pa_stream* _stream = nullptr;
  113. pa_sample_spec _specification;
  114. };