Xinyu Liu
Xinyu Liu

Reputation: 11

How to use AAudio (or other C++ layer tools recommended?) to play wav files in my android app?

Basic Info and Questions##

I was trying to play .wav files in my pure C++ Android app. Gpt recommended AAudio. And I wrote some code, but it didn't work. Could someone help me to figure out why my code didn't work properly?

info of wav file

I used mediainfo generated.wav, it gave these info of .wav file I was to play.

General
Complete name                            : generated.wav
Format                                   : Wave
Format settings                          : PcmWaveformat
File size                                : 19.5 KiB
Duration                                 : 624 ms
Overall bit rate mode                    : Constant
Overall bit rate                         : 257 kb/s

Audio
Format                                   : PCM
Format settings                          : Little / Signed
Codec ID                                 : 1
Duration                                 : 624 ms
Bit rate mode                            : Constant
Bit rate                                 : 256 kb/s
Channel(s)                               : 1 channel
Sampling rate                            : 16.0 kHz
Bit depth                                : 16 bits
Stream size                              : 19.5 KiB (100%)

Code

I used JNI, and here is the part about playing:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_demojavacpp_MainActivity_playAudioFromFile(JNIEnv *env, jobject thiz, jstring filePath) {
    const char* filename = env->GetStringUTFChars(filePath, 0);

    // Open the WAV file
    FILE* file = fopen(filename, "rb");
    if (file == nullptr) {
        __android_log_print(ANDROID_LOG_ERROR, "TTS", "Failed to open file: %s", filename);
        env->ReleaseStringUTFChars(filePath, filename);
        return;
    }else{
        __android_log_print(ANDROID_LOG_INFO, "TTS", "Open file: %s", filename);
    }

    // Read WAV header (skip for now, you can check it if necessary)
    unsigned char header[44];
    fread(header, sizeof(unsigned char), 44, file);  // Typical WAV header size

    // Read the audio data (after header)
    fseek(file, 0, SEEK_END);
    size_t fileSize = ftell(file);
    fseek(file, 44, SEEK_SET);  // Skip header
    size_t dataSize = fileSize - 44;
    float * audioData = new float [dataSize];
    fread(audioData, sizeof(unsigned char), dataSize, file);
    fclose(file);

    // Initialize AAudio player
    AAudioPlayer player;
    if (!player.initialize(16000, 1)) {  // Set sample rate (44100 Hz for example) and channels (1 for mono)
        __android_log_print(ANDROID_LOG_ERROR, "AAUDIO", "Failed to initialize AAudio player.");
        delete[] audioData;  // Clean up the allocated memory
        env->ReleaseStringUTFChars(filePath, filename);
        return;
    }

    // Play the audio
    if (!player.playAudio(audioData, dataSize / sizeof(float))) {
        __android_log_print(ANDROID_LOG_ERROR, "AAUDIO", "Failed to play audio.");
    } else {
        __android_log_print(ANDROID_LOG_INFO, "AAUDIO", "Audio is playing.");
    }

    // Clean up
    delete[] audioData;  // Free the allocated memory for audio data
    env->ReleaseStringUTFChars(filePath, filename);
}

And here are the main two functions of AAudio: AAudioPlayer::initialize and AAudioPlayer::playAudio

bool AAudioPlayer::initialize(int sampleRate, int channelCount) {
    aaudio_result_t result;

    // Create an AAudio stream builder
    result = AAudio_createStreamBuilder(&builder);
    if (result != AAUDIO_OK) {
        LOGE("Failed to create AAudio stream builder");
        return false;
    }

    // Set format, sample rate, and channel count
    AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
    AAudioStreamBuilder_setChannelCount(builder, channelCount);
    AAudioStreamBuilder_setSampleRate(builder, sampleRate);

    // Create the AAudio stream
    result = AAudioStreamBuilder_openStream(builder, &stream);
    if (result != AAUDIO_OK) {
        LOGE("Failed to create AAudio stream");
        return false;
    }

    return true;
}


bool AAudioPlayer::playAudio(const float * audioData, size_t numFrames) {
    aaudio_result_t result;

    // Allocate buffer
    bufferSize = numFrames;
    buffer = new float[bufferSize];
    memcpy(buffer, audioData, numFrames * sizeof(float));

    // Start the audio stream
    result = AAudioStream_requestStart(stream);
    if (result != AAUDIO_OK) {
        LOGE("Failed to start AAudio stream");
        aaudio_stream_state_t state = AAudioStream_getState(stream);
        __android_log_print(ANDROID_LOG_ERROR, "TTS", "Audio stream state: %d", state);
        return false;
    }

    // Write data to the stream
    result = AAudioStream_write(stream, buffer, bufferSize, 0);
    if (result != AAUDIO_OK) {
        LOGE("Failed to write audio data to stream");
        aaudio_stream_state_t state = AAudioStream_getState(stream);
        __android_log_print(ANDROID_LOG_ERROR, "TTS", "Audio stream state: %d", state);
        return false;
    }

    return true;
}

Results

When I ran my app, catlog showed: catlog

Upvotes: 0

Views: 68

Answers (1)

dev.bmax
dev.bmax

Reputation: 10621

Here's a couple of suggestions:

  1. Looks like your audio samples are 16-bit signed integers but you are are handling them as if they were floating-point numbers. So, you should use AAUDIO_FORMAT_PCM_I16 instead of AAUDIO_FORMAT_PCM_FLOAT.

  2. You are trying to play the whole audio file in one piece. But the audio stream has an internal buffer which is usually smaller than the audio file size. Instead, you should use AMediaExtractor to read fixed-sized buffers from the audio source and write them to the stream.

Upvotes: 0

Related Questions