• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / libossia / 29204108180

12 Jul 2026 06:33PM UTC coverage: 47.711% (-0.002%) from 47.713%
29204108180

push

github

jcelerier
wasm: more libremidi update

25971 of 54434 relevant lines covered (47.71%)

197940.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/ossia/audio/audio_engine.cpp
1
#include <ossia/audio/alsa_protocol.hpp>
2
#include <ossia/audio/asio_protocol.hpp>
3
#include <ossia/audio/audio_engine.hpp>
4
#include <ossia/audio/dummy_protocol.hpp>
5
#include <ossia/audio/jack_protocol.hpp>
6
#include <ossia/audio/miniaudio_protocol.hpp>
7
#include <ossia/audio/pipewire_protocol.hpp>
8
#include <ossia/audio/portaudio_protocol.hpp>
9
#include <ossia/audio/pulseaudio_protocol.hpp>
10
#include <ossia/audio/sdl_protocol.hpp>
11
#include <ossia/detail/logger.hpp>
12

13
#include <thread>
14

15
namespace ossia
16
{
17

18
namespace
19
{
20
struct default_audio_tick
21
{
22
  void operator()(const ossia::audio_tick_state& t) const noexcept
×
23
  {
24
    if(t.n_out > 0)
×
25
    {
26
      for(int i = 0; i < t.n_out; i++)
×
27
        for(std::size_t k = 0; k < t.frames; k++)
×
28
          t.outputs[i][k] = 0.f;
×
29
    }
30
  }
×
31
};
32
}
33

34
audio_engine::audio_engine()
×
35
{
36
  // audio_engine starts in the "started" state
37
  stop_processing = false;
×
38
  audio_tick = default_audio_tick{};
×
39
}
×
40

41
audio_engine::~audio_engine() = default;
×
42

43
void audio_engine::wait(int milliseconds)
×
44
{
45
  std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
×
46
}
×
47

48
void audio_engine::stop()
×
49
{
50
  stop_processing = true;
×
51
  sync();
×
52
  gc();
×
53
}
×
54

55
void audio_engine::sync()
×
56
{
57
  int64_t req = request.load();
×
58
  req++;
×
59
  request.store(req);
×
60

61
#if defined(__EMSCRIPTEN__)
62
  // On WASM, the audio runs in a worklet thread. We cannot spin-wait
63
  // on the main thread as it blocks the browser event loop entirely.
64
  // The tick will pick up the new request on its next callback.
65
  return;
66
#endif
67

68
  // The engine has started running, we wait for a couple iterations
69
  // to leave some time for the ticks to be updated
70
  int k = 0;
×
71
  int buffer_length_in_ms = 8;
×
72
  if(this->effective_sample_rate > 0)
×
73
    buffer_length_in_ms
74
        = std::ceil(this->effective_buffer_size * 1000. / this->effective_sample_rate);
×
75

76
  if(running())
×
77
  {
78
    while(this->reply.load() < req)
×
79
    {
80
      if(k++ > 20)
×
81
      {
82
        ossia::logger().error("Audio engine seems stuck?");
×
83
        break;
×
84
      }
85
      this->wait(2 * buffer_length_in_ms);
×
86
    }
87
  }
88
}
×
89

90
void audio_engine::gc()
×
91
{
92
  // try to make deallocations happen in the main thread as far as possible
93
  fun_type t;
×
94
  while(tick_gc.try_dequeue(t))
×
95
    ;
96
}
×
97

98
void audio_engine::set_tick(audio_engine::fun_type&& t)
×
99
{
100
  if(t.allocated())
×
101
    tick_funlist.enqueue(std::move(t));
×
102
  else
103
    tick_funlist.enqueue(default_audio_tick{});
×
104

105
  sync();
×
106
  gc();
×
107
}
×
108

109
void audio_engine::load_audio_tick()
×
110
{
111
  fun_type tick;
×
112
  while(tick_funlist.try_dequeue(tick))
×
113
  {
114
    tick_gc.enqueue(std::move(audio_tick));
×
115
    audio_tick = std::move(tick);
×
116
  }
117
  reply.store(request.load());
×
118
}
×
119

120
ossia::audio_engine* make_audio_engine(
×
121
    std::string proto, std::string name, std::string req_in, std::string req_out,
122
    int& inputs, int& outputs, int& rate, int& bs)
123
{
124
  proto = "JACK";
×
125
  ossia::audio_engine* p{};
×
126

127
#if defined(__EMSCRIPTEN__)
128
  rate = 48000;
129
  bs = 1024;
130
  inputs = 0;
131
  outputs = 2;
132
#if OSSIA_ENABLE_MINIAUDIO
133
  {
134
    static auto ctx = std::make_shared<ossia::miniaudio_context>();
135
    static bool ctx_init = false;
136
    if(!ctx_init)
137
    {
138
      auto cfg = ma_context_config_init();
139
      ma_context_init(nullptr, 0, &cfg, &ctx->context);
140
      ctx_init = true;
141
    }
142
    ma_device_id in_id{}, out_id{};
143
    return new ossia::miniaudio_engine{ctx, name, in_id, out_id, inputs, outputs, rate, bs};
144
  }
145
#else
146
  return new ossia::sdl_protocol{rate, bs};
147
#endif
148
#endif
149

150
  if(0)
151
  {
152
  }
153
#if OSSIA_AUDIO_PIPEWIRE
154
  else if(proto == "PipeWire")
155
  {
156
    ossia::audio_setup setup;
157
    setup.name = name;
158
    setup.card_in = "";
159
    setup.card_out = "";
160
    setup.rate = rate;
161
    setup.buffer_size = bs;
162
    for(int i = 0; i < inputs; i++)
163
      setup.inputs.push_back("in_" + std::to_string(i));
164
    for(int i = 0; i < outputs; i++)
165
      setup.outputs.push_back("out_" + std::to_string(i));
166

167
    if (auto client = libremidi::pipewire::shared_context())
168
      p = new ossia::pipewire_audio_protocol{std::move(client), setup};
169
  }
170
#endif
171

172
#if OSSIA_AUDIO_PULSEAUDIO
173
  else if(proto == "PulseAudio")
174
  {
175
    p = new ossia::pulseaudio_engine{name, req_in, req_out, inputs, outputs, rate, bs};
176
  }
177
#endif
178

179
#if OSSIA_AUDIO_PORTAUDIO
180
  else if(proto == "PortAudio")
×
181
  {
182
    p = new ossia::portaudio_engine{name,    req_in, req_out, inputs,
×
183
                                    outputs, rate,   bs,      paInDevelopment};
×
184
  }
185
#endif
186

187
#if OSSIA_AUDIO_JACK
188
  else if(proto == "JACK")
×
189
  {
190
    p = new ossia::jack_engine{std::make_shared<jack_client>(name), inputs, outputs};
×
191
  }
192
#endif
193

194
#if defined(OSSIA_AUDIO_SDL)
195
  else if(proto == "SDL")
196
  {
197
    inputs = 0;
198
    outputs = 2;
199
    return new ossia::sdl_protocol{rate, bs};
200
  }
201
#endif
202

203
  else if(proto == "Dummy")
×
204
  {
205
    p = new ossia::dummy_engine{rate, bs};
×
206
  }
207

208
  if(!p)
209
  {
210
#if OSSIA_AUDIO_PULSEAUDIO
211
    p = new ossia::pulseaudio_engine{name, req_in, req_out, inputs, outputs, rate, bs};
212
#endif
213
  }
214

215
  if(!p)
×
216
  {
217
#if OSSIA_AUDIO_PORTAUDIO
218
    p = new ossia::portaudio_engine{name,    req_in, req_out, inputs,
×
219
                                    outputs, rate,   bs,      paInDevelopment};
×
220
#endif
221
  }
222

223
  if(!p)
×
224
  {
225
#if OSSIA_AUDIO_JACK
226
    p = new ossia::jack_engine{std::make_shared<jack_client>(name), inputs, outputs};
×
227
#endif
228
  }
229

230
  if(!p)
231
  {
232
#if defined(OSSIA_AUDIO_SDL)
233
    inputs = 0;
234
    outputs = 2;
235
    p = new ossia::sdl_protocol{rate, bs};
236
#endif
237
  }
238

239
  if(!p)
×
240
  {
241
    p = new ossia::dummy_engine{rate, bs};
×
242
  }
243

244
  if(p)
×
245
  {
246
    inputs = p->effective_inputs;
×
247
    outputs = p->effective_outputs;
×
248
    rate = p->effective_sample_rate;
×
249
    bs = p->effective_buffer_size;
×
250
  }
251

252
  return p;
×
253
}
254

255
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc