2

I'm trying to build a Google glass app that supports live streaming. Am aware that Livestream app is available to do this but i don't think we can integrate it in our application or am i wrong? is there a way to integrate the livestream in our app?

I came across this https://github.com/andermaco/GlassStream open source project which do the same thing using RTSP server of Wowza. As per the instructions i have given the user name/password and updated the url. But while running there is an issue while running the application., i tried to debug it but am not successful. This is the log am getting repeatedly

java.lang.IllegalStateException at android.media.MediaCodec.dequeueOutputBuffer(Native Method) at net.majorkernelpanic.streaming.rtp.MediaCodecInputStream.read(MediaCodecInputStream.java :75) at net.majorkernelpanic.streaming.rtp.AACLATMPacketizer.run(AACLATMPacketizer.java:88) at java.lang.Thread.run(Thread.java:841)

Some of the users have used and are successful, Please share me the source code or let me know if am missing something in setting up the server. Even if there are any other resource for implementing, it would be great.

Thanks in Advance.

Vivek C A
  • 1,045
  • 1
  • 8
  • 14
  • I did post an issue in the same github project and the owner told, its not tested in the latest update XE19.1. Since there were quite a lot of changes it didn't work – Vivek C A Aug 13 '14 at 06:39
  • If you are still interested in this I have a working app using Libstreaming and Wowza. – Colin747 Feb 08 '15 at 22:06
  • ya please share me the source code. It will be very helpful. – Vivek C A Feb 09 '15 at 10:59
  • Ok, I'll add it as an answer, just one point I've been playing around with the resolution today and can only get to work at either the default resolution when I don't specify or if I do set the resolution it only seems to work at `640*480` so if you happen to get it working at any other resolution (higher or lower) can you leave a comment below the answer with the parameters you used? – Colin747 Feb 09 '15 at 11:16

1 Answers1

0

This the code I've used to get it working on Google Glass (XE22) using Wowza media server and libstreaming.

I've two classes AppConfig and MyActivity.

AppConfig:

package com.example.GlassApp;

/**
 * User: Colin Shewell
 * Date: 21/08/14
 * Time: 15:30
 */
public class AppConfig {
  public static final String STREAM_URL = "rtsp://193.61.148.73:1935/serg/android_test";
  //public static final String STREAM_URL = "rtsp://192.168.2.2:1935/serg/android_test";
  public static final String PUBLISHER_USERNAME = "";
  public static final String PUBLISHER_PASSWORD = "";
}

MyActivity:

    package com.example.GlassApp;

/**
 * User: Colin Shewell
 * Date: 21/08/14
 * Time: 15:30
 */
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    import net.majorkernelpanic.streaming.Session;
    import net.majorkernelpanic.streaming.SessionBuilder;
    import net.majorkernelpanic.streaming.audio.AudioQuality;
    import net.majorkernelpanic.streaming.gl.SurfaceView;
    import net.majorkernelpanic.streaming.rtsp.RtspClient;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.SurfaceHolder;
    import android.view.Window;
    import android.view.WindowManager;
    import net.majorkernelpanic.streaming.video.VideoQuality;

    public class MyActivity extends Activity implements RtspClient.Callback, Session.Callback, SurfaceHolder.Callback {
      // log tag
      public final static String TAG = MyActivity.class.getSimpleName();

      // surfaceview
      private static SurfaceView mSurfaceView;

      // Rtsp session
      private Session mSession;
      private static RtspClient mClient;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        // getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_main);

        mSurfaceView = (SurfaceView) findViewById(R.id.surface);

        mSurfaceView.getHolder().addCallback(this);

        // Initialize RTSP client
        initRtspClient();
      }

      @Override
      protected void onResume() {
        super.onResume();

        toggleStreaming();
      }

      @Override
      protected void onPause(){
        super.onPause();

        toggleStreaming();
      }

      private void initRtspClient() {
        // Configures the SessionBuilder
        mSession = SessionBuilder.getInstance()
            .setContext(getApplicationContext())
            .setAudioEncoder(SessionBuilder.AUDIO_NONE)
            .setVideoEncoder(SessionBuilder.VIDEO_H264)
            .setVideoQuality(new VideoQuality(640, 480, 20, 500000)) //only need if you want to change the resolution from default
            .setSurfaceView(mSurfaceView).setPreviewOrientation(0)
            .setCallback(this).build();

        // Configures the RTSP client
        mClient = new RtspClient();
        mClient.setSession(mSession);
        mClient.setCallback(this);
        mSurfaceView.setAspectRatioMode(SurfaceView.ASPECT_RATIO_PREVIEW);
        String ip, port, path;

        // We parse the URI written in the Editext
        Pattern uri = Pattern.compile("rtsp://(.+):(\\d+)/(.+)");  
        Matcher m = uri.matcher(AppConfig.STREAM_URL);
        m.find();
        ip = m.group(1);
        port = m.group(2);
        path = m.group(3);

        mClient.setCredentials(AppConfig.PUBLISHER_USERNAME,
            AppConfig.PUBLISHER_PASSWORD);
        mClient.setServerAddress(ip, Integer.parseInt(port));
        mClient.setStreamPath("/" + path);
      }

      private void toggleStreaming() {
        if (!mClient.isStreaming()) {
          // Start camera preview
          mSession.startPreview();

          // Start video stream
          mClient.startStream();
        } else {
          // already streaming, stop streaming
          // stop camera preview
          mSession.stopPreview();

          // stop streaming
          mClient.stopStream();
        }
      }

      @Override
      public void onDestroy() {
        super.onDestroy();
        mClient.release();
        mSession.release();
        mSurfaceView.getHolder().removeCallback(this);
      }

      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
      }

      @Override
      public void onSessionError(int reason, int streamType, Exception e) {
        switch (reason) {
          case Session.ERROR_CAMERA_ALREADY_IN_USE:
            break;
          case Session.ERROR_CAMERA_HAS_NO_FLASH:
            break;
          case Session.ERROR_INVALID_SURFACE:
            break;
          case Session.ERROR_STORAGE_NOT_READY:
            break;
          case Session.ERROR_CONFIGURATION_NOT_SUPPORTED:
            break;
          case Session.ERROR_OTHER:
            break;
        }

        if (e != null) {
          alertError(e.getMessage());
          e.printStackTrace();
        }
      }

      private void alertError(final String msg) {
        final String error = (msg == null) ? "Unknown error: " : msg;
        AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
        builder.setMessage(error).setPositiveButton("Ok",
            new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
              }
            });
        AlertDialog dialog = builder.create();
        dialog.show();
      }

      @Override
      public void onRtspUpdate(int message, Exception exception) {
        switch (message) {
          case RtspClient.ERROR_CONNECTION_FAILED:
          case RtspClient.ERROR_WRONG_CREDENTIALS:
            alertError(exception.getMessage());
            exception.printStackTrace();
            break;
        }
      }

      @Override
      public void onPreviewStarted() {
      }

      @Override
      public void onSessionConfigured() {
      }

      @Override
      public void onSessionStarted() {
      }

      @Override
      public void onSessionStopped() {
      }

      @Override
      public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
      }

      @Override
      public void surfaceCreated(SurfaceHolder holder) {
      }

      @Override
      public void surfaceDestroyed(SurfaceHolder holder) {
      }

      // @Override
      public void onBitrateUpdate(long bitrate) {
      }
    }

EDIT: I can confirm that the following video quality settings work:

.setVideoQuality(new VideoQuality(640, 480, 20, 500000))
.setVideoQuality(new VideoQuality(960, 720, 20, 500000))

I'd also like to add that an fps value of over 20 seems to result in the app failing to start.

Colin747
  • 4,955
  • 18
  • 70
  • 118