Android SDK Version Comparison
This page provides information about APIs and features that will no longer be supported by the beta Android SDK release but may be in use by developers that are using prior versions of the SDK. Links to the beta version of the documentation are provided when possible.
A copy of the current documentation is shown with a blue background for easier identification when comparing to beta documentation.
All beta documentation is watermarked BETA to allow easy identification.
v2022.0.3 and Earlier
PCast™ Express
Newer versions of PCast™ Express do not support certain arguments in
- PhenixPCastExpressOptionsBuilder
- PublishOptionsBuilder
- SubscribeOptionsBuilder
Using these arguments with the newer SDK will result in a failure such as unrecognised option
.
Some APIs, such as Publishing Remote Media (Ingest), are not supported by newer versions of the SDK.
In addition, token arguments are required when using the newer SDK (e.g., withStreamToken
or withAuthenticationToken
), and not including tokens will result in a failure such as bad-request
.
Initializing PCast™ Express
Beta version: Initializing
Current version:
import android.content.Context;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.environment.android.AndroidContext;
import com.phenixrts.express.ChannelExpressFactory;
import com.phenixrts.express.ChannelExpressOptions;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PCastExpressOptions;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.express.RoomExpressOptions;
// 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()
.withStreamToken("DIGEST:eyJhc...")
.withUnrecoverableErrorCallback((status, description) -> {
// Best option is to try rebuilding the ChannelExpress instance and/or quit
// your app
})
.buildPCastExpressOptions();
final RoomExpressOptions roomExpressOptions =
RoomExpressFactory.createRoomExpressOptionsBuilder()
.withPCastExpressOptions(pcastExpressOptions)
.buildRoomExpressOptions();
final ChannelExpressOptions channelExpressOptions =
ChannelExpressFactory.createChannelExpressOptionsBuilder()
.withRoomExpressOptions(roomExpressOptions)
.buildChannelExpressOptions();
final ChannelExpress channelExpress = ChannelExpressFactory.createChannelExpress(channelExpressOptions);
PCastExpressOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withBackendUri (required) | String | Url to your backend. We send requests here to authenticate and get streaming tokens. | |
withAuthenticationData (optional) | String | Your authentication data for the user. On every request, this will be sent to your backend through a HTTP POST request and all its attributes would be accessible on the request body. Needs to be valid JSON. | |
withAuthenticationToken (optional) | String | The authentication token generated using the Phenix EdgeAuth library. | |
withUnrecoverableErrorCallback (optional) | PCastExpressOptions.UnrecoverableErrorCallback | Function to be called when authentication fails or a failure occurs that is unrecoverable. | |
withPCastUri (optional) | String | Allows overriding default PCast™ URI. | |
withPCastInitializationOptions (optional) | PCastInitializeOptions | Use custom options when initializing PCast™. | |
withAuthenticationRouteOverride (optional) | String | auth | Allows override of default route for authentication tokens |
withStreamRouteOverride (optional) | String | stream | Allows override of default route for stream tokens |
buildPCastExpressOptions | none | Builds the PCastExpressOptions |
Publishing Local Media
Beta version: Publishing Local Media
Current version:
import android.view.SurfaceView;
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.AudioEchoCancelationMode;
import com.phenixrts.pcast.DeviceCapability;
import com.phenixrts.pcast.DeviceConstraint;
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.Renderer;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
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_CANCELATION_MODE,
Arrays.asList(new DeviceConstraint(AudioEchoCancelationMode.ON)));
final PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()
.withCapabilities(new String[] {"real-time"})
.withMediaConstraints(userMediaConstraints)
.buildPublishOptions();
pcastExpress.publish(publishOptions, (RequestStatus status, ExpressPublisher publisher) -> {
if (status == RequestStatus.OK) {
// Do something with publisher
} else {
// Handle error
}
});
// Create a publisher with an automatically started preview renderer
final SurfaceView view = ...; // previously obtained
final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());
final PublishOptions publishOptionsWithPreview = PCastExpressFactory.createPublishOptionsBuilder()
.withCapabilities(new String[] {"real-time"})
.withMediaConstraints(userMediaConstraints)
.withPreviewRenderer(renderSurface)
.buildPublishOptions();
pcastExpress.publish(
publishOptions, (RequestStatus status, ExpressPublisher publisher, Renderer preview) -> {
if (status == RequestStatus.OK) {
// Do something with publisher and preview renderer
} else {
// Handle error
}
});
✂ Unchanged content not shown
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. | |
withCapabilities (optional) | String[] | The list of all capabilities to publish with. Default is empty array. | |
withPreviewRenderer (optional) | AndroidVideoRenderSurface | Render layer on which to display local preview. If none of the withPreview... methods are called, no preview renderer will be instantiated. | |
withPreviewRenderer (optional) | none | Will trigger instantiation of preview renderer. Useful for audio only type streams that do not require a render surface. | |
withPreviewRendererOptions (optional) | RendererOptions | Options passed to preview renderer. Will trigger instantiation of preview renderer. | |
withMonitor (optional) | MonitorOptions.SetupFailedCallback, MonitorOptions.StreamEndedCallback, MonitorOptions | Options for monitoring a publisher for failure. | |
withConnectOptions (optional) | Strings[] | List of options for publishing. | |
withTags (optional) | Strings[] | Tags for the stream. | |
withStreamToken (optional) | String | The publish token generated using the Phenix EdgeAuth library. | |
buildPublishOptions | none | Builds the PublishOptions |
Publishing Remote Media (Ingest)
Beta version: This API is not supported by newer versions of the Android SDK. To publish remote media, please use the REST API for publishing a stream from a URI.
Current version:
Publish from remote sources into the Phenix platform. This enables us to distribute your source media using the Phenix platform. After publishing users may subscribe to the stream using either pcast subscribe or express subscribe.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ExpressPublisher;
import com.phenixrts.express.PCastExpress;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PublishRemoteOptions;
final PCastExpress pcastExpress = ...; // previously obtained
final PublishRemoteOptions publishRemoteOptions = PCastExpressFactory.createPublishRemoteOptionsBuilder()
.withStreamUri("http://mycdn.example.com/mystream.mp4")
.withCapabilities(new String[] {})
.buildPublishRemoteOptions();
pcastExpress.publishRemote(publishRemoteOptions, (RequestStatus status, ExpressPublisher publisher) -> {
if (status == RequestStatus.OK) {
// Do something with publisher
} else {
// Handle error
}
});
Publish Remote Options Parameters
Name | Type | Description |
---|---|---|
options (required) | PublishRemoteOptions | Publish Remote options |
callback (required) | PCastExpress.PublishCallback | Callback for error/success handling |
PublishRemoteOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withCapabilities (required) | String[] | The list of all capabilities to publish with. | |
withStreamUri (required) | String | Link to remote media (mp4, rtmp, etc.) | |
withStreamToken (optional) | String | The publish token generated using the Phenix EdgeAuth library. | |
withConnectOptions (optional) | Strings[] | List of options for publishing from a remote source. | |
withTags (optional) | Strings[] | Tags for the stream | |
withMaximumFrameRateConstraint (optional) | double | Maximum frame rate constraint. | |
withExactFrameRateConstraint (optional) | double | Exact frame rate constraint. | |
withPrerollSkipDuration (optional) | long | 500 | The amount of time to skip at the beginning of the media in milliseconds. |
buildPublishRemoteOptions | none | Builds the PublishRemoteOptions |
Publish Remote Options Callback Arguments
Name | Type | Description |
---|---|---|
status | RequestStatus | The status of the operation. See Publish Callback Status Codes |
publisher | ExpressPublisher | Phenix publisher object |
Subscribing to Published Media
Beta version: Subscribing to Published Media
Current version:
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")
.withCapabilities(new String[] {"streaming"})
.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
}
});
✂ Unchanged content not shown
Subscribe Options
Name | Type | Default | Description |
---|---|---|---|
withStreamId (required) | String | The stream ID of the published stream | |
withCapabilities (required) | String[] | The list of all capabilities to subscribe with. | |
withStreamToken (optional) | 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. | |
withConnectOptions (optional) | String[] | List of options for subscribing. | |
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). |
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 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, close
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 close 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. |
Channel Express
Newer versions of Channel Express do not support certain arguments in
- PublishOptionsBuilder
- PublishRemoteOptionsBuilder (this builder not supported by newer versions of the SDK)
- JoinRoomOptionsBuilder
- PCastExpressOptionsBuilder
Using these arguments with the newer SDK will result in a failure such as unrecognised option
.
These arguments are documented in either the PCast™ Express or Room Express sections of this page.
In addition, token arguments are required when using the newer SDK (e.g., withStreamToken
or withAuthenticationToken
), and not including tokens will result in a failure such as bad-request
.
View a Channel
Beta version: View a Channel
Join a channel and automatically view the most recent content published to that channel.
import android.view.SurfaceView;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ChannelExpress;
import com.phenixrts.express.ChannelExpressFactory;
import com.phenixrts.express.JoinChannelOptions;
import com.phenixrts.express.JoinRoomOptions;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.pcast.RendererOptions;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
import com.phenixrts.room.RoomService;
final ChannelExpress channelExpress = ...; // previously obtained
final SurfaceView view = ...; // previously obtained
final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());
// Just an example (you can omit renderer options if defaults are ok)
final RendererOptions rendererOptions = new RendererOptions();
rendererOptions.aspectRatioMode = AspectRatioMode.LETTERBOX;
final JoinRoomOptions joinRoomOptions = RoomExpressFactory.createJoinRoomOptionsBuilder()
.withRoomId("us-central#xxxxx#channel")
.withStreamToken("DIGEST:eyJhc...")
.buildJoinRoomOptions();
final JoinChannelOptions joinChannelOptions =
ChannelExpressFactory.createJoinChannelOptionsBuilder()
.withJoinRoomOptions(joinRoomOptions)
.withRenderer(renderSurface)
.withRendererOptions(rendererOptions)
.buildJoinChannelOptions();
this.channelExpress.joinChannel(
joinChannelOptions,
(RequestStatus status, RoomService roomService) -> {
if (status != RequestStatus.OK) {
// Handle room join error
return;
}
// Important: Store room service reference, otherwise we will leave channel again
// as soon as this RoomService instance is garbage collected:
OuterClass.this.currentRoomService = roomService;
},
(RequestStatus status, ExpressSubscriber subscriber, Renderer renderer) -> {
switch (status) {
case OK:
// Successfully subscribed to a stream. No need to hold on to any references
break;
case NO_STREAM_PLAYING:
// No stream playing in channel, update UI accordingy
break;
default:
// We failed to subscribe and retry attempts must have failed
break;
}
});
View Channel Parameters
Name | Type | Description |
---|---|---|
options (required) | Options | Options to join channel with |
joinChannelCallback (required) | ChannelExpress.JoinChannelCallback | Function to call on success/failure of joining the channel. |
subscriberCallback (required) | PCastExpress.SubscribeCallback | Function to call on when the most recent presenter changes. |
JoinChannelOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withJoinRoomOptions (required) | JoinRoomOptions | See JoinRoomOptionsBuilder | |
withStreamToken (required) | NSString | The publish 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. | |
withStreamSelectionStrategy (optional) | StreamSelectionStrategy | StreamSelectionStrategy.MOST_RECENT | Determines how member streams are selected for subscriptions. |
buildJoinChannelOptions | none | Builds the JoinChannelOptions |
Stream Selection Strategy
Strategy | Description |
---|---|
StreamSelectionStrategy.MOST_RECENT | Select the most recent stream. Viewing stream changes any time a stream starts or is updated in the room. |
StreamSelectionStrategy.HIGH_AVAILABILITY | Select streams for increased reliability and redundancy. Viewing stream will only change in the event of a failure of the prior selected stream. |
Express Join Channel Callback Arguments
Name | Type | Description |
---|---|---|
status | PhenixRequestStatus | The status of the operation |
roomService | RoomService | Room service object |
View Channel Subscriber Callback Status Codes
Status | Description |
---|---|
ok | Successfully subscribed to presenter |
no-stream-playing | No presenter in room to subscribe to. Wait for presenter to join. |
varies | Subscribe to presenter failed for other reasons |
Publish to a Channel
Beta version: Publish to a Channel
Current version:
Publish a local or remote media to a channel. Users that are viewing the channel will see your media.
✂ Unchanged content not shown
import android.view.SurfaceView;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ChannelExpress;
import com.phenixrts.express.ChannelExpressFactory;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PublishOptions;
import com.phenixrts.express.PublishToChannelOptions;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.pcast.DeviceCapability;
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.RendererOptions;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
import com.phenixrts.room.ChannelOptions;
import com.phenixrts.room.RoomServiceFactory;
final ChannelExpress channelExpress = ...; // previously obtained
final SurfaceView view = ...; // previously obtained
final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());
// Using ChannelOptions means that the channel may or may not already exist.
// If the channel ID is known in advance, it is recommended to use `withChannelId` instead
// of `withChannelOptions` when assembling the `PublishToChannelOptions` below
final ChannelOptions channelOptions = RoomServiceFactory.createChannelOptionsBuilder()
.withName("MyAwesomeChannel")
// Not required but if it is provided we will use this as the alias instead
// of pre-generating one for you:
.withAlias("MyAwesomeChannelAlias")
.buildChannelOptions();
// Example constraints. Audio and video are enabled by default
final UserMediaOptions mediaConstraints = new UserMediaOptions();
mediaConstraints.getVideoOptions().capabilityConstraints.put(
DeviceCapability.FACING_MODE, Arrays.asList(new DeviceConstraint(FacingMode.USER)));
mediaConstraints.getVideoOptions().capabilityConstraints.put(
DeviceCapability.FRAME_RATE, Arrays.asList(new DeviceConstraint(15)));
mediaConstraints.getVideoOptions().capabilityConstraints.put(
DeviceCapability.HEIGHT, Arrays.asList(new DeviceConstraint(720)));
mediaConstraints.getVideoOptions().capabilityConstraints.put(
DeviceCapability.WIDTH, Arrays.asList(new DeviceConstraint(1280)));
final PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()
.withStreamToken("DIGEST:eyJhc...")
.withMediaConstraints(mediaConstraints)
.withPreviewRenderer(renderSurface)
.buildPublishOptions();
final PublishToChannelOptions publishToChannelOptions =
ChannelExpressFactory.createPublishToChannelOptionsBuilder()
.withChannelOptions(channelOptions)
.withPublishOptions(publishOptions)
.buildPublishToChannelOptions();
channelExpress.publishToChannel(
publishToChannelOptions,
(publishStatus, roomService, publisher, previewRenderer) -> {
if (publishStatus != RequestStatus.OK) {
// Handle channel publish error
return;
}
// Important: Store publisher reference, otherwise we will stop publishing again immediately:
currentPublisher = publisher;
}
);
// OR (without a preview):
channelExpress.publishToChannel(
publishToChannelOptions,
(publishStatus, roomService, publisher) -> {
if (publishStatus != RequestStatus.OK) {
// Handle channel publish error
return;
}
// Important: Store publisher reference, otherwise we will stop publishing again immediately:
currentPublisher = publisher;
}
);
Publish To Channel Parameters
Name | Type | Description |
---|---|---|
options (required) | Options | Options to publish to channel with |
publisherCallback (required) | Function | Function to call on success/failure of publishing to the channel |
PublishToChannelOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withChannelOptions (required) | ChannelOptions | See ChannelOptionsBuilder. If omitted, then withChannelId needs to be provided. | |
withChannelId (required) | String | ID of channel to publish to. If omitted, then withChannelOptions needs to be provided. | |
withPublishOptions (required) | PublishOptions | Either provide this or remote publish options | |
withPublishRemoteOptions (required) | RemotePublishOptions | Either provide this or publish options. | |
withMemberRole (optional) | MemberRole | MemberRole.PRESENTER | Role of member to join channel as (used if not already in channel). |
withStreamType (optional) | StreamType | StreamType.PRESENTATION | Type of stream to publish. |
withScreenName (optional) | String | random unique string | Screen name of self member |
withViewerStreamSelectionStrategy (optional) | StreamSelectionStrategy | StreamSelectionStrategy.MOST_RECENT | Stream selection strategy; must match the strategy channel viewers are using. |
buildPublishToChannelOptions | none | Builds the PublishToChannelOptions |
Notes:
- Wildcard token generation is always enabled when publishing to a channel
ChannelOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withName (required) | String | Name of channel | |
withAlias (optional) | String | generated | Channel Alias |
withDescription (optional) | String | empty | Channel description |
buildChannelOptions | none | Builds the ChannelOptions |
Publish To Channel Callback Arguments
Name | Type | Description |
---|---|---|
status | RequestStatus | The status of the operation |
roomService | RoomService | Phenix room service |
publisher | ExpressPublisher | Publisher object |
Create a Channel (deprecated)
Beta version: Creating a Channel is no longer supported by the Android SDK. Please use the REST API to create a Channel.
Current version:
Creation of Channels from client SDKs is deprecated. Channels should be created by the backend using the REST API.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.ChannelExpress;
import com.phenixrts.room.ChannelOptions;
import com.phenixrts.room.RoomServiceFactory;
final ChannelExpress channelExpress = ...; // previously obtained
final ChannelOptions channelOptions = RoomServiceFactory.createChannelOptionsBuilder()
.withName("MyAwesomeChannel")
// Not required but if it is provided we will use this as the alias instead
// of pre-generating one for you.
.withAlias("MyAwesomeChannelAlias")
.buildChannelOptions();
this.channelExpress.createChannel(
channelOptions,
(status, channel) -> {
if (status != RequestStatus.OK) {
// Handle room create error
return;
}
// use `channel` to e.g. join
});
Express Create Channel Parameters
Name | Type | Description |
---|---|---|
options (required) | ChannelOptions | Options to create channel with |
callback (required) | Function | Function to call on success/failure of creating to the channel. See Create Channel Callback Arguments |
Express Create Channel Callback Arguments
Name | Type | Description |
---|---|---|
status | RequestStatus | The status of the operation. |
channel | ImmutableRoom | Immutable room object |
Room Express
Newer versions of Room Express do not support certain arguments in
- PublishOptionsBuilder
- PublishRemoteOptionsBuilder (this builder not supported by newer versions of the SDK)
- JoinRoomOptionsBuilder
- SubscribeToMemberStreamOptionsBuilder
- PCastExpressOptionsBuilder
Newer versions of Room Express do not support wildcard tokens in the PhenixPublishToRoomOptionsBuilder.
Initializing Room Express
Beta version: Initializing
Current version:
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.express.RoomExpress;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.express.RoomExpressOptions;
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()
.withStreamToken("DIGEST:eyJhc...")
.withUnrecoverableErrorCallback((RequestStatus status, String description) -> {
// Best to restart app, or attempt to re-create PCastExpress
})
.buildPCastExpressOptions();
final RoomExpressOptions roomExpressOptions =
RoomExpressFactory.createRoomExpressOptionsBuilder()
.withPCastExpressOptions(pcastExpressOptions)
.buildPCastExpressOptions();
final RoomExpress roomExpress = RoomExpressFactory.createRoomExpress(roomExpressOptions);
RoomExpressOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withPCastExpressOptions (required) | PCastExpressOptions | See PCastExpressOptionsBuilder | |
buildRoomExpressOptions | none | Builds the RoomExpressOptions |
Join a Room
Beta version: Join a Room
Current version:
Join a room and optionally, automatically subscribe to member changes.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.JoinRoomOptions;
import com.phenixrts.express.RoomExpress;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.room.Member;
import com.phenixrts.room.RoomService;
final RoomExpress roomExpress = ...; // previously obtained
final JoinRoomOptions joinRoomOptions = RoomExpressFactory.createJoinRoomOptionsBuilder()
.withRoomId("us-central#xxxxx#channel")
.withRoomAlias("myRoom42")
.withCapabilities(new String[] {"streaming"})
.buildJoinRoomOptions();
roomExpress.joinRoom(joinRoomOptions, (RequestStatus status, RoomService roomService) -> {
if (status == RequestStatus.OK) {
// Hold on to roomService reference for as long as you wish to stay in the room
} else {
// Handle error
}
});
// With optional member update notification:
this.roomExpress.joinRoom(
joinRoomOptions,
(RequestStatus status, RoomService roomService) -> {
if (status == RequestStatus.OK) {
// Hold on to roomService reference for as long as you wish to stay in the room
} else {
// Handle error
}
},
(Member[] members) -> {
// Do something with room members
});
✂ Unchanged content not shown
JoinRoomOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withRoomId (required) | String | Id of channel to view | |
withRoomAlias (optional) | String | Alias, alternative to ID | |
withCapabilities (required) | String[] | The list of all capabilities to subscribe with. | |
withRole (optional) | MemberRole | MemberRole.AUDIENCE | The Member Role to join with |
withScreenName (optional) | String | The member screen name to join with. A random string will be generated if not provided. | |
withStreams (optional) | Stream[] | [] | The member streams to join with. Empty if not provided |
buildJoinRoomOptions | none | Builds the JoinRoomOptions |
Subscribe to a Member's Stream
Beta version: Subscribe to a Member's Stream
Current version:
Subscribe to a room member's stream and automatically handle audio and video state changes.
import android.view.SurfaceView;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.RoomExpress;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.express.SubscribeToMemberStreamOptions;
import com.phenixrts.room.ImmutableRoom;
import com.phenixrts.room.Member;
import com.phenixrts.room.Stream;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
final RoomExpress roomExpress = ...; // previously obtained
final ImmutableRoom room = ...; // previously obtained
final SurfaceView view = ...; // previously obtained
final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());
// Just an example showing how to get a stream from a member.
// In a real-world app you would want to subscribe to the room-members-observable on the room
// to receive updates when the list of members changes, and then subscribe to the streams-observable
// on each member to access their streams.
final Member member = room.getObservableMembers().getValue()[0];
final Stream memberStream = member.getObservableStreams().getValue()[0];
final SubscribeToMemberStreamOptions options =
RoomExpressFactory.createSubscribeToMemberStreamOptionsBuilder()
.withRenderer(renderSurface)
.buildSubscribeToMemberStreamOptions();
roomExpress.subscribeToMemberStream(
memberStream,
options,
(status, subscriber, renderer) -> {
if (status != RequestStatus.OK) {
// Handle subscribe error
return;
}
// Important: Store subscriber reference, otherwise we will stop subscription immediately:
//currentSubscriber = subscriber;
});
✂ Unchanged content not shown
SubscribeToMemberStreamOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withCapabilities (optional) | String[] | [] | The list of all capabilities to subscribe with |
withRenderer (optional) | AndroidVideoRenderSurface | none | Render surface on which to display stream. If none of the withRenderer... methods are called, no renderer will be instantiated. |
withRenderer (optional) | none | false | Will trigger instantiation of renderer. Useful for audio only type streams that do not require a render surface |
withRendererOptions (optional) | RendererOptions | none | Options passed to renderer. Will trigger instantiation of renderer |
withMonitor (optional) | MonitorOptions.SetupFailedCallback, MonitorOptions.StreamEndedCallback, MonitorOptions | none | Options for monitoring a subscriber for failure |
withConnectOptions (optional) | String[] | [] | List of options for subscribing |
withTags (optional) | String[] | [] | Tags for the stream |
buildSubscribeToMemberStreamOptions | none | Builds the SubscribeToMemberStreamOptions |
Publish to a Room
Beta version: Publish to a Room
Current version:
Publish local or remote media to a room. An error will be returned if a room corresponding to the Room Options passed does not exist. If you have not entered the room via joinRoom or publishToRoom methods then a model for Self will be created.
import android.view.SurfaceView;
import com.phenixrts.common.RequestStatus;
import com.phenixrts.express.PCastExpressFactory;
import com.phenixrts.express.PublishOptions;
import com.phenixrts.express.PublishRemoteOptions;
import com.phenixrts.express.PublishToRoomOptions;
import com.phenixrts.express.RoomExpress;
import com.phenixrts.express.RoomExpressFactory;
import com.phenixrts.pcast.DeviceCapability;
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.RendererOptions;
import com.phenixrts.pcast.UserMediaOptions
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
import com.phenixrts.room.MemberRole;
import com.phenixrts.room.RoomOptions;
import com.phenixrts.room.RoomServiceFactory;
import com.phenixrts.room.StreamType;
final RoomExpress roomExpress = ...; // previously obtained
final SurfaceView view = ...; // previously obtained
final AndroidVideoRenderSurface renderSurface = new AndroidVideoRenderSurface(view.getHolder());
final UserMediaOptions mediaConstraints = new UserMediaOptions();
// Customize constraints if needed
final PublishOptions publishOptions = PCastExpressFactory.createPublishOptionsBuilder()
.withCapabilities(new String[]{"hd", "streaming"})
.withMediaConstraints(mediaConstraints)
.withPreviewRenderer(renderSurface)
.buildPublishOptions();
// Using RoomOptions means that the room may or may not already exist.
// If the room ID is known in advance, it is recommended to use `withRoomId` instead
// of `withRoomOptions` when assembling the `PublishToRoomOptions` below
final RoomOptions roomOptions = RoomServiceFactory.createRoomOptionsBuilder()
.withName("MyAwesomeRoom")
.buildRoomOptions();
final PublishToRoomOptions localPublishToRoomOptions =
RoomExpressFactory.createPublishToRoomOptionsBuilder()
.withStreamType(StreamType.USER)
.withMemberRole(MemberRole.PARTICIPANT)
.withRoomOptions(roomOptions)
.withPublishOptions(publishOptions)
.buildPublishToRoomOptions();
roomExpress.publishToRoom(
localPublishToRoomOptions,
(publishStatus, roomService, publisher, previewRenderer) -> {
if (publishStatus != RequestStatus.OK) {
// Handle channel publish error
return;
}
// Important: Store publisher reference, otherwise we will stop publishing again immediately:
currentPublisher = publisher;
}
);
// OR for a remote stream:
final PublishRemoteOptions remotePublishOptions = PCastExpressFactory
.createPublishRemoteOptionsBuilder()
.withStreamUri("http://example.com/mystream.mp4")
.buildPublishRemoteOptions();
final PublishToRoomOptions remotePublishToRoomOptions =
RoomExpressFactory.createPublishToRoomOptionsBuilder()
.withStreamType(StreamType.USER)
.withMemberRole(MemberRole.PARTICIPANT)
.withRoomOptions(roomOptions)
.withPublishRemoteOptions(remotePublishOptions)
.buildPublishToRoomOptions();
// Remaining code is the same as for local stream
✂ Unchanged content not shown
PublishToRoomOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withRoomOptions (required) | RoomOptions | If omitted, then withRoomId needs to be provided. | |
withRoomId (required) | String | ID of room to publish to. If omitted, then withRoomOptions needs to be provided. | |
withPublishOptions (required) | PublishOptions | Either local or remote publish options are required | |
withPublishRemoteOptions (required) | PublishRemoteOptions | Either local or remote publish options are required | |
withMemberRole (required) | MemberRole | Role of member to join room as (used if not already in room). See Member Roles | |
withStreamType (required) | StreamType | Type of stream to publish. See Stream Types | |
withScreenName (optional) | String | automatically generated | Screen name of self member |
withViewerStreamSelectionStrategy (optional) | StreamSelectionStrategy | StreamSelectionStrategy.MOST_RECENT | Stream Selection Strategy |
withWildcardTokens (optional) | true | Generate wildcard stream tokens to be appended to member's stream uri. Reduces time for subscribing to published stream. | |
buildPublishToRoomOptions | none | Builds the PublishToRoomOptions |
PCast
Newer versions of PCast™ require tokens
(e.g., withStreamToken
or withAuthenticationToken
), and not including tokens will result in a failure such as bad-request
.
Connect and Authenticate
Beta version: Connect and Authenticate
Current version:
Follow the example for connecting and authenticating to PCast™.
import android.util.Log;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.RequestStatus;
// Obtained via the EdgeAuth library
String authenticationToken = ...;
// Previously initialized
PCast pcast = ...;
pcast.start(
authenticationToken,
new PCast.AuthenticationCallback() {
@Override
public void onEvent(
PCast pcast,
RequestStatus requestStatus,
String sessionId) {
if (requestStatus == RequestStatus.OK) {
Log.i("Phenix SDK Example", "PCast started...");
} else {
Log.e("Phenix SDK Example", "Failed to start PCast...");
}
}
},
new PCast.OnlineCallback() {
@Override
public void onEvent(PCast pcast) {
Log.i("Phenix SDK Example", "We are online...");
}
},
new PCast.OfflineCallback() {
@Override
public void onEvent(PCast pcast) {
Log.i("Phenix SDK Example", "We are offline...");
}
});
Connect and Authenticate Parameters
Name | Type | Description |
---|---|---|
authenticationToken (required) | string | The authentication token generated using the Phenix EdgeAuth library |
authenticationCallback (required) | PCast.AuthenticationCallback | Called upon successful authentication or when authentication failed or has to be redone. Upon successful authentication, the authenticationCallback will be called with status=RequestStatus.OK. If at any time a new authenticationToken is required, then the authenticationCallback is called with status=RequestStatus.UNAUTHORIZED to indicate that we are no longer authenticated. |
onlineCallback (required) | PCast.OnlineCallback | Called when the client is connected to the streaming platform |
offlineCallback (required) | PCast.OfflineCallback | Called when the client is disconnected from the streaming platform. Ongoing streams may continue while we are temporarily disconnected. However, no new streams can be started while being disconnected. The client automatically tries to reconnect and will call onlineCallback when it succeeds in doing so or eventually call authenticationCallback to indicate that re-authentication is required. |
Authentication Callback Status Codes
Status | Valid Fields | Description |
---|---|---|
RequestStatus.OK | sessionId | Authentication succeeded, the sessionId is populated |
RequestStatus.UNAUTHORIZED | none | Authentication failed or re-authentication required |
varies | none | Authentication failed for other reasons |
Get Local User Media
Beta version: Get Local User Media
Current version:
Please follow the self explanatory example for getting local user media.
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.UserMediaStream;
import com.phenixrts.pcast.android.AndroidPCastFactory;
// Previously initialized and started
PCast pcast = ...;
UserMediaOptions gumOptions = new UserMediaOptions();
// Customize options if desired
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.FACING_MODE, Arrays.asList(new DeviceConstraint(FacingMode.USER)));
gumOptions.getAudioOptions().enabled = false;
pcast.getUserMedia(
gumOptions,
new PCast.UserMediaCallback() {
@Override
public void onEvent(
PCast pcast,
RequestStatus status,
UserMediaStream userMediaStream) {
// Check status and store 'userMediaStream'
}
});
Get Local User Media Parameters
Name | Type | Description |
---|---|---|
options (required) | UserMediaOptions | The options defining the requested user media stream |
userMediaCallback (required) | PCast.UserMediaCallback | Upon acquiring of the user media stream, the userMediaCallback will be called with status=RequestStatus.OK. If the user media is currently used by another application, then you may receive a code status=RequestStatus.CONFLICT . If the operation fails with status=RequestStatus.FAILED then please check the logs for more information |
Device Capability
Name | Description |
---|---|
DeviceCapability.WIDTH | Width in pixels |
DeviceCapability.HEIGHT | Height in pixels |
DeviceCapability.FRAME_RATE | Number of frames per second |
DeviceCapability.FACING_MODE | Facing mode |
DeviceCapability.FLASH_MODE | Flash mode |
DeviceCapability.DEVICE_ID | Device ID string (obtain from here) |
DeviceCapability.LOCATION | Device Location |
DeviceCapability.POLAR_PATTERN | Polar pattern |
DeviceCapability.AUDIO_ECHO_CANCELATION_MODE | Audio echo cancelation mode |
Constraint Type
Name | Description |
---|---|
ConstraintType.MIN | Hard constraint: Capability must have at least the specified value |
ConstraintType.MAX | Hard constraint: Capability must have at most the specified value |
ConstraintType.EXACT | Hard constraint: Capability must have exactly the specified value |
ConstraintType.IDEAL | Soft constraint: Capability should have specified value, but other values are acceptable (default) |
Facing Mode
Name | Description |
---|---|
FacingMode.AUTOMATIC | Select a facing mode automatically (default) |
FacingMode.ENVIRONMENT | Facing the surrounding environment (e.g., back camera) |
FacingMode.USER | Facing the user (e.g., front camera) |
Flash Mode
Only applicable to video devices
Name | Description |
---|---|
FlashMode.AUTOMATIC | Flash is turned on automatically when needed (default) |
FlashMode.ALWAYS_ON | Flash is on (if available) |
FlashMode.ALWAYS_OFF | Flash is off |
Device Location
Name | Description |
---|---|
Location.AUTOMATIC | Select any device (default) |
Location.UPPER | Mounted on top of phone/tablet |
Location.LOWER | Mounted at bottom of phone/tablet |
Polar Pattern
Only applicable to audio devices
Name | Description |
---|---|
PolarPattern.AUTOMATIC | Automatically select pattern (default) |
PolarPattern.OMNIDIRECTIONAL | Equally sensitive to sound from any direction |
PolarPattern.CARDIOID | Most sensitive to sound from the direction in which the data source points and is (nearly) insensitive to sound from the opposite direction |
PolarPattern.SUBCARDIOID | Most sensitive to sound from the direction in which the data source points and is less sensitive to sound from the opposite direction |
Note: This option is currently not supported on Android
Audio Echo Cancelation Mode
Only applicable to audio devices
Name | Description |
---|---|
AudioEchoCancelationMode.AUTOMATIC | Automatically select AEC mode (default) |
AudioEchoCancelationMode.ON | Enable AEC if available |
AudioEchoCancelationMode.OFF | Disable AEC |
Note (as of v2019.2.0): Automatic mode is currently always set to "off" on Android.
Note 2 (as of v2019.2.0): AudioEchoCancelationMode must be set to ON in the UserMediaOptions for all published streams and RendererOptions for all subscribed streams in order for AEC to work reliably on all Android devices.
Updating Options
Sometimes you find it useful to change the camera while a stream is running or just would like to turn on the flash light temporarily.
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.UserMediaStream;
// Previously obtained via 'getUserMedia'
UserMediaStream userMediaStream = ...;
// Previously initialized and used with 'getUserMedia'
UserMediaOptions gumOptions = new UserMediaOptions();
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.FACING_MODE, Arrays.asList(new DeviceConstraint(FacingMode.ENVIRONMENT)));
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.FLASH_MODE, Arrays.asList(new DeviceConstraint(FlashMode.ALWAYS_ON)));
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.HEIGHT,
Arrays.asList(new DeviceConstraint(720, ConstraintType.EXACT)));
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.WIDTH,
Arrays.asList(
new DeviceConstraint(800, ConstraintType.MIN),
new DeviceConstraint(1500, ConstraintType.MAX)));
userMediaStream.applyOptions(gumOptions);
Enumerating Source Devices
Beta version: Enumerating Source Devices
Current version:
You can get a list of available source devices.
import android.util.Log;
import com.phenixrts.pcast.MediaType;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.SourceDeviceInfo;
// Previously initialized and started
PCast pcast = ...;
pcast.enumerateSourceDevices(
MediaType.VIDEO,
new PCast.EnumerateSourceDevicesCallback() {
@Override
public void onEvent(PCast pcast, SourceDeviceInfo[] devices) {
// Store devices as needed
}
});
Enumerating Source Devices Parameters
Name | Type | Description |
---|---|---|
mediaType (required) | MediaType | The media type for which to enumerate source devices |
SourceDeviceInfo fields
Name | Type | Description |
---|---|---|
id | String | Source device ID |
name | String | Source device Name |
mediaType | MediaType | Source device media type |
deviceType | SourceDeviceType | Source device type |
facingMode | FacingMode | Source device facing mode |
Media Type
Name | Description |
---|---|
MediaType.VIDEO | Video |
MediaType.AUDIO | Audio |
Source Device Type
Name | Description |
---|---|
SourceDeviceType.NULL | Null device (e.g. blank screen or silence) |
SourceDeviceType.PHYSICAL | Physical device (e.g. camera or microphone) |
SourceDeviceType.SYSTEM_OUTPUT | System output capture (screencast) |
Screencasting android 5.0 or later
Beta version: Screencasting
Current version:
You can also stream the screen of your phone.
In order to do this, you must first enumerate the available source devices to find the screencast device ID.
Find the screencast device ID
import android.util.Log;
import com.phenixrts.pcast.MediaType;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.SourceDeviceInfo;
import com.phenixrts.pcast.SourceDeviceType;
// Previously initialized and started
PCast pcast = ...;
pcast.enumerateSourceDevices(
MediaType.VIDEO,
new PCast.EnumerateSourceDevicesCallback() {
@Override
public void onEvent(PCast pcast, SourceDeviceInfo[] devices) {
for (SourceDeviceInfo info : devices) {
if (info.sourceDeviceType == SourceDeviceType.SYSTEM_OUTPUT) {
Log.i("Phenix SDK Example", "Screencasting is available");
String screenCaptureDeviceId = info.id;
// Store screenCaptureDeviceId
}
}
}
});
pcast.enumerateSourceDevices();
The screen capture device requires a valid android.media.projection.MediaProjection object to be passed to the SDK before it can be used. The MediaProjection must stay valid for the duration of the screencast.
Next, pass a valid android.media.projection.MediaProjection object
import android.media.projection.MediaProjection;
import com.phenixrts.pcast.android.AndroidPCastFactory;
// Previously obtained by calling
// android.media.projection.MediaProjectionManager.getMediaProjection(),
// see Android API reference.
MediaProjection mediaProjection = ...;
AndroidPCastFactory.setMediaProjection(mediaProjection);
Finally, pass the screen capture device ID
Next, pass the screen capture device ID to getUserMedia() in the user media options.
import com.phenixrts.pcast.FacingMode;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.UserMediaStream;
// Previously initialized and started
PCast pcast = ...;
// Found by calling enumerateSourceDevices() as described above
String screenCaptureDeviceId = ...;
UserMediaOptions gumOptions = new UserMediaOptions();
gumOptions.getVideoOptions().capabilityConstraints.put(
DeviceCapability.DEVICE_ID, Arrays.asList(new DeviceConstraint(screenCaptureDeviceId)));
pcast.getUserMedia(
gumOptions,
new PCast.UserMediaCallback() {
@Override
public void onEvent(
PCast pcast,
RequestStatus status,
UserMediaStream userMediaStream) {
// Check status and store 'userMediaStream'
}
});
Please follow the self explanatory code snippets for understanding above steps.
Publish a Stream
Beta version: Publish a Stream
Current version:
import android.util.Log;
import com.phenixrts.pcast.MediaStream;
import com.phenixrts.pcast.PCast;
import com.phenixrts.pcast.Publisher;
import com.phenixrts.pcast.RequestStatus;
import com.phenixrts.pcast.StreamEndedReason;
import com.phenixrts.pcast.UserMediaOptions;
import com.phenixrts.pcast.UserMediaStream;
// Previously initialized and started
PCast pcast = ...;
// Previously obtained via EdgeAuth library
String streamToken = ...;
// Previously obtained via either PCast.subscribe()
// or UserMediaStream.getMediaStream()
MediaStream mediaStream = ...;
String[] tags = { "my-tag" };
pcast.publish(
streamToken,
mediaStream,
new PCast.PublishCallback() {
@Override
public void onEvent(
PCast pcast,
RequestStatus requestStatus,
Publisher publisher) {
// Check status and store 'publisher'
// The "streamId" of the publisher
String streamId = publisher.getStreamId();
if (publisher.hasEnded()) {
// Checks if the publisher has ended
}
// Attach publisher ended callback
publisher.setPublisherEndedCallback(
new Publisher.PublisherEndedCallback() {
@Override
public void onEvent(
Publisher publisher,
StreamEndedReason reason,
String reasonDescription) {
// Called when the stream has ended
Log.i("Phenix SDK Example",
"Publish stream ended with reason ["
+ reasonDescription + "]");
}
});
// To stop later
publisher.stop("I-am-done-publishing");
}
},
tags);
Publishing a Stream Parameters
Name | Type | Description |
---|---|---|
streamToken (required) | String | The publish token is generated using the Phenix EdgeAuth library |
mediaStream (required) | MediaStream | The user media stream acquired through PCast.subscribe(...) or locally with UserMediaStream.getMediaStream() |
publishCallback (required) | PCast.PublishCallback | Called upon completion of the operation |
tags (optional) | String[] | Tags that will be provided with the stream notifications to your backend callback endpoint |
StreamEndedReason
Reason | Description |
---|---|
StreamEndedReason.ENDED | The stream ended normally |
StreamEndedReason.FAILED | The stream failed |
StreamEndedReason.CENSORED | The stream was censored |
StreamEndedReason.MAINTENANCE | A maintenance event caused this stream to be terminated |
StreamEndedReason.CAPACITY | The stream was terminated due to capacity limitations |
StreamEndedReason.APP_BACKGROUND | The stream was terminated due to the mobile app entering into the background |
StreamEndedReason.CUSTOM | A custom termination reason is provided in the "reasonDescription" field |
View a Stream
Beta version: View a Stream
Current version:
In order to view a stream you have to supply a Surface for the Renderer to draw on.
import com.phenixrts.pcast.MediaStream;
import com.phenixrts.pcast.Renderer;
import com.phenixrts.pcast.RendererStartStatus;
import com.phenixrts.pcast.android.AndroidVideoRenderSurface;
// Previously obtained via either PCast.subscribe
// or PhenixUserMediaStream.mediaStream
MediaStream mediaStream = ...;
// Previously obtained, e.g., from a SurfaceView
Surface renderSurface = ...;
Renderer renderer = mediaStream.createRenderer();
RendererStartStatus status =
renderer.start(new AndroidVideoRenderSurface(renderSurface));
if (status == RendererStartStatus.OK) {
Log.i("Phenix SDK Example", "Renderer started successfully");
} else {
Log.e("Phenix SDK Example", "Renderer start failed");
}
// To stop later
renderer.stop();
Renderer options
It is possible to pass additional options when creating a renderer.
import com.phenixrts.pcast.AspectRatioMode;
import com.phenixrts.pcast.MediaStream;
import com.phenixrts.pcast.Renderer;
import com.phenixrts.pcast.RendererOptions;
// Previously obtained via either PCast.subscribe or UserMediaStream.mediaStream
MediaStream mediaStream = ...;
RendererOptions options = new RendererOptions();
options.aspectRatioMode = AspectRatioMode.FILL;
Renderer renderer = mediaStream.createRenderer(options);
Properties
Name | Type | Description |
---|---|---|
aspectRatioMode (optional) | AspectRatioMode | How to fill available video render surface |
audioEchoCancelationMode (optional) | AudioEchoCancelationMode | Audio echo cancelation mode |
hardwareAcceleratedDecodingMode (optional) | HardwareAcceleratedDecodingMode | Hardware accelerated decoding mode |
Aspect Ratio Mode
Name | Description |
---|---|
AspectRatioMode.AUTOMATIC | Defaults to fill |
AspectRatioMode.FILL | Fill entire render area. Video may be truncated |
AspectRatioMode.LETTERBOX | Black bars are added on sides or top/bottom of render area, video will not be truncated |
Note: This option is currently only supported for Real-Time streams
Hardware Accelerated Decoding Mode
Name | Description |
---|---|
HardwareAcceleratedDecodingMode.AUTOMATIC | Use hardware decoding on certified devices |
HardwareAcceleratedDecodingMode.ON | Always use hardware decoding |
HardwareAcceleratedDecodingMode.OFF | Always use software decoding |
Room
Newer versions of Room do not support certain arguments in
- PublishOptionsBuilder
- PublishRemoteOptionsBuilder (this builder not supported by newer versions of the SDK)
- JoinRoomOptionsBuilder
- SubscribeToMemberStreamOptionsBuilder
- PCastExpressOptionsBuilder
Newer versions of Room do not support wildcard tokens in the PhenixPublishToRoomOptionsBuilder.
Initializing a Room
Beta version: Initializing
Current version:
First you will need to initialize a room service object. This object is used for creating, joining, and leaving a room. As well, use this object for managing the room you enter (active room), members, and the model of your Self.
Note: PCast™ must be initialized and started when invoking createRoomService
so that a valid session ID is present.
import android.content.Context;
import com.phenixrts.environment.android.AndroidContext;
import com.phenixrts.pcast.PCast;
import com.phenixrts.room.RoomService;
import com.phenixrts.room.RoomServiceFactory;
// 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 PCast pcast = ...; // previously obtained
final RoomService roomService = RoomServiceFactory.createRoomService(pcast);
Initializing Parameters
Name | Type | Description |
---|---|---|
pcast (required) | PCast | Instantiated PCast™ object. Must already be authenticated |
RoomService
Name | Signature | Returns | Description |
---|---|---|---|
getRoomInfo | (roomId, alias, callback) | Room | See Get Room Info |
createRoom | (room, callback) | Room | See Create a Room |
joinRoom | (roomId, alias, callback) | Room | See Join a Room |
leaveRoom | (callback) | void | See Leave a Room |
destroyRoom | (callback) | void | See Destroy a Room |
getSelf | () | Observable of Member) | Observable of self member |
getObservableActiveRoom | () | Observable of Room) | Observable of the active room |
Create a Room (deprecated)
Beta version: Creating a Room is no longer supported by the Android SDK. Please use the REST API to create a Room.
Current version:
Creation of Rooms from client SDKs is deprecated. Rooms should be created by the backend using the REST API.
Create a room with the provided details.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.room.Room;
import com.phenixrts.room.RoomOptions;
import com.phenixrts.room.RoomService;
import com.phenixrts.room.RoomServiceFactory;
import com.phenixrts.room.RoomType;
final RoomService roomService = ...; // previously obtained
final String roomName = "My Room Name";
final String description = "Deep thoughts only";
final RoomOptions roomOptions = RoomServiceFactory.createRoomOptionsBuilder()
.withName(roomName)
.withDescription(description)
.withType(RoomType.MULTI_PARTY_CHAT)
.buildRoomOptions();
roomService.createRoom(
roomOptions,
(RoomService service, RequestStatus status, Room room) -> {
if (status == RequestStatus.OK) {
// Do something with room
} else {
// Handle error
}
});
Create Room Parameters
Name | Type | Description |
---|---|---|
options (required) | RoomOptions | Room creation options |
callback (required) | RoomService.CreateRoomCallback | Callback with the status of the request and the room model |
Create Room Callback Arguments
Name | Type | Description |
---|---|---|
roomService | RoomService | The room service making the callback |
status | RequestStatus | The status of the operation |
room | Room | Immutable room object |
Create Room Callback Status Codes
Status | Description |
---|---|
ok | Create room succeeded. This can also mean that the room already existed |
varies | Create room failed for other reasons |
RoomOptionsBuilder
Name | Type | Default | Description |
---|---|---|---|
withName (required) | String | Name of room | |
withType (required) | RoomType | Room type | |
withAlias (optional) | String | generated | Room Alias |
withDescription (optional) | String | empty | Room description |
buildRoomOptions | none | Builds the RoomOptions |
Join a Room
Beta version: Joining a Room is no longer supported by the Low-Level Android APIs. Use the Room Express API to join a Room.
Current version:
Join a room with the Self model. After successfully joining a room that room becomes the active room and can be returned via the getObservableActiveRoom method.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.room.Room;
import com.phenixrts.room.RoomService;
final RoomService roomService = ...; // previously obtained
// Either provide alias or roomId, other can be null or empty
final String roomId = null;
final String alias = "exampleRoom";
roomService.joinRoom(roomId, alias, (RoomService roomService, RequestStatus status, Room room) -> {
if (status == RequestStatus.OK) {
// Do something with room
} else {
// Handle error
}
});
Join Room Parameters
Name | Type | Description |
---|---|---|
roomId (required) | String | ID of the room |
alias (optional) | String | Alternative to roomId - alias of the room |
callback (required) | RoomService.JoinRoomCallback | Callback with the status of the request and the room model |
Join Room Callback Arguments
Name | Type | Description |
---|---|---|
roomService | RoomService | The room service making the callback |
status | RequestStatus | The status of the operation |
room | Room | Immutable room object |
Join Room Callback Status Codes
Status | Description |
---|---|
ok | Join room succeeded |
not-found | Join room failed. Room does not exist - create room first |
varies | Join room failed for other reasons |
Destroy a Room
Beta version: Destroying a Room is no longer supported by the Android SDK. Please use the REST API to delete a Room.
Current version:
Destroys the current active room assuming your self member has the permissions.
import com.phenixrts.common.RequestStatus;
import com.phenixrts.room.Room;
import com.phenixrts.room.RoomService;
final RoomService roomService = ...; // previously obtained
roomService.destroyRoom((RoomService roomService, RequestStatus status) -> {
if (status == RequestStatus.OK) {
// Successfully destroyed room, no action required
} else {
// Handle error
}
});
Destroy Room Parameters
Name | Type | Description |
---|---|---|
callback (required) | RoomService.DestroyRoomCallback | Callback with the status of the request |
Destroy Room Callback Arguments
Name | Type | Description |
---|---|---|
roomService | RoomService | The room service making the callback |
status | RequestStatus | The status of the operation |
Destroy Room Callback Status Codes
Status | Description |
---|---|
ok | Destroy room succeeded |
varies | Destroy room failed for other reasons |