Browse Source

Fix AudioEffectRecord not working without thread support

Marcelo Fernandez 6 years ago
parent
commit
7da55fb739

+ 46 - 17
servers/audio/effects/audio_effect_record.cpp

@@ -44,20 +44,25 @@ void AudioEffectRecordInstance::process(const AudioFrame *p_src_frames, AudioFra
 	}
 }
 
+void AudioEffectRecordInstance::_update_buffer() {
+	//Case: Frames are remaining in the buffer
+	while (ring_buffer_read_pos < ring_buffer_pos) {
+		//Read from the buffer into recording_data
+		_io_store_buffer();
+	}
+}
+
+void AudioEffectRecordInstance::_update(void *userdata) {
+	AudioEffectRecordInstance *ins = (AudioEffectRecordInstance *)userdata;
+	ins->_update_buffer();
+}
+
 bool AudioEffectRecordInstance::process_silence() const {
 	return true;
 }
 
 void AudioEffectRecordInstance::_io_thread_process() {
-
-	//Reset recorder status
 	thread_active = true;
-	ring_buffer_pos = 0;
-	ring_buffer_read_pos = 0;
-
-	//We start a new recording
-	recording_data.resize(0); //Clear data completely and reset length
-	is_recording = true;
 
 	while (is_recording) {
 		//Check: The current recording has been requested to stop
@@ -65,13 +70,9 @@ void AudioEffectRecordInstance::_io_thread_process() {
 			is_recording = false;
 		}
 
-		//Case: Frames are remaining in the buffer
-		if (ring_buffer_read_pos < ring_buffer_pos) {
-			//Read from the buffer into recording_data
-			_io_store_buffer();
-		}
-		//Case: The buffer is empty
-		else if (is_recording) {
+		_update_buffer();
+
+		if (is_recording) {
 			//Wait to avoid too much busy-wait
 			OS::get_singleton()->delay_usec(500);
 		}
@@ -103,7 +104,35 @@ void AudioEffectRecordInstance::_thread_callback(void *_instance) {
 }
 
 void AudioEffectRecordInstance::init() {
+	//Reset recorder status
+	ring_buffer_pos = 0;
+	ring_buffer_read_pos = 0;
+
+	//We start a new recording
+	recording_data.resize(0); //Clear data completely and reset length
+	is_recording = true;
+
+#ifdef NO_THREADS
+	AudioServer::get_singleton()->add_update_callback(&AudioEffectRecordInstance::_update, this);
+#else
 	io_thread = Thread::create(_thread_callback, this);
+#endif
+}
+
+void AudioEffectRecordInstance::finish() {
+
+#ifdef NO_THREADS
+	AudioServer::get_singleton()->remove_update_callback(&AudioEffectRecordInstance::_update, this);
+#else
+	if (thread_active) {
+		Thread::wait_to_finish(io_thread);
+	}
+#endif
+}
+
+AudioEffectRecordInstance::~AudioEffectRecordInstance() {
+
+	finish();
 }
 
 Ref<AudioEffectInstance> AudioEffectRecord::instance() {
@@ -145,8 +174,8 @@ Ref<AudioEffectInstance> AudioEffectRecord::instance() {
 
 void AudioEffectRecord::ensure_thread_stopped() {
 	recording_active = false;
-	if (current_instance != 0 && current_instance->thread_active) {
-		Thread::wait_to_finish(current_instance->io_thread);
+	if (current_instance != 0) {
+		current_instance->finish();
 	}
 }
 

+ 4 - 0
servers/audio/effects/audio_effect_record.h

@@ -62,14 +62,18 @@ class AudioEffectRecordInstance : public AudioEffectInstance {
 	void _io_store_buffer();
 	static void _thread_callback(void *_instance);
 	void _init_recording();
+	void _update_buffer();
+	static void _update(void *userdata);
 
 public:
 	void init();
+	void finish();
 	virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count);
 	virtual bool process_silence() const;
 
 	AudioEffectRecordInstance() :
 			thread_active(false) {}
+	~AudioEffectRecordInstance();
 };
 
 class AudioEffectRecord : public AudioEffect {

+ 24 - 0
servers/audio_server.cpp

@@ -1004,6 +1004,11 @@ void AudioServer::update() {
 	AudioDriver::get_singleton()->reset_profiling_time();
 	prof_time = 0;
 #endif
+
+	for (Set<CallbackItem>::Element *E = update_callbacks.front(); E; E = E->next()) {
+
+		E->get().callback(E->get().userdata);
+	}
 }
 
 void AudioServer::load_default_bus_layout() {
@@ -1129,6 +1134,25 @@ void AudioServer::remove_callback(AudioCallback p_callback, void *p_userdata) {
 	unlock();
 }
 
+void AudioServer::add_update_callback(AudioCallback p_callback, void *p_userdata) {
+	lock();
+	CallbackItem ci;
+	ci.callback = p_callback;
+	ci.userdata = p_userdata;
+	update_callbacks.insert(ci);
+	unlock();
+}
+
+void AudioServer::remove_update_callback(AudioCallback p_callback, void *p_userdata) {
+
+	lock();
+	CallbackItem ci;
+	ci.callback = p_callback;
+	ci.userdata = p_userdata;
+	update_callbacks.erase(ci);
+	unlock();
+}
+
 void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) {
 
 	ERR_FAIL_COND(p_bus_layout.is_null() || p_bus_layout->buses.size() == 0);

+ 4 - 0
servers/audio_server.h

@@ -262,6 +262,7 @@ private:
 	};
 
 	Set<CallbackItem> callbacks;
+	Set<CallbackItem> update_callbacks;
 
 	friend class AudioDriver;
 	void _driver_process(int p_frames, int32_t *p_buffer);
@@ -357,6 +358,9 @@ public:
 	void add_callback(AudioCallback p_callback, void *p_userdata);
 	void remove_callback(AudioCallback p_callback, void *p_userdata);
 
+	void add_update_callback(AudioCallback p_callback, void *p_userdata);
+	void remove_update_callback(AudioCallback p_callback, void *p_userdata);
+
 	void set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout);
 	Ref<AudioBusLayout> generate_bus_layout() const;