Build a basic app with GoCoder SDK for Android

Learn how to use Android Studio to build a basic streaming app with the Wowza GoCoder™ SDK for Android.

Contents


Create an app project
Add a camera preview and broadcast button to the layout definition file
Define app properties
Register and initialize the SDK
Check for app permissions
Start the camera preview
Add and configure a broadcast
Add broadcast monitoring callbacks
Start streaming
Build and deploy an app
Example MainActivity class
More resources

Create an app project


First, create an app project in Android Studio.

  1. Start Android Studio and, in the Welcome to Android Studio window, click Start a New Android Studio Project.
  2. On the Create Android Project page, click Edit to edit the Package Name, and replace the package name with the App ID in your license key email, and then click Next.
  3. On the Target Android Devices page, select the form factors your app will run on (typically Phone and Tablet), select a minimum SDK version of API 21 or higher, and then click Next.
  4. On the Add an Activity to Mobile page, select Empty Activity and then click Next.
  5. On the Configure Activity page, accept the default values and click Next.
  6. On the Component Installer page, click Finish.
  7.  Make sure the GoCoder SDK library is installed and the permissions are added to AndroidManifest.xml according to the instructions in Configure an Android Studio project to use the Wowza GoCoder SDK.

Add a camera preview and broadcast button to the layout definition file


Next, add a camera preview and a broadcast button to the app's layout definition file.

  1. In Android Studio, click File and then click Open.
  2. Navigate to and open [project_root]/app/src/main/res/layout/activity_main.xml.
  3. Replace the contents of the activity_main.xml file with the following, making sure to replace com.mycompany.myapp in the tools:context property with the package name for the app's MainActivity class.
     
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      xmlns:wowza="http://schemas.android.com/apk/res-auto"
      android:id="@+id/activity_main"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="com.mycompany.myapp.MainActivity">
    
      <!-- The camera preview display -->
      <com.wowza.gocoder.sdk.api.devices.WOWZCameraView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/camera_preview"
        wowza:scaleMode="fill"
        wowza:defaultCamera="back"
        wowza:frameSizePreset="frameSize1280x720"/>
    
      <!-- The broadcast button -->
      <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Broadcast"
        android:id="@+id/broadcast_button"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />
    
    </RelativeLayout>

  4. Add the android:configChanges property to the definition of the activity element in the [project_root]/app/src/main/AndroidManifest.xml file.
     
    <activity android:name=".MainActivity"
        android:configChanges="orientation|keyboardHidden|screenSize">
  5. Enable Android's immersive, sticky full-screen mode by adding the onWindowFocusChanged() method to the MainActivity class. To do so, copy all of the code below and paste it just above the last curly brace in the class.
     
    //
    // Enable Android's immersive, sticky full-screen mode
    //
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
      super.onWindowFocusChanged(hasFocus);
    
      View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
      if (rootView != null)
        rootView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }

Define app properties


Add the following member variables to the MainActivity class in MainActivity.java.

public class MainActivity extends AppCompatActivity {

    // The top-level GoCoder API interface
    private WowzaGoCoder goCoder;

    // The GoCoder SDK camera view
    private WOWZCameraView goCoderCameraView;

    // The GoCoder SDK audio device
    private WOWZAudioDevice goCoderAudioDevice;

    // The GoCoder SDK broadcaster
    private WOWZBroadcast goCoderBroadcaster;

    // The broadcast configuration settings
    private WOWZBroadcastConfig goCoderBroadcastConfig;

    // Properties needed for Android 6+ permissions handling
    private static final int PERMISSIONS_REQUEST_CODE = 0x1;
    private boolean mPermissionsGranted = true;
    private String[] mRequiredPermissions = new String[] {
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
    };

Register and initialize the SDK


Next, register your GoCoder SDK license and initialize the SDK by adding the following to the onCreate() method in the MainActivity class, replacing GOSK-XXXX-XXXX-XXXX-XXXX-XXXX with your registered license key.

// Initialize the GoCoder SDK
goCoder = WowzaGoCoder.init(getApplicationContext(), "GOSK-XXXX-XXXX-XXXX-XXXX-XXXX");

if (goCoder == null) {
    // If initialization failed, retrieve the last error and display it
    WOWZError goCoderInitError = WowzaGoCoder.getLastError();
    Toast.makeText(this,
        "GoCoder SDK error: " + goCoderInitError.getErrorDescription(),
        Toast.LENGTH_LONG).show();
    return;
}

Check for app permissions


Next, you must define the permissions the app requires.

  1. Add the following permissions to the [project_root]/app/src/main/AndroidManifest.xml file just below the top-level <manifest> element.
     
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
              package="com.cintimedia.foobar">
    
        <!-- Define the required application permissions -->
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.FLASHLIGHT" />
    
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
  2. For Android 6.0 and later, add the onResume() and onRequestPermissionsResult() methods to the MainActivity class to check that the user has granted the app permission to access the camera and microphone.
     
    //
    // Called when an activity is brought to the foreground
    //
    @Override
    protected void onResume() {
        super.onResume();
    
        // If running on Android 6 (Marshmallow) and later, check to see if the necessary permissions
        // have been granted
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mPermissionsGranted = hasPermissions(this, mRequiredPermissions);
            if (!mPermissionsGranted)
                ActivityCompat.requestPermissions(this, mRequiredPermissions, PERMISSIONS_REQUEST_CODE);
        } else
            mPermissionsGranted = true;
    
    }
    
    //
    // Callback invoked in response to a call to ActivityCompat.requestPermissions() to interpret
    // the results of the permissions request
    //
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        mPermissionsGranted = true;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_CODE: {
                // Check the result of each permission granted
                for(int grantResult : grantResults) {
                    if (grantResult != PackageManager.PERMISSION_GRANTED) {
                        mPermissionsGranted = false;
                    }
                }
            }
        }
    }
    
    //
    // Utility method to check the status of a permissions request for an array of permission identifiers
    //
    private static boolean hasPermissions(Context context, String[] permissions) {
        for(String permission : permissions)
            if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
                return false;
    
        return true;
    }

Start the camera preview


Then, configure and start the camera preview.

  1. Associate the view defined in the activity's layout with the corresponding WOWZCameraView class member and create an audio input device instance by adding the following to the onCreate() method in the MainActivity class just below the SDK initialization.
     
    // Associate the WOWZCameraView defined in the U/I layout with the corresponding class member
    goCoderCameraView = (WOWZCameraView) findViewById(R.id.camera_preview);
    
    // Create an audio device instance for capturing and broadcasting audio
    goCoderAudioDevice = new WOWZAudioDevice();
  2. Add the following to the bottom of the onResume() method in the Main
    Activity
     class (after the permission-checking logic) to turn on the camera preview when the app is brought to the foreground.
     
    // Start the camera preview display
    if (mPermissionsGranted && goCoderCameraView != null) {
        if (goCoderCameraView.isPreviewPaused())
            goCoderCameraView.onResume();
        else
            goCoderCameraView.startPreview();    
    }

Add and configure a broadcast

After a live stream is captured and encoded, your mobile streaming app needs to deliver your live stream to Wowza Streaming Cloud™ or Wowza Streaming Engine™ media server software. To add this functionality to your app, you need to create a WOWZBroadcast object instance. In addition, you need to create a WOWZBroadcastConfig object instance and use it to configure the broadcast's connection to a Wowza Streaming Cloud™ live stream or a Wowza Streaming Engine™ media server software instance. You will also add some additional code in this step to designate the video and audio sources.

To add a broadcast

  1. In the onCreate() method in MainActivity, find the code for creating an audio device instance.
     
    // Create an audio device instance for capturing and broadcasting audio
    goCoderAudioDevice = new WOWZAudioDevice();
  2. After the code shown above, add the following code:
     
    // Create a broadcaster instance
    goCoderBroadcaster = new WOWZBroadcast();
    
    // Create a configuration instance for the broadcaster
    goCoderBroadcastConfig = new WOWZBroadcastConfig(WOWZMediaConfig.FRAME_SIZE_1920x1080);
    
    // Set the connection properties for the target Wowza Streaming Engine server or Wowza Streaming Cloud live stream
    goCoderBroadcastConfig.setHostAddress("live.someserver.net");
    goCoderBroadcastConfig.setPortNumber(1935);
    goCoderBroadcastConfig.setApplicationName("live");
    goCoderBroadcastConfig.setStreamName("myStream");
    
    // Designate the camera preview as the video source
    goCoderBroadcastConfig.setVideoBroadcaster(goCoderCameraView);
    
    // Designate the audio device as the audio broadcaster
    goCoderBroadcastConfig.setAudioBroadcaster(goCoderAudioDevice);
    

To configure the broadcast's connection to a Wowza Streaming Cloud live stream

  1. In Wowza Streaming Cloud:

    1. If you haven't already, add a live stream.
    2. After adding the live stream, click the Overview tab.
    3. Scroll down to Source Connection Information.
    4. Note the source connection values. For example:
  2. In Android Studio:

    1. Find the connection properties section in the onCreate() method.
    2. Enter the source connection value for each connection property. For example:

goCoderBroadcastConfig.setHostAddress("my_hostAddress");
goCoderBroadcastConfig.setPortNumber("my_port");
goCoderBroadcastConfig.setApplicationName("my_applicationName");
goCoderBroadcastConfig.setStreamName("my_streamName");

To configure the broadcast's connection to a Wowza Steaming Engine live application

  1. Configure a live application in Wowza Streaming Engine to use an RTMP stream from your SDK app. For instructions, see Set up live streaming using an RTMP-based encoder in Wowza Streaming Engine.
  2. Get the following connection information from your Wowza Streaming Engine live application.

    Property Description
    applicationName The name of the live streaming application in Wowza Streaming Engine, for example, live.
    hostAddress The IP address for your Wowza Streaming Engine instance. Use the Host - Server specified in the Application Connection Settings panel on the Home page of Wowza Streaming Engine Manager.
    password The password for source authentication, if any. Use the Source Password specified on the Source Authentication page of Wowza Streaming Engine Manager.
    portNumber The port number for the server connection. Use the Host - Port specified in the Application Connection Settings panel on the Home page of Wowza Streaming Engine Manager (1935 by default).
    streamName The name of the stream, for example myStream.
    userName The user name for source authentication, if any. Use the Source Username specified on the Source Authentication page of Wowza Streaming Engine Manager.

    Note: Your mobile device must be able to reach your Wowza Streaming Engine server. To see if it can, enter the following URL in your mobile device's browser: http://[hostAddress]:[portNumber]/crossdomain.xml.
  3. Find the connection properties section in the onCreate() method.
  4. In the connection properties section, enter the connection information. For example:

goCoderBroadcastConfig.setHostAddress("my_hostAddress");
goCoderBroadcastConfig.setPortNumber("my_port");
goCoderBroadcastConfig.setApplicationName("my_applicationName");
goCoderBroadcastConfig.setStreamName("my_streamName");
goCoderBroadcastConfig.setUsername("
my_userName");
goCoderBroadcastConfig.setPassword("my_password");

Add broadcast monitoring callbacks


Next, add callbacks to monitor the broadcast's status updates and errors.

  1. Add the WOWZStatusCallback interface to the primary activity class (MainActivity) definition to monitor status updates and errors during live stream broadcast.
     
    // Main app activity class
    public class MainActivity extends AppCompatActivity
        implements WOWZStatusCallback {
  2. Add the methods defined by the WOWZStatusCallback interface to the MainActivity class to monitor status updates and errors during a live streaming broadcast.
     
    //
    // The callback invoked upon changes to the state of the broadcast
    //
    @Override
    public void onWZStatus(final WOWZStatus goCoderStatus) {
     // A successful status transition has been reported by the GoCoder SDK
     final StringBuffer statusMessage = new StringBuffer("Broadcast status: ");
    
     switch (goCoderStatus.getState()) {
      case WOWZState.STARTING:
       statusMessage.append("Broadcast initialization");
       break;
    
      case WOWZState.READY:
       statusMessage.append("Ready to begin streaming");
       break;
    
      case WOWZState.RUNNING:
       statusMessage.append("Streaming is active");
       break;
    
      case WOWZState.STOPPING:
       statusMessage.append("Broadcast shutting down");
       break;
    
      case WOWZState.IDLE:
       statusMessage.append("The broadcast is stopped");
       break;
    
      default:
       return;
     }
    
     // Display the status message using the U/I thread
     new Handler(Looper.getMainLooper()).post(new Runnable() {
      @Override
      public void run() {
       Toast.makeText(MainActivity.this, statusMessage, Toast.LENGTH_LONG).show();
      }
     });
    }
    
    //
    // The callback invoked when an error occurs during a broadcast
    //
    @Override
    public void onWZError(final WOWZStatus goCoderStatus) {
     // If an error is reported by the GoCoder SDK, display a message
     // containing the error details using the U/I thread
     new Handler(Looper.getMainLooper()).post(new Runnable() {
      @Override
      public void run() {
       Toast.makeText(MainActivity.this,
       "Streaming error: " + goCoderStatus.getLastError().getErrorDescription(),
       Toast.LENGTH_LONG).show();
      }
     });
    }

Start streaming


Configure the broadcast button to start and stop the stream when tapped.

  1. Add the View.onClickListener interface to the MainActivity class definition.
     
    // Main app activity class
    public class MainActivity extends AppCompatActivity
      implements  WOWZStatusCallback, View.OnClickListener {
  2. Add an onClick() event handler to the bottom of the onCreate() method in the MainActivity class to be invoked when the broadcast button is tapped.
     
    //
    // The callback invoked when the broadcast button is tapped
    //
    @Override
    public void onClick(View view) {
      // return if the user hasn't granted the app the necessary permissions
      if (!mPermissionsGranted) return;
    
      // Ensure the minimum set of configuration settings have been specified necessary to
      // initiate a broadcast streaming session
      WOWZStreamingError configValidationError = goCoderBroadcastConfig.validateForBroadcast();
    
      if (configValidationError != null) {
        Toast.makeText(this, configValidationError.getErrorDescription(), Toast.LENGTH_LONG).show();
      } else if (goCoderBroadcaster.getStatus().isRunning()) {
        // Stop the broadcast that is currently running
        goCoderBroadcaster.endBroadcast(this);
      } else {
        // Start streaming
        goCoderBroadcaster.startBroadcast(goCoderBroadcastConfig, this);
      }
    }
  3. Associate the onClick() event handler with the broadcast button defined in the activity's layout by adding the following to the bottom of the onCreate() method in the MainActivity class.
     
    // Associate the onClick() method as the callback for the broadcast button's click event
    Button broadcastButton = (Button) findViewById(R.id.broadcast_button);
    broadcastButton.setOnClickListener(this);

Build and deploy an app


Finally, you're ready to build and deploy the app. Click the Run menu, choose Run or Debug, and then select a device for deployment.

Example MainActivity class


The following is an example of the ViewController class with all of the settings described in this article.

public class MainActivity extends AppCompatActivity
  implements WOWZStatusCallback, View.OnClickListener {

  // The top-level GoCoder API interface
  private WowzaGoCoder goCoder;

  // The GoCoder SDK camera view
  private WOWZCameraView goCoderCameraView;

  // The GoCoder SDK audio device
  private WOWZAudioDevice goCoderAudioDevice;

  // The GoCoder SDK broadcaster
  private WOWZBroadcast goCoderBroadcaster;

  // The broadcast configuration settings
  private WOWZBroadcastConfig goCoderBroadcastConfig;

  // Properties needed for Android 6+ permissions handling
  private static final int PERMISSIONS_REQUEST_CODE = 0x1;
  private boolean mPermissionsGranted = true;
  private String[] mRequiredPermissions = new String[] {
    Manifest.permission.CAMERA,
    Manifest.permission.RECORD_AUDIO
  };

  @Override
  protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Initialize the GoCoder SDK
  goCoder = WowzaGoCoder.init(getApplicationContext(), "GOSK-XXXX-XXXX-XXXX-XXXX-XXXX");

  if (goCoder == null) {
    // If initialization failed, retrieve the last error and display it
    WOWZError goCoderInitError = WowzaGoCoder.getLastError();
    Toast.makeText(this,
      "GoCoder SDK error: " + goCoderInitError.getErrorDescription(),
      Toast.LENGTH_LONG).show();
    return;
  }

  // Associate the WOWZCameraView defined in the U/I layout with the corresponding class member
  goCoderCameraView = (WOWZCameraView) findViewById(R.id.camera_preview);

  // Create an audio device instance for capturing and broadcasting audio
  goCoderAudioDevice = new WOWZAudioDevice();

  // Create a broadcaster instance
  goCoderBroadcaster = new WOWZBroadcast();

  // Create a configuration instance for the broadcaster
  goCoderBroadcastConfig = new WOWZBroadcastConfig(WOWZMediaConfig.FRAME_SIZE_1920x1080);

  // Set the connection properties for the target Wowza Streaming Engine server or Wowza Streaming Cloud live stream
  goCoderBroadcastConfig.setHostAddress("live.someserver.net");
  goCoderBroadcastConfig.setPortNumber(1935);
  goCoderBroadcastConfig.setApplicationName("live");
  goCoderBroadcastConfig.setStreamName("myStream");

  // Designate the camera preview as the video broadcaster
  goCoderBroadcastConfig.setVideoBroadcaster(goCoderCameraView);

  // Designate the audio device as the audio broadcaster
  goCoderBroadcastConfig.setAudioBroadcaster(goCoderAudioDevice);

  // Associate the onClick() method as the callback for the broadcast button's click event
  Button broadcastButton = (Button) findViewById(R.id.broadcast_button);
  broadcastButton.setOnClickListener(this);
  }

  //
  // Called when an activity is brought to the foreground
  //
  @Override
  protected void onResume() {
  super.onResume();

  // If running on Android 6 (Marshmallow) or above, check to see if the necessary permissions
  // have been granted
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    mPermissionsGranted = hasPermissions(this, mRequiredPermissions);
    if (!mPermissionsGranted)
    ActivityCompat.requestPermissions(this, mRequiredPermissions, PERMISSIONS_REQUEST_CODE);
  } else
    mPermissionsGranted = true;

  // Start the camera preview display
  if (mPermissionsGranted && goCoderCameraView != null) {
    if (goCoderCameraView.isPreviewPaused())
    goCoderCameraView.onResume();
    else
    goCoderCameraView.startPreview();
  }

  }

  //
  // Callback invoked in response to a call to ActivityCompat.requestPermissions() to interpret
  // the results of the permissions request
  //
  @Override
  public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
  mPermissionsGranted = true;
  switch (requestCode) {
    case PERMISSIONS_REQUEST_CODE: {
    // Check the result of each permission granted
    for(int grantResult : grantResults) {
      if (grantResult != PackageManager.PERMISSION_GRANTED) {
      mPermissionsGranted = false;
      }
    }
    }
  }
  }

  //
  // Utility method to check the status of a permissions request for an array of permission identifiers
  //
  private static boolean hasPermissions(Context context, String[] permissions) {
  for(String permission : permissions)
    if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
    return false;

  return true;
  }

  //
  // The callback invoked when the broadcast button is tapped
  //
  @Override
  public void onClick(View view) {
  // return if the user hasn't granted the app the necessary permissions
  if (!mPermissionsGranted) return;

  // Ensure the minimum set of configuration settings have been specified necessary to
  // initiate a broadcast streaming session
  WOWZStreamingError configValidationError = goCoderBroadcastConfig.validateForBroadcast();

  if (configValidationError != null) {
    Toast.makeText(this, configValidationError.getErrorDescription(), Toast.LENGTH_LONG).show();
  } else if (goCoderBroadcaster.getStatus().isRunning()) {
    // Stop the broadcast that is currently running
    goCoderBroadcaster.endBroadcast(this);
  } else {
    // Start streaming
    goCoderBroadcaster.startBroadcast(goCoderBroadcastConfig, this);
  }
  }

  //
  // The callback invoked upon changes to the state of the steaming broadcast
  //
  @Override
  public void onWZStatus(final WOWZStatus goCoderStatus) {
  // A successful status transition has been reported by the GoCoder SDK
  final StringBuffer statusMessage = new StringBuffer("Broadcast status: ");

  switch (goCoderStatus.getState()) {
    case WOWZState.STARTING:
    statusMessage.append("Broadcast initialization");
    break;

    case WOWZState.READY:
    statusMessage.append("Ready to begin streaming");
    break;

    case WOWZState.RUNNING:
    statusMessage.append("Streaming is active");
    break;

    case WOWZState.STOPPING:
    statusMessage.append("Broadcast shutting down");
    break;

    case WOWZState.IDLE:
    statusMessage.append("The broadcast is stopped");
    break;

    default:
    return;
  }

  // Display the status message using the U/I thread
  new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
    Toast.makeText(MainActivity.this, statusMessage, Toast.LENGTH_LONG).show();
    }
  });
  }

  //
  // The callback invoked when an error occurs during a broadcast
  //
  @Override
  public void onWOWZError(final WOWZStatus goCoderStatus) {
  // If an error is reported by the GoCoder SDK, display a message
  // containing the error details using the U/I thread
  new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
    Toast.makeText(MainActivity.this,
      "Streaming error: " + goCoderStatus.getLastError().getErrorDescription(),
      Toast.LENGTH_LONG).show();
    }
  });
  }

   //
   // Enable Android's immersive, sticky full-screen mode
   //
  @Override
  public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);

  View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
  if (rootView != null)
    rootView.setSystemUiVisibility(
      View.SYSTEM_UI_FLAG_LAYOUT_STABLE
        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_FULLSCREEN
        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  }

}

More resources