How to build a basic app with GoCoder SDK for Android

Learn how to use Android Studio to build a basic streaming app that uses 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
Configure a broadcast stream
Add broadcast monitoring callbacks
Start streaming
Build and deploy an app
Example MainActivity class

Create an app project


First, you must 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 New Project page of the Create New Project window, click Edit to edit the Package Name, and enter the application package name that was used to generate your SDK license key, 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 19 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 Customize the Activity page, accept the default values and click Finish.
  6.  Make sure the GoCoder SDK library is installed and the permissions are added to AndroidManifest.xml according to the instructions in How to install GoCoder SDK for Android.

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


Next, add 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.
  4. <?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.WZCameraView
        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>

  5. 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">
  6. Enable Android's immersive full-screen mode by adding the onWindowFocusChanged() method to the MainActivity class.
    //
    // Enable Android's sticky immersive 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 WZCameraView goCoderCameraView;

    // The GoCoder SDK audio device
    private WZAudioDevice goCoderAudioDevice;

    // The broadcast configuration settings
    private WZBroadcastConfig 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, you must 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
    WZError 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 the 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) 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;
    
    }
    
    //
    // 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 WZCameraView 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 WZCameraView defined in the U/I layout with the corresponding class member
    goCoderCameraView = (WZCameraView) findViewById(R.id.camera_preview);
    
    // Create an audio device instance for capturing and broadcasting audio
    goCoderAudioDevice = new WZAudioDevice();
  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();    
    }

Configure a broadcast stream


Add the hostAddress, portNumber, applicationName, and streamName for your Wowza Streaming Engine™ server or Wowza Streaming Cloud™ account to the onCreate() method in the MainActivity class.

Note: If you're using Wowza Streaming Cloud, the Connection Code is on the Overview tab of the live stream detail page in the Wowza Streaming Cloud web interface.

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

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

// Set the connection properties for the target Wowza Streaming Engine server or Wowza Cloud account
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);

Add broadcast monitoring callbacks


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

  1. Add the WZStatusCallback 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 WZStatusCallback {
  2. Add the methods defined by the WZStatusCallback 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 steaming broadcast
    //
    @Override
    public void onWZStatus(final WZStatus goCoderStatus) {
     // A successful status transition has been reported by the GoCoder SDK
     final StringBuffer statusMessage = new StringBuffer("Broadcast status: ");
    
     switch (goCoderStatus.getState()) {
      case WZState.STARTING:
       statusMessage.append("Broadcast initialization");
       break;
    
      case WZState.READY:
       statusMessage.append("Ready to begin streaming");
       break;
    
      case WZState.RUNNING:
       statusMessage.append("Streaming is active");
       break;
    
      case WZState.STOPPING:
       statusMessage.append("Broadcast shutting down");
       break;
    
      case WZState.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 WZStatus 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


Before streaming, you must configure the broadcast button to start and stop the stream when pressed.

  1. Add the View.onClickListener interface to the MainActivity class definition.
    // Main app activity class
    public class MainActivity extends AppCompatActivity
      implements  WZStatusCallback, 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 pressed.
    //
    // The callback invoked when the broadcast button is pressed
    //
    @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
      WZStreamingError 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 additions described in this article.

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

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

  // The GoCoder SDK camera view
  private WZCameraView goCoderCameraView;

  // The GoCoder SDK audio device
  private WZAudioDevice goCoderAudioDevice;

  // The GoCoder SDK broadcaster
  private WZBroadcast goCoderBroadcaster;

  // The broadcast configuration settings
  private WZBroadcastConfig 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
    WZError goCoderInitError = WowzaGoCoder.getLastError();
    Toast.makeText(this,
      "GoCoder SDK error: " + goCoderInitError.getErrorDescription(),
      Toast.LENGTH_LONG).show();
    return;
  }

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

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

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

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

  // Set the connection properties for the target Wowza Streaming Engine server or Wowza Cloud account
  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 pressed
  //
  @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
  WZStreamingError 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 WZStatus goCoderStatus) {
  // A successful status transition has been reported by the GoCoder SDK
  final StringBuffer statusMessage = new StringBuffer("Broadcast status: ");

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

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

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

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

    case WZState.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 WZStatus 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 sticky immersive 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);
  }

}

If you're having problems or want to discuss this article, post in our forum.