owntone / owntone-server

Linux/FreeBSD DAAP (iTunes) and MPD audio server with support for AirPlay 1 and 2 speakers (multiroom), Apple Remote (and compatibles), Chromecast, Spotify and internet radio.
https://owntone.github.io/owntone-server
GNU General Public License v2.0
2.09k stars 234 forks source link

Soundbridge selective transcoding #1665

Closed frankusb closed 4 months ago

frankusb commented 1 year ago

1) Could httpd_rsp.c transcode to CBR MP3 instead of WAV? This is mostly a question of if ffmpeg can do FLAC to MP3 like it does FLAC to WAV now. 2) If so, could it do it on a per client basis?

Wireless Soundbridges can't handle WAV bitrates. Currently I have two instances of owntone running, one in conjunction with mp3fs to allow reliable playback on wireless Soundbridges. Besides the duplication of resources, the real annoyance is when I update a playlist, the mp3fs owntone then churns for 30-40 minutes re-reading all of the metadata since inotify is not supported with mp3fs.

ejurgensen commented 1 year ago

Sounds like it should be possible, I'll look into it.

ejurgensen commented 1 year ago

For testing this concept, I have made a branch with a very rudimentary implementation where the transcoding is switched to CBR MP3 at 256 kbit/s. Could you try if this works with a flac and the Soundbridge?

This is the branch: https://github.com/owntone/owntone-server/tree/rspmp3

frankusb commented 1 year ago

I get httpd: Transcoding error, file id 37484 in the log.

Also, if it's not obvious, the Soundbridge does not play.

ejurgensen commented 1 year ago

Which version of ffmpeg is it?

Also, can you confirm it doesn't play and you get the same error if you try from a browser? Try with http://[address]:3689/rsp/stream/37484

frankusb commented 1 year ago

ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers built with gcc 12 (Debian 12.2.0-14) configuration: --disable-decoder=amrnb --disable-decoder=libopenjpeg --disable-gnutls --disable-liblensfun --disable-libopencv --disable-podpages --disable-sndio --disable-stripping --enable-avfilter --enable-chromaprint --enable-frei0r --enable-gcrypt --enable-gpl --enable-ladspa --enable-libaom --enable-libaribb24 --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libdavs2 --enable-libdc1394 --enable-libdrm --enable-libfdk-aac --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libglslang --enable-libgme --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libkvazaar --enable-libmp3lame --enable-libmysofa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librist --enable-librsvg --enable-librubberband --enable-libshine --enable-libsmbclient --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-nonfree --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-openssl --enable-postproc --enable-pthreads --enable-shared --enable-version3 --enable-vulkan --incdir=/usr/include/x86_64-linux-gnu --libdir=/usr/lib/x86_64-linux-gnu --prefix=/usr --toolchain=hardened --enable-vaapi --enable-libvpl --enable-libvmaf --enable-libilbc --enable-libjxl --disable-altivec --shlibdir=/usr/lib/x86_64-linux-gnu libavutil 58. 2.100 / 58. 2.100 libavcodec 60. 3.100 / 60. 3.100 libavformat 60. 3.100 / 60. 3.100 libavdevice 60. 1.100 / 60. 1.100 libavfilter 9. 3.100 / 9. 3.100 libswscale 7. 1.100 / 7. 1.100 libswresample 4. 10.100 / 4. 10.100 libpostproc 57. 1.100 / 57. 1.100 Hyper fast Audio and Video encoder

It does not play and I get the same error if I try from a browser.

I also noticed that the Soundbridge shows the song info as "Kind:WAV audio file" and "Bit Rate: 1411 kbps" for FLAC files which is not what I would expect.

ejurgensen commented 1 year ago

Ok, I found the reason it's not playing in the browser. I'll get back to you with a new attempt.

ejurgensen commented 1 year ago

I've pushed a commit to the branch that I think should fix at least playback in browser. Please test and let me know.

frankusb commented 1 year ago

I won't be able to test until Wednesday.

On Sat, Oct 28, 2023, 8:30 AM ejurgensen @.***> wrote:

I've pushed a commit to the branch that I think should fix at least playback in browser. Please test and let me know.

— Reply to this email directly, view it on GitHub https://github.com/owntone/owntone-server/issues/1665#issuecomment-1783848886, or unsubscribe https://github.com/notifications/unsubscribe-auth/APETTJUHWGXWH76DC27DLDLYBUQJHAVCNFSM6AAAAAA57G5SBKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTOOBTHA2DQOBYGY . You are receiving this because you authored the thread.Message ID: @.***>

frankusb commented 1 year ago

The Soundbridge is unable to stream. It still shows shows the song info as "Kind:WAV audio file" and "Bit Rate: 1411 kbps" for FLAC files. I can stream to my web browser.

[2023-11-01 09:27:09] [DEBUG] db: Starting query 'SELECT f. FROM files f JOIN playlistitems pi ON f.path = pi.filepath WHERE f.disabled = 0 AND f.data_kind = 0 AND pi.playlistid = 12 ORDER BY pi.id ASC ;' [2023-11-01 09:27:09] [DEBUG] db: End of query results [2023-11-01 09:27:09] [DEBUG] httpd: Gzipping response [2023-11-01 09:27:09] [DEBUG] rsp: RSP request '/rsp/db/0?query=id%3D12702&type=full' in worker thread 386760 [2023-11-01 09:27:09] [DEBUG] db: Running query 'SELECT COUNT() FROM files f WHERE f.disabled = 0 AND (f.id = 12702) AND f.data_kind = 0;' [2023-11-01 09:27:09] [DEBUG] db: Starting query 'SELECT f. FROM files f WHERE f.disabled = 0 AND (f.id = 12702) AND f.data_kind = 0 ORDER BY f.title_sort ;' [2023-11-01 09:27:09] [DEBUG] db: End of query results [2023-11-01 09:27:09] [DEBUG] httpd: Gzipping response [2023-11-01 09:27:09] [DEBUG] rsp: RSP request '/rsp/stream/12702' in worker thread 386760 [2023-11-01 09:27:09] [DEBUG] db: Running query 'SELECT f. FROM files f WHERE f.id = 12702;' [2023-11-01 09:27:09] [ INFO] httpd: Preparing to transcode /var/autofs/removable/easystore10TB/Music/Travis Larson Band/Travis Larson Band-The New Exhibit/02-And Then.flac [2023-11-01 09:27:09] [DEBUG] xcode: Selected encoder 'libmp3lame MP3 (MPEG audio layer 3)' [2023-11-01 09:27:09] [DEBUG] ffmpeg: tb:1/44100 samplefmt:s16 samplerate:44100 chlayout:stereo [2023-11-01 09:27:09] [DEBUG] xcode: Created 'abuffer' filter: 'time_base=1/44100:sample_rate=44100:sample_fmt=s16:channel_layout=stereo' [2023-11-01 09:27:09] [DEBUG] xcode: Created 'aformat' filter: 'sample_fmts=s16p:sample_rates=44100:channel_layouts=stereo' [2023-11-01 09:27:09] [DEBUG] xcode: Created 'abuffersink' filter: '' [2023-11-01 09:27:09] [DEBUG] ffmpeg: auto-inserting filter 'auto_aresample_0' between the filter 'abuffer' and the filter 'aformat' [2023-11-01 09:27:09] [DEBUG] ffmpeg: ch:2 chl:stereo fmt:s16 r:44100Hz -> ch:2 chl:stereo fmt:s16p r:44100Hz [2023-11-01 09:27:09] [ INFO] httpd: Kicking off streaming for /var/autofs/removable/easystore10TB/Music/Travis Larson Band/Travis Larson Band-The New Exhibit/02-And Then.flac [2023-11-01 09:27:09] [DEBUG] httpd: Got 66037 bytes from transcode; streaming file id 12702

ejurgensen commented 1 year ago

Ok, that's progress then. It could sound like the Soundbridge gets some metadata that makes it expect wav, so I will check what is sent to it before streaming.

ejurgensen commented 1 year ago

I see the RSP playlist response returns info about the media format, so now I made a change so that the response instead tells the Soundbridge that it is 256 kbit mp3. Please try again with the latest commit from the branch included.

frankusb commented 1 year ago

It works perfect.

ejurgensen commented 1 year ago

Excellent. Does seeking also work?

To change the implementation from experimental to actual, I have to decide which clients should get what formats. In the branch, all clients get 256 kbit mp3, even iTunes (haven't tested if it works, though). I would like to set some good defaults, so that configuration generally isn't needed. I am always weary about adding config options. What defaults do you suggest for RSP?

frankusb commented 1 year ago

The Soundbridge does not support seeking, only next and previous tracks and that does work.

For bit rate default, I would suggest 320kbps. That's what I've been using with mp3fs for a while now. I used to frequent the Soundbridge forums and there were never complaints about mp3 bit rates needing to be reduced that I recall. May as well maximize sound quality.

Are there other default settings you are asking about?

To be clear, I am interested in this feature so that I can set wireless Soundbridges to receive 320kbps MP3 and wired Soundbridges to receive 1411kbps WAV. I have been thinking if the default should be 320kbps MP3 to insure that owntone will work with all Soundbridges regardless of type of network connection.

Porco-Rosso commented 1 year ago

Agreed 320kbps is a good default. Lots of literature to say that it's the level where its almost impossible to hear any difference from lossless files. It's also the most common mp3 format to download online.

ejurgensen commented 1 year ago

While looking at how to do this, I came across this which seems to imply that the Soundbridge supports ALAC. Do you know if that is the case @frankusb? If so, would it be a better alternative? You would get lossless, but with less compression than the 320 kbps mp3, so requires more wifi bandwidth (I think the compression is about 50%, so half of 1411 kbps I guess).

frankusb commented 1 year ago

You tried ALAC transcoding previously. I also found that the Soundbridge could not handle ALAC over wireless reliably by dropping some ALAC files in owntone.

ejurgensen commented 11 months ago

I've been working some more on this, trying to make it more clean/less hardcoded, so that it can be merged. If you have the opportunity, please give the current rspmp3 branch a try again and let me know if it works.

frankusb commented 11 months ago

It compiles and the Soundbridge plays fine. I'll leave it running and let you know if I notice anything.

frankusb commented 11 months ago

I did notice that the file size shows the FLAC size rather than the MP3 effective size in the Soundbridge song info. If I recall correctly, it also did this with WAV trans-coding as well. It doesn't affect anything that I can tell.

ejurgensen commented 11 months ago

I've now merged the change into master. It should also show the correct file size now.

frankusb commented 11 months ago

Do I understand correctly that there is nothing selective about this? All RSP will be 320kbps?

ejurgensen commented 11 months ago

Yes, indeed. Also DAAP, actually. I didn't add an option because in general I think mp3 is a better option than wav. Of course there is a slight quality loss, but wav could also be said to have that when the source was resampled to 44100. Another possible downside of mp3 is that the encoding requires cpu, but I figure that isn't much of problem these days.

One issue with mp3 that occurs to me now is that some installations might not have the encoder (I think it's only in "libavcodec-extras"?). I will look into adding something that checks for that.

frankusb commented 11 months ago

Ripped CDs stored in FLAC format have zero quality loss transcoding to WAV at 44100 for the record unless there is something else I am unaware of in the transcoding from FLAC to WAV. The slight quality loss is only necessary for the wireless Soundbridges. Wired can have bit perfect playback.

And to be overly pedantic, only the M500, M1000 and M2000 have a codec that can play 44.1kHz. For M1001 and R1000, the audio codec can only do 48kHz. For best quality, one would transcode for those to 48kHz as the 400MHz Blackfin in the Soundbridges have audible artifacts upsampling from 44.1kHz to 48kHz.

If one wanted to be able to provide theoretical best quality, each individual device would need control over transcode output (WAV or MP3) and sample rate (44.1kHz vs 48kHz).

ejurgensen commented 11 months ago

Yes, agree. What would you suggest as selection strategy? It should preferably be with no configuration, or at least as little as possible.

frankusb commented 11 months ago

Well, you can't tell if a connection is bandwith limited (wireless), can you? It may be possible to determine the model and if so the optimal frequency could be selected. M500, M1000, M2000: 44.1kHz. M1001, R1000: 48kHz.

Actually for R1000, it's only wireless so it could be MP3 320kbps 48kHz and it's optimal. The M models can be either wired or wireless so I think would require user configuration to optimize.

ejurgensen commented 11 months ago

By adding timers it might be possible to detect network and encoding bottlenecks, but it would be quite complicated and certainly nice to avoid. Reaction to an identified bottleneck would also be complex.

I'm not sure how much the Roku's reveal about themselves, but I've made a branch where the request headers are dumped to the log. If you have some of these devices then please try the branch debug_dump_headers and share the results.

I'm thinking I should make another attempt with ALAC. Seems like it could be a silver bullet.

ejurgensen commented 11 months ago

I'm thinking I should make another attempt with ALAC. Seems like it could be a silver bullet.

Scratch that, now I see you said before that "I also found that the Soundbridge could not handle ALAC over wireless reliably by dropping some ALAC files in owntone."

frankusb commented 11 months ago

I've tried ALAC at my house and my parent's house and it's better than WAV but still has dropouts. That and you said ffmpeg didn't support FLAC to ALAC transcoding.

Unfortunately, it appears the headers you captured are not unique between models (at least M2000 and M1001).

[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'User-Agent': 'Roku SoundBridge/3.0'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'Host': '192.168.1.119:3689'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'Accept': '*/*'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'Pragma': 'no-cache'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'accept-codecs': 'wma,mpeg,wav,mp4a,alac'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'rsp-version': '0.1'
[2023-12-05 08:30:25] [DEBUG]    httpd: Request header 'transcode-codecs': 'wav,mp3'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'User-Agent': 'Roku SoundBridge/3.0'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'Host': '192.168.1.119:3689'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'Accept': '*/*'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'Pragma': 'no-cache'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'accept-codecs': 'wma,mpeg,wav,mp4a,alac'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'rsp-version': '0.1'
[2023-12-05 08:31:13] [DEBUG]    httpd: Request header 'transcode-codecs': 'wav,mp3'
frankusb commented 11 months ago

OK, I've got the wired vs wireless worked out. Owntone is currently finding all Soundbridges on the local network and adding them as speakers. The RCP protocal is used to do this. The RCP protocol allows one to query wifi parameters. So, GetConnectedWiFiNetwork or GetWiFiSignalQuality could be used to determine the type of network connection and select FLAC transcoding as WAV or MP3 automatically.

frankusb commented 11 months ago

Actually, probably a better option is GetIfConfig. Below shows the return value of a wired and wireless Soundbridge.

GetIfConfig
GetIfConfig: B200   Interface: 0 (kWireless) has a dhcp assigned address
GetIfConfig:  MAC Address: 00:0D:4B:0A:04:40
GetIfConfig:   IP Address: 192.168.1.44
GetIfConfig:      Netmask: 255.255.255.0
GetIfConfig:      Gateway: 192.168.1.254
GetIfConfig:        DNS 1: 192.168.1.254
GetIfConfig:        DNS 2: 0.0.0.0

GetIfConfig
GetIfConfig: DM90   Interface: 0 (kEthernet) has a dhcp assigned address
GetIfConfig:  MAC Address: 00:0D:4B:04:4F:4B
GetIfConfig:   IP Address: 192.168.1.46
GetIfConfig:      Netmask: 255.255.255.0
GetIfConfig:      Gateway: 192.168.1.254
GetIfConfig:        DNS 1: 192.168.1.254
GetIfConfig:        DNS 2: 0.0.0.0
GetIfConfig: B200   Interface: 1 (kWireless) is disabled
GetIfConfig:  MAC Address: 00:0D:4B:04:CF:4B
ejurgensen commented 11 months ago

Yes, that sounds like it could work. It would require some internal redesign, however, because right now the RCP implementation is separated from the streaming.

I took a new stab at ALAC and made some progress. Scouring the internet for clues, I found a ffmpeg option that made it work, at least partially. Not with old versions of ffmpeg (not sure where the cutoff is exactly) and not with alll clients. Unfortunately, iTunes is among those - it only plays a few seconds and then aborts.

Could you try with your Roku's? I made a new branch for this, it is rsp_daap_format1.

frankusb commented 11 months ago

It does not play on the Soundbridge.

[2023-12-05 16:16:06] [ INFO]    httpd: Preparing to transcode /var/autofs/removable/easystore10TB/Music/Pink Floyd/Pink Floyd-The Dark Side Of The Moon (Live at Wembley 1974)/10-Eclipse.flac
[2023-12-05 16:16:06] [DEBUG]    xcode: Selected encoder 'ALAC (Apple Lossless Audio Codec)'
[2023-12-05 16:16:06] [DEBUG]   ffmpeg: tb:1/44100 samplefmt:s16 samplerate:44100 chlayout:stereo
[2023-12-05 16:16:06] [DEBUG]    xcode: Created 'abuffer' filter: 'time_base=1/44100:sample_rate=44100:sample_fmt=s16:channel_layout=stereo'
[2023-12-05 16:16:06] [DEBUG]    xcode: Created 'aformat' filter: 'sample_fmts=s16p:sample_rates=44100:channel_layouts=stereo'
[2023-12-05 16:16:06] [DEBUG]    xcode: Created 'abuffersink' filter: ''
[2023-12-05 16:16:06] [DEBUG]   ffmpeg: auto-inserting filter 'auto_aresample_0' between the filter 'abuffer' and the filter 'aformat'
[2023-12-05 16:16:06] [DEBUG]   ffmpeg: ch:2 chl:stereo fmt:s16 r:44100Hz -> ch:2 chl:stereo fmt:s16p r:44100Hz
[2023-12-05 16:16:06] [ INFO]    httpd: Kicking off streaming for /var/autofs/removable/easystore10TB/Music/Pink Floyd/Pink Floyd-The Dark Side Of The Moon (Live at Wembley 1974)/10-Eclipse.flac
[2023-12-05 16:16:06] [DEBUG]    httpd: Got 123255 bytes from transcode; streaming file id 40178
[2023-12-05 16:16:10] [ WARN]      rsp: Connection to '::ffff:192.168.1.40' was closed

The Soundbridge shows Kind: Apple Lossless audio file Bit Rate: 1411 kbps Sample Rate: 44.100 kHz Size: 23.0 MB

From that list, Bit Rate appears incorrect. Size does not match the actual file size of 14M.

ls -lh ~/easystore10TB/Music/Pink\ Floyd/Pink\ Floyd-The\ Dark\ Side\ Of\ The\ Moon\ \(Live\ at\ Wembley\ 1974\)/10-Eclipse.flac 
-rw-r--r-- 1 frank frank 14M Mar 23  2023 '/home/frankbanul/easystore10TB/Music/Pink Floyd/Pink Floyd-The Dark Side Of The Moon (Live at Wembley 1974)/10-Eclipse.flac'
ejurgensen commented 11 months ago

Darn, looks a bit like the iTunes error, where it disconnects after reading a bit.

Calculating the size of ALAC before encoding is impossible, I would think. Some audio can be compressed a lot, some not so much. The bitrate I just set to the same as wav. I think both are probably just used as metadata, so not likely to be the cause of the problem.

Btw, in the branch I also changed the wav implementation so that it no longer resamples. Of course that can make your bandwidth problems worse. There is also new option in the config called "prefer_format" (not per device), so there you can switch between alac, wav and mp3.

frankusb commented 11 months ago

In my last effort with alac, I found the ffmpeg flags -movflags +faststart to be important. Do these apply to your efforts?

frankusb commented 11 months ago

Adding av_dict_set(&options, "movflags", "faststart", 0); did not change anything for me.

frankusb commented 11 months ago

OK, I've been doing some wireshark captures. First difference I notice between an actual alac and a transcoded flac is a missing Content-Length: 28118563 before the file is served. I have not started digging into the alac format yet but the "header" certainly has differences as well.

Alac.txt FlacXcode.txt

frankusb commented 11 months ago

Content-Length seems to just be based on if it's a transcoded file or not. FLAC to MP3 transcode is missing it as well but plays fine while actual MP3s provide Content-Length. So probably nothing there.

ejurgensen commented 11 months ago

Good that you found how to set those options, it would be great if you could experiment with them. I didn’t try faststart myself, but the internet told me that “movflags” = “empty_moov” was the thing to do. That did in fact make the encoder (the mp4a muxer) stop complaining, but neither VLC nor ffplay could play the stream. Then I tried with “frag_size” instead, because it seems aimed at streaming, and that was better – no encoder errors and works with VLC/ffplay, but not with iTunes. I didn’t try if using both would fix iTunes.

frankusb commented 11 months ago

I tried various combinations. I observed that in some cases, the Soundbridge took longer before it failed. I could also cause the transcode to fail. I would guess the Soundbridge does not support fragmented ALAC.

For the record, I tried faststart, frag_every_frame, empty_moov, separate_moof.

ejurgensen commented 11 months ago

I would guess the Soundbridge does not support fragmented ALAC

Yes, I could also fear this, but I will give it a few more shots with iTunes, maybe I will get lucky.

frankusb commented 11 months ago

I may have misused av_dict_set. I called it multiple times and I think that only the last option will be set for a given key.

ejurgensen commented 11 months ago

Yes, for the same key you might need to use +, e.g. frag_keyframe+empty_moov.

I found out that if I increase the fragment size, then iTunes will play more of the track. I increased it by changing STREAM_CHUNK_SIZE in transcode.c from 64 x 1024 og 640 x 1024. How does such a change affect your Soundbridge? If you have a short track, you could even try increasing it so much that it becomes larger than the file size. Then it might play the entire track?

I also found out that the problem with iTunes is the same even if I download a transcoded track from OwnTone and then import it in iTunes for local playback. So that means it's the file that is the problem, not http headers or anything like that.

Both observations point at iTunes not supporting fragmented mp4, which is also what some internet sources say.

frankusb commented 11 months ago

I don't see a good path forward but if you have any ideas I will try them.

av_dict_set_int(&options, "frag_size", 6410241024, 0); fails in a few seconds av_dict_set(&options, "movflags", "faststart", 0); results in xcode: Error writing header to output buffer: Invalid argument av_dict_set(&options, "movflags", "empty_moov", 0); fails in a few seconds av_dict_set(&options, "movflags", "frag_every_frame", 0); fails immediately av_dict_set(&options, "movflags", "separate_moof", 0); fails immediately av_dict_set(&options, "movflags", "empty_moov+frag_every_frame", 0); fails immediately av_dict_set(&options, "movflags", "empty_moov+faststart", 0); fails in a few seconds av_dict_set(&options, "movflags", "empty_moov+separate_moof", 0); fails in a few seconds av_dict_set(&options, "movflags", "separate_moof+frag_every_frame", 0); fails immediately av_dict_set(&options, "movflags", "separate_moof+faststart", 0); results in xcode: Error writing header to output buffer: Invalid argument av_dict_set(&options, "movflags", "empty_moov+separate_moof+faststart", 0); fails in a few seconds

ejurgensen commented 11 months ago

I have one more idea which is about dropping fragmentation and writing best effort mp4 header and footer myself.

But I realized that more fundamentally whether alac/m4a will be viable depends on how the client deals with such a file:

  1. Downloads the first part, then starts playback
  2. Downloads start and end, then starts playback
  3. Downloads the entire file, then starts playback

The last one would make it not viable, as it would of course be super slow.

I'm going to test this with iTunes and a regular alac-encoded m4a, so without transcoding. Please do the same with Soundbridge if you can.

frankusb commented 11 months ago

I am unsure exactly how I would determine the portions of the file the Soundbridge accesses during playback. But I can rule out 3, the Soundbridge streams the entire time a file is being played. The Soundbridge has 13343k of memory as reported by memstat.

I would assert that the Soundbridge can do 1 or 2 depending on the file format and the change in behavior I observed when encoding with faststart.

ejurgensen commented 11 months ago

Yes, the Soundbridge probably just reads the file from the beginning. That's what iTunes does. I found that iTunes will only play mp4's made with ffmpeg if the "faststart" flag is used. This flag means that ffmpeg will move the so-called "moov" atom to the beginning of the file. The "moov" atom is about 7k bytes and has various metadata. Importantly for this, it contains an index (chunk table), which, as I understand, tells the player where to find frames in the file. This is useful for seeking (find frame X at byte position Y). Such an index can of course only be made after encoding the entire file. So that's a problem.

I would think that for linear playback without seeking the index shouldn't be needed, so I made some tests to see if iTunes (and ffmpeg) would still play the file if the index was missing or had dummy values. Unfortunately, that wasn't the case. I'm going to try a few more things. If they don't work out, I guess the only way of achieving alac would be to let the filescanner encode files termporarily, just to save this "moov" atom. Would be a rather heavy operation. :-(

frankusb commented 11 months ago

I would pay 7k per file to get lossless Soundbridge playback. When I tried my wireless ALAC playback, the wireless Soundbridge and dedicated wireless access point were one room apart. In trying to get WAV to work, I installed a wired drop on the wall in the same room as the wireless Soundbridge. So now the wireless and Soundbridge and dedicated wireless access point are about 6 foot from each other with line of site. And WAV still doesn't work all the time, just mostly. ALAC drops from 1.4Mbps to around 800kbps. I have doubts that it would be 100% like 320kbps MP3 but who knows.

ejurgensen commented 11 months ago

would pay 7k per file to get lossless Soundbridge playback

Yes, what I meant by heavy wasn't the 7k, it's that owntone would need to temporarily alac encode all files added to the library. And the initial scan of library with a few thousand tracks would take pretty long, during which the server wouldn't be particularly responsive since it would eat cpu (unless consumption could be limited).

frankusb commented 11 months ago

Yes, what I meant by heavy wasn't the 7k, it's that owntone would need to temporarily alac encode all files added to the library. And the initial scan of library with a few thousand tracks would take pretty long, during which the server wouldn't be particularly responsive since it would eat cpu (unless consumption could be limited).

Again, not something that would bother me as it only does it once per file. But I obviously don't speak for everyone, especially those on non intel processors.