oboe icon indicating copy to clipboard operation
oboe copied to clipboard

How can I read an audio file from res/raw? And from SDCard?

Open rafagan opened this issue 5 years ago • 1 comments

I studied the RhythmGame example and it only works at NDK level using the assets folder. I need to support other ways of file import, like from R.raw and from folder Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

How can I achieve that? Any help?

rafagan avatar Jun 11 '20 15:06 rafagan

The solution is read details about the file descriptor and adapt the code to skip de AAsset_openFileDescriptor step.

SDK side (using SD Card):

val path ="${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)}/file.mp3"
val file = ParcelFileDescriptor.open(File(path), ParcelFileDescriptor.MODE_READ_ONLY)
val fileDescriptor = file.fileDescriptor
val field = fileDescriptor.javaClass.getDeclaredField("descriptor")
field.isAccessible = true
val fileDescriptorId = field.getInt(file.fileDescriptor)
jniCall(fileDescriptorId, file.statSize.toInt(), 0)

SDK side (using res/raw folder)

val file = context.get()!!.resources.openRawResourceFd(rawFileId)
val fileOffset = file.startOffset.toInt()
val fileLength = file.length.toInt()

val fileDescriptor = file.fileDescriptor
val field = fileDescriptor.javaClass.getDeclaredField("descriptor")
field.isAccessible = true
val fileDescriptorId = field.getInt(file.fileDescriptor)
jniCall(fileDescriptorId, fileLength), fileOffset)

NDK side:

Java_package_Player_jniCall(
        JNIEnv* env,
        jobject __unused,
        jint fd,
        jint fileLength,
        jint fileOffset) {

    // Instead of calling NDKExtractor::decode(AAsset *asset, uint8_t *targetData, AudioProperties targetProperties), lets adapt to NDKExtractor::decodeFileDescriptor(int fd, int offset, int length, uint8_t* targetData, AudioProperties targetProperties)
}

NDKExtractor:

int32_t NDKExtractor::decodeFileDescriptor(int fd, int offset, int length, uint8_t* targetData, AudioProperties targetProperties) {
   // Ignoring AAsset_openFileDescriptor step...

    // Extract the audio frames
    AMediaExtractor *extractor = AMediaExtractor_new();
    media_status_t amresult = AMediaExtractor_setDataSourceFd(extractor, fd, offset, length);
    if (amresult != AMEDIA_OK){
        LOGE("Error setting extractor data source, err %d", amresult);
        return 0;
    }

   // ...

I still not tried any solution using the FFMpegExtractor, if anyone could help that would be nice.

rafagan avatar Jun 19 '20 17:06 rafagan

You may be able to use ExoPlayer Media3 Transformer to convert an MP3 file or URI to a WAV or PCM.

https://developer.android.com/guide/topics/media/transformer/getting-started

robertwu1 avatar Jun 16 '23 21:06 robertwu1