openal-soft icon indicating copy to clipboard operation
openal-soft copied to clipboard

Compiling OpenAL `1.23.0` for Android.

Open Brahvim opened this issue 1 year ago • 31 comments

Hello,

I'd like to know how I can (separately) compile OpenAL for Android with an OpenSL-ES or Oboe 'background'.

I'm sorry, but my knowledge of build systems is bleak.

All of my personal attempts ended with me generating a Visual Studio solution, and building that, which would give me DLLs and not Shared Objects.

I have also tried using the CMake commands mentioned in the XCompile-Android.txt file, but they throw errors about my Visual Studio installation not supporting Clang (even after installing the 'toolchain' components for Mobile Development in Visual Studio).

Could you please provide guidance on what I should be doing?

I thank you, in advance.

Brahvim avatar Feb 21 '23 17:02 Brahvim

You will need to install a compiler toolchain for building code for Android. The Android NDK provides compilers for compiling to Android from other systems. Unfortunately I don't know much about VS's Android support to know how to build a CMake project with it to generate Android binaries.

What exactly did you try to run, and what was the output? Can you paste it here?

kcat avatar Feb 21 '23 18:02 kcat

...I guess it's not a good idea to use Visual Studio for this right now.

CMake also seems to prefer to build for Visual Studio for some reason. Wondering if there's an environment variable (or CMake script variable) to fix that.

I get the following output when using CMake (cmake .. -DANDROID_STL=c++_shared -DCMAKE_TOOLCHAIN_FILE=C:\Projects\Android\AAA_LIBS\SDK\ndk\21.4.7075529\build\cmake\android.toolchain.cmake):

-- Building for: Visual Studio 17 2022
-- ANDROID_PLATFORM not set. Defaulting to minimum supported version
16.
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: C:/Projects/Android/AAA_LIBS/SDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe
-- Check for working C compiler: C:/Projects/Android/AAA_LIBS/SDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe - broken
CMake Error at C:/Program Files/CMake/share/cmake-3.23/Modules/CMakeTestCCompiler.cmake:69 (message):
  The C compiler

    "C:/Projects/Android/AAA_LIBS/SDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: C:/Users/Brahvim/Documents/GitHub/OpenAL_Soft/build/CMakeFiles/CMakeTmp

    Run Build Command(s):C:/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/amd64/MSBuild.exe cmTC_acf46.vcxproj /p:Configuration=Debug /p:Platform=x64 /p:VisualStudioVersion=17.0 /v:m && MSBuild version 17.4.1+9a89d02ff for .NET Framework
      ANDROID_HOME=C:\Program Files (x86)\Android\android-sdk
      ANDROID_SDK_ROOT=C:\Program Files (x86)\Android\android-sdk
      ANT_HOME=
      JAVA_HOME=
      NDK_ROOT=
      testCCompiler.c
    TRACKER : error TRK0005: Failed to locate: "clang.exe". The system cannot find the file specified. [C:\Users\Brahvim\Documents\GitHub\OpenAL_Soft\build\CMakeFiles\CMakeTmp\cmTC_acf46.vcxproj]

Brahvim avatar Feb 22 '23 02:02 Brahvim

You can try to remove the -DANDROID_STL=c++_shared parameter, let it use the default STL it wants to use and see if that lets it work. If not, does the listed file

C:/Projects/Android/AAA_LIBS/SDK/ndk/21.4.7075529/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe

not exist?

The -G switch can be used to tell CMake to use other generators (availability depending on platform) if you don't want it to use VS. cmake --help shows what generators are available.

kcat avatar Feb 22 '23 04:02 kcat

I used CMake-gui to delete CMake's cache and then specified a location for NDK's clang.exe and clang++.exe. Doing so brought me to this screen:

image

After adding the OPENSL_INCLUDE_DIR (path\to\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include\SLES),

OPENSL_ANDROID_INCLUDE_DIR (path\to\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include\SLES), and the

OPENSL_LIBRARY (path\to\ndk\21.4.7075529\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\lib\arm-linux-androideabi\16) entries, and 'turning off' the ALSOFT_BACKEND_* entries, I was able to compile the library, and as expected, the generated programs (such as altonegen.exe do not know what devices are available (because this build had no audio backend?).

Later, I realized I didn't 'turn on' ALSOFT_OPENSL_BACKEND. CMake does not work as expected when that is 'turned on':

Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.22000.
Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) 
Could NOT find ALSA (missing: ALSA_LIBRARY ALSA_INCLUDE_DIR) 
Could NOT find OSS (missing: OSS_INCLUDE_DIR) 
Could NOT find AudioIO (missing: AUDIOIO_INCLUDE_DIR) 
Could NOT find SoundIO (missing: SOUNDIO_LIBRARY SOUNDIO_INCLUDE_DIR) 
Could NOT find PortAudio (missing: PORTAUDIO_LIBRARY PORTAUDIO_INCLUDE_DIR) 
Could NOT find PulseAudio (missing: PULSEAUDIO_LIBRARY PULSEAUDIO_INCLUDE_DIR) 
Could NOT find JACK (missing: JACK_LIBRARY JACK_INCLUDE_DIR) 
Could NOT find OpenSL (missing: OPENSL_LIBRARY OPENSL_INCLUDE_DIR OPENSL_ANDROID_INCLUDE_DIR) 
CMake Error at CMakeLists.txt:1143 (message):
  Failed to enabled required OpenSL backend.

Since OpenSL is no longer well supported on Android anyway, could you please provide any guidance on how I should go about getting Oboe to work?

Again, thank you very much for your time, in advance!

Brahvim avatar Feb 22 '23 14:02 Brahvim

Later, I realized I didn't 'turn on' ALSOFT_OPENSL_BACKEND. CMake does not work as expected when that is 'turned on':

The ALSOFT_xxx_BACKEND options just tell CMake to allow the backend, to look for and enable it if found, and disable it if not. The ALSOFT_REQURE_xxx options tell CMake to require the given backend, to fail if its not enabled.

Since OpenSL is no longer well supported on Android anyway, could you please provide any guidance on how I should go about getting Oboe to work?

If you don't already have it, you need to get the Oboe sources. Then set the OBOE_SOURCE option for CMake to the path where its CMakeLists.txt is (e.g. -DOBOE_SOURCE=path/to/oboe, where path/to/oboe/CMakeLists.txt exists for Oboe). OpenAL Soft will then build it as part of its build process and enable the backend to use it.

kcat avatar Feb 22 '23 20:02 kcat

Hello there!

Compiling with the OpenSL backend has succeeded! (Resulting in a ~15.7 MB libopenal.so, among others.) Compiling with Oboe failed. Compiling Oboe was giving me some issues with Oboe itself, which I could go report at the Oboe repository.

Not only did I succeed, I learnt a lot about build systems as well. Thank you very-much for your immeasurably important guidance, sir @kcat!

I'll leave instructions for anyone inexperienced with build systems like me:

  1. Get the source code for OpenAL Soft from a release of your choice (like the one I used here!). ...Yes, you could also just git clone it into a folder, but I felt it was safer to go for a release.

  2. Start up cmake-gui on your computer (Download link!).

  3. After specifying the folder where the contents of the repository reside (folder of unzipped contents / git repository), and the build directory inside of it, press "Configure". Select "Ninja" in the drop-down menu.

  4. Now, we'll fix the error with the configuration CMake may inform you of. Select "Specify toolchain for cross-compiling". CMake should ask you for the location of the "Toolchain file". For this, find android.toolchain.cmake in path/to/sdk/ndk/xyz/build/cmake/, where path/to/sdk is the path to the Android SDK folder, and xyz is any version number for the Android NDK you may have installed. The complete path would look like so: path/to/sdk/ndk/xyz/build/cmake/android.toolchain.cmake.

  5. Toggle "Advanced" - a checkbox right under the "Where to build the binaries" textbox, once or twice. This should reveal an 'entry', CMAKE_MAKE_PROGRAM. Do not create it yourself using "Add Entry". That fails!

Set the value for this entry to path/to/sdk/cmake/xyz/bin/ninja.exe, where xyz is any version number of your choice installed on your system. Hold onto this path string for a bit in your clipboard - we'll need it soon!

(For the fellow *nix users, this probably would be somewhere in /usr/bin instead. Oh, and an APT package called ninja-build exists. I couldn't find any package/repository lists online for YUM or DNF, but AUR lists a package called just ninja, which shows that ninja should be installed by other packages. Wondering why this didn't come with APT's android-sdk-platform-tools too.)

Click "Configure" again, and now we play the 'waiting game' :)

  1. Make sure to check ALSOFT_REQUIRE_OPENSL or ALSOFT_REQUIRE_OBOE as per your needs (using both is probably not a good idea, though I haven't tested this hypothesis of using both together).

  2. Since @kcat stated during the discussion of this issue that this step is not a necessary, you may optionally uncheck all of the ALSOFT_BACKEND_* options other than the one for OpenSL or Oboe, whichever you wish to use. I did it literally just for a cleaner-looking log from CMake.

  3. If you're using Oboe, search for the OBOE_SOURCE entry. As you can tell, this refers to the directory where you must've stored the Oboe repository on your computer. As @kcat suggested, it should be the directory containing the CMakeLists.txt file.

  4. As per your wish, and also completely optionally, you may specify an ANDROID_STL entry. Oboe needs for this to be c++_shared, I think. The builds I tried using this entry for also failed after I was done with CMake, so I don't know what you can and cannot do with these values. Let's see!

...and with that, all you need to do for the CMake part of this process, is press "Generate", ...and wait!

  1. Open in a terminal, the build directory inside the OpenAL Soft source folder. Remember that path to ninja.exe we used in CMake? It's time to use that. Paste this into your terminal, ...and now again, we wait.

This program, ninja.exe, should be done building by the time you see a line, like [98/98] Linking C executable al* (al* refers to anything executable OpenAL comes with, such as altonegen or alrecord), output into your terminal. For Oboe, there are about a hundred more tasks, and not just 98.

...anyway, that's it! We're done! Enjoy using OpenAL Soft as libopenal.so! (And the other files!)

Brahvim avatar Feb 25 '23 17:02 Brahvim

Compiling with the OpenSL backend has succeeded! (Resulting in a ~15.7 MB libopenal.so, among others.)

That would be due to compiling with the default RelWithDebInfo setting. Debug info adds quite a bit of data to the binary to aid in debugging. You can use Release mode instead to cut the size down significantly.

Now, we'll fix the error with the configuration CMake may inform you of. Select "Specify toolchain for cross-compiling".

You should select the toolchain for cross-compiling before clicking Configure. The toolchain contains persistent settings for the host and target environment, so if you configure normally, then try to set the toolchain and configure again, it may not work as expected.

If you're using Oboe, click "Add Entry" and add entries for OBOE_INCLUDE_DIR, OBOE_LIBRARY, OBOE_SOURCE and oboe_DIR

Not all of these are needed. OBOE_INCLUDE_DIR and OBOE_LIBRARY are only used if Oboe is prebuilt/preinstalled somewhere and you want to use that. oboe_DIR would be used (presumably by Oboe's own find/config module) to detect OBOE_INCLUDE_DIR and OBOE_LIBRARY, so all three aren't needed together. OBOE_SOURCE will tell OpenAL Soft's CMake script to look in the provided location for Oboe's CMake script, which will then be added as a sub-project that will get built and used automatically during OpenAL Soft's build. If you set OBOE_SOURCE, the others are ignored.

kcat avatar Feb 25 '23 22:02 kcat

I built a binary in Release mode and surprisingly it's still 15 MB. Is the debug info actually useful for a consumer? I could cut down on it if it is related to OpenAL Soft only.

Brahvim avatar Feb 26 '23 01:02 Brahvim

Is the debug info actually useful for a consumer?

Not typically, unless they experience a problem in the library and try to get a backtrace or something. You can also use the strip command to remove excess data from the binary.

kcat avatar Feb 26 '23 01:02 kcat

Alright, I think my problem has mostly been solved. I should close this issue now. Thank you very much!

Brahvim avatar Feb 26 '23 03:02 Brahvim

Hello there! I'm sorry to open this issue again, but there's a problem that I did not mention at all - I did not get a static library (.a).

In order to use shared objects on Android, I need one of those, too.

As far as I can see, the CMake script has no options for this. How do I do this?

Thank you very much in advance!

Brahvim avatar Apr 04 '23 01:04 Brahvim

Hello there! I'm sorry to open this issue again, but there's a problem that I did not mention at all - I did not get a static library (.a).

In order to use shared objects on Android, I need one of those, too.

Unlike Windows, separate .a files are unnecessary for using shared libraries on Android/Linux/macOS.

Static libraries essentially contain compiled object files (.o files) that are linked with the executable as if they were all built as the same project. Shared libraries (.so files, or .dylib on macOS) stay separate, the linker uses them directly to know what symbols they provide and which are needed at runtime. The two are mutually exclusive; if you use a static library for some library, you don't also use the shared library, and vice-versa.

kcat avatar Apr 04 '23 13:04 kcat

Thank you very much for explaining that to me! For the entirety of this issue, I've only been messing up basic terms related to C++ development environments.

I will read up on, and experiment with setting up shared libraries on Android with more effort this time. Will try not to disturb you with this further.

I deeply appreciate your patience. Thank you very much.

Brahvim avatar Apr 04 '23 17:04 Brahvim

Thank you very much for the guide how to build OpenAL-Soft for Android. As a Dephi developer, I didn't know anythig about CMake and building projects this way. I was able to build libopenal.so following this guide. That's great. However, the resulting library binary is 32bit. Is it possible to build 64bit library also? I have tried to add some CMake entries regarding Android architecture to no vain. I also tried to modify build.ninja file, replacing -march=arm7-a with 64bit equivalents, with no success. A dlopen() call returns an error about 32bit library (since my app is 64bit native).

Centurion96 avatar Oct 30 '23 18:10 Centurion96

I have managed to solve the issue how to build OpenAL-Soft for Android amr64. One needs to add entry (via GUI "Add Entry", or via command line parameter) ANDRIOD_ABI = arm64-v8a, and specifying desired API version via ANDROID_PLATFORM entry. One also needs to modify OPENSL_LIBRARY to point to the aarch64-linux-android folder with desired API version.

Centurion96 avatar Nov 03 '23 15:11 Centurion96

Thank you very much for looking around here, @Centurion96! ...And you even solved your own issue yourself. That's awesome. Thank you very much!

PS Could you please tell me which aarch64-linux-android folder we're talking about here? I haven't looked back at this issue in a while, <gulp>, so I don't have any context either. Thank you, thank you.

Brahvim avatar Nov 05 '23 02:11 Brahvim

By default, cmake sets OPENSL_LIBRARY to {ndk_version_path}/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/arm-linux-androideabi/21/libOpenSLES.so, where 21 is the default platform version when you didn't specify one.

In order to compile and link for a different architecture and different platform version, the path needs to point to the library file specific for that architecture and that platform version.

For example, if you set ANDRIOD_ABI = arm64-v8a and ANDROID_PLATFORM = 25 then you need to modify OPENSL_LIBRARY path in the following way: {ndk_version_path}/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/aarch64-linux-android/25/libOpenSLES.so

Centurion96 avatar Nov 06 '23 10:11 Centurion96

I have managed to solve the issue how to build OpenAL-Soft for Android amr64. One needs to add entry (via GUI "Add Entry", or via command line parameter) ANDRIOD_ABI = arm64-v8a, and specifying desired API version via ANDROID_PLATFORM entry. One also needs to modify OPENSL_LIBRARY to point to the aarch64-linux-android folder with desired API version.

@Centurion96 Nicely done. Would you mind sharing your compiled libopenal.so? Also I wonder if we could add android compilation to GitHub actions 🤔

I recently found that there's an android build of sView which should've been able to virtualize surround and spatialize ambisonics, but the library is too old so I'm hoping replacing it (rooted) fixes the issue like on Windows so that I can confirm this is what the dev needs to do to fix this.

ThreeDeeJay avatar Feb 07 '24 11:02 ThreeDeeJay

Android.arm64-v8a.zip This is a compiled OpenAL Soft 1.23.1 for Android Arm64 with OpenSL backend.

Centurion96 avatar Feb 07 '24 12:02 Centurion96

Android.arm64-v8a.zip This is a compiled OpenAL Soft 1.23.1 for Android Arm64 with OpenSL backend.

Dang it, App Manager lied to me.. That's why I thought "armeabi-v7a" here was just outdated, but apparently the library's actually 32-bit? image

so would you or @Brahvim happen to have a somewhat recent armeabi-v7a libopenal.so handy? 👀 I managed to compile sView for Android and also found where it pulls dependencies from so I might be able to put together a PR to save the dev some work

ThreeDeeJay avatar Feb 07 '24 14:02 ThreeDeeJay

Android.armeabi-v7a.zip This is a compiled OpenAL Soft 1.23.1 for Android 32bit arm + neon with OpenSL backend.

Centurion96 avatar Feb 07 '24 16:02 Centurion96

Android.armeabi-v7a.zip This is a compiled OpenAL Soft 1.23.1 for Android 32bit arm + neon with OpenSL backend.

Thanks so much mate! Now the app started and loaded the DLL properly Though now i just gotta figure out why it's not respecting the HRTF settings 🤔 Screenshot_20240207-115309_sView.png

Screenshot_20240207-114821_sView.png

The dev is probably gonna have to look at the code to see why the settings aren't sticking, but in the meantime, the log tells me where it expects the config file and even MHRs, so hopefully it'll allow me to use my HRTF 🤞

ThreeDeeJay avatar Feb 07 '24 17:02 ThreeDeeJay

Android.arm64-v8a.zip This is a compiled OpenAL Soft 1.23.1 for Android Arm64 with OpenSL backend.

<Clearly very informally:> AYY! Congrats to everybody here. We finally figured it out! 😂 It's great to see this! I'll be compiling OpenAL for my armeabi-v8 device, probably.

...Wait, this binary is called "Android.arm64-v8a.zip"? ...Oh. Okay... Anyway: So... can I use this via the JNI with a CMake script now...? (I don't know much about native development on Android or build systems just like back in the day, sorry!)

Thank you very much for answering :) And yet again - congrats! To everybody here! ":D!

Brahvim avatar Feb 09 '24 10:02 Brahvim

@Centurion96 So I figured out the issue with HRTF in sView (and potentially other OpenAL apps on Android) and explained it here. But tl;dr, updating the library was just one part of the puzzle. The other part is getting it to load an MHR, which it currently lacks since it's not embedded and apparently it's attempting to use Linux paths that either don't exist or are root-restricted on Android.

So sorry to bother you again but do you think it would be possible to embed Default HRTF.mhr into libopenal.so like how it's loaded from OpenAL32.dll on Windows? If you do get a chance to take a stab at it, perhaps it might also be useful to compile with Release configuration to reduce the filesize 👀👌

ThreeDeeJay avatar Feb 11 '24 16:02 ThreeDeeJay

Should we ask kcat?

Brahvim avatar Feb 11 '24 17:02 Brahvim

After a bit more digging I found he already mentioned a way to do it here https://github.com/kcat/openal-soft/issues/46#issuecomment-232238857 So I guess what we need is compile with -DALSOFT_EMBED_HRTF_DATA=TRUE though I agree with https://github.com/kcat/openal-soft/issues/46#issuecomment-232005192 that it'd be better to also have an external, easily-accessible folder to load custom MHRs and I'm not sure if there's a flag for that we don't have to copy an alsoft.config with external hrtf-paths set into a system folder that requires root access. So @kcat what would you recommend?

ThreeDeeJay avatar Feb 11 '24 17:02 ThreeDeeJay

Should we ask kcat?

The default HRTF is embedded by default (ALSOFT_EMBED_HRTF_DATA is true be default), a build has to explicitly disable it when configuring with cmake to exclude it. Which some people may do because they don't want to use HRTF (they don't like it, or it's too resource-intensive), or they don't want to increase the file size of the library (by about ~157KB).

As for specifying extra folders for custom MHRs, you can either set the ALSOFT_LOCAL_PATH environment variable to a path where it can find .mhr files, or add an extra path to the XDG_DATA_DIRS environment variable where it will look for <path>/openal/hrtf/*.mhr files. If there are extra paths Android systems would prefer to look in for application data by default (aside from the XDG specified paths, and the current working directory), I can consider adding them to OpenAL Soft.

kcat avatar Feb 11 '24 18:02 kcat

@kcat In that case I can look into setting up an Android build workflow so I don't have to keep botherin Centurion96 😅 Also, it seems like specifying external paths on OpenAL Soft's end won't cut it, because apparently recent Android limits the locations apps can access (thanks, ~~Obama~~ Scoped storage.) image

So it fails to find the MHR copied to most folders set in hrtf-paths:

/storage/self/primary/Download image

/storage/self/primary/openal/hrtf image

/storage/self/primary/Android/data/com.sview/openal/hrtf image However, the problem with using the app's data folder is that users without root won't be able to copy anything to it.

On the bright side, I think that if the app creates a public folder in the internal storage, it might allow other apps to read and write to it. So do you think it might be possible to make OpenAL Soft create /storage/self/primary/openal/hrtf on its own? Otherwise, I guess it'd require modifying the app's behavior to create its own folder, request to access a user-created folder or even use special permissions to have more access to user-created folders. 🤔 To be honest, I'm not particularly experienced in Android programming so I'm just spitballing here lol

ThreeDeeJay avatar Feb 11 '24 20:02 ThreeDeeJay

It doesn't sound like a good idea for OpenAL Soft to create publicly accessible directories on the app. That should be up to the app itself to do if it wants.

kcat avatar Feb 12 '24 03:02 kcat

@kcat Fair enough, so the only reasonable, non-root alternative I can think of is for the app to add a scoped storage folder picker dialog for the user to explicitly allow the app to access a specific, public folder containing HRTF/*.mhr and probably alsoft.conf and instructing OpenAL Soft to use it (by adding it to XDG_DATA_DIRS and XDG_CONFIG_DIRS, respectively, I presume) Would that work? 🤔 image

ThreeDeeJay avatar Feb 12 '24 11:02 ThreeDeeJay