Android PCast™ Express - PhenixRTS Docs

PCast™ Express

The PCast™ Express extends the PCast™ API to provide a single-step configuration based API for:

This API is intended to be used as a supplement to the Room Express although it can be used to stream all on its own.

Initializing

import android.content.Context;

import com.phenixrts.common.RequestStatus;
import com.phenixrts.environment.android.AndroidContext;
import com.phenixrts.express.PCastExpress;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PCastExpressOptions;
import com.phenixrts.pcast.PCastInitializeOptions;

// IMPORTANT: Before accessing any of the static factories, make sure the context is passed to Phenix:
final Context context = ...;  // e.g. Activity.getApplication();
AndroidContext.setContext(context);

final PCastExpressOptions pcastExpressOptions =
    PCastExpressFactory.createPCastExpressOptionsBuilder((RequestStatus status, String description) -> {
          // Best to restart app, or attempt to re-create PCastExpress
        })
        .buildPCastExpressOptions();

final PCastExpress pcastExpress = PCastExpressFactory.createPCastExpress(pcastExpressOptions);

PCastExpressOptionsBuilder

Name Type Default Description
withAuthenticationToken (required) String The authentication token generated using the Phenix EdgeAuth library.
withPCastUri (optional) String Allows overriding default PCast™ URI.
withPCastInitializationOptions (optional) PCastInitializeOptions Use custom options when initializing PCast™.
buildPCastExpressOptions none Builds the PCastExpressOptions

Publishing Local Media

Publish local user media:

import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ExpressPublisher;
import com.phenixrts.express.PCastExpress;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PublishOptions;
import com.phenixrts.pcast.AudioEchoCancellationMode;
import com.phenixrts.pcast.DeviceCapability;
import com.phenixrts.pcast.DeviceConstraint;
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.UserMediaOptions;
import java.util.Arrays;

final PCastExpress pcastExpress = ...;  // previously obtained

final UserMediaOptions userMediaConstraints = new UserMediaOptions();

userMediaConstraints.getVideoOptions().enabled = true;
userMediaConstraints.getVideoOptions().capabilityConstraints.put(
    DeviceCapability.FACING_MODE,
    Arrays.asList(new DeviceConstraint(FacingMode.USER)));

userMediaConstraints.getAudioOptions().enabled = true;
userMediaConstraints.getAudioOptions().capabilityConstraints.put(
    DeviceCapability.AUDIO_ECHO_CANCELLATION_MODE,
    Arrays.asList(new DeviceConstraint(AudioEchoCancellationMode.ON)));

final PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()
    .withStreamToken("DIGEST:eyJhc...")
    .withMediaConstraints(userMediaConstraints)
    .buildPublishOptions();

pcastExpress.publish(publishOptions, (RequestStatus status, ExpressPublisher publisher) -> {
  if (status == RequestStatus.OK) {
    // Do something with publisher
  } else {
    // Handle error
  }
});

// Create a publisher
final PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()
    .withStreamToken("DIGEST:eyJhc...")
    .withMediaConstraints(userMediaConstraints)
    .buildPublishOptions();

pcastExpress.publish(
    publishOptions, (RequestStatus status, ExpressPublisher publisher) -> {
  if (status == RequestStatus.OK) {
    // Do something with publisher
  } else {
    // Handle error
  }
});

Notes:

Publisher Parameters

Name Type Description
options (required) PublishOptions Publish options
callback (required) PCastExpress.PublishCallback Callback for error/success handling

PublishOptionsBuilder

Name Type Default Description
withMediaConstraints (required) UserMediaOptions getUserMedia options Constraints to get the user media.
withUserMedia (optional) UserMediaStream alternative to withMediaConstraints - you can pass user media stream returned from getUserMedia.
withMonitor (optional) MonitorOptions.SetupFailedCallback, MonitorOptions.StreamEndedCallback, MonitorOptions Options for monitoring a publisher for failure.
withTags (optional) Strings[] Tags for the stream.
withStreamToken (required) String The publish token generated using the Phenix EdgeAuth library.
buildPublishOptions none Builds the PublishOptions

ExpressPublisher Callback Arguments

Name Type Description
status RequestStatus The status of the operation
publisher ExpressPublisher Publisher object

ExpressPublisher

Shares most methods with regular Publisher returned by PCast™, see Publish a Stream.

Name Signature Returns Description
stop () void Stops publisher. Subscribers will receive stream ended.
stop (reason) void Stops publisher with a custom reason. Subscribers will receive StreamEndedReason.CUSTOM reason.
enableAudio () void Unmutes audio.
disableAudio () void Mutes audio.
enableVideo () void Unmutes video.
disableVideo () void Mutes video (black frames).
setDataQualityChangedCallback (callback) void Listen for Data Quality Feedback
limitBandwidth (bandwidthLimitInBps) Disposable Temporarily limit published video bitrate, see Limit Bitrate
getStreamId () String Returns stream ID of publisher
hasEnded () bool Indicates whether publisher has ended, e.g. by stop having been invoked

Subscribing to Published Media

Subscribe to streams published with the Phenix platform

import android.view.SurfaceView;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ExpressSubscriber;
import com.phenixrts.express.PCastExpress;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.SubscribeOptions;
import com.phenixrts.pcast.Renderer;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;

final PCastExpress pcastExpress = ...;  // previously obtained
final SurfaceView view = ...;  // previously obtained

final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());

final SubscribeOptions subscribeOptions = PCastExpressFactory.createSubscribeOptionsBuilder()
    .withStreamId("us-west#us-west1-b.zzzzzzzz.20000000.xxxxxxxx")
    .withStreamToken("DIGEST:eyJhc...")
    .withRenderer(renderSurface)
    .buildSubscribeOptions();

pcastExpress.subscribe(
    subscribeOptions,
    (RequestStatus status, ExpressSubscriber subscriber, Renderer renderer) -> {
  if (status == RequestStatus.OK) {
    // Do something with subscriber

if (renderer != null) {
      // Returned if `withRenderer...` option was enabled - Do something with renderer
    }
  } else {
    // Handle error
  }
});

Notes:

Subscribe Parameters

Name Type Description
options (required) SubscribeOptions Subscribe options
callback (required) PCastExpress.SubscribeCallback Callback for error/success handling

Subscribe Options

Name Type Default Description
withStreamId (required) String The stream ID of the published stream
withStreamToken (required) String The subscribe token generated using the Phenix EdgeAuth library.
withRenderer (optional) AndroidVideoRenderSurface Render layer on which to display stream. If none of the withRenderer... methods are called, no renderer will be instantiated.
withRenderer (optional) none Will trigger instantiation of renderer. Useful for audio only type streams that do not require a render surface.
withRendererOptions (optional) RendererOptions Options passed to renderer. Will trigger instantiation of renderer.
withMonitor (optional) MonitorOptions.SetupFailedCallback, MonitorOptions.StreamEndedCallback, MonitorOptions Options for monitoring a subscriber for failure.
withTags (optional) NSString[] Tags for the stream
buildSubscribeOptions none Builds the SubscribeOptions

ExpressSubscriber

Shares most methods with regular MediaStream returned by PCast™, see Subscribe to a Stream.

Name Signature Returns Description
createRenderer () Renderer Creates a new renderer. This should only be called if none of the withRenderer... builder methods were invoked.
createRenderer (RendererOptions) Renderer Creates a new renderer with RendererOptions. This should only be called if none of the withRenderer... builder methods were invoked.
getAudioTracks () MediaStreamTrack[] Returns all associated audio tracks of this stream
getVideoTracks () MediaStreamTrack[] Returns all associated video tracks of this stream
getTracks () MediaStreamTrack[] Returns all associated tracks of this stream
stop () void Stops subscription. This will trigger the stream ended event.
disableAudio () void Mutes audio.
enableVideo () void Unmutes video.
disableVideo () void Mutes video (black frames).
subscribeToNielsenId3Tag (NielsenId3TagCallback, NielsenId3ErrorCallback) Disposable Register a callback to be called when a new Nielsen ID3 tag is received. When the error callback is called, no further notifications are emitted. You may re-subscribe in the error callback if you want to keep receiving Nielsen ID3 tag after an error.

NielsenId3TagCallback Arguments

Name Type Description
data byte[] The latest Nielsen ID3 tag data

NielsenId3ErrorCallback Arguments

Name Type Description
message String The message describing what caused the error

Monitor

Note: On Android, the monitor options are currently ignored, but the callbacks for stream setup and stream ended will be triggered.

Monitor callbacks and options can be passed to subscribe and publish options builders. The first callback gets invoked only when we internally fail to setup a stream. The second callback gets invoked whenever a stream ends, whether it is due to failure or not. The retry OptionalAction allows you to retry publishing or subscribing to the failed stream. You must test first whether there is a retry action present by calling isPresent as it may not be possible to retry the stream (example: a stream that ended normally cannot be retried). You should call dismiss on the retry action to dismiss it, dispose has the same effect. You also may defer invoking the retry action.

Example Monitor for subscribing

import com.phenixrts.common.OptionalAction;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ExpressSubscriber;
import com.phenixrts.express.MonitorOptions;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.SubscribeOptions;
import com.phenixrts.pcast.StreamEndedReason;

final MonitorOptions monitorOptions = PCastExpressFactory.createMonitorOptionsBuilder()
    .buildMonitorOptions();

final SubscribeOptions subscribeOptions = PCastExpressFactory.createSubscribeOptionsBuilder()
    .withStreamId("us-west#us-west1-b.zzzzzzzz.20000000.xxxxxxxx")
    .withStreamToken("DIGEST:eyJhc...")
    .withMonitor(
        (RequestStatus status, OptionalAction retry) -> {
          if (retry.isPresent()) {
            if (shouldRetry()) {  // <- Your logic goes here
              retry.perform();
            } else {
              retry.dismiss();
            }
          }
        },
        (StreamEndedReason reason, String description, OptionalAction retry) -> {
          if (retry.isPresent()) {
            if (reason == StreamEndedReason.FAILED) {  // <- Just an example
              retry.perform();
            } else {
              retry.dismiss();
            }
          }
        },
        monitorOptions)
    .buildSubscribeOptions();

OptionalAction

Name Signature Returns Description
perform () void Performs the action. This will cause a failure if isPresent is false.
dismiss () void Dismisses the action (if any). Can be called multiple times, will result in isPresent to return false. Invoking dispose has same effect.
isPresent () boolean Indicates whether an action can be performed.

MonitorSetupFailedCallback Callback Arguments

Name Type Description
status RequestStatus The status of the operation.
retry OptionalAction Optionally allow retrying the failed stream.

MonitorStreamEndedCallback Callback Arguments

Name Type Description
reason StreamEndedReason Reason for stream ended.
description String Optional additional ended reason description. Carries custom message.
retry OptionalAction Optionally allow retrying the failed stream. For normally ended streams isPresent will always return false.

Express Get User Media

Get local user media. For now this is merely a wrapper around Get Local User Media.

import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.PCastExpress;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.UserMediaStream;

final PCastExpress pcastExpress = ...;  // previously obtained

final UserMediaOptions userMediaOptions = new UserMediaOptions();

pcastExpress.getUserMedia(userMediaOptions, (RequestStatus status, UserMediaStream userMedia) -> {
  if (status == RequestStatus.OK) {
    // Do something with user media stream
  } else {
    // Handle error
  }
});

Express Get User Media Parameters

Name Type Description
options (required) UserMediaOptions User media options
callback (required) PCastExpress.GetUserMediaCallback Callback for error/success handling

Express Get User Media Callback Arguments

Name Type Description
status RequestStatus The status of the operation.
userMedia UserMediaStream User media stream

Get PCast™

Get the underlying instance of the PCast™. This is preferred to creating another instance as this will introduce more overhead.

import com.phenixrts.express.PCastExpress;
import com.phenixrts.pcast.PCast;

final PCastExpress pcastExpress = ...;  // previously obtained

final PCast pcast = pcastExpress.getPCast();

Handling authentication failure

To observe SDK AuthenticationStatus:

import com.phenixrts.common.AuthenticationStatus;
import com.phenixrts.common.Disposable;

Disposable disposable = ...  // declare a property

this.disposable = pcastExpress.getObservableAuthenticationStatus().subscribe((change) -> {
  if (change == AuthenticationStatus.UNAUTHENTICATED) {
    this.handleUnauthenticatedStatus();
  }
});

To fetch a new fresh Authentication token and set a new fetched token to SDK:

import com.phenixrts.common.RequestStatus;

void fetchANewAuthenticationToken(closure: (token: String) -> Unit) {
    // This method calls a client backend to fetch a new authentication token generated using [EdgeAuth library](../api/#creating-authentication-and-stream-tokens).
    // and returns a fetched token using closure callback
}

void handleUnauthenticatedStatus() {
    fetchANewAuthenticationToken((token) -> {
        // Set a new token to SDK
        final RequestStatus status = this.pcastExpress.setAuthenticationToken(token)
        if (status != PhenixRequestStatus.ok) {
            // Handle error when setting a new token
            // This situation can only occur if the token is invalid and cannot be processed by the SDK.
        }
    });
}

PCastExpress

Name Signature Returns Description
setAuthenticationToken (String) RequestStatus Setting an authentication token in the SDK triggers re-authentication if the current SDK AuthenticationStatus is unauthenticated. Otherwise, the new authentication token will be used during the next SDK re-authentication attempt.
getObservableAuthenticationStatus () Observable(of AuthenticationStatus) Get the observable of the SDK authentication status. Use this to refresh the SDK's authentication token when the AuthenticationStatus becomes 'unauthenticated'.

When the SDK attempts to authenticate with an expired token, it receives an "unauthenticated" status. In this state, publish and subscribe operations are not possible.

The code sample shows how to re-authenticate the SDK when necessary.

Notes:

Clean up

Subscribers and publishers are kept alive for as long as they are being referenced in your app. To force SDK objects to release their resources, you can call dispose on them. PCastExpress will only shut down once it is no longer being referenced or dispose has been called on it.