// Path: app/src/main/java/net/ossrs/yasea/rtmp/RtmpPublisher.java
// public interface RtmpPublisher {
//     
//     void connect(String url) throws IOException;
//     
//     /**
//      * Issues an RTMP "publish" command and write the media content stream packets (audio and video). 
//      * 
//      * @param publishType specify the way to publish raw RTMP packets among "live", "record" and "append"
//      * @return An outputStream allowing you to write the incoming media content data
//      * @throws IllegalStateException if the client is not connected to a RTMP server
//      * @throws IOException if a network/IO error occurs
//      */
//     void publish(String publishType) throws IllegalStateException, IOException;
//      
//     /**
//      * Stops and closes the current RTMP stream
//      */
//     void closeStream() throws IllegalStateException;
//     
//     /**
//      * Shuts down the RTMP client and stops all threads associated with it
//      */
//     void shutdown();
// 
//     /**
//      * publish a video content packet to server
//      *
//      * @param data video stream byte array
//      */
//     void publishVideoData(byte[] data) throws IllegalStateException;
// 
//     /**
//      * publish an audio content packet to server
//      *
//      * @param data audio stream byte array
//      */
//     void publishAudioData(byte[] data) throws IllegalStateException;
// 
//     /**
//      * obtain event handler in publisher
//      */
//     EventHandler getEventHandler();
// 
//     /**
//      * obtain video frame number cached in publisher
//      */
//     AtomicInteger getVideoFrameCacheNumber();
// 
//     /**
//      * obtain the IP address of the peer if any
//      */
//     String getServerIpAddr();
// 
//     /**
//      * obtain the PID of the peer if any
//      */
//     int getServerPid();
// 
//     /**
//      * obtain the ID of the peer if any
//      */
//     int getServerId();
// 
//     /**
//      * set video resolution
//      *
//      * @param width
//      * @param height
//      */
//     void setVideoResolution(int width, int height);
// 
//     /**
//      * RTMP event handler.
//      */
//     interface EventHandler {
// 
//         void onRtmpConnecting(String msg);
// 
//         void onRtmpConnected(String msg);
// 
//         void onRtmpVideoStreaming(String msg);
// 
//         void onRtmpAudioStreaming(String msg);
// 
//         void onRtmpStopped(String msg);
// 
//         void onRtmpDisconnected(String msg);
// 
//         void onRtmpOutputFps(double fps);
//     }
// }


import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import net.ossrs.yasea.rtmp.RtmpPublisher;
            publisher.publishAudioData(frame.tag.data.array());
        }

        if (frame.is_keyframe()) {
            Log.i(TAG, String.format("worker: send frame type=%d, dts=%d, size=%dB",
                    frame.type, frame.dts, frame.tag.size));
        }
    }

    /**
     * start to the remote SRS for remux.
     */
    public void start(String url) throws IOException {
        rtmpUrl = url;

        worker = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    // Keep at least one audio and video frame in cache to ensure monotonically increasing.
                    while (!frameCache.isEmpty()) {
                        SrsFlvFrame frame = frameCache.poll();
                        try {
                            // only connect when got keyframe.
                            if (frame.is_keyframe()) {
                                connect(rtmpUrl);
                            }
                            // when sequence header required,
                            // adjust the dts by the current frame and sent it.
                            if (!sequenceHeaderOk) {
// Path: app/src/main/java/net/ossrs/yasea/rtmp/RtmpPublisher.java
// public interface RtmpPublisher {
//     
//     void connect(String url) throws IOException;
//     
//     /**
//      * Issues an RTMP "publish" command and write the media content stream packets (audio and video). 
//      * 
//      * @param publishType specify the way to publish raw RTMP packets among "live", "record" and "append"
//      * @return An outputStream allowing you to write the incoming media content data
//      * @throws IllegalStateException if the client is not connected to a RTMP server
//      * @throws IOException if a network/IO error occurs
//      */
//     void publish(String publishType) throws IllegalStateException, IOException;
//      
//     /**
//      * Stops and closes the current RTMP stream
//      */
//     void closeStream() throws IllegalStateException;
//     
//     /**
//      * Shuts down the RTMP client and stops all threads associated with it
//      */
//     void shutdown();
// 
//     /**
//      * publish a video content packet to server
//      *
//      * @param data video stream byte array
//      */
//     void publishVideoData(byte[] data) throws IllegalStateException;
// 
//     /**
//      * publish an audio content packet to server
//      *
//      * @param data audio stream byte array
//      */
//     void publishAudioData(byte[] data) throws IllegalStateException;
// 
//     /**
//      * obtain event handler in publisher
//      */
//     EventHandler getEventHandler();
// 
//     /**
//      * obtain video frame number cached in publisher
//      */
//     AtomicInteger getVideoFrameCacheNumber();
// 
//     /**
//      * obtain the IP address of the peer if any
//      */
//     String getServerIpAddr();
// 
//     /**
//      * obtain the PID of the peer if any
//      */
//     int getServerPid();
// 
//     /**
//      * obtain the ID of the peer if any
//      */
//     int getServerId();
// 
//     /**
//      * set video resolution
//      *
//      * @param width
//      * @param height
//      */
//     void setVideoResolution(int width, int height);
// 
//     /**
//      * RTMP event handler.
//      */
//     interface EventHandler {
// 
//         void onRtmpConnecting(String msg);
// 
//         void onRtmpConnected(String msg);
// 
//         void onRtmpVideoStreaming(String msg);
// 
//         void onRtmpAudioStreaming(String msg);
// 
//         void onRtmpStopped(String msg);
// 
//         void onRtmpDisconnected(String msg);
// 
//         void onRtmpOutputFps(double fps);
//     }
// }


// Path: app/src/main/java/net/ossrs/yasea/SrsFlvMuxer.java
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.util.Log;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import net.ossrs.yasea.rtmp.RtmpPublisher;

            publisher.publishAudioData(frame.tag.data.array());
        }

        if (frame.is_keyframe()) {
            Log.i(TAG, String.format("worker: send frame type=%d, dts=%d, size=%dB",
                    frame.type, frame.dts, frame.tag.size));
        }
    }

    /**
     * start to the remote SRS for remux.
     */
    public void start(String url) throws IOException {
        rtmpUrl = url;

        worker = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()) {
                    // Keep at least one audio and video frame in cache to ensure monotonically increasing.
                    while (!frameCache.isEmpty()) {
                        SrsFlvFrame frame = frameCache.poll();
                        try {
                            // only connect when got keyframe.
                            if (frame.is_keyframe()) {
                                connect(rtmpUrl);
                            }
                            // when sequence header required,
                            // adjust the dts by the current frame and sent it.
                            if (!sequenceHeaderOk) {
                                if (videoSequenceHeader != null) {