class EL_AUDIO_SOURCE_PRODUCER

(source code)

description

Audio source producer

note
	description: "Audio source producer"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2022-11-15 19:56:06 GMT (Tuesday 15th November 2022)"
	revision: "5"

class
	EL_AUDIO_SOURCE_PRODUCER [SAMPLE_TYPE -> EL_AUDIO_PCM_SAMPLE create make end]

inherit
	EL_INTERRUPTABLE_THREAD

	EL_MODULE_LOG

	EL_AUDIO_PLAYER_CONSTANTS

	EL_THREAD_CONSTANTS

create
	make

feature {NONE} -- Initialization

	make
			--
		do
			make_default
			create buffer_list.make (new_pointer_list)
			create source.make (Void)
			create timer.make
		end

feature -- Basic operations

	queue_next_buffer
			-- Queue next buffer if available
		local
			l_source: EL_AUDIO_SAMPLE_SOURCE [SAMPLE_TYPE]
		do
			log.enter ("queue_next_buffer")
			source.lock
--			synchronized
				l_source := source.item
				if not l_source.after then
					l_source.forth
					buffer_list.lock
--					synchronized
						buffer_list.item.extend (l_source.data_item)
						if l_source.after then
							buffer_list.item.extend (Last_buffer_marker)
						end
--					end
					buffer_list.unlock
				end
--			end
			source.unlock
			log.exit
		end

	buffer_audio_from_source (event_listener: EL_AUDIO_PLAYER_EVENT_LISTENER; player_waiting_thread: EL_SUSPENDABLE)
			--
		local
			l_source: EL_AUDIO_SAMPLE_SOURCE [SAMPLE_TYPE]
			sample_count, minimum_sample_count: INTEGER
		do
			log.enter ("buffer_audio_from_source")
			if source_under_production_rate > 0 then
				source.lock
--				synchronized
					l_source := source.item
					minimum_sample_count := (Duration_to_buffer_for * source_under_production_rate).rounded
					event_listener.on_buffering_start
					buffer_list.lock
--					synchronized
						from until is_interrupted or l_source.after or sample_count > minimum_sample_count loop
							buffer_list.item.extend (l_source.data_item)
							sample_count := sample_count + l_source.data_item_sample_count
							if l_source.index \\ 5 = 1 then
								event_listener.on_buffering_step ((sample_count / minimum_sample_count).truncated_to_real)
							end
							if sample_count < minimum_sample_count then
								l_source.forth
							end
						end
--					end
					buffer_list.unlock
					event_listener.on_buffering_end
--				end
				source.unlock
			end
			player_waiting_thread.resume
			previous_call_is_thread_signal
-- THREAD SIGNAL

			log.put_integer_field ("sample_count", sample_count)
			log.put_new_line
			log.exit
		end

	initialize (relative_start_position: REAL)
			--
		local
			l_source: EL_AUDIO_SAMPLE_SOURCE [SAMPLE_TYPE]
			source_production_rate, minimum_sample_count, sample_count: INTEGER
			is_minimum_data_buffered: BOOLEAN
		do
			log.enter_with_args ("initialize", << relative_start_position >>)
			set_uninterrupted
			source.lock
--			synchronized
				l_source := source.item
				minimum_sample_count := (Minimum_buffer_duration * l_source.header.samples_per_sec).rounded

				timer.start
				buffer_list.lock
				buffer_list.item.wipe_out
--				synchronized
					from
						l_source.go_relative_position (relative_start_position)
					until
						is_interrupted or l_source.after or is_minimum_data_buffered
					loop
						buffer_list.item.extend (l_source.data_item)
						sample_count := sample_count + l_source.data_item_sample_count

						if buffer_list.item.count >= Minimum_buffer_count and sample_count > minimum_sample_count then
							is_minimum_data_buffered := true
						else
							l_source.forth
						end
					end
--				end
				buffer_list.unlock
				timer.stop
				source_production_rate := (sample_count / timer.elapsed_time.fine_seconds_count).rounded
				source_under_production_rate := l_source.header.samples_per_sec - source_production_rate
--			end
			source.unlock
			log.put_integer_field ("source_under_production_rate", source_under_production_rate)
			log.put_new_line
			log.exit
		end

feature -- Element change

	set_source (a_source: EL_AUDIO_SAMPLE_SOURCE [SAMPLE_TYPE])
			--
		do
			source.lock
--			synchronized
				source.set_item (a_source)
--			end
			source.unlock
		end

feature {EL_AUDIO_SOURCE_PRODUCER_I} -- Access

	buffer_list: EL_MUTEX_REFERENCE [like new_pointer_list]

feature {NONE} -- Implementation

	new_pointer_list: LINKED_LIST [MANAGED_POINTER]
		do
			create Result.make
		end

feature {NONE} -- Internal attributes

	source: EL_MUTEX_REFERENCE [EL_AUDIO_SAMPLE_SOURCE [SAMPLE_TYPE]]

	source_under_production_rate: INTEGER
			-- Rate at which production lags behind play rate in samples per sec
			-- (Difference between play rate and production rate)

	timer: EL_EXECUTION_TIMER

end