Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/188.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Android需要这么长时间';让MediaPlayer准备一些实时流以便播放?_Android_Audio_Streaming_Android Mediaplayer_Audio Streaming - Fatal编程技术网

为什么Android需要这么长时间';让MediaPlayer准备一些实时流以便播放?

为什么Android需要这么长时间';让MediaPlayer准备一些实时流以便播放?,android,audio,streaming,android-mediaplayer,audio-streaming,Android,Audio,Streaming,Android Mediaplayer,Audio Streaming,我发现Android MediaPlayer为不同流的实时流播放做准备所需的时间有很大差异 硬数据 我在prepareAsync()和onPrepared(MediaPlayer mp)回调之间添加了日志记录,并对每个流进行了几次测试。每个流的时间非常一致(+/-1秒),结果如下: MPR新闻流:27秒(http://newsstream1.publicradio.org:80/) 经典音乐流:15秒(http://classicalstream1.publicradio.org:80/) MP

我发现Android MediaPlayer为不同流的实时流播放做准备所需的时间有很大差异

硬数据

我在prepareAsync()和onPrepared(MediaPlayer mp)回调之间添加了日志记录,并对每个流进行了几次测试。每个流的时间非常一致(+/-1秒),结果如下:

  • MPR新闻流:27秒(http://newsstream1.publicradio.org:80/)
  • 经典音乐流:15秒(http://classicalstream1.publicradio.org:80/)
  • MPR当前流:7秒(http://currentstream1.publicradio.org:80/)
  • 优先级流:52秒(http://pri-ice.streamguys.biz/pri1)
  • 这些测试是在Nexus S上进行的,Android 2.3.4支持3G连接(~1100 Kbps)

    播放非流式MP3音频文件不是问题

    以下是我如何播放流的片段:

    准备MediaPlayer:

    ...
    mediaPlayer.setDataSource(playUrl);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.prepareAsync();
    ...
    
    然后在onPrepared(MediaPlayer mp)中:

    为什么要花这么长的时间来准备一些溪流而不是其他溪流?上述数据似乎表明,这可能是基于已缓冲的数据量,而不是缓冲音频内容的持续时间。真的会这样吗


    更新:我已经在使用Android 1.6、2.2和2.3.4的物理设备以及使用1.6、2.1、2.2、2.3.1和2.3.3的模拟器上测试了流媒体直播。我只看到2.3.3和2.3.4的长时间延迟。较旧的版本在5秒内开始播放。

    它似乎是在缓冲固定数量的数据,而不是固定时间。对于那些不知道各种类型的NPR流的比特率的人来说,数据如下所示:

  • MPR新闻流:27秒(),64 kbps
  • MPR经典音乐流:15秒(),128 kbps
  • MPR当前流:7秒(),128 kbps
  • PRI流:52秒(),32 kbps
  • 除了两个128 kbps流之间的差异外,比特率和缓冲持续时间之间有很好的相关性

    在任何情况下,Android都是开源的,所以你可以一直使用它。不幸的是,
    prepareAsync()
    prepare()
    是本机方法,与缓冲区相关的事件似乎也是从本机进程调度的


    您是否尝试将
    OnBufferingUpdateListener
    附加到MediaPlayer以获得关于缓冲区状态的更细粒度更新?比较事件的传递速率以及不同流中每个事件的缓冲区填充百分比可能会很有趣。您可以将其与流比特率进行交叉引用,如果32kbps的4秒缓冲与128kbps的1秒缓冲所占的百分比相同,那么我想您已经找到了答案。

    我尝试了10个数据点,3个快,7个慢。 这是一致的,快的流是快的,慢的流总是慢的

    我认为这与服务器提供的“内容长度”有关,如果没有正确指定内容长度,Android不知道要缓冲多少


    可能是错误的,没有达到有线共享的程度。

    我最近与流媒体音频提供商调试了相同的问题。该问题与stagefright和32kbps及以下的流媒体源有关。我们以24、32、48、64和128 kbps的速率测量响应时间

    • 24->46秒开始播放流媒体
    • 32->24秒开始播放流媒体
    • 48->2秒开始播放流媒体
    • 64->2秒开始播放流媒体
    • 128->2秒开始播放流媒体
    这是来自一致的无线连接,每个比特率平均超过10次尝试。特拉维斯指出,关键在于stagefright无法计算音频缓冲时间。有时我会看到一条消息“error:1,-21492389”左右,这似乎会使stagefright播放器安静地崩溃。我试图追踪这一点,最终得出结论,非常慢的流(低于24 kbps)似乎会导致缓冲区溢出,因为它们会一直缓冲到设备耗尽音频流的空间


    我想补充一点,在整个测试过程中,
    OnBufferingUpdateListener
    根本没有为我触发。我不知道它是干什么用的。我认为你能知道加载方式的唯一方法是代理加载,就像上面提到的NPR应用程序一样。

    切换
    MediaPlayer
    MediaPlayer
    效果好得多。如果你想测试你的流,你可以通过他们拥有的应用程序来完成。

    如果你是从Icecast流媒体,查看
    突发大小设置:

    突发大小是要突发到客户端的数据量(以字节为单位) 在连接时间。就像突发连接一样,这是为了快速填充 媒体播放器使用的预缓冲区。默认值为64 KB,这是一个 大多数客户使用的典型尺寸,因此通常不需要更改 必修的。此设置适用于所有装入点,除非在中被重写 安装设置。确保此值小于队列大小, 如有必要,增加队列大小,使其大于所需大小 突发大小。否则可能导致侦听器客户端中止 连接尝试,由于导致连接的初始突发 已超过队列大小限制


    我将服务器上的
    突发大小增加到131072,现在基于
    MediaPlayer
    的Android应用程序可以毫不延迟地播放流。

    当我遇到这个问题时,我决定在打开播放器之前测试流是否可用。如果你让用户等待很长时间,音乐就会开始播放
    mediaPlayer.start();
    
    public static boolean isLiveStreamingAvailable() {
            SocketAddress sockaddr = new InetSocketAddress(STREAMING_HOST, STREAMING_PORT);
            // Create your socket
            Socket socket = new Socket();
            boolean online = true;
            // Connect with 10 s timeout
            try {
                socket.connect(sockaddr, 10000);
            } catch (SocketTimeoutException stex) {
                // treating timeout errors separately from other io exceptions
                // may make sense
                return false;
            } catch (IOException iOException) {
                return false;
            } finally {
                // As the close() operation can also throw an IOException
                // it must caught here
                try {
                    socket.close();
                } catch (IOException ex) {
                    // feel free to do something moderately useful here, eg log the event
                }
    
            }
            return true;
        }
    
    public static boolean isRecordedStreamingAvailable() {
            try {
                HttpURLConnection.setFollowRedirects(false);
                // note : you may also need
                //        HttpURLConnection.setInstanceFollowRedirects(false)
                HttpURLConnection con =
                        (HttpURLConnection) new URL(RECORDED_URL).openConnection();
                con.setRequestMethod("HEAD");
                return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
            }
            catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }