Qt application with FMOD audio library crashes on launch on Android

Hello. I made an example that works on desktop when I build it to EXE but crashes when I run APK on smartphone. I use 2.02.16 API version, JDK 17, NDK 22, Qt 6.2.4, and Redmi 4x (Android 7)

Settings:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

INCLUDEPATH += $$PWD/libs/fmod-2.2.16/inc

contains(ANDROID_TARGET_ARCH, armeabi-v7a)
{
    ANDROID_EXTRA_LIBS += $$PWD/jniLibs/armeabi-v7a/libfmod.so
}

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    assets.qrc

APK is created after 1-2 minutes without problems. This is a source code of my example:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtWidgets/QWidget>
#include <fmod.h>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    FMOD_SYSTEM *m_pSystem;
    FMOD_SOUND *m_pSound;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    FMOD_System_Create(&m_pSystem, FMOD_VERSION);
    FMOD_System_Init(m_pSystem, 32, FMOD_INIT_NORMAL, 0);

    QString soundPath(":/assets/audio/music.wav");
    QFile f(soundPath);
    if (!f.open(QIODevice::ReadOnly))
    {
        qDebug() << "Faild to open the file: " << soundPath;
        return;
    }
    QByteArray soundData = f.readAll();

    FMOD_CREATESOUNDEXINFO* exinfo = new FMOD_CREATESOUNDEXINFO();
    exinfo->length = static_cast<unsigned int>(soundData.length());
    exinfo->cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
    FMOD_System_CreateSound(m_pSystem, soundData.data(), FMOD_OPENMEMORY, exinfo, &m_pSound);

    FMOD_Sound_SetMode(m_pSound, FMOD_LOOP_OFF);

    FMOD_System_PlaySound(m_pSystem, m_pSound, 0, false, 0);
}

Widget::~Widget()
{
}

main.cpp

#include "widget.h"

#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

I use armeabi-v7a to build a release:

image

I tried without FMOD and it runs on smartphone without problems. But my example above crashes with this report:

Build fingerprint: ‘Xiaomi/santoni/santoni:7.1.2/N2G47H/9.6.27:user/release-keys’
Revision: ‘0’
ABI: ‘arm’
pid: 11662, tid: 11682, name: qtMainLoopThrea >>> org.qtproject.example.fmode_2d_qt6_cpp <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: ‘art/runtime/java_vm_ext.cc:475] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn’t find class “org.fmod.AudioDevice” on path: DexPathList[[zip file “/data/app/org.qtproject.example.fmode_2d_qt6_cpp-1/base.apk”],nativeLibraryDirectories=[/data/app/org.qtproject.example.fmode_2d_qt6_cpp-1/lib/arm, /data/app/org.qtproject.example.fmode_2d_qt6_cpp-1/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]’
r0 00000000 r1 00002da2 r2 00000006 r3 00000008
r4 c7780978 r5 00000006 r6 c7780920 r7 0000010c
r8 00000000 r9 0000000a sl 00000fbd fp da07b900
ip 0000000b sp c777f610 lr e843f2d7 pc e8441b58 cpsr 200f0010

backtrace:
#00 pc 00049b58 /system/lib/libc.so (tgkill+12)
#01 pc 000472d3 /system/lib/libc.so (pthread_kill+34)
#02 pc 0001d575 /system/lib/libc.so (raise+10)
#03 pc 000190c1 /system/lib/libc.so (__libc_android_abort+34)
#04 pc 00017124 /system/lib/libc.so (abort+4)
#05 pc 0031c3d9 /system/lib/libart.so (_ZN3art7Runtime5AbortEPKc+328)
#06 pc 000b569d /system/lib/libart.so (_ZN3art10LogMessageD2Ev+1132)
#07 pc 0023ab55 /system/lib/libart.so (ZN3art9JavaVMExt8JniAbortEPKcS2+1664)
#08 pc 0023ad47 /system/lib/libart.so (_ZN3art9JavaVMExt9JniAbortVEPKcS2_St9__va_list+58)
#09 pc 000cb09b /system/lib/libart.so (_ZN3art11ScopedCheck6AbortFEPKcz+46)
#10 pc 000cac87 /system/lib/libart.so (_ZN3art11ScopedCheck11CheckThreadEP7_JNIEnv+362)
#11 pc 000c9c9f /system/lib/libart.so (_ZN3art11ScopedCheck22CheckPossibleHeapValueERNS_18ScopedObjectAccessEcNS_12JniValueTypeE+26)
#12 pc 000c917b /system/lib/libart.so (_ZN3art11ScopedCheck5CheckERNS_18ScopedObjectAccessEbPKcPNS_12JniValueTypeE+802)
#13 pc 000cbe49 /system/lib/libart.so (_ZN3art8CheckJNI6NewRefEPKcP7_JNIEnvP8_jobjectNS_15IndirectRefKindE+452)
#14 pc 003382fd /system/lib/libart.so (_ZN3art6Thread22SetClassLoaderOverrideEP8_jobject+32)
#15 pc 0023c857 /system/lib/libart.so (ZN3art9JavaVMExt17LoadNativeLibraryEP7_JNIEnvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEP8_jobjectP8_jstringPS9+1878)
#16 pc 00003167 /system/lib/libopenjdkjvm.so (JVM_NativeLoad+178)
#17 pc 00584c6d /system/framework/arm/boot.oat (offset 0x51c000) (java.lang.Runtime.nativeLoad+144)
#18 pc 005848ad /system/framework/arm/boot.oat (offset 0x51c000) (java.lang.Runtime.doLoad+136)
#19 pc 005859dd /system/framework/arm/boot.oat (offset 0x51c000) (java.lang.Runtime.load0+368)
#20 pc 0059e383 /system/framework/arm/boot.oat (offset 0x51c000) (java.lang.System.load+78)
#21 pc 000a9b41 /system/lib/libart.so (art_quick_invoke_stub_internal+64)
#22 pc 00406ff5 /system/lib/libart.so (art_quick_invoke_static_stub+228)
#23 pc 000b0dff /system/lib/libart.so (_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+178)
#24 pc 001edfed /system/lib/libart.so (_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPKNS_7DexFile8CodeItemEPNS_11ShadowFrameEPNS_6JValueE+200)
#25 pc 001e859d /system/lib/libart.so (_ZN3art11interpreter6DoCallILb0ELb0EEEbPNS_9ArtMethodEPNS_6ThreadERNS_11ShadowFrameEPKNS_11InstructionEtPNS_6JValueE+492)
#26 pc 003ffaf9 /system/lib/libart.so (MterpInvokeStatic+236)
#27 pc 0009cb14 /system/lib/libart.so (ExecuteMterpImpl+14612)
#28 pc 001cb8c7 /system/lib/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameENS_6JValueEb+286)
#29 pc 001d042f /system/lib/libart.so (_ZN3art11interpreter33ArtInterpreterToInterpreterBridgeEPNS_6ThreadEPKNS_7DexFile8CodeItemEPNS_11ShadowFrameEPNS_6JValueE+114)
#30 pc 001e8583 /system/lib/libart.so (_ZN3art11interpreter6DoCallILb0ELb0EEEbPNS_9ArtMethodEPNS_6ThreadERNS_11ShadowFrameEPKNS_11InstructionEtPNS_6JValueE+466)
#31 pc 003ff61b /system/lib/libart.so (MterpInvokeInterface+834)
#32 pc 0009cb94 /system/lib/libart.so (ExecuteMterpImpl+14740)
#33 pc 001cb8c7 /system/lib/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameENS_6JValueEb+286)
#34 pc 001d042f /system/lib/libart.so (_ZN3art11interpreter33ArtInterpreterToInterpreterBridgeEPNS_6ThreadEPKNS_7DexFile8CodeItemEPNS_11ShadowFrameEPNS_6JValueE+114)
#35 pc 001e8583 /system/lib/libart.so (_ZN3art11interpreter6DoCallILb0ELb0EEEbPNS_9ArtMethodEPNS_6ThreadERNS_11ShadowFrameEPKNS_11InstructionEtPNS_6JValueE+466)
#36 pc 003ff61b /system/lib/libart.so (MterpInvokeInterface+834)
#37 pc 0009cb94 /system/lib/libart.so (ExecuteMterpImpl+14740)
#38 pc 001cb8c7 /system/lib/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadEPKNS_7DexFile8CodeItemERNS_11ShadowFrameENS_6JValueEb+286)
#39 pc 001d0399 /system/lib/libart.so (_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadEPKNS_7DexFile8CodeItemEPNS_11ShadowFrameE+92)
#40 pc 003f63e7 /system/lib/libart.so (artQuickToInterpreterBridge+706)
#41 pc 000ae593 /system/lib/libart.so (art_quick_to_interpreter_bridge+34)
#42 pc 005a22e9 /system/framework/arm/boot.oat (offset 0x51c000) (java.lang.Thread.run+52)
#43 pc 000a9b41 /system/lib/libart.so (art_quick_invoke_stub_internal+64)
#44 pc 00406eed /system/lib/libart.so (art_quick_invoke_stub+232)
#45 pc 000b0dd5 /system/lib/libart.so (_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+136)
#46 pc 00317349 /system/lib/libart.so (_ZN3artL18InvokeWithArgArrayERKNS_33ScopedObjectAccessAlreadyRunnableEPNS_9ArtMethodEPNS_8ArgArrayEPNS_6JValueEPKc+56)
#47 pc 00318115 /system/lib/libart.so (_ZN3art35InvokeVirtualOrInterfaceWithJValuesERKNS_33ScopedObjectAccessAlreadyRunnableEP8_jobjectP10_jmethodIDP6jvalue+256)
#48 pc 0032f29d /system/lib/libart.so (_ZN3art6Thread14CreateCallbackEPv+848)
#49 pc 00046da3 /system/lib/libc.so (_ZL15__pthread_startPv+22)
#50 pc 00019b0d /system/lib/libc.so (__start_thread+6)

This is a comment form Stack Overflow:

The error seems pretty clear to me: “java.lang.ClassNotFoundException: Didn’t find class “org.fmod.AudioDevice”. You did not include the FMOD SDK in your APK. Quick documentation link

Is he right? Or only Java developers must include fmod.jar in their projects?

This is the APK file: android-build-with-fmod-for-forums.apk

Could someone run it? Music must play. Maybe my device is too old and FMOD doesn’t support it.

I tried to unzip the APK. How to make sure that the libfmod.so with the correct path?

image

Path is correct. I think I need to load fmod.jar like is written in the documentation: https://www.fmod.com/docs/2.01/api/platforms-android.html#java

FMOD is primarily a native C/C++ library implementation but does have a Java component that is invoked from native code. To ensure the Java component is properly operating please make sure you reference the fmod.jar in your project. This means telling the IDE or build system where to find the fmod.jar file so it’s included in the application.

I need to find how to load jar-files and how to call Java code from Qt C++.

Loading a jar inside a QT android application should just be a matter of placing it in the android/libs directory: Third-party Android Libraries | Qt 6.5.
image

Everything else looks like it should be correct- make sure you also add your “audio” directory to your project’s INSTALLS to ensure they are bundled into your assets directory: Porting to Android | Qt 5.15.

android {
...
    deploy.files = $$PWD/android/audio/*
    deploy.files += $$PWD/android/audio/music.wav
    deploy.path = /assets
    INSTALLS += deploy
}

This way, as long as your main activity calls org.fmod.FMOD.init you should be able to lookup assets using "file:///audio_assets/{NAME OF AUDIO FAILE}.wav":

MainActivity.java

 public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        org.fmod.FMOD.init(this);
    }

    @Override
    protected void onDestroy()
    {
        org.fmod.FMOD.close();
    }

    static
    {
        System.loadLibrary("fmod");
    }
}

Widget.cpp

FMOD_System_CreateSound(m_pSystem, "file:///android_asset/music.wav", FMOD_DEFAULT, 0, &sound);

I have the fmod.jar inside of the jniLibs folder:

image

But I don’t see this file inside of the final APK file:

image

image

image

Maybe is it because I don’t call anything from the fmod.jar library?

MainActivity.java

What should I do with this file? How to include it to my project? Should I call System.loadLibrary("fmod"), onCreate, onDestroy? How to do it from Qt C++ code?

You won’t see a jar file in a built apk. jar files are compiled to dex files, which I can see you have a couple of. You can verify fmod.jar has been included successfully by using dexdump to view the dex contents, and search for occurrences of “FMOD”. On Windows, you can do this using powershell with the following command:

dexdump.exe classes.dex | Select-String "FMOD" | Select-String "Class descriptor"

  Class descriptor  : 'Lorg/fmod/AudioDevice;'
  Class descriptor  : 'Lorg/fmod/FMOD$PluginBroadcastReceiver;'
  Class descriptor  : 'Lorg/fmod/FMOD;'
  Class descriptor  : 'Lorg/fmod/FMODAudioDevice;'
  Class descriptor  : 'Lorg/fmod/MediaCodec$1DataSource;'
  Class descriptor  : 'Lorg/fmod/MediaCodec$2DataSource;'
  Class descriptor  : 'Lorg/fmod/MediaCodec;'
  Class descriptor  : 'Lorg/fmod/a;'

Please refer to the Java section of our Android platform docs for an understanding of how to initialize the Java component of FMOD.

These calls must be made inside Java- Java Activities/Services inherit from Context, which we need to initialize FMOD, and there is no way to get access to this from C++ code.

It might be worth running one of our Android examples from Android Studio before trying to get the same thing working in Qt. This will give you an understanding of the expected way to use FMOD in an Android application using Java, and how to call into C++ code via the Java native interface. The 3D example can be found in “api\core\examples\androidstudio\cmake\3d”.

After that, you can get the equivalent running in a Qt example, which will give you the C++ and Java parts to start working with. Most of the Qt Android examples will give you a Java activity or Service that you can pass to org.fmod.FMOD.init.

Where should I create the MainActivity.java file? Is the MainActivity.java predefined name? Is this file run automatically by Android?

If you are unfamiliar with how to setup an Android application, I strongly recommend you take a look at our Android examples. It isn’t really in the scope of our forums to show you how to setup an Android application- for that you should refer to the Application fundamentals section of the official Android documentation.

I know it is not very intuitive and there is a lot of information out there, so I will try to point you in the right direction.

The Qt Android examples provide a good template for how to setup a Qt Android project. In their examples, activities are placed in “Other files/android/src/org/qtproject/example/activityhandler”
image

You can call your activity whatever you like, and there are many ways to run it, but it does not run by default. The simplest thing to do would be to declare it as your main action in your manifest.

<application android:label="My App" android:extractNativeLibs="true">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
1 Like