Start new stream with AACDecoder

2019-08-02 05:14发布

问题:

I'm doing a radio Application (Tune In like)

The situations :

  • When the radio start at first it play an audio AD and then start the radio (AD and radio are 2 diferents streams)
  • When a AACPlayer is currently playing music and the user change station

Two problems :

  • When the ad finish the AACPlayer need to stop and start with another URL
  • When the user select another radio it is the same

With the AACDecoder library there are only two methods - start() - stop()

Those methods can interfere with each other and get the player in an indeterminate state


I start a player with this code :

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

and stop it like this :

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

I use this callback interface :

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);
}

and i update the state of the player with this enum :

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
}

I can't find a solution to do Stop() -> start(url) on a player that is already playing a stream, while securing the state of the player (i must take the latency of the network in account)

How can i achieve that ?

EDIT

Here is a quick view of how things are done :

[PlayerActivity -> StreamingService -> PlayerObject]

In order :

Click on button play -> call method playRadio from StreamingService through the instance got from serviceConnection-> call method play from PlayerObject-> playerState=starting -> method playerStarted auto-called -> playerState=started -> callback method from StreamingService -> broadcast an intent to inform UI -> ui get the intent and update interface...

Here is the BroadcastReceiver :

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) {
                                                                }
                                                            }
                                                        };

Somethimes i get this exception :

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)

回答1:

I think it should be done by callback function playercallback interface can be found here:

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

and the function in AACPlayer itself is :

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

then when player stops this function is executed:

/**
 * 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 );

just put your restarting logic inside this function.

link to sources of aacPlayer:

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

EDIT 1

there is a link to source of Activity using aacPlayer : https://code.google.com/p/aacplayer-android/source/browse/trunk/src/com/spoledge/aacplayer/AACPlayerActivity.java

You should notice that in callback function a Handler is used and a code is executed in separate thread not executed in players thread:

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

Somethimes i get this exception :

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)

edit 2

link to simmilar questions:

Android Application crashes after generating an audio signal a few times

AudioFlinger could not create track. status: -12