@@ -25,12 +25,16 @@ defmodule Membrane.HLS.Source do
2525 def_output_pad :video_output ,
2626 accepted_format: any_of ( H264 , % RemoteStream { content_format: H264 } ) ,
2727 flow_control: :manual ,
28- demand_unit: :buffers
28+ demand_unit: :buffers ,
29+ availability: :on_request ,
30+ max_instances: 1
2931
3032 def_output_pad :audio_output ,
3133 accepted_format: any_of ( AAC , % RemoteStream { content_format: AAC } ) ,
3234 flow_control: :manual ,
33- demand_unit: :buffers
35+ demand_unit: :buffers ,
36+ availability: :on_request ,
37+ max_instances: 1
3438
3539 # The boundary on how many chunks of one stream will be requested
3640 # from Membrane.HLS.Source.ClientGenServer at once.
@@ -88,6 +92,7 @@ defmodule Membrane.HLS.Source do
8892 @ impl true
8993 def handle_init ( _ctx , opts ) do
9094 initial_pad_state = % {
95+ ref: nil ,
9196 requested: 0 ,
9297 qex: Qex . new ( ) ,
9398 qex_size: 0 ,
@@ -106,6 +111,12 @@ defmodule Membrane.HLS.Source do
106111 { [ ] , state }
107112 end
108113
114+ @ impl true
115+ def handle_pad_added ( Pad . ref ( pad_name , _id ) = pad_ref , _ctx , state ) do
116+ state = state |> put_in ( [ pad_name , :ref ] , pad_ref )
117+ { [ ] , state }
118+ end
119+
109120 @ impl true
110121 def handle_setup ( _ctx , state ) do
111122 { :ok , client_genserver } =
@@ -119,20 +130,53 @@ defmodule Membrane.HLS.Source do
119130
120131 @ impl true
121132 def handle_playing ( _ctx , state ) do
122- { [ audio_stream_format ] , [ video_stream_format ] } =
133+ stream_formats =
123134 ClientGenServer . get_tracks_info ( state . client_genserver )
124135 |> Map . values ( )
125- |> Enum . split_with ( & audio_stream_format? / 1 )
126136
127- actions = [
128- stream_format: { :audio_output , audio_stream_format } ,
129- stream_format: { :video_output , video_stream_format }
130- ]
137+ :ok = ensure_pads_match_stream_formats! ( stream_formats , state )
138+
139+ actions =
140+ stream_formats
141+ |> Enum . map ( fn stream_format ->
142+ pad_ref =
143+ if audio_stream_format? ( stream_format ) ,
144+ do: state . audio_output . ref ,
145+ else: state . video_output . ref
146+
147+ { :stream_format , { pad_ref , stream_format } }
148+ end )
131149
132150 state = request_media_chunks ( state )
133151 { actions , state }
134152 end
135153
154+ defp ensure_pads_match_stream_formats! ( stream_formats , state ) do
155+ audio_format_occurs? =
156+ Enum . any? ( stream_formats , & audio_stream_format? / 1 )
157+
158+ video_format_occurs? =
159+ Enum . any? ( stream_formats , & ( not audio_stream_format? ( & 1 ) ) )
160+
161+ if audio_format_occurs? and state . audio_output . ref == nil do
162+ raise "Audio pad should be linked"
163+ end
164+
165+ if video_format_occurs? and state . video_output . ref == nil do
166+ raise "Video pad should be linked"
167+ end
168+
169+ if not audio_format_occurs? and state . audio_output . ref != nil do
170+ raise "Audio pad should not be linked"
171+ end
172+
173+ if not video_format_occurs? and state . video_output . ref != nil do
174+ raise "Video pad should not be linked"
175+ end
176+
177+ :ok
178+ end
179+
136180 defp audio_stream_format? ( stream_format ) do
137181 case stream_format do
138182 % RemoteStream { content_format: AAC } -> true
@@ -151,7 +195,7 @@ defmodule Membrane.HLS.Source do
151195
152196 @ impl true
153197 def handle_info ( { data_type , % ExHLS.Chunk { } = chunk } , _ctx , state ) do
154- pad_ref = data_type_to_pad_ref ( data_type )
198+ pad_name = data_type_to_pad_name ( data_type )
155199
156200 buffer = % Buffer {
157201 payload: chunk . payload ,
@@ -162,55 +206,55 @@ defmodule Membrane.HLS.Source do
162206
163207 state =
164208 state
165- |> update_in ( [ pad_ref , :qex ] , & Qex . push ( & 1 , buffer ) )
166- |> update_in ( [ pad_ref , :qex_size ] , & ( & 1 + 1 ) )
167- |> update_in ( [ pad_ref , :requested ] , & ( & 1 - 1 ) )
168- |> update_in ( [ pad_ref , :oldest_buffer_dts ] , fn
209+ |> update_in ( [ pad_name , :qex ] , & Qex . push ( & 1 , buffer ) )
210+ |> update_in ( [ pad_name , :qex_size ] , & ( & 1 + 1 ) )
211+ |> update_in ( [ pad_name , :requested ] , & ( & 1 - 1 ) )
212+ |> update_in ( [ pad_name , :oldest_buffer_dts ] , fn
169213 nil -> buffer . dts
170214 oldest_dts -> oldest_dts
171215 end )
172216 |> request_media_chunks ( )
173217
174- { [ redemand: pad_ref ] , state }
218+ { [ redemand: state [ pad_name ] . ref ] , state }
175219 end
176220
177221 @ impl true
178222 def handle_info ( { data_type , :end_of_stream } , _ctx , state ) do
179- pad_ref = data_type_to_pad_ref ( data_type )
223+ pad_name = data_type_to_pad_name ( data_type )
180224
181225 state =
182- if state [ pad_ref ] . eos_received? do
226+ if state [ pad_name ] . eos_received? do
183227 state
184228 else
185229 state
186- |> put_in ( [ pad_ref , :eos_received? ] , true )
187- |> update_in ( [ pad_ref , :qex ] , & Qex . push ( & 1 , :end_of_stream ) )
188- |> update_in ( [ pad_ref , :qex_size ] , & ( & 1 + 1 ) )
230+ |> put_in ( [ pad_name , :eos_received? ] , true )
231+ |> update_in ( [ pad_name , :qex ] , & Qex . push ( & 1 , :end_of_stream ) )
232+ |> update_in ( [ pad_name , :qex_size ] , & ( & 1 + 1 ) )
189233 end
190234
191- state = state |> update_in ( [ pad_ref , :requested ] , & ( & 1 - 1 ) )
235+ state = state |> update_in ( [ pad_name , :requested ] , & ( & 1 - 1 ) )
192236
193- { [ redemand: pad_ref ] , state }
237+ { [ redemand: state [ pad_name ] . ref ] , state }
194238 end
195239
196- defp data_type_to_pad_ref ( :audio_chunk ) , do: :audio_output
197- defp data_type_to_pad_ref ( :video_chunk ) , do: :video_output
240+ defp data_type_to_pad_name ( :audio_chunk ) , do: :audio_output
241+ defp data_type_to_pad_name ( :video_chunk ) , do: :video_output
198242
199- defp pop_buffers ( pad_ref , demand , state ) do
200- how_many_pop = min ( state [ pad_ref ] . qex_size , demand )
243+ defp pop_buffers ( Pad . ref ( pad_name , _id ) = pad_ref , demand , state ) do
244+ how_many_pop = min ( state [ pad_name ] . qex_size , demand )
201245
202246 1 .. how_many_pop // 1
203247 |> Enum . flat_map_reduce ( state , fn _i , state ->
204- { buffer_or_eos , qex } = state [ pad_ref ] . qex |> Qex . pop! ( )
248+ { buffer_or_eos , qex } = state [ pad_name ] . qex |> Qex . pop! ( )
205249
206250 state =
207251 state
208- |> put_in ( [ pad_ref , :qex ] , qex )
209- |> update_in ( [ pad_ref , :qex_size ] , & ( & 1 - 1 ) )
252+ |> put_in ( [ pad_name , :qex ] , qex )
253+ |> update_in ( [ pad_name , :qex_size ] , & ( & 1 - 1 ) )
210254
211255 case buffer_or_eos do
212256 % Buffer { } = buffer ->
213- state = state |> put_in ( [ pad_ref , :oldest_buffer_dts ] , buffer . dts )
257+ state = state |> put_in ( [ pad_name , :oldest_buffer_dts ] , buffer . dts )
214258 { [ buffer: { pad_ref , buffer } ] , state }
215259
216260 :end_of_stream ->
@@ -221,13 +265,13 @@ defmodule Membrane.HLS.Source do
221265
222266 defp request_media_chunks ( state ) do
223267 [ :audio_output , :video_output ]
224- |> Enum . reduce ( state , fn pad_ref , state ->
225- oldest_dts = state [ pad_ref ] . oldest_buffer_dts
226- eos_received? = state [ pad_ref ] . eos_received?
268+ |> Enum . reduce ( state , fn pad_name , state ->
269+ % { eos_received?: eos_received? , oldest_buffer_dts: oldest_dts , ref: pad_ref } =
270+ state [ pad_name ]
227271
228272 request_size =
229- case state [ pad_ref ] . qex |> Qex . first ( ) do
230- _any when eos_received? ->
273+ case state [ pad_name ] . qex |> Qex . first ( ) do
274+ _any when pad_ref == nil or eos_received? ->
231275 0
232276
233277 # todo: maybe we should handle rollovers
@@ -236,14 +280,14 @@ defmodule Membrane.HLS.Source do
236280 0
237281
238282 _empty_or_not_new_enough ->
239- @ requested_chunks_boundary - state [ pad_ref ] . requested
283+ @ requested_chunks_boundary - state [ pad_name ] . requested
240284 end
241285
242286 1 .. request_size // 1
243- |> Enum . each ( fn _i -> request_single_chunk ( pad_ref , state ) end )
287+ |> Enum . each ( fn _i -> request_single_chunk ( pad_name , state ) end )
244288
245289 state
246- |> update_in ( [ pad_ref , :requested ] , & ( & 1 + request_size ) )
290+ |> update_in ( [ pad_name , :requested ] , & ( & 1 + request_size ) )
247291 end )
248292 end
249293
0 commit comments