I am trying to fetch an audio file from MediaStore
, extract audio data from it, decode it, and play it, on Android 10.
I am getting the following error when I call setDataSource
on my MediaExtractor
instance:
Error setting extractor data source, err -10002
To reproduce:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val path = getSong().get(0).path
stringToJNI("file://"+ path)
val URI = Uri.parse(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString() + "/" + getSong().get(0).id)
stringToJNI(URI!!.toString())
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringToJNI(URI: String)
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
fun getSong() : MutableList<Songs> {
val SONGS_PROJECTION = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA
)
val cursor = contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
SONGS_PROJECTION,
null,
null,
MediaStore.Audio.Media._ID +
" ASC LIMIT 100"
)
val items: MutableList<Songs> = mutableListOf()
cursor?.let {
if (cursor.count > 0) {
cursor.moveToFirst()
while (!cursor.isAfterLast) {
val s0 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[0]))
val s1 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[1]))
val s2 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[2]))
items.add(Songs(s0, s1, s2))
cursor.moveToNext()
}
}
cursor.close()
}
return items
}
}
In MainActivity
, I pass to native side once the path and second time the URI, each time without luck.
#include <jni.h>
#include <string>
#include <media/NdkMediaExtractor.h>
#include <android/log.h>
#include <bitset>
#define APP_NAME "MediaStoreToNativeAudio"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediastoretonativeaudio_MainActivity_stringToJNI(
JNIEnv *env,
jobject jobj,
jstring URI) {
const char *uri = env->GetStringUTFChars(URI, NULL);
std::string s(uri);
AMediaExtractor *extractor = AMediaExtractor_new();
media_status_t amresult = AMediaExtractor_setDataSource(extractor, uri);
if (amresult != AMEDIA_OK) {
LOGE("AMediaExtractor_setDataSource called with: [%s]", s.c_str());
LOGE("Error setting extractor data source, err %d", amresult);
}
return;
}
from logs:
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/NdkMediaExtractor: can't create http service
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: AMediaExtractor_setDataSource called with: [file:///storage/emulated/0/Music/Thank you for the drum machine/01 - Everything Moves.mp3]
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: Error setting extractor data source, err -10002
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/NdkMediaExtractor: can't create http service
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: AMediaExtractor_setDataSource called with: [content://media/external/audio/media/472]
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: Error setting extractor data source, err -10002
My manifest:
After installing app I also give permission through settings.
Edit:
A public repository with test code: https://github.com/AndrewBloom/MediaStoreToNativeAudioSample
the same behaviour results using:
android:requestLegacyExternalStorage="true"
This to me seems a bug on Android 10. It seems that android:requestLegacyExternalStorage="true" does not change the situation. You may have to request on manifest and ask same permission at runtime. The AMediaExtractor_setDataSource function must be called on a thread that is attached to Java. Doing all of that correctly will allow you to make it work on other versions of Android but not on Android 10. I've reported the issue on Android Bug Tracker here: https://issuetracker.google.com/144837266 As per google answer, it seems that all the app using native libraries that require file access through path can be affected and they know the issue https://www.youtube.com/watch?v=UnJ3amzJM94 .
A workaround in my case was to use AMediaExtractor_setDataSourceFd, getting the file descriptor at Java level through contentResolver and its method openFileDescriptor.