android - MediaPlayer setDataSource falló con estado=0x80000000 para el tono de llamada establecido por filepath en 2.3.4
android-mediaplayer ringtone (6)
El título dice la mayor parte.
Mi aplicación ha estado reproduciendo tonos de llamada apuntados por uri como content://media/internal/audio/media/387
o content://media/external/audio/media/1655
(para tonos de llamada personalizados en la tarjeta SD, creo) usando ambos setDataSource(fileInfo)
y setDataSource(mContext, Uri.parse(fileInfo))
.
En cada caso, he recibido registros con información sobre setDataSource failed.: status=0x80000000
excepción en teléfonos que usan Android 4.x (versiones diferentes).
Al ver que el error solo ocurre con los tonos de llamada apuntados por el contenido de uri, pero no con los archivos individuales apuntados por ruta, he decidido usar las rutas de los tonos de llamada también, lo que solucionó el problema en los teléfonos anteriores (al tiempo que utilizaba setDataSource(mContext, Uri.parse(fileInfo))
)
Sin embargo, ha iniciado problemas en teléfonos con Android 2.3.4-2.3.6 (aunque no en Mine 2.3.3):
- He recibido algunos registros con excepción:
setDataSource failed.: status=0x80000000
para archivos con rutas como/system/media/audio/ringtones/TwirlAway.ogg
También recibí un registro sobre el método
MediaPlayer.onErrorListener.onError(int what, int extra)
conwhat=1
yextra=-2147483648
, que, por lo que sé, sugiere que falta ese archivo o que está dañado. Sin embargo realizoFile file = new File(fileInfo); if (!file.exists())
compruebe tal situación y devolvió que el archivo existe, ¿está dañado entonces? Muy poco probable para archivos de música en la memoria interna.
Para resumir:
- funciona con
setDataSource("content://media/internal/audio/media/52")
- lanza la excepción:
setDataSource failed.: status=0x80000000
parasetDataSource(mContext, "/system/media/audio/ringtones/TwirlAway.ogg")
Curiosamente, las primeras líneas del setDataSource(Context context, Uri uri, Headers headers)
son llamadas por setDataSource(Context context, Uri uri)
son ( de la fuente GrepCode para 2.3.4 ):
String scheme = uri.getScheme();
if(scheme == null || scheme.equals("file")) {
setDataSource(uri.getPath());
return;
}
Entonces, después de todo, simplemente falla para setDataSource("/system/media/audio/ringtones/TwirlAway.ogg")
. He tomado caminos a los tonos de llamada de uris usando:
private static String getRingtonePathFromContentUri(Context context,
Uri contentUri) {
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor ringtoneCursor = context.getContentResolver().query(contentUri,
proj, null, null, null);
ringtoneCursor.moveToFirst();
return ringtoneCursor.getString(ringtoneCursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
}
¿Alguna idea de lo que puede estar causando error al lanzar? Tal vez esos son algunos problemas causados por la falta de permisos de lectura? Supongo que el código fuente para la función nativa setDataSource (String path) ayudaría mucho, pero no pude encontrarlo.
Esto puede suceder debido al formato de archivo que intenta reproducir o comprimir. Estaba comprimiendo un archivo mp4 que funciona bien, pero cuando comprimo un archivo mov, la aplicación se bloqueó dando una excepción fallida a setDataSource.
Hubo un cambio en el comportamiento de setDataSource(String path)
debido a una corrección de errores en Android 4.1.1. En 4.1.1 o posterior necesita usar una ruta local (sin protocolo). Sin embargo, en la versión 4.0.4 y anteriores, necesitaba usar un URI (por ejemplo, con el archivo: // protocolo).
Aquí hay un fragmento de código incompleto que debe ilustrar la solución:
// as of 4.1.1 (JELLY_BEAN) we need to use a local path (without protocol)
// on 4.0.4 and earlier we needed a URI (with file:// protocol)
final String cachedFile = android.os.Build.VERSION.SDK_INT >= 16 // android.os.Build.VERSION_CODES.JELLY_BEAN
? getCacheFilePath(file)
: getCacheFileUri(file);
// for the purpose of this example
// assume cacheFolder is a String and getCacheFile returns a String
public String getCacheFilePath(String file) {
return cacheFolder + getCacheFile(file);
}
public String getCacheFileUri(String file) {
return "file://" + cacheFolder + getCacheFile(file);
}
La respuesta de Lorne a continuación fue de gran ayuda cuando se trata de este problema.
Para cualquier otra persona que esté luchando con él, aquí está el código que he estado usando durante más de 6 meses, con errores que ya casi no se informan.
fileinfo
puede ser de los dos siguientes (ejemplos):
/system/media/audio/alarms/Walk_in_the_forest.ogg
content://media/internal/audio/media/20
public static void setMediaPlayerDataSource(Context context,
MediaPlayer mp, String fileInfo) throws Exception {
if (fileInfo.startsWith("content://")) {
try {
Uri uri = Uri.parse(fileInfo);
fileInfo = getRingtonePathFromContentUri(context, uri);
} catch (Exception e) {
}
}
try {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
try {
setMediaPlayerDataSourcePreHoneyComb(context, mp, fileInfo);
} catch (Exception e) {
setMediaPlayerDataSourcePostHoneyComb(context, mp, fileInfo);
}
else
setMediaPlayerDataSourcePostHoneyComb(context, mp, fileInfo);
} catch (Exception e) {
try {
setMediaPlayerDataSourceUsingFileDescriptor(context, mp,
fileInfo);
} catch (Exception ee) {
String uri = getRingtoneUriFromPath(context, fileInfo);
mp.reset();
mp.setDataSource(uri);
}
}
}
private static void setMediaPlayerDataSourcePreHoneyComb(Context context,
MediaPlayer mp, String fileInfo) throws Exception {
mp.reset();
mp.setDataSource(fileInfo);
}
private static void setMediaPlayerDataSourcePostHoneyComb(Context context,
MediaPlayer mp, String fileInfo) throws Exception {
mp.reset();
mp.setDataSource(context, Uri.parse(Uri.encode(fileInfo)));
}
private static void setMediaPlayerDataSourceUsingFileDescriptor(
Context context, MediaPlayer mp, String fileInfo) throws Exception {
File file = new File(fileInfo);
FileInputStream inputStream = new FileInputStream(file);
mp.reset();
mp.setDataSource(inputStream.getFD());
inputStream.close();
}
private static String getRingtoneUriFromPath(Context context, String path) {
Uri ringtonesUri = MediaStore.Audio.Media.getContentUriForPath(path);
Cursor ringtoneCursor = context.getContentResolver().query(
ringtonesUri, null,
MediaStore.Audio.Media.DATA + "=''" + path + "''", null, null);
ringtoneCursor.moveToFirst();
long id = ringtoneCursor.getLong(ringtoneCursor
.getColumnIndex(MediaStore.Audio.Media._ID));
ringtoneCursor.close();
if (!ringtonesUri.toString().endsWith(String.valueOf(id))) {
return ringtonesUri + "/" + id;
}
return ringtonesUri.toString();
}
public static String getRingtonePathFromContentUri(Context context,
Uri contentUri) {
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor ringtoneCursor = context.getContentResolver().query(contentUri,
proj, null, null, null);
ringtoneCursor.moveToFirst();
String path = ringtoneCursor.getString(ringtoneCursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
ringtoneCursor.close();
return path;
}
Tienes que establecer explícitamente la longitud de tu archivo. Utilice el método sobrecargado:
AssetFileDescriptor afd = ctx.getAssets().openFd([your asset name]); mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
Tuve el mismo error cuando intentaba reproducir un archivo .wav. Hagamos un ejemplo:
private void start_player(){
// create raw folder inside the res folder if not present
MediaPlayer mPlayer = MediaPlayer.create(activity, R.raw.your_wave_audio_file);
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
mp.release();
// Your Stuff
}
});
mPlayer.start();
}
}
Yo también tengo el error de estado = 0x80000000. En mi caso, la solución fue volver a codificar el archivo de audio (por ejemplo, a 16-BIT PCM para un archivo .wav) y todo funcionó como se esperaba.
MediaPlayer mPlayer = MediaPlayer.create(activity, R.raw.your_wave_audio_file);
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
No puede hacerlo, porque la función de creación se llamó a prepare, por lo tanto, no puede cambiar el tipo de transmisión de audio después.
A continuación el código está bien para mí:
sMediaPlayer = new MediaPlayer();
sMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
AssetFileDescriptor assetFileDescriptor = context.getResources().
openRawResourceFd(R.raw.cool_song);
if(assetFileDescriptor == null) return;
try {
sMediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(),
assetFileDescriptor.getStartOffset(),
assetFileDescriptor.getLength());
assetFileDescriptor.close();
sMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
if(sMediaPlayer != null){
sMediaPlayer.release();
sMediaPlayer = null;
}
}
});
sMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
sMediaPlayer.start();
}
});
sMediaPlayer.prepare();
} catch (IllegalArgumentException e) {
HelpFunctions.showLog("ERROR = " + e);
} catch (IllegalStateException e) {
HelpFunctions.showLog("ERROR = " + e);
} catch (IOException e) {
HelpFunctions.showLog("ERROR = " + e);
}