Menu

#121 Content length of FLAC transcoded to WAV incorrect

4.9
open
nobody
FLAC (1)
1
2017-08-25
2014-06-21
Anonymous
No

When transcoding FLAC to WAV using either flac or ffmpeg, the Content Length is reported as filesize (else if clause below):

            if (range != null) {
                LOG.info("Got HTTP range: " + range);
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                Util.setContentLength(response, range.isClosed() ? range.size() : fileLength - range.getFirstBytePos());
                long lastBytePos = range.getLastBytePos() != null ? range.getLastBytePos() : fileLength - 1;
                response.setHeader("Content-Range", "bytes " + range.getFirstBytePos() + "-" + lastBytePos + "/" + fileLength);
            } else if (!isHls && (!isConversion || estimateContentLength)) {
                Util.setContentLength(response, fileLength);
            }

This causes issue with Chromecast playback, as the track doesn't complete. If the FLAC file is padded with nulls to match the size of the decoded wav, it plays to completion.

Discussion

  • Anonymous

    Anonymous - 2014-06-22

    Same problem here with 4.9. It generates a stack trace in the subsonic log file:
    WARN RESTFilter - Error in REST API: Closed
    java.io.IOException: Closed
    at org.mortbay.jetty.AbstractGenerator$Output.write(AbstractGenerator.java:617)
    at org.mortbay.jetty.AbstractGenerator$Output.write(AbstractGenerator.java:575)
    at net.sourceforge.subsonic.io.RangeOutputStream.write(RangeOutputStream.java:143)
    at net.sourceforge.subsonic.controller.StreamController.handleRequest(StreamController.java:221)
    at net.sourceforge.subsonic.controller.RESTController.stream(RESTController.java:1172)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(MultiActionController.java:473)
    at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(MultiActionController.java:410)
    at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:265)
    at org.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:107)
    at org.acegisecurity.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:72)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.ui.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:166)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:81)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at net.sourceforge.subsonic.security.RESTRequestParameterProcessingFilter.doFilter(RESTRequestParameterProcessingFilter.java:108)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.ui.basicauth.BasicProcessingFilter.doFilter(BasicProcessingFilter.java:173)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.ui.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
    at org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
    at org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149)
    at org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at net.sourceforge.subsonic.filter.RequestEncodingFilter.doFilter(RequestEncodingFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at net.sourceforge.subsonic.filter.RESTFilter.doFilter(RESTFilter.java:55)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at net.sourceforge.subsonic.filter.ParameterDecodingFilter.doFilter(ParameterDecodingFilter.java:54)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at net.sourceforge.subsonic.filter.BootstrapVerificationFilter.doFilter(BootstrapVerificationFilter.java:54)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
    at org.mortbay.jetty.Server.handle(Server.java:313)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
    at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)

     
  • Anonymous

    Anonymous - 2014-07-02

    This happens because the transcoded size is guessed. In a first request the Content-Length is not set for guessed file sizes but the header that ranges are accepted. But the bug happens to start if a request uses ranges like Rang: 0- then the code above sends a length with it the client closes then the connection after the guessed size and the server tries to write the rest of the file whioch then fails. For me it is solved by changing in the StreamController the line above "if (range != null) {" to "if (range != null && !isConversion) {".

     
  • Anonymous

    Anonymous - 2015-03-18

    This is still happening in version 5.2.1.
    Implementing the fix would be greatly appreciated

     
  • Anonymous

    Anonymous - 2015-04-14

    +1, would also love a fix for this

     
  • Anonymous

    Anonymous - 2015-06-02

    In addition to seeing this happen transcoding FLAC to WAV, I've seen the same "INFO StreamController - Got HTTP range: 0-" message from time to time when transcoding FLAC to 320kbps mp3s.

    I'm streaming from my NAS at home to my laptop at work with VLC.

     
  • Anonymous

    Anonymous - 2015-11-06

    This same thing is also happening with Subsonic 5.3 while trying to cast to chromecast (flac->mp3 transcode) .

     
  • Anonymous

    Anonymous - 2016-01-15

    Still happens as of latest version.

     
  • Anonymous

    Anonymous - 2016-05-20

    I'm running into this trying to cast to my tv. Anyone have a fix yet?

     
  • Anonymous

    Anonymous - 2017-08-25

    The current version still has a problem when encoding to FLAC / decoding the WAV and listening with frontend player. Songs won't play completely with the frontend player.

    I'm getting the following error messages from flac:

    [8/25/17 8:33:07 AM EEST]   INFO    InputStreamReaderThread (c:\subsonic\transcode\flac) -: ERROR during encoding
    [8/25/17 8:33:07 AM EEST]   INFO    InputStreamReaderThread (c:\subsonic\transcode\flac) state = FLAC__STREAM_ENCODER_CLIENT_ERROR
    [8/25/17 8:33:07 AM EEST]   INFO    InputStreamReaderThread (c:\subsonic\transcode\flac)
    [8/25/17 8:33:07 AM EEST]   INFO    InputStreamReaderThread (c:\subsonic\transcode\flac) An error occurred while writing; the most common cause is that the disk is full.
    

    If I play the stream with an external player, no problems. If I lower the maximum bitrate of the frontend player, the songs get even shorter.

    This problem is related to the one which is already closed.

    Could you please set the maximum bitrate of the frontend player so, that users could stream LPCM (WAV, not even losslessly compressed) to the frontend player with a file size that is estimated from input file's channels, bit depth, sample rate and duration (and if resampling etc. is performed, count that too)?

     

Anonymous
Anonymous

Add attachments
Cancel