From the source code here, we can see the final implementation of the scanner has two steps to scan an audio file. If either of these two step fail, the audio file will not insert into media provider.
step 1 check the file extension
static bool FileHasAcceptableExtension(const char *extension) {
static const char *kValidExtensions[] = {
".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
".avi", ".mpeg", ".mpg"
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
for (size_t i = 0; i < kNumValidExtensions; ++i) {
if (!strcasecmp(extension, kValidExtensions[i])) {
return true;
}
}
return false;
}
More extensions have been added since Android 5.0. The common container for opus codec is ogg
, this extension exists before Android 5.0. Assume your audio file extension is ogg
, the scanning process is fine at this step.
step2 retrieve metadata
After the first step passed, the scanner need to retrieve media's metadata for later database insertion. I think the scanner do the codec level checking at this step.
sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
int fd = open(path, O_RDONLY | O_LARGEFILE);
status_t status;
if (fd < 0) {
// couldn't open it locally, maybe the media server can?
status = mRetriever->setDataSource(path);
} else {
status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL);
close(fd);
}
if (status) {
return MEDIA_SCAN_RESULT_ERROR;
}
For Android version before 5.0, the scanner might be failed at this step. Because of lacking of built-in opus codec support, setDataSource
will get failed at last. The media file won't be added to media provider finally.
suggested solution
Because we know the audio file will be added to
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
we can do database operation manually. If you want your audio file keeps consistent with other audio files in the database, you have to retrieve all the metadata by yourself. Since you can play the opus file, I think it's easy to retrieve the metadata.
// retrieve more metadata, duration etc.
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Audio.AudioColumns.DATA, "/mnt/sdcard/Music/example.opus");
contentValues.put(MediaStore.Audio.AudioColumns.TITLE, "Example track");
contentValues.put(MediaStore.Audio.AudioColumns.DISPLAY_NAME, "example");
// more columns should be filled from here
Uri uri = getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, contentValues);
Log.d(TAG, uri.toString());
After that, you app can find the audio file.
getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI...