Dealing With Interruptions on Android Devices

QUESTION:

How can I minimize my app and resume streaming or deal with other interruptions on an Android device?

 

ANSWER:

Here is a guide of how you could potentially write the code to allow the Android app to deal with interruptions.  Please note this is intended as a basic guide and will need some custom work in order to integrate it into your application.  If you have any issues getting this to work, please feel free to contact the support team.

Pausing and Resuming Recording on Android Interruptions
In this guide, we will show how to resume a broadcast from an Android Interruption, such as a Phone Call or Minimizing App.

Feature
We can explain our feature(s) of resumable interrupt recording as such:

Scenario 1: App Interrupt pauses current broadcast session
*Given* I have started a broadcast session
*When* I receive an interrupt in my App (e.g., Phone Call, Minimizing App)
*Then* My recording session is paused

Scenario 2: Return from Interrupt resumes broadcast session
*Given* I have started a broadcast session
*And* I receive an interrupt in my App (e.g., Phone Call, Minimizing App)
*When* I return from the interrupt (e.g., Decline of Phone Call)
*Then* My recording is resumed from the point of interruption

Scenario 3: Return from Background does not resume broadcast session
*Given* I have started a broadcast session
*And* I receive an interrupt in my App (e.g., Phone Call, Minimizing App)
*When* I enter my App into the background (e.g., Accept of Phone Call)
*And* I re-launch the App
*Then* A new broadcast session is started

Implementation
In order to implement the expectations of our feature specification, we need to first establish the Givens in of our scenarios which describe the creation of a broadcast session.

Base
We will use an R5VideoViewController from the Red5 Pro SDK as the base for our broadcast session and logic for maintaining our interrupt and background recording feature specifications.

For additional information on creating a ViewController for streaming on Android, visit the documentation.

View Controller:

public class PublishViewController extends R5VideoViewController {

  protected R5VideoView preview;
  protected R5Stream publish;
  protected R5Configuration config;
  protected boolean isResumable;
  protected String streamName;

  public PublishViewController () {

  }

  protected void start (String streamName) {

  }

  protected void stop () {

  }

  protected void resume (String streamName) {

  }

}

This serves as the initial class template for a ViewController that will handle the logic of the feature specifications, with the internal property declarations to manage the configuration and stream.

Configuration
We'll create a method to generate a class-local configuration that can be used throughout the recording sessions on the PublishViewController:

protected void createConfiguration () {
  config = new R5Configuration(R5StreamProtocol.RTSP,
                              "localhost",
                              8554,
                              "live",
                              2.0);
}



Establishing a Broadcast-able Session
The following method will establish a connection and make a broadcast session eligible for publishing:

protected void preview () {
  Camera camera = null;
  Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
  int cameraCount = Camera.getNumberOfCameras();

  for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) {
    Camera.getCameraInfo(cameraIndex, cameraInfo);

    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
      try {
        camera = Camera.open(cameraIndex);
        break;
      } catch (RuntimeException e) {
        e.printStackTrace();
      }
    }
  }

  R5Camera r5Camera = new R5Camera(camera, 320, 240);
  r5Camera.setBitrate(512);

  R5Microphone r5Microphone = new R5Microphone();

  R5Connection r5Connection = new R5Connection(config);
  r5Connection.delegate = this;

  publish = new R5Stream(r5Connection);
  publish.delegate = this;

  preview = (R5VideoView) rootView.findViewById(R.id.videoPreview);
  preview.attachStream(publish);

  publish.attachCamera(r5Camera);
  publish.attachMic(r5Microphone);

  r5Camera.startPreview();
}

In order to start showing a Broadcasters video without publishing to the Red5 Pro server, we will invoke the configuration and preview in the onCreateView override of PublishViewController:

@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.publish_view, container, false);

  createConfiguration();
  preview();
}


Start, Stop and Resume Actions
Now that we have established the references for config and stream, we can think about the specifics of the actions within a broadcast session.

start:streamName
In the start:streamName method, we will use the stream created upon viewDidLoad and start a publishing session with the publish type of R5RecordTypeRecord:

protected void start (String streamName) {
  this.streamName = streamName;
  showPreview(false);
  publish.publish(streamName, R5Stream.RecordType.Record);
}


stop
In the stop method, we will stop the publishing session, deallocate the currently established stream and reset the preview:

protected void stop () {
  publish.stop();
  publish.delegate = null;
  publish = null;
}


resume:streamName
The resume:streamName method is relatively similar to the start:streamName method, however in resume: we do not assign the class-local streamName (using its value already defined) and specify the R5RecordTypeAppend type:

protected void resume (String streamName) {
  showPreview(false);
  publish.publish(streamName, R5Stream.RecordType.Record);
}


Listening for Notifications
In order to properly handle interrupts and background entrance of your App, assign NSNotification handlers in the viewDidLoad override of PublishViewController:

@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.publish_view, container, false);

  createConfiguration();
  preview();
}

When your Android device enters an "interrupt", your application is still active - meaning not in the background - and is waiting for a response to the interrupt. Such interruptions can be a Phone Call or Minimizing the App. During such interruptions, the User action will determine the following state and notification.

If you chose, for instance, to Decline a phone call, the subsequent method triggered will be onResume. If you chose to Accept the phone call, the subsequent method triggered will be onStop and your App will be put into the background.

onPause
The onPause method is triggered on the observer when the device enters an "interrupt". In such a case, we want to stop or broadcast session, but retain the possibility of resuming the broadcast if the user declines or dismisses the "interrupt" without the application going into the background. A most common case is the Decline of an incoming Phone Call.

@Override
public void onPause () {
  if (publish != null && publish.mode == R5Stream.StreamMode.Publish) {
    isResumable = true;
  }

  stop();
  preview();
}

We first check if we have a stream established and are currently in a publishing session. If so, then we can consider the app in an isResumable state if we were to come back from an "interrupt" without the app going into the background.

onResume
The onResume method is triggered in two cases:
* User has declined an interrupt
* The App is launched from the background

In the first case, we have defined the App in an isResumable state in case we return from an "interrupt" without sending the App into the background. In such as case, we want to invoke the resume:streamName method:

@Override
public void onResume () {
  if (isResumable) {
    isResumable = false;
    resume(streamName);
  }
}

In the second case, we do not want to consider the broadcast resumable. As such, we need to handle when the App does go into the background following an "interrupt".

onStop

@Override
public void onStop () {
  isResumable = false;
  stop();
}


Conclusion
In this example, we created a resumable broadcast from an Android interrupt - such as from a Decline from Phone Call. We used the R5RecordTypeAppend option for R5Stream:publish:type when the App was considered in an isResumable state following an "interrupt" without sending the App into the background.

Cheers,
Holden

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.