Index: Slim/Formats.pm =================================================================== --- Slim/Formats.pm (revision 33764) +++ Slim/Formats.pm (working copy) @@ -63,6 +63,7 @@ 'mpc' => 'Slim::Formats::Musepack', 'ape' => 'Slim::Formats::APE', 'wvp' => 'Slim::Formats::WavPack', + 'ogf' => 'Slim::Formats::OggFLAC', # Playlist types 'asx' => 'Slim::Formats::Playlists::ASX', @@ -168,7 +169,11 @@ } } - $tags = $tagReaderClass->getTag($filepath, $anchor); + ($tags, my $ctOverride) = $tagReaderClass->getTag($filepath, $anchor); + + if ($ctOverride) { + $type = $ctOverride; + } $loadedTagClasses{$type} = 1; } Index: Slim/Player/Squeezebox.pm =================================================================== --- Slim/Player/Squeezebox.pm (revision 33764) +++ Slim/Player/Squeezebox.pm (working copy) @@ -656,7 +656,7 @@ } } - } elsif ($format eq 'flc') { + } elsif ($format eq 'flc' || $format eq 'ogf') { $formatbyte = 'f'; $pcmsamplesize = '?'; @@ -672,6 +672,13 @@ } } + # Oggflac support for Squeezeplay - uses same decoder with flag to indicate ogg transport stream + # increase default output buffer threshold as this is used for high bitrate internet radio streams + if ($format eq 'ogf') { + $pcmsamplesize = 'o'; + $outputThreshold = 20; + } + } elsif ( $format =~ /(?:wma|asx)/ ) { $formatbyte = 'w'; Index: Slim/Utils/Scanner/Remote.pm =================================================================== --- Slim/Utils/Scanner/Remote.pm (revision 33764) +++ Slim/Utils/Scanner/Remote.pm (working copy) @@ -460,6 +460,17 @@ passthrough => [ $track, $args ], } ); } + elsif ( $type eq 'ogg' ) { + + # Read the header to allow support for oggflac as it requires different decode path + main::DEBUGLOG && $log->is_debug && $log->debug('Reading Ogg header'); + + $http->read_body( { + readLimit => 4 * 1024, + onBody => \&parseOggHeader, + passthrough => [ $track, $args ], + } ); + } else { # If URL was mms but content-type is not wma, change URL if ( $track->url =~ /^mms/i ) { @@ -718,6 +729,34 @@ $cb->( $track, undef, @{$pt} ); } +sub parseOggHeader { + my ( $http, $track, $args ) = @_; + + my $client = $args->{client}; + my $cb = $args->{cb} || sub {}; + my $pt = $args->{pt} || []; + + my $header = $http->response->content; + + my $fh = File::Temp->new(); + $fh->write( $header, length($header) ); + $fh->seek(0, 0); + + my $ogg = Audio::Scan->scan_fh( ogg => $fh ); + + # search for Ogg FLAC headers within the data - if so change the content type to ogf for OggFlac + # OggFlac header defined: http://flac.sourceforge.net/ogg_mapping.html + if ($ogg && $ogg->{'info'} && $ogg->{'info'}->{'ogg_type'} eq 'flac') { + main::DEBUGLOG && $log->is_debug && $log->debug("Ogg stream is OggFlac - setting content type [ogf]"); + Slim::Schema->clearContentTypeCache( $track->url ); + Slim::Music::Info::setContentType( $track->url, 'ogf' ); + $track->content_type('ogf'); + } + + # All done + $cb->( $track, undef, @{$pt} ); +} + sub streamAudioData { my ( $http, $dataref, $track, $args, $url ) = @_; Index: Slim/Formats/Ogg.pm =================================================================== --- Slim/Formats/Ogg.pm (revision 33764) +++ Slim/Formats/Ogg.pm (working copy) @@ -76,6 +76,12 @@ my $tags = $s->{tags}; return unless $info->{song_length_ms}; + + # Use Formats::FLAC for OggFlac and force the content type + if ($s->{info}->{ogg_type} eq 'flac') { + Slim::Formats->loadTagFormatForType('flc'); + return (Slim::Formats::FLAC->_getStandardTag($s), 'ogf'); + } # Map tags while ( my ($old, $new) = each %tagMapping ) { Index: Slim/Formats/OggFLAC.pm =================================================================== --- Slim/Formats/OggFLAC.pm (revision 0) +++ Slim/Formats/OggFLAC.pm (revision 0) @@ -0,0 +1,13 @@ +package Slim::Formats::OggFLAC; + +use base qw(Slim::Formats::FLAC); + +sub findFrameBoundaries { 0 } + +sub scanBitrate{ + return (-1, undef); +} + +sub canSeek { 0 } + +1; Index: Slim/Schema.pm =================================================================== --- Slim/Schema.pm (revision 33764) +++ Slim/Schema.pm (working copy) @@ -728,6 +728,12 @@ return $contentType; } +# The contentTypeCache can used above can erroneously be set to type inferred from url path - allow it to be cleared +sub clearContentTypeCache { + my ($self, $urlOrObj) = @_; + delete $contentTypeCache{$urlOrObj}; +} + =head2 objectForUrl( $args ) The workhorse for getting L or L