用于音频流的最佳实践 [英] Best practices for audio streaming

查看:86
本文介绍了用于音频流的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个应用程序从远程服务器播放音频。我试图实现流式音频几种方式,但他们都没有对我不够好。 这就是我已经试过:

I'm writing an application to play audio from remote server. I tried several ways to implement streaming audio, but they all are not good enough for me. That's what I've tried:

是这样的:

MediaPlayer player = new MediaPlayer(); 
player.setDataSource(context, Uri.parse("http://whatever.com/track.mp3"));
player.prepare();
player.start();

(或 prepareAsync ,不管)

但标准的MediaPlayer 远程播放内容时很不稳定。它往往是下降或停止播放,我无法处理此。在另一边,我想要实现的媒体缓存。但我没有发现任何方式来获得MediaPlayer的缓冲内容的地方将其保存在设备中。

But standard MediaPlayer is quite unstable when playing remote content. It is often falls or stops playback and I can't process this. On the other side, I want to implement media caching. But I haven't found any way to get buffered content from MediaPlayer to save it somewhere on device.

再有成为一个想法,下载媒体文件中的块,将它们组合成一个本地文件并播放该文件。下载整个文件,可能是因为不良的连接速度慢,所以这将是罚款下载足够的最初一块,然后开始播放,并继续下载和追加本地文件。此外,我们得到缓存功能。

Then there became an idea to download media file by chunks, combine them into one local file and play this file. Downloading the whole file can be slow because of bad connection, so it will be fine to download enough initially piece, then start playback and continue downloading and appending local file. Besides, we get caching functionality.

听起来像一个计划,但它并不总是工作。它的工作原理完全可以在HTC感觉XE,但没有读完了这最初的片后,4.1平板电脑播放停止。不知道,为什么是这样的。我问过<一个href="http://stackoverflow.com/questions/16273133/play-media-file-and-append-it-in-the-same-time">question这一点,但没有得到答案。

Sounds like a plan, but it didn't always work. It works perfectly on HTC Sensation XE but didn't on 4.1 tablet playback stopped after finishing this initial piece. Don't know, why is so. I've asked question about this, but received no answers.

我创建了两个MediaPlayer的实例,并试图让他们改变对方。的逻辑如下:

I've created two MediaPlayer instances and tried to make them change each other. The logic is following:

  • 在开始下载最初的介质
  • 当它被下载,通过currentMediaPlayer开始播放。媒体的其他部分继续 下载
  • 在当前下载的片几乎是打了(之前完成1秒),prepare secondaryMediaPlayer具有相同的源文件(因为它在播放过程中被追加)
  • 在261毫秒currentMediaPlayer的之前完成 - 暂停,启动辅助,设置二次电流,进度$ P $下一二级运动员pparing
  • Start downloading initial piece of media
  • When it is downloaded, start playback via currentMediaPlayer. The rest of media continues downloading
  • When downloaded piece is almost played (1 sec before finish), prepare secondaryMediaPlayer with the same source file (as it was appended during playback)
  • 261 ms before finish of currentMediaPlayer – pause it, start secondary, set secondary as current, schedule preparing of next secondary player.

来源:

private static final String FILE_NAME="local.mp3";
private static final String URL = ...;
private static final long FILE_SIZE = 7084032;

private static final long PREPARE_NEXT_PLAYER_OFFSET = 1000;
private static final int START_NEXT_OFFSET = 261;

private static final int INIT_PERCENTAGE = 3;

private MediaPlayer mPlayer;
private MediaPlayer mSecondaryPlayer;

private Handler mHandler = new Handler();

public void startDownload() {
    mDownloader = new Mp3Downloader(FILE_NAME, URL, getExternalCacheDir());
    mDownloader.setDownloadListener(mInitDownloadListener);
    mDownloader.startDownload();
}


private Mp3Downloader.DownloadListener mInitDownloadListener = new Mp3Downloader.DownloadListener() {
    public void onDownloaded(long bytes) {
        int percentage = Math.round(bytes * 100f / FILE_SIZE);

        // Start playback when appropriate piece of media downloaded
        if (percentage >= INIT_PERCENTAGE) {
            mPlayer = new MediaPlayer();
            try {
                mPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
                mPlayer.prepare();
                mPlayer.start();

                mHandler.postDelayed(prepareSecondaryPlayerRunnable, mPlayer.getDuration() - PREPARE_NEXT_PLAYER_OFFSET);
                mHandler.postDelayed(startNextPlayerRunnable, mPlayer.getDuration() - START_NEXT_OFFSET);

            } catch (IOException e) {
                Log.e(e);
            }

            mDownloader.setDownloadListener(null);
        }
    }
};

// Starting to prepare secondary MediaPlayer
private Runnable prepareSecondaryPlayerRunnable = new Runnable() {
    public void run() {
        mSecondaryPlayer = new MediaPlayer();
        try {
            mSecondaryPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
            mSecondaryPlayer.prepare();
            mSecondaryPlayer.seekTo(mPlayer.getDuration() - START_NEXT_OFFSET);

        } catch (IOException e) {
            Log.e(e);
        }
    }
};

// Starting secondary MediaPlayer playback, scheduling creating next MediaPlayer
private Runnable startNextPlayerRunnable = new Runnable() {
    public void run() {
        mSecondaryPlayer.start();

        mHandler.postDelayed(prepareSecondaryPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - PREPARE_NEXT_PLAYER_OFFSET);
        mHandler.postDelayed(startNextPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - START_NEXT_OFFSET);

        mPlayer.pause();
        mPlayer.release();

        mPlayer = mSecondaryPlayer;

    }
};

再次 - 声音,像一个计划,但工作不完美。切换MediaPlayers的时刻是相当可听。在这里,我有相反的情况:在4.1平板电脑是好的,但在HTC感觉有明显的滞后

Again – sounds, like a plan, but works not perfectly. The moments of switching MediaPlayers are quite hearable. Here I have opposite situation: on 4.1 tablet it's ok, but on HTC Sensation there are evident lags.

我也试过来实现不同的下载技术。我已经通过10KB块和MP3帧来实现下载。我不知道到底,但似乎对于MP3帧seekTo并开始更好地工作。但是,这只是一种感觉,我不知道解释。

I also tried to implement different download techniques. I've implemented download by 10Kb chunks and by MP3 frames. I don't know exactly, but it seems that in case of MP3 frames seekTo and start work better. But it's just a feeling, I don't know explanation.

我看到这个词好几次,而谷歌上搜索,发现这个实现:<一href="https://$c$c.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18">https://$c$c.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18

I saw to this word several times while googling, and found this implementation: https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18

这是一个解决方案,每个人都使用?

It is a solution everybody use?

如果是的,这是可悲的,因为它不工作对我好了。而且我没有看到实施任何新的想法。

If yes, it's sad, because it is not working good for me too. And I don't see any fresh ideas in implementation.

你们如何在你的应用程序中实现音频流?我不敢相信我是谁遇到过这样的问题的唯一的人。应该有一些好的做法。

How do you guys implement audio streaming in your applications? I don't beleive I am the only person who faced problems like this. There should be some good practices.

推荐答案

在我来说,我使用FFMPEG与OpenSL ES。缺点是复杂。你必须熟悉的东西很多:JNI,OpenSL,FFMPEG。这也是很难调试(用纯Java的Andr​​oid应用程序相比)。你的情况,我建议你去尝试低水平媒体API 。唯一的一点是缺乏的例子。但是有一个<一个href="https://$c$c.google.com/p/android-source-browsing/source/browse/tests/tests/media/src/android/media/cts/De$c$crTest.java?repo=platform--cts"相对=nofollow>单元测试这表明你可以如何处理的音频(您需要更改的InputStream 参考 - 线82)。

In my case I use FFMPEG with OpenSL ES. The disadvantage is complexity. You must be familiar with a lot of things: JNI, OpenSL, FFMPEG. It's also hard to debug(comparing with pure java android app). In your case I suggest you to try low level Media API. The only thing is lack of examples. But there is a unit test which shows how you can handle audio(you need to change InputStream reference - line 82).

这篇关于用于音频流的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆