mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 03:22:43 +00:00 
			
		
		
		
	 5ea5ae85d2
			
		
	
	
		5ea5ae85d2
		
	
	
	
	
		
			
			Now that `Thread` keeps itself alive when it is running detached, we do not need to hold onto it in the PulseAudio playback stream's internal state object. This was a hack that did not work correctly because the `Thread` object and its action `Function` would be deleted before the action had exited and cause a crash.
		
			
				
	
	
		
			58 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			58 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2023, Gregory Bertilson <zaggy1024@gmail.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include <LibAudio/PlaybackStream.h>
 | |
| #include <LibAudio/PulseAudioWrappers.h>
 | |
| 
 | |
| namespace Audio {
 | |
| 
 | |
| class PlaybackStreamPulseAudio final
 | |
|     : public PlaybackStream {
 | |
| public:
 | |
|     static ErrorOr<NonnullRefPtr<PlaybackStream>> create(OutputState initial_state, u32 sample_rate, u8 channels, u32 target_latency_ms, AudioDataRequestCallback&& data_request_callback);
 | |
| 
 | |
|     virtual void set_underrun_callback(Function<void()>) override;
 | |
| 
 | |
|     virtual NonnullRefPtr<Core::ThreadedPromise<Duration>> resume() override;
 | |
|     virtual NonnullRefPtr<Core::ThreadedPromise<void>> drain_buffer_and_suspend() override;
 | |
|     virtual NonnullRefPtr<Core::ThreadedPromise<void>> discard_buffer_and_suspend() override;
 | |
| 
 | |
|     virtual ErrorOr<Duration> total_time_played() override;
 | |
| 
 | |
|     virtual NonnullRefPtr<Core::ThreadedPromise<void>> set_volume(double) override;
 | |
| 
 | |
| private:
 | |
|     // This struct is kept alive until the control thread exits to prevent a use-after-free without blocking on
 | |
|     // the UI thread.
 | |
|     class InternalState : public AtomicRefCounted<InternalState> {
 | |
|     public:
 | |
|         void set_stream(NonnullRefPtr<PulseAudioStream> const&);
 | |
|         RefPtr<PulseAudioStream> stream();
 | |
| 
 | |
|         void enqueue(Function<void()>&&);
 | |
|         void thread_loop();
 | |
|         ErrorOr<void> check_is_running();
 | |
|         void exit();
 | |
| 
 | |
|     private:
 | |
|         RefPtr<PulseAudioStream> m_stream { nullptr };
 | |
| 
 | |
|         Queue<Function<void()>> m_tasks;
 | |
|         Threading::Mutex m_mutex;
 | |
|         Threading::ConditionVariable m_wake_condition { m_mutex };
 | |
| 
 | |
|         Atomic<bool> m_exit { false };
 | |
|     };
 | |
| 
 | |
|     PlaybackStreamPulseAudio(NonnullRefPtr<InternalState>);
 | |
|     ~PlaybackStreamPulseAudio();
 | |
| 
 | |
|     RefPtr<InternalState> m_state;
 | |
| };
 | |
| 
 | |
| }
 |