Skip to content

Commit 1d682ae

Browse files
committed
Fully lock mainloop during all PulseAudio operations
As far as I can tell basically every operation not happening in a callback needs to be locked, so just lock once at the top level instead of locking for each operation individually. This makes the logic much easier to reason about too.
1 parent 7feaf4a commit 1d682ae

1 file changed

Lines changed: 10 additions & 8 deletions

File tree

src/audio_player_pulse.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ PulseAudioPlayer::PulseAudioPlayer(agi::AudioProvider *provider) : AudioPlayer(p
219219
if (pa_threaded_mainloop_start(mainloop.get()))
220220
throw AudioPlayerOpenError("Failed to start PulseAudio threaded mainloop");
221221

222+
PAThreadedMainloopLock lock{mainloop.get()};
223+
222224
// Create context
223225
context.reset(pa_context_new(pa_threaded_mainloop_get_api(mainloop.get()), "Aegisub"), mainloop.get());
224226
if (!context.get())
@@ -283,14 +285,15 @@ PulseAudioPlayer::PulseAudioPlayer(agi::AudioProvider *provider) : AudioPlayer(p
283285

284286
PulseAudioPlayer::~PulseAudioPlayer()
285287
{
288+
PAThreadedMainloopLock lock{mainloop.get()};
286289
if (is_playing) Stop();
287290
}
288291

289292
void PulseAudioPlayer::Play(int64_t start,int64_t count)
290293
{
294+
PAThreadedMainloopLock lock{mainloop.get()};
291295
if (is_playing) {
292296
// If we're already playing, do a quick "reset"
293-
PAThreadedMainloopLock lock{mainloop.get()};
294297
is_playing = false;
295298

296299
PAOperation op{pa_stream_flush(stream.get(), (pa_stream_success_cb_t)PAStreamSuccessCB, this)};
@@ -311,15 +314,11 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
311314
is_playing = true;
312315

313316
play_start_time = 0;
314-
{
315-
PAThreadedMainloopLock lock{mainloop.get()};
316-
if (int paerror = pa_stream_get_time(stream.get(), (pa_usec_t*) &play_start_time))
317-
LOG_E("audio/player/pulse") << "Error getting stream time: " << pa_strerror(paerror) << "(" << paerror << ")";
318-
}
317+
if (int paerror = pa_stream_get_time(stream.get(), (pa_usec_t*) &play_start_time))
318+
LOG_E("audio/player/pulse") << "Error getting stream time: " << pa_strerror(paerror) << "(" << paerror << ")";
319319

320320
PulseAudioPlayer::PAStreamWriteCB(stream.get(), pa_stream_writable_size(stream.get()), this);
321321

322-
PAThreadedMainloopLock lock{mainloop.get()};
323322
PAOperation op{pa_stream_trigger(stream.get(), (pa_stream_success_cb_t)PAStreamSuccessCB, this)};
324323

325324
while (pa_operation_get_state(op.get()) == PA_OPERATION_RUNNING)
@@ -333,6 +332,7 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
333332

334333
void PulseAudioPlayer::Stop()
335334
{
335+
PAThreadedMainloopLock lock{mainloop.get()};
336336
if (!is_playing) return;
337337

338338
is_playing = false;
@@ -342,7 +342,6 @@ void PulseAudioPlayer::Stop()
342342
end_frame = 0;
343343

344344
// Flush the stream of data
345-
PAThreadedMainloopLock lock{mainloop.get()};
346345
PAOperation op{pa_stream_flush(stream.get(), (pa_stream_success_cb_t)PAStreamSuccessCB, this)};
347346

348347
while (pa_operation_get_state(op.get()) == PA_OPERATION_RUNNING)
@@ -356,11 +355,14 @@ void PulseAudioPlayer::Stop()
356355

357356
void PulseAudioPlayer::SetEndPosition(int64_t pos)
358357
{
358+
PAThreadedMainloopLock lock{mainloop.get()};
359359
end_frame = pos;
360360
}
361361

362362
int64_t PulseAudioPlayer::GetCurrentPosition()
363363
{
364+
PAThreadedMainloopLock lock{mainloop.get()};
365+
364366
if (!is_playing) return 0;
365367

366368
// FIXME: this should be based on not duration played but actual sample being heard

0 commit comments

Comments
 (0)