OxygenCobalt / Auxio

A simple, rational music player for android
GNU General Public License v3.0
1.78k stars 117 forks source link

ffmpeg build failing #766

Closed shanet closed 3 weeks ago

shanet commented 3 weeks ago

I've been trying to get this app building so I could do some hacking around with it but it seems to be failing on the ffmpeg build:

> Task :media-lib-decoder-ffmpeg:assembleFfmpeg FAILED
FFMPEG_MODULE_PATH is /auxio/Auxio/media/libraries/decoder_ffmpeg/src/main
NDK path is /opt/android/ndk/25.2.9519653
Host platform is linux-x86_64
ANDROID_ABI is 21
Enabled decoders are flac alac
Using 24 jobs for make
Unknown option "--disable-vulkan".
See ./configure --help for available options.

I removed the --disable-vulkan flag from media/libraries/decoder_ffmpeg/src/main/jni/build_ffmpeg.sh but then I get the following:

Execution failed for task ':media-lib-decoder-ffmpeg:buildCMakeDebug[arm64-v8a]'.
> com.android.ide.common.process.ProcessException: ninja: Entering directory `/auxio/media/libraries/decoder_ffmpeg/.cxx/Debug/c93f5u23/arm64-v8a'
  [1/2] Building CXX object CMakeFiles/ffmpegJNI.dir/ffmpeg_jni.cc.o
  FAILED: CMakeFiles/ffmpegJNI.dir/ffmpeg_jni.cc.o 
  /opt/android/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android21 --sysroot=/opt/android/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/sysroot -DffmpegJNI_EXPORTS -I/auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security   -fno-limit-debug-info  -fPIC -std=gnu++11 -MD -MT CMakeFiles/ffmpegJNI.dir/ffmpeg_jni.cc.o -MF CMakeFiles/ffmpegJNI.dir/ffmpeg_jni.cc.o.d -o CMakeFiles/ffmpegJNI.dir/ffmpeg_jni.cc.o -c /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc
  /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc:218:39: error: no member named 'ch_layout' in 'AVCodecContext'
    return ((AVCodecContext *)context)->ch_layout.nb_channels;
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~  ^
  /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc:298:41: error: no member named 'ch_layout' in 'AVCodecContext'
      av_channel_layout_default(&context->ch_layout, rawChannelCount);
                                 ~~~~~~~  ^
  /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc:341:33: error: no member named 'ch_layout' in 'AVCodecContext'
      int channelCount = context->ch_layout.nb_channels;
                         ~~~~~~~  ^
  /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc:350:41: error: no member named 'ch_layout' in 'AVCodecContext'
                                &context->ch_layout,          // out_ch_layout
                                 ~~~~~~~  ^
  /auxio/media/libraries/decoder_ffmpeg/src/main/jni/ffmpeg_jni.cc:353:41: error: no member named 'ch_layout' in 'AVCodecContext'
                                &context->ch_layout,          // in_ch_layout
                                 ~~~~~~~  ^
  5 errors generated.
  ninja: build stopped: subcommand failed.

To reproduce, here's the Dockerfile I've been using:

FROM ubuntu:jammy

RUN apt-get update && apt-get upgrade --yes

RUN apt-get install --yes \
  cmake \
  curl \
  git \
  ninja-build \
  openjdk-21-jdk-headless \
  unzip

RUN mkdir /opt/android
WORKDIR /opt/android
RUN curl --output android_sdk.zip https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
RUN echo "2d2d50857e4eb553af5a6dc3ad507a17adf43d115264b1afc116f95c92e5e258  android_sdk.zip" | sha256sum --check
RUN unzip android_sdk.zip
WORKDIR /

RUN yes y | /opt/android/cmdline-tools/bin/sdkmanager --sdk_root=/opt/android --licenses
RUN /opt/android/cmdline-tools/bin/sdkmanager --sdk_root=/opt/android --install "build-tools;34.0.0"
RUN /opt/android/cmdline-tools/bin/sdkmanager --sdk_root=/opt/android --install "ndk;25.2.9519653"
RUN /opt/android/cmdline-tools/bin/sdkmanager --sdk_root=/opt/android --install "platform-tools"

RUN git clone --recurse-submodules https://github.com/OxygenCobalt/Auxio.git
WORKDIR /Auxio
RUN echo sdk.dir=/opt/android > local.properties
RUN ./gradlew assembleDebug

CMD bash

Then running docker build . -t auxio.

What am I missing with getting ffmpeg to build here?

Also, is there any desire to improve the docs for building this app? The README currently doesn't have much info about how to build it. Documenting the supported versions of Java, Android SDK, build-tools, platform-tools, NDK, and Kotlin would be great. For example, gradle seems to fail with OpenJDK 22 and I had to downgrade to 21. I was initially trying to get this running on Arch but gave up and switched to a Docker image with Ubuntu to hopefully make it more isolated.

I'd be happy to write some docs on this based on my experience once I get it building and contribute a Dockerfile if that makes it easier to get a basic dev environment set up in order to lower the barrier to entry for new contributors.

OxygenCobalt commented 3 weeks ago

I think you need to update the submodule currently with git submodule update --recursive --init --remote. This is a recent issue I've noticed and have not had the time to fix.

As for documented versions:

A docker container really wouldn't lower the barrier of entry for new contributors. Android studio more or less takes care of the dependency issues automatically save the NDK, and doing basically any android app development is best done within studio anyway.

shanet commented 3 weeks ago

Thanks for the info. I ran git submodule update --recursive --init --remote before ./gradlew assembleDebug and got it building successfully now.

When it comes to documentation though, if this is a known issue, shouldn't that be documented somewhere rather than closing the issue? It would have saved me hours of screwing around with the build tools if that were documented somewhere here.

Supported JDK is on Gradle's end and should be obvious about what they support

It isn't obvious though. If you run Gradle with OpenJDK 22 it fails with an obscure error like General error during semantic analysis: Unsupported class file major version 66. Maybe that's obvious to Java folks, but as someone that rarely writes Java I had to look it up and only then found that Gradle is not yet compatible with OpenJDK 22. If there's a known compiler incompatibility, especially with the most recent version, that seems like a valuable thing to document in a project's docs, no?

As for Android Studio, for what it's worth, I personally prefer my vim setup for writing code and don't like using IDEs like Android Studio. I understand the convenience something like it provides and why that's attractive to many, but I also wouldn't say it's "weird" to compile an app with the same tooling that Android Studio is using but from the command line rather than the IDE.

As for Docker, that's irrelevant here. I was using Docker to provide a reproducible and isolated build environment to demonstrate the issue in the hopes of creating a useful bug report. I tried doing it on my base Arch system first and was running into the same problems there outside of Docker.

That said, if it were me, a 20 line Dockerfile to get a dev environment up and running is pretty great for making it easy to get someone working with a project and requires minimal maintenance. In my case, I was interested in doing some debugging on why an M3U playlist of mine is failing to import but I spent so much time just trying to get it to build that I almost gave up on it entirely. If I knew I could just do docker build . and get something running in a known-good environment that would definitely have gotten me running with what I really wanted to spend my time on, the app itself rather than Android's build system. It's your project, of course, so just something to consider since you don't hear from the people that gave up and silently went away without ever getting started.

OxygenCobalt commented 2 weeks ago

Hm. I guess I should have expected that catering my app to the FOSS ecosystem would lead to more enthusiasts that prefer very efficient setups wanting to work on the app. I'll consider a docker container.

OxygenCobalt commented 2 weeks ago

Additionally @shanet, you might want to consult the other playlist issues #673 #693 and #700 for possible issues about your playlist files. I haven't been able to fix these just yet.

OxygenCobalt commented 2 weeks ago

Update: I think I fixed the weird submodule issue. Feel free to test again.

shanet commented 2 weeks ago

Update: I think I fixed the weird submodule issue. Feel free to test again.

Awesome, yeah I tried doing a new build from a fresh clone without running git submodule update --recursive --init --remote and it built as expected without any other intervention!


For reference (and for anyone who is here from a search result in the future), the two issues I was looking at were:

  1. My M3U playlists failing to import and me not being sure why
  2. The album field of the currently playing song not showing up on my car's headunit

For the M3U import issue, I did get it working now that I understand how Auxio handles path resolutions. In my case, I was attempting to import playlists created on my desktop with an MPD client. My MPD config has a directory structure as such:

Music/
  Artists/
    [artist]/
      [album]/
        [song].mp3
  Playlists/
    [playlist].m3u

The M3U files are relative to the Music/Artists directory. For example:

[artist]/[album]/[song].mp3

This works because MPD has a setting to tell it where my playlists directory is located and then knows to interpret the paths in those playlists as being relative to the root of the music library (Music/Artists). However, in Auxio, there's not really a concept of a "root directory" for the music library as it can source files from multiple folders.

Once I understood the path parsing logic in Auxio's M3UImpl.read function then I knew I had to add a ../Artists prefix to each line in my M3U playlist. This allowed it to parse the relative directory correctly and import the playlist. I have a script to sync my music library with my phone via adb so it was pretty easy at this point to append that prefix to each line in the M3U files after they get copied to my phone.

Some docs around the expected M3U format could be helpful to others here though. I was confused initially because the error message when an import failed was something along the lines of "could not import a playlist from this file." As an end user, I had no idea why it couldn't. My other Android music app read these M3U files just fine so I was lost as to why Auxio had a problem with them. Better error messages would be useful, but in lieu of that some docs around the supported M3U format and how paths are resolved could help others avoid the same problem I believe.


For the second issue with my car's headunit not showing the album field, I thought this was a problem with Auxio because the other Android music app I use displays it as expected. However, after looking into this I found that Auxio is setting the album name correctly in its Song.toMediaItem function. After some debugging I tried connecting my phone to another car and found that it displayed the album field as expected there. So the question became why does playing media with Auxio not the display the album field but another Android music app does even though the phone and headunit remain the same?

After doing some more reading about how this info gets transmitted over a Bluetooth connection I found that AVRCP has a few different versions and that the Android developer settings lets you choose which to use. Version 1.5 was selected by default, I tried 1.6 and 1.4 and still nothing. But when I changed it to version 1.3 then the album field displayed on my headunit again!

I'm not quite sure why this is other than there's a bug in Android bluetooth libraries or simply an incompatibility with my car's headunit and Android. I'm leaning towards the latter since my headunit is the crappy one from the factory, even though it's only a few years old. I assume that it works with the other music app I use because it's linked against an older bluetooth library that doesn't have this incompatibility (the reason I've been trying Auxio is because this other app isn't updated anymore and is closed source so I can't maintain it myself).

So yeah, it's more of an obscure topic but some info on Bluetooth AVRCP versions may be good info for a troubleshooting section of a readme or something.

Ultimately, neither of the problems I was facing were actual bugs and could be avoided by others in the future with some docs written. I'm happy to write some in a wiki, readme or docs directory if that's desirable (I think the M3U format documentation would be especially valuable).


Hm. I guess I should have expected that catering my app to the FOSS ecosystem would lead to more enthusiasts that prefer very efficient setups wanting to work on the app. I'll consider a docker container.

It's all a matter of personal preferences at the end of the day. I'm not disagreeing that it's unreasonable to officially support every possible dev environment out there. I was just coming at it from the perspective of someone that tries to take a stab at fixing issues in a myriad of projects when I run across them. If I was doing heavy Android development I'd probably be getting Android Studio set up. But for wanting to take a quick look at one or two minor issues, the longer it takes me to get a dev build running for a given project (and the more bloat I have to install on my system to get it building) the more likely I am to just move on if it becomes too much trouble. So even a not-optimal/efficient dev setup could make it more likely to get smaller contributors involved.

OxygenCobalt commented 2 weeks ago

Okay.

M3U: Yeah, that's really hard to handle, and I don't like having a playlist folder setting since it basically violates the M3U specification by making relative paths not actually relative to where the file is. I've also been meaning to show better errors (see #739), but the issue is that I need to cram another component into a UI that's already buckling under the weight of all of the hacks and crazy things I do in it.

AVRCP: This is weird. What music players did you compare to? If it's something like Poweramp I can't do anything since they probably do insane hacks to control AVRCP by themselves. I'm stuck with whatever support Media3/MediaBrowserService gives me.

Containers: That's also a good justification. I'll see if I can make a less hacky container than the one you provided.

shanet commented 1 week ago

I've been using Blackplayer EX. Mainly because it doesn't use Android's MediaStore (which I despise since I use ADB to sync my music library from my computer and it takes ages to recognize new files), but the author doesn't seem to update it anymore and the number of bugs with newer versions of Android are starting to accumulate. Because it's closed source I couldn't tell you what it's using to convey the currently playing info via Bluetooth, all I know is that it works regardless of AVRCP version in the Android dev settings.

OxygenCobalt commented 1 week ago

Yeah @shanet, BlackPlayer sounds a lot like the old school players that are stuck targeting like Android Nougat from all the crazy low-level functionality overrides they have. I don't take that approach and try to aggressively delegate to the Android OS unless it makes the app unusable. As part of this, I delegate AVRCP metadata to media3 rather than writing my own brittle code that will rot over time.

I think if you go to the media3 repository, get the demos/session_service demo app built, and then are able to reproduce the problem with that, you could file an issue for that bug. It could be fixable on their end, or it could be an android OS issue, or it could be a OEM issue. They'll be able to figure it out.

OxygenCobalt commented 1 week ago

Additionally: I also really hate MediaStore, and am trying to make it a little better with #322. Whether it helps your issue is to be seen.