Reputation: 11
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?
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%)
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;
}
When I ran my app, catlog showed:
Upvotes: 0
Views: 68
Reputation: 10621
Here's a couple of suggestions:
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
.
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