Skip to content

Commit 6fec311

Browse files
committed
rollback initialAudioBlock change + make a note for the forgetful
1 parent a8e1574 commit 6fec311

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

DEVELOPERS.txt

+37-12
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ everytime a new scanning chunk is received, until a header is successfully parse
124124
failure, -1 if it needs more bytes, a value > 0 to jump to that offset in the stream and a hash
125125
containing parsed information when done. See Slim::Format::Movie.pm for a most complete example.
126126

127-
- getInitialAudioBlock() is used to get such acquired header to send it to the player at the
128-
beginning of playback. In most of cases, it's simple and the default function will work.
127+
- getInitialAudioBlock() is used to get such header that will be sent to the player at the beginning
128+
of playback. It is called only when there is a processor, so see explanation below to handle header
129+
acquisition properly. In most of cases, it's simple and the default function will work.
129130

130131
The handling for every format is spread between Slim::Formats::XXX and Slim::Utils::Scanner::Remote
131132
and this could be refactored a bit. In a nutshell, after parsing stream's header, it is decided if
@@ -134,16 +135,40 @@ audio bytes to the player. Such tweaked headers can be added never, once, every
134135
seeking (this also influences the possibility for a track to be directly played or proxied)
135136

136137
Upon actual streaming of audio and when header needs to be tweaked, the Slim::Player::HTTP::request
137-
will look for "processors" in the track. Such processors are set upon initial scanning. A track can
138-
output multiple formats, so that's why there are multiple processors possible. LMS will pickup one
139-
depending on what the scan offered and what the player can accept.
140-
141-
The relevant processor is then called in Slim::Player::HTTP and can simply create a tweaked header
142-
that will then be passed to the player but it can also return a structure with a method to be called
143-
for every chunk of audio data received. This is used for adts frames extraction from mp4 file, when
144-
player wants 'aac' and not 'mp4'. This is also used for flac synchronization where some IP3K players
145-
can't resynchronize when seeking in a middle of a flac stream. The more simple case is wav file that
146-
just need a header tweak but then don't need further handling of audio chunks.
138+
will look for "processors" in the track. Such processors are set upon initial scanning or by a
139+
handler in scanURL. A track can output multiple formats, so that's why there are multiple processors
140+
possible. LMS will pickup one depending on what the scan offered and what the player can accept.
141+
142+
The relevant processor is then called in Slim::Player::HTTP::request and can simply create a tweaked
143+
header that will then be passed to the player but it can also return a structure with a method to be
144+
called for every chunk of audio data received. This is used for adts frames extraction from mp4 file,
145+
when player wants 'aac' and not 'mp4'. This is also used for flac synchronization where some IP3K
146+
players can't resynchronize when seeking in a middle of a flac stream. The more simple case is wav
147+
file that just need a header tweak but then don't need further handling of audio chunks.
148+
149+
Processors must set 'initial_block_type' to either ONCE, ONSEEK or ALWAYS to set when
150+
getInitialAudioBlock() will be called by Slim::Player::HTTP::request and also decide when/if direct
151+
streaming is possible. When there is nothing returned by getInitialAudioBlock(), it will be treated
152+
as a defined-but-empty initial block.
153+
154+
The 'GET' request for the actual audio data uses a 'Range' byte offset to skip the header (if any).
155+
If the $track->audio_offset has been set *and* the initial audio block is defined, then this is the
156+
range. Now, if there is a processor, it can override it by setting sourceStreamOffset but if there
157+
is no processor this cannot be changed.
158+
159+
So understand the implication of setting $track->audio_offset. When it is not set, then the GET
160+
range will be 0 unless a processor has set the sourceStreamOffset. Note that the stored initial block
161+
will only be sent to the player when there is a processor.
162+
163+
In other words, if you want LMS to GET the whole file from 0 and send it to the player but you don't
164+
want/need to set a processor, then DO NOT set $track->audio_offset!
165+
166+
When there is a processor, direct streaming is enable only if 'initial_block_type' is set to ONSEEK
167+
and track starts from zero (no seekdata). Streaming will always be proxied otherwise. When there is
168+
no processor, direct streaming will be attempted according to usual rules but the $track->audio_offset
169+
logic described above will apply and be passed to the player as range.
170+
171+
The logic is the same when seeking, except that the byte seek offset is added.
147172

148173
Look at Slim::Misc::Utils::Scanner::Remote and Slim::Formats::Movie or Slim::Formats::FLAC for
149174
general understanding and at Slim::Plugin::WiMP::ProtocolHandler to see how a plugin can use this

Slim/Player/Protocols/HTTP.pm

+4-4
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ sub request {
138138
my $track = $song->currentTrack;
139139
my $processor = $track->processors($song->wantFormat);
140140

141-
# no other guidance, define AudioBlock to make sure that audio_offset is skipped in requestString
141+
# no other guidance, define AudioBlock if needed so that audio_offset is skipped in requestString
142142
if (!$processor || $song->stripHeader) {
143-
$song->initialAudioBlock('') if $song->stripHeader;
143+
$song->initialAudioBlock('');
144144
return $self->SUPER::request($args);
145145
}
146146

@@ -179,7 +179,7 @@ sub request {
179179
${*$self}{'initialAudioBlockRemaining'} = length $$blockRef;
180180

181181
# dynamic headers need to be re-calculated every time
182-
$song->initialAudioBlock(undef) if $processor->{'initial_block_type'};
182+
$song->initialAudioBlock(undef) if $processor->{'initial_block_type'} != Slim::Schema::RemoteTrack::INITIAL_BLOCK_ONCE;
183183

184184
main::DEBUGLOG && $log->debug("streaming $args->{url} with header of ", length $$blockRef, " from ",
185185
$song->seekdata ? $song->seekdata->{sourceStreamOffset} || 0 : $track->audio_offset,
@@ -440,7 +440,7 @@ sub canDirectStreamSong {
440440
return $direct if $song->stripHeader || !$processor;
441441

442442
# with dynamic header 2, always go direct otherwise only when not seeking
443-
if ($processor->{'initial_block_type'} == Slim::Schema::RemoteTrack::INITIAL_BLOCK_ALWAYS || $song->seekdata) {
443+
if ($processor->{'initial_block_type'} != Slim::Schema::RemoteTrack::INITIAL_BLOCK_ONSEEK || $song->seekdata) {
444444
main::INFOLOG && $directlog->info("Need to add header, cannot stream direct");
445445
return 0;
446446
}

0 commit comments

Comments
 (0)