cn.videochat.VideoChat.java Source code

Java tutorial

Introduction

Here is the source code for cn.videochat.VideoChat.java

Source

/**
 * 
 * Copyright (C) 2013 Dai Jingjing (jjyyis@qq.com)
 *
 * Licensed under the GPLv2 license. See 'COPYING' for more details.
 *
 */
package cn.videochat;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import cn.videochat.VideoChat.View.MyVideoRender;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
import android.os.AsyncTask;
import android.util.Log;

public class VideoChat {
    private static final String TAG = "VideoChat.LOG";

    //
    // Error Codes
    //
    public static final int ERROR_FETCH_PLAYER_URL = -1; // ??
    public static final int ERROR_CONNECT_MEDIA_SERVER = -2;// ?
    public static final int ERROR_RECV_MEDIA_PACKET = -3; // 
    public static final int ERROR_INVALID_PACKET_TYPE = -4; // ?

    //
    //
    //
    public static final int EVENT_BUFFERING_BEGIN = 1;
    public static final int EVENT_BUFFERING_UPDATE_S = 100;
    public static final int EVENT_BUFFERING_UPDATE_E = 200;
    public static final int EVENT_BUFFERING_COMPLETION = 3;
    public static final int EVENT_COMPLETION = 4;

    //
    // ?
    //
    public interface BufferingUpdateListener {
        public void onBufferingBegin(VideoChat player);

        public void onBufferingComplete(VideoChat player);

        public void onBufferingUpdate(VideoChat player, int bufferingProgress);
    }

    public interface CompletionListener {
        public void onCompletionListener(VideoChat player);
    }

    public interface ErrorListener {
        public boolean onError(VideoChat player, int what, int extra);
    }

    protected interface glSurfaceViewCreateListener {
        public void onCreateListener(MyVideoRender myVideoRender);
    }

    public static class View extends GLSurfaceView {

        MyVideoRender render = new MyVideoRender();

        public View(Context context) {
            super(context);
            setEGLContextClientVersion(2);
            setRenderer(render);
        }

        public MyVideoRender getRender() {
            return render;
        }

        public class MyVideoRender implements GLSurfaceView.Renderer {
            private long renderTime = System.currentTimeMillis();
            private final int fps = 1000 / 15; // max 25fps
            private long _handler = 0;

            public MyVideoRender() {
            }

            public void Destory() {
                VideoChat.RenderRelease(_handler);
                _handler = 0;
                Log.i("FUCK", "[Destory]");
            }

            public long getHandler() {
                return _handler;
            }

            public void onDrawFrame(GL10 gl) {
                // GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
                // GLES20.GL_DEPTH_BUFFER_BIT);

                long dt = System.currentTimeMillis() - renderTime;
                if (dt < fps) {
                    try {
                        Thread.sleep(fps - dt);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                VideoChat.RenderFrame(_handler);
                renderTime = System.currentTimeMillis();
            }

            public void onSurfaceChanged(GL10 gl, int width, int height) {
                if (height == 0) {
                    height = 1;
                }
                gl.glViewport(0, 0, width, height);
                Log.i("FUCK", "[onSurfaceChanged]");
            }

            public void onSurfaceCreated(GL10 gl, EGLConfig config) {
                Log.i("FUCK", "[onSurfaceCreated]");
                this.Destory();
                _handler = VideoChat.CreateRender();
                Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

                fireCreateEvent();
            }

            private HashSet<glSurfaceViewCreateListener> createListeners = new HashSet<glSurfaceViewCreateListener>();

            public void addCreateListener(glSurfaceViewCreateListener listener) {
                createListeners.add(listener);
            }

            public void removeCreateListener(glSurfaceViewCreateListener listener) {
                createListeners.remove(listener);
            }

            private void fireCreateEvent() {
                Iterator<glSurfaceViewCreateListener> itr = createListeners.iterator();
                while (itr.hasNext()) {
                    glSurfaceViewCreateListener listener = (glSurfaceViewCreateListener) itr.next();
                    listener.onCreateListener(this);
                }
            }
        } // class MyVideoRender
    } // class View

    //
    // api params
    //
    private String apiHost = "122.0.67.180";
    private int apiPort = 80;
    private String apiApp = "videochat";
    private String url;
    private String UserID = "";
    private String MyID = "";
    private View view;
    private long _handler = 0L;
    private boolean _isPlayering = false;

    public VideoChat() {
        _handler = Init();
    }

    public VideoChat(String _apiHost, int _apiPort, String _apiApp) {
        apiHost = _apiHost;
        apiPort = _apiPort;
        apiApp = _apiApp;
        _handler = Init();
    }

    public void release() {
        Release(_handler);
        _handler = 0;
        Log.i(TAG, "[release]");
    }

    public void setDataSource(String myId, String uId) {
        UserID = uId;
        MyID = myId;
        StringBuffer sb = new StringBuffer(buildApiUrl());
        sb.append("liveUrl?myid=").append(myId).append("&uid=").append(uId);
        url = sb.toString();
        Log.i(TAG, "[setDataSource]");
    }

    public void setUrl(String _url) {
        url = _url;
        Log.i(TAG, "[setUrl]");
    }

    public void play() {
        OpenPlayer(_handler, url);
        Log.i(TAG, "[play]");
    }

    public boolean isPlaying() {
        return _isPlayering;
    }

    public void pause(boolean paused) {
        PausePlayer(_handler, paused);
        Log.i(TAG, "[pause]");
    }

    public void stop() {
        ClosePlayer(_handler);
        Log.i(TAG, "[stop]");
    }

    public void setRender(View view) {
        SetVideoRender(_handler, view.getRender().getHandler());
        view.getRender().addCreateListener(onViewCreated);
    }

    //
    // surface view created
    //
    glSurfaceViewCreateListener onViewCreated = new glSurfaceViewCreateListener() {
        @Override
        public void onCreateListener(MyVideoRender myVideoRender) {
            SetVideoRender(_handler, myVideoRender.getHandler());
        }
    };

    public void render() {
        RenderFrame(_handler);
    }

    //
    // ??
    //
    private HashSet<BufferingUpdateListener> bufferingUpdateListeners = new HashSet<BufferingUpdateListener>();

    public void addBufferingUpdateListener(BufferingUpdateListener listener) {
        bufferingUpdateListeners.add(listener);
    }

    public void removeBufferingUpdateListener(BufferingUpdateListener listener) {
        bufferingUpdateListeners.remove(listener);
    }

    private void fireBufferingBeginEvent() {
        Iterator<BufferingUpdateListener> itr = bufferingUpdateListeners.iterator();
        while (itr.hasNext()) {
            BufferingUpdateListener listener = (BufferingUpdateListener) itr.next();
            listener.onBufferingBegin(this);
            listener.onBufferingUpdate(this, 0);
        }
    }

    private void fireBufferingCompleteEvent() {
        Iterator<BufferingUpdateListener> itr = bufferingUpdateListeners.iterator();
        while (itr.hasNext()) {
            BufferingUpdateListener listener = (BufferingUpdateListener) itr.next();
            listener.onBufferingUpdate(this, 100);
            listener.onBufferingComplete(this);
        }
    }

    private void fireBufferingUpdateEvent(int bufferingProgress) {
        Iterator<BufferingUpdateListener> itr = bufferingUpdateListeners.iterator();
        while (itr.hasNext()) {
            BufferingUpdateListener listener = (BufferingUpdateListener) itr.next();
            listener.onBufferingUpdate(this, bufferingProgress);
        }
    }

    private HashSet<ErrorListener> errorListeners = new HashSet<ErrorListener>();

    public void addErrorListener(ErrorListener listener) {
        errorListeners.add(listener);
    }

    public void removeErrorListener(ErrorListener listener) {
        errorListeners.remove(listener);
    }

    private void fireErrorEvent(int what, int extra) {
        Iterator<ErrorListener> itr = errorListeners.iterator();
        while (itr.hasNext()) {
            ErrorListener listener = (ErrorListener) itr.next();
            listener.onError(this, what, extra);
        }
    }

    private HashSet<CompletionListener> completionListeners = new HashSet<CompletionListener>();

    public void addCompletionListener(CompletionListener listener) {
        completionListeners.add(listener);
    }

    public void removeCompletionListener(CompletionListener listener) {
        completionListeners.remove(listener);
    }

    private void fireCompletionEvent() {
        Iterator<CompletionListener> itr = completionListeners.iterator();
        while (itr.hasNext()) {
            CompletionListener listener = (CompletionListener) itr.next();
            listener.onCompletionListener(this);
        }
    }

    private String buildApiUrl() {
        return new StringBuffer("http://").append(apiHost).append(":").append(apiPort).append("/").append(apiApp)
                .append("/api/").toString();
    }

    // ??OpenGL ES 2.0
    public static boolean IsSupportOpenGLES2(Context context) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();

        return configurationInfo.reqGlEsVersion >= 0x20000;
    }

    // /////////////////////////////////////////////////////////////////////////
    //
    // JNI
    //
    // /////////////////////////////////////////////////////////////////////////
    static {
        System.loadLibrary("vc");
    }

    //
    // Video Player
    //
    private native long Init();

    private native void Release(long handler);

    private native void SetVideoRender(long handler, long videoRender);

    private native void OpenPublisher(long handler, String rtmpUrl);

    private native void PausePublisher(long handler, boolean paused);

    private native void ClosePublisher(long handler);

    private native void OpenPlayer(long handler, String rtmpUrl);

    private native void PausePlayer(long handler, boolean paused);

    private native void ClosePlayer(long handler);

    //
    // Video Render
    //
    private native static long CreateRender();

    private native static long SetRenderViewPort(long handler, int width, int height);

    private native static void RenderFrame(long handler);

    private native static void RenderRelease(long handler);

    //
    // JNI?(???)
    //
    int lastErrorId = 0;

    public void onJniEvent(int eventId) {
        Log.i(TAG, "[onJniEvent] eventId=" + eventId);
        if (eventId == 0) {
            // NDK ping
        } else if (eventId == EVENT_BUFFERING_BEGIN) {
            StringBuffer sb = new StringBuffer(buildApiUrl());
            sb.append("postLog?type=client&event=start&uid=").append(UserID).append("&myid=").append(MyID);
            new PostLog().execute(sb.toString());

            _isPlayering = true;
            fireBufferingBeginEvent();
        } else if (eventId >= EVENT_BUFFERING_UPDATE_S && eventId <= EVENT_BUFFERING_UPDATE_E) {
            fireBufferingUpdateEvent(eventId - 100);
        } else if (eventId == EVENT_BUFFERING_COMPLETION) {
            lastErrorId = 0;
            fireBufferingCompleteEvent();
        } else if (eventId == EVENT_COMPLETION) {
            StringBuffer sb = new StringBuffer(buildApiUrl());
            sb.append("postLog?type=client&event=stop&uid=").append(UserID).append("&myid=").append(MyID);
            new PostLog().execute(sb.toString());

            _isPlayering = false;
            fireCompletionEvent();
        } else if (eventId < 0) {
            if (lastErrorId != eventId) {
                lastErrorId = eventId;
                StringBuffer sb = new StringBuffer(buildApiUrl());
                sb.append("postLog?type=client&event=error&code=").append(Math.abs(eventId)).append("&uid=")
                        .append(UserID).append("&myid=").append(MyID);
                new PostLog().execute(sb.toString());
            }

            fireErrorEvent(eventId, 0);
        }
    }

    private class PostLog extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... uri) {
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response;
            String responseString = null;
            try {
                response = httpclient.execute(new HttpGet(uri[0]));
                StatusLine statusLine = response.getStatusLine();
                if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
                }
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return responseString;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
        }
    }

}