使用 AACDecoder 开始新的流

Posted

技术标签:

【中文标题】使用 AACDecoder 开始新的流【英文标题】:Start new stream with AACDecoder 【发布时间】:2014-07-11 09:46:51 【问题描述】:

我正在做一个广播应用程序(喜欢调谐)

情况:

当收音机首先启动时,它会播放音频 AD,然后启动收音机(AD 和收音机是 2 个不同的流) 当 AACPlayer 当前正在播放音乐并且用户更换电台时

两个问题:

当广告结束时,AACPlayer 需要停止并从另一个 URL 开始 当用户选择另一个收音机时,它是相同的

使用 AACDecoder 库只有两种方法 - 开始() - 停止()

这些方法可能会相互干扰并使玩家处于不确定状态


我用这个代码启动一个播放器:

public void start(String url) throws Exception 
    if (mPlayer == null) 
        mPlayer = new MultiPlayer(this);
    
    mPlayer.playAsync(url);
    mState = StreamingState.PREPARING;

然后像这样停止它:

public void stop() 
    if (mPlayer == null) 
        return;
    
    try 
        mPlayer.stop();
        mPlayer = null;
     catch (Exception e) 
    
    setState(StreamingState.STOPPING);


我使用这个回调接口:

static interface RadioPlayerCallBack 
    public void radioPlayerStarted();
    public void radioPlayerStopped(int perf);
    public void radioPlayerException(Throwable e);
    public void radioPlayerMetadata(String key, String value);
    public void radioPlayerPCMFeedBuffer(boolean isPlaying, int audioBufferSizeMs, int audioBufferCapacityMs);

我用这个枚举更新玩家的状态:

public enum StreamingState 
    EMPTY, // media player rested or releasedS
    CREATED, // created ready to prepare
    PREPARING, // preparing...
    PREPARED, // prepared
    STARTED, // started, and maybe playing (ready to play)
    PAUSED, // paused (media player ready!)
    STOPPED, // stopped and not prepared to play
    ERROR, // an error occured, mediaplayer is reseted
    STOPPING, // startAsync after stop

我找不到在已经在播放流的播放器上执行 Stop() -> start(url) 的解决方案,同时确保播放器(我必须考虑网络的延迟)

我怎样才能做到这一点?

编辑

这里是如何完成的快速视图:

[PlayerActivity -> StreamingService -> PlayerObject]

按顺序:

点击按钮播放->通过从serviceConnection获取的实例从StreamingService调用playRadio方法->从PlayerObject调用play方法-> playerState=starting->方法playerStarted自动调用-> playerState=started->从StreamingService回调方法-> 广播意图通知 UI -> ui 获取意图并更新界面...

这是广播接收器:

final private BroadcastReceiver mPlayBackReceiver       = new BroadcastReceiver() 

                                                            @Override
                                                            public void onReceive(Context context, Intent intent) 
                                                                String actionString = intent.getAction();
                                                                if (actionString == ServiceStreaming.SERVICE_PLAY) 
                                                                 else if (actionString == ServiceStreaming.SERVICE_STOP) 
                                                                 else if (actionString == ServiceStreaming.SERVICE_LOADING) 
                                                                 else if (actionString == ServiceStreaming.SERVICE_ERROR) 
                                                                 else if (actionString == ServiceStreaming.SERVICE_KILLED) 
                                                                
                                                            
                                                        ;

有时我得到这个异常:

06-04 10:15:43.531: E/AudioTrack(8218): AudioFlinger could not create track, status: -12
06-04 10:15:43.531: E/AudioTrack-JNI(8218): Error initializing AudioTrack
06-04 10:15:43.531: E/android.media.AudioTrack(8218): Error code -20 when initializing AudioTrack.
06-04 10:15:43.531: E/PCMFeed(8218): error in playback feed: -3
06-04 10:15:43.541: E/BufferReader(8218): Exception when reading: java.net.SocketException: Socket closed
06-04 10:15:43.901: A/libc(8218): Fatal signal 11 (SIGSEGV) at 0x76652748 (code=1), thread 8955 (Thread-5266)
06-04 10:15:43.911: E/AACPlayer(8218): playAsync():
06-04 10:15:43.911: E/AACPlayer(8218): java.lang.IllegalStateException
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.Decoder.start(Decoder.java:231)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.playImpl(AACPlayer.java:424)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.play(AACPlayer.java:386)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.play(AACPlayer.java:338)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer$1.run(AACPlayer.java:296)
06-04 10:15:43.911: E/AACPlayer(8218):  at java.lang.Thread.run(Thread.java:841)

【问题讨论】:

如果 mPlayer.playAsync(url);在开始和结束时返回任何值,然后您可以使用该值在结束广告上开始另一个网址。 您能具体说明您的实际问题吗?据我了解,您问过如何在前一个停止时开始流式传输?现在您要求在不提供源代码的情况下调试代码? 异常是我提出问题的原因。 AAC 库在这个问题上非常不稳定,它只提供启动和停止方法,没有任何异常捕获。此外,不可能“重置播放器”选项有限,因此问题更多关于算法。在问题中我指定了“保护播放器的状态。我也不能发布我所有的代码,这太多了,我只是粘贴了相关部分 如果异常是一个问题:***.com/questions/17527996/… 谢谢,我会尝试从回调中获取音轨并在 onStopped 中关闭它...不是很干净,但如果可行的话(〜 ̄△ ̄)〜 【参考方案1】:

我觉得应该是通过回调函数来完成的 playercallback接口可以在这里找到:

https://code.google.com/p/aacplayer-android/source/browse/trunk/src/com/spoledge/aacplayer/PlayerCallback.java

AACPlayer 本身的功能是:

/**
 * Sets the PlayerCallback.
 * NOTE: this should be set BEFORE any of the play methods are called.
 */
public void setPlayerCallback( PlayerCallback playerCallback )

然后当播放器停止时执行此函数:

/**
 * This method is called when the player is stopped.
 * Note: __after__ this method the method playerException might be also called.
 */
public void playerStopped( int perf );

只需将你的重启逻辑放在这个函数中。

aacPlayer 来源链接:

https://code.google.com/p/aacplayer-android/source/browse/trunk/src/com/spoledge/aacplayer/AACPlayer.java

编辑 1

有一个使用 aacPlayer 的 Activity 源链接: https://code.google.com/p/aacplayer-android/source/browse/trunk/src/com/spoledge/aacplayer/AACPlayerActivity.java

您应该注意到,在回调函数中使用了一个 Handler,并且代码在单独的线程中执行,而不是在玩家线程中执行:

public void playerStopped( final int perf ) 
    uiHandler.post( new Runnable() 
        public void run() 
            enableButtons();
            ...
            playerStarted = false;
        
    );

有时我得到这个异常:

06-04 10:15:43.531: E/AudioTrack(8218): AudioFlinger could not create track, status: -12
06-04 10:15:43.531: E/AudioTrack-JNI(8218): Error initializing AudioTrack
06-04 10:15:43.531: E/android.media.AudioTrack(8218): Error code -20 when initializing AudioTrack.
06-04 10:15:43.531: E/PCMFeed(8218): error in playback feed: -3
06-04 10:15:43.541: E/BufferReader(8218): Exception when reading: java.net.SocketException: Socket closed
06-04 10:15:43.901: A/libc(8218): Fatal signal 11 (SIGSEGV) at 0x76652748 (code=1), thread 8955 (Thread-5266)
06-04 10:15:43.911: E/AACPlayer(8218): playAsync():
06-04 10:15:43.911: E/AACPlayer(8218): java.lang.IllegalStateException
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.Decoder.start(Decoder.java:231)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.playImpl(AACPlayer.java:424)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.play(AACPlayer.java:386)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer.play(AACPlayer.java:338)
06-04 10:15:43.911: E/AACPlayer(8218):  at com.spoledge.aacdecoder.AACPlayer$1.run(AACPlayer.java:296)
06-04 10:15:43.911: E/AACPlayer(8218):  at java.lang.Thread.run(Thread.java:841)

编辑 2

类似问题的链接:

Android Application crashes after generating an audio signal a few times

AudioFlinger could not create track. status: -12

【讨论】:

我使用回调查看我的编辑。在 playerStopped 中重启播放器你不觉得有风险吗? 我不确定我们是否在这里谈论相同的回调,我认为您的回调没有实现com.spoledge.aacplayer.PlayerCallback,因此如果玩家停止它不会收到通知。上面提到的回调是这个库的一部分,并且在播放器状态发生更改时会收到通知,因此当您收到停止通知时播放()不同的 url 没有问题 我在我的Object player中实现com.spoledge.aacplayer.PlayerCallback,然后我的回调接口给我的服务反馈 然后 playerStopped 函数在播放器实际停止时执行 stop() 函数只是告诉播放器线程开始停止并在完成时通知回调 是的。知道我用 playerStarted 阻止按钮并用 playerStopped 启用它们。但是当我快速且多次(大约 10-15 次)时,播放器会给我一个我无法从库中捕获的异常。

以上是关于使用 AACDecoder 开始新的流的主要内容,如果未能解决你的问题,请参考以下文章

看完这位父亲的流调,我彻底破防了

无论如何,是不是有一个新的流不会每次都检查测试方法?

Flink 如何实现新的流处理应用第二部分:版本化状态

Flink 如何实现新的流处理应用第二部分:版本化状态

Flink 如何现实新的流处理应用第一部分:事件时间与无序处理

Flink 如何现实新的流处理应用第一部分:事件时间与无序处理