Home of the Squeezebox™ & Transporter® network music players.
Page 7 of 7 FirstFirst ... 567
Results 61 to 70 of 70
  1. #61
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    3,537
    Quote Originally Posted by marcoc1712 View Post

    EDIT:

    We then have 'structural' characteristic in SB that we must accept, so - for instance - we could not store in buffer more than the current and the next track, the only hack is to use large enougth buffers to full download them in large advance, so most of 'temporary' line problems could be masked, resulting in less hicups or dropouts at playback time.
    But if Qobuz can't offer the right average on at least a song "horizon", then their service is purely download. Because if you really want to go that route (I don't have so many issues with Qobuz), get a large pre-download before you start releasing data to LMS. Then get as much as you can. It will not solve the problem that this will happen at everysong as you'll receive the request for next track only once the decoder of the player has finished, which my be pretty late on uncompressed format. I won't start a debate on raw 24/96 and above... but such a waste of BW, memory and everything for no difference
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express, GGMM E5

  2. #62
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582
    Quote Originally Posted by philippe_44 View Post
    But if Qobuz can't offer the right average on at least a song "horizon", then their service is purely download. Because if you really want to go that route (I don't have so many issues with Qobuz), get a large pre-download before you start releasing data to LMS. Then get as much as you can. It will not solve the problem that this will happen at everysong as you'll receive the request for next track only once the decoder of the player has finished, which my be pretty late on uncompressed format. I won't start a debate on raw 24/96 and above... but such a waste of BW, memory and everything for no difference
    To understand if the problem is by my (ADSL provvider) or Qobuz side is not easy, I see many others suffering from the same, I could use other services with no problem and I was using Qobusz since 2015 with no problem until this Christmas, so I'm keen to think is related to Qobuz, but they explicity said that they encurage developers to download tracks in advance to avoid pèroblems.

    Today Telecom is porting fiber to my house, so we will see if thinghs will make better.

    What you are suggesting is exactly what I' trying to do, I know problem could not be" solved", but using a large initial buffer (delay) and store as much as you can in advance could help to mask it.

    Too bad limit is from LMS here, You are right that it let player ask for second track when decode of the first is finished (in my system means, normally, few seconds after start, depending on length), then it download the second and store it in the buffer, but then it wait before asking for the third track until the first steam out.

    When tracks are shorts (think some operas) real 'time' of buffer is short and you are more likely to be in a rush.

    Other than this, plugin disables 'seeks' and that means - as a collateral effect - that connection coud not be restarted at a specific point, but only flushed and restarted from the beginning and this is forced to happen at previous track stremout. That way you loose what you already downloaded, waste time wayting for stream out and , becouse of hardcoded parameters in Player.pm, with a too short minimun advance.

    I think LMS behaviour is not going to change, so what we could do is use an HTTP implementation that could handle chunk download with no intervention of LMS, in order to eliminate the case when second track download is stale until the track start, this will not eliminate drops out - when happening in the first track - but could reduce them.

    What I have to better investigate are 'hicups', seems to me is like system play what has in the buffer, filling the reminder with silence, instead to wait until we have a long enought amount of data, that way keeping connection alive until stream out.

    P.S.

    "no difference" in respect of what?

    I think Flac 44100/16 is different from mp3, a very good classical and jazz catalogue to choose from is a big plus and no advertising has no price.

    Tidal is also good but classical catalog is not at same level, in my opinion, Spotify is maybe the best, if you are OK with mp3.

    I was spending much more than 180 Euro by year (means 10 CD!) buying music before, so - to me - is not a waste at all.
    Last edited by marcoc1712; 2018-01-29 at 07:31.
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  3. #63
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    3,537
    Quote Originally Posted by marcoc1712 View Post
    To understand if the problem is by my (ADSL provvider) or Qobuz side is not easy, I see many others suffering from the same, I could use other services with no problem and I was using Qobusz since 2015 with no problem until this Christmas, so I'm keen to think is related to Qobuz, but they explicity said that they encurage developers to download tracks in advance to avoid pèroblems.

    Today Telecom is porting fiber to my house, so we will see if thinghs will make better.

    What you are suggesting is exactly what I' trying to do, I know problem could not be" solved", but using a large initial buffer (delay) and store as much as you can in advance could help to mask it.

    Too bad limit is from LMS here, You are right that it let player ask for second track when decode of the first is finished (in my system means, normally, few seconds after start, depending on length), then it download the second and store it in the buffer, but then it wait before asking for the third track until the first steam out.

    When tracks are shorts (think some operas) real 'time' of buffer is short and you are more likely to be in a rush.

    Other than this, plugin disables 'seeks' and that means - as a collateral effect - that connection coud not be restarted at a specific point, but only flushed and restarted from the beginning and this is forced to happen at previous track stremout. That way you loose what you already downloaded, waste time wayting for stream out and , becouse of hardcoded parameters in Player.pm, with a too short minimun advance.

    I think LMS behaviour is not going to change, so what we could do is use an HTTP implementation that could handle chunk download with no intervention of LMS, in order to eliminate the case when second track download is stale until the track start, this will not eliminate drops out - when happening in the first track - but could reduce them.

    What I have to better investigate are 'hicups', seems to me is like system play what has in the buffer, filling the reminder with silence, instead to wait until we have a long enought amount of data, that way keeping connection alive until stream out.

    P.S.

    "no difference" in respect of what?

    I think Flac 44100/16 is different from mp3, a very good classical and jazz catalogue to choose from is a big plus and no advertising has no price.

    Tidal is also good but classical catalog is not at same level, in my opinion, Spotify is maybe the best, if you are OK with mp3.

    I was spending much more than 180 Euro by year (means 10 CD!) buying music before, so - to me - is not a waste at all.
    Did you see a difference in when you changed buffers in Player.pm? If you did, you can increase these by overloading Player.pm. Michael showed me a very useful trick, you can create you own Player.pm and only overload what you want, put that with the Qobuz plugin. It will override Players.pm system-wide but as long as it's just for you it's your choice. See what I did in Source.pm in the "Group Players" plugin

    wrt to format, to be precise, yes there is of course 2 dimensions: lossless or not and the samplesize/rate. What I'm saying is anything else than a choice between flac/mp3 for 16/.44.1 is useless. You have more than enough SNR with 16 bits and more than enough BW with 44.1 and flac gives you bit-perfect while mp3 gives you lossy with a wide choice of bitrate. IMHO, a player supporting both would be all you need.
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express, GGMM E5

  4. #64
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582
    Quote Originally Posted by philippe_44 View Post
    Did you see a difference in when you changed buffers in Player.pm?
    Is not easy to test this kind of things, becouse you have to wait for line errors to occours and discerne if it is the one you where looking for, just detaching the plug is not the same... This said, yes changing the threashold (the buffersize could be changed via the pref) affect the behaviour in case of errors.

    Changin rebuffering to somethink like 4Mb instead of the calculed 344Kb makes hicUps to disappear, but then we have dropouts instead and, often, restart of the track (becose we miss the seek capability here), probably we should hack a little the timer too, but - to me - this is better than having hicups until the end of the track or having to stop and restart it manually.

    Let we see what's happening replacing the sysread, I'm working on that.

    Quote Originally Posted by philippe_44 View Post

    If you did, you can increase these by overloading Player.pm. Michael showed me a very useful trick, you can create you own Player.pm and only overload what you want, put that with the Qobuz plugin. It will override Players.pm system-wide but as long as it's just for you it's your choice. See what I did in Source.pm in the "Group Players" plugin
    You mean I could do the same for any module in LMS?
    With "system-wide" you mean if the plugin is just loaded, no matter if is involved in the calling chain?

    Quote Originally Posted by philippe_44 View Post
    wrt to format, to be precise, yes there is of course 2 dimensions: lossless or not and the samplesize/rate. What I'm saying is anything else than a choice between flac/mp3 for 16/.44.1 is useless. You have more than enough SNR with 16 bits and more than enough BW with 44.1 and flac gives you bit-perfect while mp3 gives you lossy with a wide choice of bitrate. IMHO, a player supporting both would be all you need.
    Agree and AFAIK Qobuz is streaming only mp3 or Flac 44.1/16, You could buy and download HiRez, not streaming. I'm sure we are not so far, but we will see then.
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  5. #65
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582

    First results

    Having restored all standard and plugin modules to original versions and just overridden sysread in Plugins::Qobuz::ProtocolHandler in order to use chunk http get using Slim::Networking::SimpleAsyncHTTP, with parameters:

    range size = 1024*1024.

    and, indirectly:

    buffer threshold as calculate by Squeezebox.pm ( depending on bitrate , 80*1024 per flac)

    buffer size as resulting using 1500 as buffersecs in preference (is not exposed, so I've manually updated) = 512 MB.

    result is I've got no streamout or hicups in the last day. It never happen sysread hangs causing playback to restart, but if i detach the plug, i could see 30 secs of retry and then a track stop (or restart if i'm rapid enougth to replug).

    Usig a lower buffer cause download time to be longer , so if problems happens it's more likely it broke connection, causing a restart of the track.

    Using a much lower range size makes download to slow down and buffer underrun arise, bigger values let playback to be delayed more than the few seconds expected.

    I'll make some more test, but related code is here:

    Code:
    use List::Util qw(min max first);
    use Slim::Utils::Errno;
    use constant MIN_OUT => 256*1024;    # delay before playback starts.
    use constant MAX_OUT => 4*1024*1024; # safety limit, the out should always be empty.
    use constant DATA_CHUNK => 1024*1024; #size of range in the http get request.
    
    ...
    
    sub new {
    	my $class  = shift;
    	my $args   = shift;
        
            my $song      = $args->{'song'};
        
    	my $client    = $args->{client};
    	my $streamUrl = $song->streamUrl() || return;
    
    	main::DEBUGLOG && $log->is_debug && $log->debug( 'Remote streaming Qobuz track: ' . $streamUrl );
        
    	my $mime = $song->pluginData('mime');
    
    	my $sock = $class->SUPER::new( {
    		url     => $streamUrl,
    		song    => $song,
    		client  => $client,
            
    #		bitrate => $mime =~ /flac/i ? 750_000 : 320_000,
    	} ) || return;
        
    	${*$sock}{contentType} = $mime;
       
        if (defined($sock)) {
    		${*$sock}{'vars'} = {                   # variables which hold state for this instance:
    			'inBuf'       => '',                # buffer of received data
    			'outBuf'      => '',                # buffer of processed audio
    			'offset'      => 0,                 # offset for next HTTP request
    			'streaming'   => 1,                 # flag for streaming, changes to 0 when all data received
    			'fetching'    => 0,                 # waiting for HTTP data
    		};
    	}
        
        return $sock;
    }
    sub vars {
    	return ${*{$_[0]}}{'vars'};
    }
    
    sub sysread {
    	my $self = $_[0];
        #my $chunk = $_[1];
    	my $chunkSize = $_[2];
    
    	my $metaInterval = ${*$self}{'metaInterval'};
    	my $metaPointer  = ${*$self}{'metaPointer'};
            my $readLength;
    
        #Data::Dump::dump("Plugins::Qobuz::ProtocolHandler - sysread: ", $metaInterval, $metaPointer, $chunkSize);
        
    	if ($metaInterval && ($metaPointer + $chunkSize) > $metaInterval) {
    
    		$chunkSize = $metaInterval - $metaPointer;
    
    		# This is very verbose...
    		#$log->debug("Reduced chunksize to $chunkSize for metadata");
            Data::Dump::dump("Reduced chunksize for metadata", $chunkSize);
            
            $readLength = CORE::sysread($self, $_[1], $chunkSize, length($_[1] || '' ))
    
        } else{
    
            $readLength = _sysread($self, $_[1], $chunkSize);
        }
        
        #Data::Dump::dump("sysread: ", $_[1], $chunkSize, length($_[1]));
        #my $readLength = CORE::sysread($self, $_[1], $chunkSize, length($_[1] || '' ));
    
    	if ($metaInterval && $readLength) {
    
    		$metaPointer += $readLength;
    		${*$self}{'metaPointer'} = $metaPointer;
    
    		# handle instream metadata for shoutcast/icecast
    		if ($metaPointer == $metaInterval) {
    
    			$self->readMetaData();
    
    			${*$self}{'metaPointer'} = 0;
    
    		} elsif ($metaPointer > $metaInterval) {
    
    			main::DEBUGLOG && $log->debug("The shoutcast metadata overshot the interval.");
    		}	
    	}
    
    	return $readLength;
    }
    
    sub _sysread(){
        use bytes;
        
        my $self = $_[0];
        #my $chunk  = $_[1];
        #my $chunkSize = $_[2];
        
        my $v = $self->vars;
        my $url = ${*$self}{'url'};
    
        # need more data
    	if ( length $v->{'outBuf'} < MAX_OUT && !$v->{'fetching'} && $v->{'streaming'} ) {
    		my $range = "bytes=$v->{offset}-" . ($v->{offset} + DATA_CHUNK - 1);
    		
    		$v->{offset} += DATA_CHUNK;
    		$v->{'fetching'} = 1;
            
            Data::Dump::dump("* Going to fetch:  ", $url, $range, length($v->{'inBuf'} || ''), $v->{'fetching'},$v->{'streaming'});
    						
    		Slim::Networking::SimpleAsyncHTTP->new(
    			sub {
    				$v->{'inBuf'} .= $_[0]->content;
    				$v->{'fetching'} = 0;
    				$v->{'streaming'} = 0 if length($_[0]->content) < DATA_CHUNK;
    				main::DEBUGLOG && $log->is_debug && $log->debug("got chunk length: ", length $_[0]->content, " from ", $v->{offset} - DATA_CHUNK, " for $url");
                    Data::Dump::dump("* Got chunk length: ", length $_[0]->content, $v->{offset} - DATA_CHUNK, length $v->{'inBuf'});
                },
    			
    			sub { 
    				$log->warn("error fetching $url");
    				$v->{'inBuf'} = '';
    				$v->{'fetching'} = 0;
                    Data::Dump::dump("error fetching $url");
    			}, 
    			
    		)->get($url, 'Range' => $range );
    		
    	}	
        if (length $v->{'inBuf'} >= MIN_OUT || !$v->{'streaming'}){
            
            Data::Dump::dump("Going to feed OUT BUF:  ", length $v->{'inBuf'}, MIN_OUT);
            
            $v->{'outBuf'} = $v->{'outBuf'}.$v->{'inBuf'};
            $v->{'inBuf'}='';
        }
        
        my $bytes = min(length $v->{'outBuf'}, MIN_OUT);
    
        if ($bytes) {
            Data::Dump::dump("Going to return OUT BUF:  ",$bytes, length $v->{'outBuf'}, MIN_OUT);
    		$_[1] = $_[1].substr($v->{'outBuf'}, 0, $bytes);
    		$v->{'outBuf'} = substr($v->{'outBuf'}, $bytes);
    		return $bytes;
    	} elsif ( $v->{streaming} ) {
    		$! = EINTR;
    		return undef;
    	} else {
            Data::Dump::dump("EOF");
            return 0; #EOF.
        }
        
    }
    
    ...
    Any suggestion is apreciated.

    Thanks, Marco.
    Last edited by marcoc1712; 2018-01-31 at 09:52.
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  6. #66
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582
    Still testing and found that when Pipeline.pm is involved we could not pass an EINTR error, but EWOULDBLOCK also when it will not block but we have got no data. Maybe is better to add the rigth test to Pipeline, but untill that moment...

    @Philippe, I think the plugins you pointed me to suffers from this problem.
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  7. #67
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582
    Quote Originally Posted by philippe_44 View Post
    ...you can increase these by overloading Player.pm. Michael showed me a very useful trick, you can create you own Player.pm and only overload what you want, put that with the Qobuz plugin. It will override Players.pm system-wide but as long as it's just for you it's your choice. See what I did in Source.pm in the "Group Players" plugin
    I should miss something obvious here:

    copied Player.pm and Squeezelbox.pm into the plugin folder, removed everything from the new files but "play" routine in squeezebox.pm and "rebuffer" in player.pm, added some debug to check, but LMS still uses the original ones.

    Get lost...
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  8. #68
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    3,537
    Quote Originally Posted by marcoc1712 View Post
    I should miss something obvious here:

    copied Player.pm and Squeezelbox.pm into the plugin folder, removed everything from the new files but "play" routine in squeezebox.pm and "rebuffer" in player.pm, added some debug to check, but LMS still uses the original ones.

    Get lost...
    You need the plugin (or something) to do one "use" of your squeezebox.pm to get it loaded
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express, GGMM E5

  9. #69
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582
    Quote Originally Posted by philippe_44 View Post
    You need the plugin (or something) to do one "use" of your squeezebox.pm to get it loaded
    Yes, I got it.

    In your plugin you instantiate a new client as
    Code:
    my $client = Plugins::Groups::Player->new(...)
    , that way it override and load all classes it needs to run.

    Point is this is a 'virtual' client, it never send and Hello to slimproto and you use a fresh socket to instantiate it, where I have to deal with 'real' players that are instantiated from Slimproto::_hello_handler, where socket is already there as input parameter.

    I tried to 'replace' slimproto created $client with a new one from a my class overidding Slim::Player::Player, but problem is how to get the socket out of the original one and use it to create the new one, for all other paramethers there is the accessor, but not for socket (or at least I could not see where is stored).

    Cleanest way shoud be override Slimproto::_hello_handler and using a custom class to define $client, but don't know if it 's possible from a plugin and, in case, I think it will be better do this in a specific plugin (i.e. named 'custom player').

    BTW, at moment, the main work is done thanks to your and bpa help, here the parameters used :

    a. Range size (the chunck of data being read per cicle). Is hardcoded at 1Mb, but I think it should be a preference.
    b. Minimum buffer threshold. Today is calculated and could be overloaded by plugins for 'normal' playback', but when rebuffering others (hardcoded) are used.
    c. Maximum buffer threshold. Based on pref->('buffersecs').
    d. Buffer size. This is not really a parameter, it comes from player.

    I think we could live with that, mainly becouse major problems are from other LMS limits. Only minor concern is Minimum buffer threshold when rebuffering, that should really modified in standard, I think.

    Marco
    Last edited by marcoc1712; 2018-02-02 at 06:19.
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

  10. #70
    Senior Member
    Join Date
    Dec 2009
    Location
    Albinea (Bologna Area) Italy
    Posts
    582

    pull request submitted

    Hi all,

    I've just submitted a pull request for changes to Plugin::Qobuz::ProtocolHandler.pm.

    Thanks to all for help received.

    Marco
    __________________________________________________ ______________________
    Author of C-3PO plugin, Squeezelite-R2, Falcon Web interface - See www.marcoc1712.it

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •