การสตรีมเสียงจาก URL ใน Android โดยใช้ MediaPlayer?


87

ฉันพยายามสตรีม mp3 ผ่าน http โดยใช้คลาส MediaPlayer ในตัวของ Android เอกสารนี้จะแนะนำให้ฉันทราบว่าสิ่งนี้ควรจะง่ายเหมือน:

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

อย่างไรก็ตามฉันได้รับสิ่งต่อไปนี้ซ้ำ ๆ ฉันได้ลองใช้ URL อื่นแล้วเช่นกัน โปรดอย่าบอกฉันว่าการสตรีมไม่ทำงานกับ mp3

E/PlayerDriver(   31): Command PLAYER_SET_DATA_SOURCE completed with an error or info PVMFErrNotSupported
W/PlayerDriver(   31): PVMFInfoErrorHandlingComplete
E/MediaPlayer(  198): error (1, -4)
E/MediaPlayer(  198): start called in state 0
E/MediaPlayer(  198): error (-38, 0)
E/MediaPlayer(  198): Error (1,-4)
E/MediaPlayer(  198): Error (-38,0)

ความช่วยเหลือใด ๆ ที่ชื่นชมมากขอบคุณ S


คำถามสองสามข้อ: (1) คุณใช้ SDK เวอร์ชันใด (2) คุณกำลังทดสอบอุปกรณ์ใด ทำงานได้ดีบน SDK 2.0.1 ทดสอบบน Droid
Roman Nurik

สวัสดี Roman ขอบคุณที่สละเวลา ฉันกำลังลองกับ 1.6 และฉันใช้ HTC Hero ฉันจะลองใช้ 2.01 ตามความคิดเห็นของคุณ แต่มันจะเป็นผลลัพธ์ที่ไร้สาระหากสิ่งนี้ใช้ได้กับอุปกรณ์ 2.x และสูงกว่าเท่านั้น
Pandalover

เพิ่งลองใช้กับโปรแกรมจำลอง 2.01 ไม่ทำงานอย่างน่าเสียดาย ฉันรู้สึกทึ่งที่ได้ลองใช้กับอุปกรณ์ 1.6 จริงและอุปกรณ์ 2.01 จริง ฉันอยู่ในการทดสอบของ Google ในวันที่ 4 บางทีฉันอาจต้องรอถึงตอนนั้น ฉันไม่ต้องการที่จะทำเช่นนั้น
Pandalover

ฉันไม่สงสัยว่า 2.0 กับ 2.0.1 จะสร้างความแตกต่าง แต่ตัวจำลองเทียบกับอุปกรณ์ถ่ายทอดสดอาจสร้างความแตกต่างได้ ฉันแปลกใจที่มันใช้ไม่ได้กับฮีโร่ ฉันจะตรวจสอบและดูว่าจะได้รับคำตอบที่ดีกว่านี้หรือไม่ นอกจากนี้เพื่อเป็นการตรวจสอบความสมบูรณ์คุณควรตรวจสอบให้แน่ใจว่าคุณได้ขออนุญาตอินเทอร์เน็ตในรายการ
Roman Nurik

ฉันมีคำถาม ถ้าฉันใช้ mp.setDataSource (URL_OF_FILE); เราไม่จำเป็นต้องบันทึกไฟล์ใด ๆ สำหรับการสตรีมเสียง ไม่ใช่เหรอ? ดังนั้นวิธีนี้จึงเป็นวิธีที่ดีที่สุดในการสตรีมเสียงจากทุกสถานที่ ความคิดใด ๆ ?
Bohemian

คำตอบ:


78

Media Player อย่างง่ายพร้อมตัวอย่างการสตรีมสำหรับส่วน xml คุณต้องมีปุ่มเดียวที่มี id button1 และสองภาพในโฟลเดอร์ drawable ของคุณด้วยชื่อ button_pause และ button_play และโปรดอย่าลืมเพิ่มสิทธิ์อินเทอร์เน็ตในรายการของคุณ

public class MainActivity extends Activity {
private Button btn;
/**
 * help to toggle between play and pause.
 */
private boolean playPause;
private MediaPlayer mediaPlayer;
/**
 * remain false till media is not completed, inside OnCompletionListener make it true.
 */
private boolean intialStage = true;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (Button) findViewById(R.id.button1);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    btn.setOnClickListener(pausePlay);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

private OnClickListener pausePlay = new OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub

        if (!playPause) {
            btn.setBackgroundResource(R.drawable.button_pause);
            if (intialStage)
                new Player()
                        .execute("http://www.virginmegastore.me/Library/Music/CD_001214/Tracks/Track1.mp3");
            else {
                if (!mediaPlayer.isPlaying())
                    mediaPlayer.start();
            }
            playPause = true;
        } else {
            btn.setBackgroundResource(R.drawable.button_play);
            if (mediaPlayer.isPlaying())
                mediaPlayer.pause();
            playPause = false;
        }
    }
};
/**
 * preparing mediaplayer will take sometime to buffer the content so prepare it inside the background thread and starting it on UI thread.
 * @author piyush
 *
 */

class Player extends AsyncTask<String, Void, Boolean> {
    private ProgressDialog progress;

    @Override
    protected Boolean doInBackground(String... params) {
        // TODO Auto-generated method stub
        Boolean prepared;
        try {

            mediaPlayer.setDataSource(params[0]);

            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    intialStage = true;
                    playPause=false;
                    btn.setBackgroundResource(R.drawable.button_play);
                    mediaPlayer.stop();
                    mediaPlayer.reset();
                }
            });
            mediaPlayer.prepare();
            prepared = true;
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Log.d("IllegarArgument", e.getMessage());
            prepared = false;
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        }
        return prepared;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        if (progress.isShowing()) {
            progress.cancel();
        }
        Log.d("Prepared", "//" + result);
        mediaPlayer.start();

        intialStage = false;
    }

    public Player() {
        progress = new ProgressDialog(MainActivity.this);
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        this.progress.setMessage("Buffering...");
        this.progress.show();

    }
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (mediaPlayer != null) {
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}

มีปัญหาเล็กน้อยเกี่ยวกับสิ่งนี้หากฉันล็อกโทรศัพท์ขณะที่ MediaPlayer กำลังเล่นแอปของฉันจะขัดข้องเมื่อฉันปลดล็อก
CiaranC94

3
ฉันเพิ่งลองแสดงความคิดเห็นในบรรทัด "mediaPlayer.release ()" ใน onPause () และตอนนี้แอปของฉันไม่ขัดข้องเมื่อปลดล็อก
CiaranC94

@PiyushMishra คุณลักษณะเหล่านี้ได้รับการยอมรับจาก Developer Console หรือไม่? เนื่องจากแอปของฉันถูกปฏิเสธ b'coz ฉันได้ใช้ Vitamio เวอร์ชัน 4.x
Pallavi

35

Android MediaPlayer ไม่รองรับการสตรีม MP3 แบบดั้งเดิมจนถึง 2.2 ใน OS เวอร์ชันเก่าดูเหมือนว่าจะสตรีม 3GP แบบเนทีฟเท่านั้น คุณสามารถลองใช้รหัส pocketjourney ได้แม้ว่ามันจะเก่า (มีเวอร์ชั่นใหม่อยู่ที่นี่ ) และฉันมีปัญหาในการทำให้มันเหนียว - มันจะพูดติดอ่างทุกครั้งที่เติมบัฟเฟอร์

แอป NPR News สำหรับ Android เป็นโอเพ่นซอร์สและใช้พร็อกซีเซิร์ฟเวอร์ภายในเพื่อจัดการสตรีมมิ่ง MP3 ในระบบปฏิบัติการเวอร์ชันก่อน 2.2 คุณสามารถดูรหัสที่เกี่ยวข้องในบรรทัด 199-216 (r94) ได้ที่นี่: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

และนี่คือคลาส StreamProxy: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

แอป NPR ยังคงได้รับ "ข้อผิดพลาด (-38, 0)" ในบางครั้งขณะสตรีม นี่อาจเป็นปัญหาการเธรดหรือปัญหาการเปลี่ยนแปลงเครือข่าย ตรวจสอบติดตามปัญหาสำหรับการปรับปรุง


คุณแน่ใจจริงๆเกี่ยวกับเรื่องนี้หรือไม่? ความเข้าใจของฉันคือมันเกี่ยวข้องกับประเภทละครใบ้ คุณช่วยตรวจสอบได้ไหมว่า t ทำงานกับประเภท MIME ก่อน 2.1 ได้ถูกต้อง ตอนนี้ฉันกำลังทำงานอย่างอื่นและไม่สามารถตรวจสอบได้สักพัก
Pandalover

1
ตามบันทึกประจำรุ่น 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ) ประกอบด้วย "กรอบงานสื่อใหม่ (Stagefright) ที่รองรับการเล่นไฟล์ในเครื่องและสตรีมแบบ HTTP แบบโปรเกรสซีฟ" ในการทดสอบทั้งหมดของฉันฉันไม่สามารถรับอุปกรณ์ 2.1 เพื่อสตรีมจากเซิร์ฟเวอร์ Shoutcast ได้โดยตรง ฉันเชื่อว่าปัญหาคือเซิร์ฟเวอร์ Shoutcast ส่งคืนโปรโตคอลของ ICY / 1.1 แทนที่จะเป็น HTTP / 1.1 และเครื่องเล่นสื่อจะเดินทางไปที่สิ่งนี้เนื่องจากไม่รู้ว่าจะตอบสนองต่อเนื้อหานั้นอย่างไร
jwadsack

@jwadsack จะเป็นอย่างไรหากไฟล์เสียงควรดาวน์โหลดเพียงครั้งเดียวและกว่าผู้ใช้จะสามารถเล่นไฟล์แบบออฟไลน์ได้ด้วย?
Devendra Singh

@DevendraSingh ฉันไม่รู้ว่าคุณสามารถบันทึกไฟล์ในขณะที่สตรีมด้วยการใช้งานโปรแกรมเล่นสื่อปัจจุบันได้หรือไม่ (คำตอบนี้มีอายุเกือบห้าปีและมีการเปลี่ยนแปลงมากมายตั้งแต่ 2.2) หากไม่มีอะไรอื่นคุณสามารถสร้างพร็อกซีตามตัวอย่างนี้และเขียนไฟล์ไปยังที่เก็บข้อมูลในขณะที่คุณส่งผ่านพร็อกซี
jwadsack

11

ฉันเดาว่าคุณกำลังพยายามเล่นไฟล์. pls โดยตรงหรืออะไรที่คล้ายกัน

ลองสิ่งนี้:

1: รหัส

mediaPlayer = MediaPlayer.create(this, Uri.parse("http://vprbbc.streamguys.net:80/vprbbc24.mp3"));
mediaPlayer.start();

2: ไฟล์. pls

URL นี้มาจาก BBC เป็นตัวอย่าง มันเป็นไฟล์. pls ที่ฉันดาวน์โหลดด้วยลินุกซ์

wget http://foo.bar/file.pls

จากนั้นฉันก็เปิดด้วย vim (ใช้โปรแกรมแก้ไขที่คุณชื่นชอบ;) และฉันได้เห็น URL จริงภายในไฟล์นี้ น่าเสียดายที่ไม่ใช่. pls ทั้งหมดเป็นข้อความธรรมดาแบบนั้น

ฉันได้อ่านว่า 1.6 ไม่รองรับการสตรีม mp3 ผ่าน http แต่ฉันเพิ่งทดสอบรหัส obove กับ Android 1.6 และ 2.2 และไม่มีปัญหาใด ๆ

โชคดี!


7
จำไว้ว่าหากคุณต้องการสตรีมเพลงที่คุณต้องใช้ mediaplayer.prepareAsync ไม่ใช่ mediaplayer.prepare ดังนั้นคุณจึงไม่สามารถใช้ mediaplayer.create () ได้เนื่องจากฟังก์ชัน .create () ใด ๆ จะทำให้ออบเจ็กต์ Media Player ของคุณเข้าสู่สถานะ Prepared โดยตรงซึ่งคุณจะไม่สามารถเรียกใช้โปรแกรมจัดเตรียม developer.android.com/reference/android/media/MediaPlayer.html
marienke

4

ใช้

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });

2

ฉันมีข้อผิดพลาดเดียวกันกับที่คุณมีและปรากฎว่าไม่มีอะไรผิดปกติกับรหัส ปัญหาคือเว็บเซิร์ฟเวอร์ส่งส่วนหัว Content-Type ผิด

ลองใช้ Wirehark หรืออะไรที่คล้ายกันเพื่อดูว่าเว็บเซิร์ฟเวอร์กำลังส่งเนื้อหาประเภทใด


สำหรับไฟล์ mp3 ควรเป็น Content-Type: audio / mpeg ที่ช่วยแก้ปัญหาของฉันได้ :)
doep

1
คุณสตรีมไฟล์นั้นได้อย่างไร
Nauman Khalid

2

กำลังมองหาโครงการของฉัน:

  1. https://github.com/master255/ImmortalPlayer รองรับ http / FTP เธรดเดียวเพื่ออ่านส่งและบันทึกลงในข้อมูลแคช วิธีที่ง่ายที่สุดและทำงานเร็วที่สุด ตรรกะที่ซับซ้อน - วิธีที่ดีที่สุด!
  2. https://github.com/master255/VideoViewCache Simple Videoview พร้อมแคช สองเธรดสำหรับการเล่นและบันทึกข้อมูล ตรรกะไม่ดี แต่ถ้าคุณต้องการใช้สิ่งนี้

1

ไม่มีการเรียก mp เริ่มต้นด้วย OnPreparedListener เพื่อหลีกเลี่ยงสถานะเป็นศูนย์ในบันทึก ..


ฉันยังคงได้รับบรรทัดบันทึก 05-22 20: 26: 13.625: E / MediaPlayer (23818): หยุดเรียกในสถานะ 0 แม้ว่าฉันจะเริ่ม Media Player ในฟังก์ชันที่เตรียมไว้ () ฉันยังมีฟังก์ชัน onError ที่ฉันรีเซ็ตวัตถุ Media Player ยังคงใช้เวลาถึง 2 นาทีก่อนที่สตรีมของฉันจะเริ่มเล่น ดูคำถามของฉันที่นี่: stackoverflow.com/questions/16672568/…
marienke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.