سؤال

لدي ملف MP3 الخاص بي في Byte [] (تم تنزيله من خدمة) وأرغب في تشغيله على جهازي على غرار كيفية تشغيل الملفات:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();

لكن لا يمكنني العثور على طريقة للقيام بذلك. لا أمانع في حفظ الملف للهاتف ثم تشغيله. كيف يمكنني تشغيل الملف ، أو تنزيله ثم تشغيله؟

هل كانت مفيدة؟

المحلول

حسنًا ، شكرًا لكم جميعًا ، لكنني كنت بحاجة إلى تشغيل MP3 من Byte [] عندما أحصل على ذلك من .NET WebService (لا أرغب في تخزين MP3s تم إنشاؤها ديناميكيًا على الخادم).

في النهاية - يوجد عدد من "gotchas" للعب MP3 بسيط ... إليك رمز لأي شخص يحتاج إليه:

private MediaPlayer mediaPlayer = new MediaPlayer();
private void playMp3(byte[] mp3SoundByteArray) {
    try {
        // create temp file that will hold byte array
        File tempMp3 = File.createTempFile("kurchina", "mp3", getCacheDir());
        tempMp3.deleteOnExit();
        FileOutputStream fos = new FileOutputStream(tempMp3);
        fos.write(mp3SoundByteArray);
        fos.close();

        // resetting mediaplayer instance to evade problems
        mediaPlayer.reset();

        // In case you run into issues with threading consider new instance like:
        // MediaPlayer mediaPlayer = new MediaPlayer();                     

        // Tried passing path directly, but kept getting 
        // "Prepare failed.: status=0x1"
        // so using file descriptor instead
        FileInputStream fis = new FileInputStream(tempMp3);
        mediaPlayer.setDataSource(fis.getFD());

        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException ex) {
        String s = ex.toString();
        ex.printStackTrace();
    }
}

تعديل: لقد كتبت هذه الإجابة منذ أكثر من 4 سنوات - من الواضح أن الكثير من الأشياء قد تغيرت منذ ذلك الحين. انظر تعليق جاستن على كيفية إعادة استخدام مثيل MediaPlayer. أيضًا ، لا أعرف ما إذا كان .deleteOnexit () ستعمل من أجلك الآن - لا تتردد في اقتراح تحسين حتى لا تتراكم ملفات temp.

نصائح أخرى

لقد وجدت حلًا سهلًا عن طريق ترميز ملف MP3 الخاص بي على أنه BASE64 (لقد تلقيت بالفعل البيانات المشفرة من خدمة API RESTFLE) ، ثم إنشاء كائن URL. لقد اختبرته في Android 4.1.

public void PlayAudio(String base64EncodedString){
        try
        {
            String url = "data:audio/mp3;base64,"+base64EncodedString; 
            MediaPlayer mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(url);
            mediaPlayer.prepare();
            mediaPlayer.start();
        }
        catch(Exception ex){
            System.out.print(ex.getMessage());
        }
    }

بدء Android Marshmellow (كود الإصدار 23) ، هناك واجهة برمجة تطبيقات جديدة تجعل هذا ممكنًا.

MediaPlayer.setDatasource (Android.media.mediadatasource)

يمكنك توفير تنفيذ مخصص لـ MediaDataSource ولف بايت []. تطبيق أساسي يرد أدناه.

import android.annotation.TargetApi;
import android.media.MediaDataSource;
import android.os.Build;
import java.io.IOException;


@TargetApi(Build.VERSION_CODES.M)
public class ByteArrayMediaDataSource extends MediaDataSource {

    private final byte[] data;

    public ByteArrayMediaDataSource(byte []data) {
        assert data != null;
        this.data = data;
    }
    @Override
    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
        System.arraycopy(data, (int)position, buffer, offset, size);
        return size;
    }

    @Override
    public long getSize() throws IOException {
        return data.length;
    }

    @Override
    public void close() throws IOException {
        // Nothing to do here
    }
}

لست متأكدًا من BYTEARRAYS/BYTERESHERS ، ولكن إذا كان لديك عنوان URL من الخدمة ، فيمكنك محاولة تعيين مصدر البيانات على شبكة URI عن طريق الاتصال

setDataSource(Context context, Uri uri)

انظر مستندات API.

رمز خاطئ:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.prepare();
 mp.start();

الكود الصحيح:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.setOnpreparedListener(this);
 mp.prepare();

//Implement OnPreparedListener 
OnPrepared() {
    mp.start();
 }

انظر API Demos ..

إذا كنت تستهدف API 23 وما فوق ، فقم بإنشاء فصل مثل هذا

class MyMediaDataSource(val data: ByteArray) : MediaDataSource() {

override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int {

    if (position >= data.size) return -1 // -1 indicates EOF 

    val endPosition: Int = (position + size).toInt()
    var size2: Int = size
    if (endPosition > data.size)
        size2 -= endPosition - data.size

    System.arraycopy(data, position.toInt(), buffer, offset, size2)
    return size2
}

override fun getSize(): Long {
    return data.size.toLong()
}

override fun close() {}

}

واستخدم مثل هذا

val mediaSource = MyMediaDataSource(byteArray)
MediaPlayer().apply {
    setAudioStreamType(AudioManager.STREAM_MUSIC)
    setDataSource(mediaSource)
    setOnCompletionListener { release() }
    prepareAsync()
    setOnPreparedListener { start() }
}

ائتمانات إلى إجابة Krishnakumarp أعلاه و هذه المقالة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top