PCast™ API
Initializing
Before using a PCast™ object, it must be initialized as shown.
1import com.phenixrts.pcast.PCast;2import com.phenixrts.pcast.PCastInitializeOptions;3import com.phenixrts.pcast.android.AndroidPCastFactory;45PCast pcast = AndroidPCastFactory.createPCast(this);67// #1 Default initialization options8pcast.initialize();910// OR1112// #2 Custom initialization options (initialized by constructor)13final boolean enableProcessTerminationSignalHandling = false;14PCastInitializeOptions initOptions = new PCastInitializeOptions(15 enableProcessTerminationSignalHandling);1617pcast.initialize(initOptions);
Initialize Options
Name | Description |
---|---|
enableProcessTerminationSignalHandling | Controls if process termination signal handling is enabled or not |
configureLogging | Control if phenix logging is enabled |
streamingSourceMapping | Allows partial override of streaming source URIs |
Stream Source Mapping
Optional field that can be provided with PCastInitializeOptions
. It only has an effect on the subscriber side, and only for streams with the "streaming" capability (on both publisher and subscriber side). The property allows you to redirect requests from the SDKs player to your own CDN.
1import com.phenixrts.pcast.PCastInitializeOptions;2import com.phenixrts.pcast.StreamingSourceMapping;34final String patternToReplace = "https:\\/\\/phenixrts\\.com\\/video";5final String replacement = "https://myown.cdn.com";6final StreamingSourceMapping streamingSourceMapping = new StreamingSourceMapping(7 patternToReplace, replacement);89final boolean enableProcessTerminationSignalHandling = false;10final boolean configureLogging = true;1112final PCastInitializeOptions pcastInitOptions = new PCastInitializeOptions(13 enableProcessTerminationSignalHandling,14 configureLogging,15 streamingSourceMapping);
Name | Description |
---|---|
patternToReplace | A regular expression indicating with part of the incoming streaming source URI to replace |
replacement | The replacement string to insert into the streaming source URI |
Note: The regular expression has to be properly escaped to work correctly.
Connect and Authenticate
Follow the example for connecting and authenticating to PCast™.
1import android.util.Log;2import com.phenixrts.pcast.PCast;3import com.phenixrts.pcast.RequestStatus;45// Created via EdgeAuth library6String authenticationToken = ...;7// Previously initialized8PCast pcast = ...;910pcast.start(11 authenticationToken,12 new PCast.AuthenticationCallback() {13 @Override14 public void onEvent(15 PCast pcast,16 RequestStatus requestStatus,17 String sessionId) {18 if (requestStatus == RequestStatus.OK) {19 Log.i("Phenix SDK Example", "PCast started...");20 } else {21 Log.e("Phenix SDK Example", "Failed to start PCast...");22 }23 }24 },25 new PCast.OnlineCallback() {26 @Override27 public void onEvent(PCast pcast) {28 Log.i("Phenix SDK Example", "We are online...");29 }30 },31 new PCast.OfflineCallback() {32 @Override33 public void onEvent(PCast pcast) {34 Log.i("Phenix SDK Example", "We are offline...");35 }36 });
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 |
Disconnect
Please follow the self explanatory example for disconnecting from PCast™.
1import com.phenixrts.pcast.PCast;2import com.phenixrts.pcast.RequestStatus;34// Previously initialized and started5PCast pcast = ...;67pcast.stop();89// Once you are done using PCast (e.g. exiting the app)10pcast.shutdown();
Get Local User Media
Please follow the self explanatory example for getting local user media.
1import com.phenixrts.pcast.FacingMode;2import com.phenixrts.pcast.PCast;3import com.phenixrts.pcast.UserMediaOptions;4import com.phenixrts.pcast.UserMediaStream;5import com.phenixrts.pcast.android.AndroidPCastFactory;67// Previously initialized and started8PCast pcast = ...;910UserMediaOptions gumOptions = new UserMediaOptions();1112// Customize options if desired13gumOptions.getVideoOptions().capabilityConstraints.put(14 DeviceCapability.FACING_MODE, Arrays.asList(new DeviceConstraint(FacingMode.USER)));15gumOptions.getAudioOptions().enabled = false;1617pcast.getUserMedia(18 gumOptions,19 new PCast.UserMediaCallback() {20 @Override21 public void onEvent(22 PCast pcast,23 RequestStatus status,24 UserMediaStream userMediaStream) {25 // Check status and store 'userMediaStream'26 }27 });
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.
1import com.phenixrts.pcast.UserMediaOptions;2import com.phenixrts.pcast.UserMediaStream;34// Previously obtained via 'getUserMedia'5UserMediaStream userMediaStream = ...;67// Previously initialized and used with 'getUserMedia'8UserMediaOptions gumOptions = new UserMediaOptions();910gumOptions.getVideoOptions().capabilityConstraints.put(11 DeviceCapability.FACING_MODE, Arrays.asList(new DeviceConstraint(FacingMode.ENVIRONMENT)));12gumOptions.getVideoOptions().capabilityConstraints.put(13 DeviceCapability.FLASH_MODE, Arrays.asList(new DeviceConstraint(FlashMode.ALWAYS_ON)));14gumOptions.getVideoOptions().capabilityConstraints.put(15 DeviceCapability.HEIGHT,16 Arrays.asList(new DeviceConstraint(720, ConstraintType.EXACT)));17gumOptions.getVideoOptions().capabilityConstraints.put(18 DeviceCapability.WIDTH,19 Arrays.asList(20 new DeviceConstraint(800, ConstraintType.MIN),21 new DeviceConstraint(1500, ConstraintType.MAX)));2223userMediaStream.applyOptions(gumOptions);
Enumerating Source Devices
You can get a list of available source devices.
1import android.util.Log;2import com.phenixrts.pcast.MediaType;3import com.phenixrts.pcast.PCast;4import com.phenixrts.pcast.SourceDeviceInfo;56// Previously initialized and started7PCast pcast = ...;89pcast.enumerateSourceDevices(10 MediaType.VIDEO,11 new PCast.EnumerateSourceDevicesCallback() {12 @Override13 public void onEvent(PCast pcast, SourceDeviceInfo[] devices) {14 // Store devices as needed15 }16 });
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
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
1import android.util.Log;2import com.phenixrts.pcast.MediaType;3import com.phenixrts.pcast.PCast;4import com.phenixrts.pcast.SourceDeviceInfo;5import com.phenixrts.pcast.SourceDeviceType;67// Previously initialized and started8PCast pcast = ...;910pcast.enumerateSourceDevices(11 MediaType.VIDEO,12 new PCast.EnumerateSourceDevicesCallback() {13 @Override14 public void onEvent(PCast pcast, SourceDeviceInfo[] devices) {15 for (SourceDeviceInfo info : devices) {16 if (info.sourceDeviceType == SourceDeviceType.SYSTEM_OUTPUT) {17 Log.i("Phenix SDK Example", "Screencasting is available");18 String screenCaptureDeviceId = info.id;19 // Store screenCaptureDeviceId20 }21 }22 }23 });2425pcast.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
1import android.media.projection.MediaProjection;2import com.phenixrts.pcast.android.AndroidPCastFactory;34// Previously obtained by calling5// android.media.projection.MediaProjectionManager.getMediaProjection(),6// see Android API reference.7MediaProjection mediaProjection = ...;89AndroidPCastFactory.setMediaProjection(mediaProjection);
Finally, pass the screen capture device ID
Next, pass the screen capture device ID to getUserMedia() in the user media options.
1import com.phenixrts.pcast.FacingMode;2import com.phenixrts.pcast.PCast;3import com.phenixrts.pcast.UserMediaOptions;4import com.phenixrts.pcast.UserMediaStream;56// Previously initialized and started7PCast pcast = ...;89// Found by calling enumerateSourceDevices() as described above10String screenCaptureDeviceId = ...;1112UserMediaOptions gumOptions = new UserMediaOptions();1314gumOptions.getVideoOptions().capabilityConstraints.put(15 DeviceCapability.DEVICE_ID, Arrays.asList(new DeviceConstraint(screenCaptureDeviceId)));1617pcast.getUserMedia(18 gumOptions,19 new PCast.UserMediaCallback() {20 @Override21 public void onEvent(22 PCast pcast,23 RequestStatus status,24 UserMediaStream userMediaStream) {25 // Check status and store 'userMediaStream'26 }27 });
Please follow the self explanatory code snippets for understanding above steps.
Publish a Stream
1import android.util.Log;2import com.phenixrts.pcast.MediaStream;3import com.phenixrts.pcast.PCast;4import com.phenixrts.pcast.Publisher;5import com.phenixrts.pcast.RequestStatus;6import com.phenixrts.pcast.StreamEndedReason;7import com.phenixrts.pcast.UserMediaOptions;8import com.phenixrts.pcast.UserMediaStream;910// Previously initialized and started11PCast pcast = ...;12// Previously created via EdgeAuth library13String streamToken = ...;14// Previously obtained via either PCast.subscribe()15// or UserMediaStream.getMediaStream()16MediaStream mediaStream = ...;1718String[] tags = { "my-tag" };1920pcast.publish(21 streamToken,22 mediaStream,23 new PCast.PublishCallback() {24 @Override25 public void onEvent(26 PCast pcast,27 RequestStatus requestStatus,28 Publisher publisher) {29 // Check status and store 'publisher'3031 // The "streamId" of the publisher32 String streamId = publisher.getStreamId();3334 if (publisher.hasEnded()) {35 // Checks if the publisher has ended36 }3738 // Attach publisher ended callback39 publisher.setPublisherEndedCallback(40 new Publisher.PublisherEndedCallback() {41 @Override42 public void onEvent(43 Publisher publisher,44 StreamEndedReason reason,45 String reasonDescription) {46 // Called when the stream has ended47 Log.i("Phenix SDK Example",48 "Publish stream ended with reason ["49 + reasonDescription + "]");50 }51 });5253 // To stop later54 publisher.stop("I-am-done-publishing");55 }56 },57 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 |
Process Raw Frames
The frame-ready API allows for pre-processing of raw audio and video frames before they are encoded and transmitted.
Any processing needs to keep up with the incoming frame rate; otherwise some of the incoming frames will be dropped to compensate.
1import android.graphics.Bitmap;2import com.phenixrts.media.audio.android.AndroidAudioFrame;3import com.phenixrts.media.video.android.AndroidVideoFrame;4import com.phenixrts.pcast.FrameNotification;5import com.phenixrts.pcast.MediaStreamTrack;6import com.phenixrts.pcast.PCast;7import com.phenixrts.pcast.UserMediaStream;8import com.phenixrts.pcast.android.AndroidReadAudioFrameCallback;9import com.phenixrts.pcast.android.AndroidReadVideoFrameCallback;1011// Previously obtained via PCast.getUserMedia12final UserMediaStream userMediaStream = ...;1314final MediaStreamTrack[] videoTracks = userMediaStream.getMediaStream().getVideoTracks();1516for (MediaStreamTrack videoTrack : videoTracks) {17 userMediaStream.setFrameReadyCallback(videoTrack,18 (frameNotification) -> {19 frameNotification.read(new AndroidReadVideoFrameCallback() {20 @Override21 public void onVideoFrameEvent(AndroidVideoFrame videoFrame) {22 final Bitmap pixelBuffer = videoFrame.bitmap;23 final int displayHeightInPixels = pixelBuffer.getHeight();24 final int displayWidthInPixels = pixelBuffer.getWidth();2526 // Manipulate bitmap as needed27 ...2829 frameNotification.write(videoFrame);30 }31 });32 });33}3435final MediaStreamTrack[] audioTracks = userMediaStream.getMediaStream().getAudioTracks();3637for (MediaStreamTrack audioTrack : audioTracks) {38 userMediaStream.setFrameReadyCallback(audioTrack,39 (frameNotification) -> {40 frameNotification.read(new AndroidReadAudioFrameCallback() {41 @Override42 public void onAudioFrameEvent(AndroidAudioFrame audioFrame) {43 // Attenuate audio:44 for (int sampleIndex = 0; sampleIndex < audioFrame.audioSamples.length; ++sampleIndex) {45 audioFrame.audioSamples[sampleIndex] *= 0.1;46 }4748 frameNotification.write(audioFrame);49 }50 });51 });52}
Frame Notification API
Name | Argument | Description |
---|---|---|
read | FrameReadyForProcessingCallback | Retrieves current raw frame in form of an AndroidAudioFrame or AndroidVideoFrame |
write | AndroidAudioFrame/AndroidVideoFrame | Writes back a processed or newly generated frame. The frame can have a different resolution and timestamps |
drop | (none) | Instructs stream to drop the current frame |
AndroidAudioFrame
Name | Type | Description |
---|---|---|
sampleRateInHz | int | Audio sampling frequency, e.g. 48000 |
numberOfChannels | int | Number of channels, e.g. 1 for mono, 2 for stereo |
timestampInMicroseconds | long | Timestamp of current audio frame in us |
audioSamples | short[] | Audio samples; if more than one channel is present, then samples will be interleaved |
AndroidVideoFrame
Name | Type | Description |
---|---|---|
bitmap | android.graphics.Bitmap | Bitmap containing the pixel data. This object also contains other properties such as width and height. |
timestampInMicroseconds | long | Timestamp of current video frame in us |
durationInMicroseconds | long | Duration of the current video frame in us |
Limit Bitrate
The published video bitrate can be limited temporarily if needed. The returned disposable allows you to control for how long the limitation should stay in effect. If limitBandwidth
is called multiple times before any of the previous disposables are released, then only the most recent override will remain in effect until its disposable is released. Relasing any of the disposables from earlier limitBandwidth
calls will have no effect.
To release a Disposable deterministrically, call close
on it.
1import com.phenixrts.common.Disposable;2import com.phenixrts.pcast.Publisher;34// Previously obtained5Publisher publisher = ...;67Disposable disposable = publisher.limitBandwidth(200000);89// ... after some time: force dispose to cancel bandwidth limitation:10disposable.close();
Limit Bitrate Parameters
Name | Type | Description |
---|---|---|
bandwidthLimitInBps (required) | long | Maximum bitrate limit in bps for video |
Subscribe to a Stream
1import android.util.Log;2import com.phenixrts.pcast.MediaStream;3import com.phenixrts.pcast.PCast;4import com.phenixrts.pcast.RequestStatus;5import com.phenixrts.pcast.StreamEndedReason;67// Previously initialized and started8PCast pcast = ...;9// Previously created via EdgeAuth library10String streamToken = ...;1112pcast.subscribe(13 streamToken,14 new PCast.SubscribeCallback() {15 @Override16 public void onEvent(17 PCast pcast,18 RequestStatus requestStatus,19 MediaStream mediaStream) {20 // Check status and store 'mediaStream'2122 // Attach stream ended callback23 mediaStream.setStreamEndedCallback(24 new MediaStream.StreamEndedCallback() {25 @Override26 public void onEvent(27 MediaStream mediaStream,28 StreamEndedReason reason,29 String reasonDescription) {30 Log.i("Phenix SDK Example",31 "Subscriber stream ended with reason ["32 + reasonDescription + "]");33 }34 }35 });3637 // To stop later38 mediaStream.stop();39 }40 });
Subscribe to a Stream Parameters
Name | Type | Description |
---|---|---|
streamToken (required) | String | The publish token is generated using the Phenix EdgeAuth library |
subscribeCallback (required) | PCast.SubsribeCallback | Called upon completion of the operation |
View a Stream
In order to view a stream you have to supply a Surface for the Renderer to draw on.
1import com.phenixrts.pcast.MediaStream;2import com.phenixrts.pcast.Renderer;3import com.phenixrts.pcast.RendererStartStatus;4import com.phenixrts.pcast.android.AndroidVideoRenderSurface;56// Previously obtained via either PCast.subscribe7// or PhenixUserMediaStream.mediaStream8MediaStream mediaStream = ...;910// Previously obtained, e.g., from a SurfaceView11Surface renderSurface = ...;1213Renderer renderer = mediaStream.createRenderer();1415RendererStartStatus status =16 renderer.start(new AndroidVideoRenderSurface(renderSurface));1718if (status == RendererStartStatus.OK) {19 Log.i("Phenix SDK Example", "Renderer started successfully");20} else {21 Log.e("Phenix SDK Example", "Renderer start failed");22}2324// To stop later25renderer.stop();
Renderer options
It is possible to pass additional options when creating a renderer.
1import com.phenixrts.pcast.AspectRatioMode;2import com.phenixrts.pcast.MediaStream;3import com.phenixrts.pcast.Renderer;4import com.phenixrts.pcast.RendererOptions;56// Previously obtained via either PCast.subscribe or UserMediaStream.mediaStream7MediaStream mediaStream = ...;89RendererOptions options = new RendererOptions();10options.aspectRatioMode = AspectRatioMode.FILL;1112Renderer 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 |
Preview Local User Media
1import com.phenixrts.pcast.Renderer;2import com.phenixrts.pcast.UserMediaStream;34// Previously obtained via 'getUserMedia'5UserMediaStream userMediaStream = ...;67Renderer renderer = userMediaStream.getMediaStream().createRenderer();
Muting and Unmuting of Audio
1import com.phenixrts.pcast.Renderer;23// Previously obtained from media stream4Renderer renderer = ...;56boolean isMuted = renderer.isAudioMuted();7renderer.muteAudio();8renderer.unmuteAudio();
Taking a Screenshot
If you would like to show a preview, you can take a still image from a renderer.
1import com.phenixrts.pcast.Renderer;2import com.phenixrts.android.AndroidLastFrameRenderedCallback;34// Previously obtained from media stream and started5Renderer renderer = ...;67renderer.setLastVideoFrameRenderedReceivedCallback(8 new AndroidLastFrameRenderedCallback() {9 @override10 public void onEvent(Renderer renderer, Bitmap videoFrame) {11 // Process the frame as needed12 }13 });1415renderer.requestLastVideoFrameRendered();
You can also take a still image from a local stream.
1import com.phenixrts.pcast.UserMediaStream;2import com.phenixrts.android.AndroidLastFrameCapturedCallback;34// Previously obtained via 'getUserMedia'5UserMediaStream userMediaStream = ...;67userMediaStream.setLastVideoFrameCapturedReceivedCallback(8 new AndroidLastFrameCapturedCallback() {9 @override10 public void onEvent(Renderer renderer, Bitmap videoFrame) {11 // Process the frame as needed12 }13 });1415userMediaStream.requestLastVideoFrameCaptured();
Data Quality Feedback
If you like to show the user feedback about how their internet connectivity affects the stream quality, you can listen for data quality notifications.
1import com.phenixrts.pcast.DataQualityReason;2import com.phenixrts.pcast.DataQualityStatus;3import com.phenixrts.pcast.Publisher;4import com.phenixrts.pcast.Renderer;56// Previously obtained from media stream and started7Renderer renderer = ...;89renderer.setDataQualityChangedCallback(10 new Renderer.DataQualityChangedCallback() {11 @Override12 public void onEvent(13 Renderer renderer,14 DataQualityStatus quality,15 DataQualityReason reason) {16 // Inform user, take action based on status and reason17 }18 });1920// Previously obtained via PCast.publish21Publisher publisher = ...;2223publisher.setDataQualityChangedCallback(24 new Publisher.DataQualityChangedCallback() {25 @Override26 public void onEvent(27 Publisher publisher,28 DataQualityStatus quality,29 DataQualityReason reason) {30 // Inform user, take action based on status and reason31 }32 });
Data Quality Status for Publishers
Status | Reason | Description |
---|---|---|
DataQualityStatus.NO_DATA | DataQualityReason.NONE | The publisher has a bad internet connection and no data is being streamed. |
DataQualityStatus.NO_DATA | DataQualityReason.UPLOAD_LIMITED | The publisher has a bad internet connection and no data is being streamed. |
DataQualityStatus.ALL | DataQualityReason.NONE | Good internet connection and no quality reduction in effect. |
DataQualityStatus.ALL | DataQualityReason.UPLOAD_LIMITED | The publisher has a slow internet connection and the quality of the stream is reduced. |
DataQualityStatus.ALL | DataQualityReason.NETWORK_LIMITED | Subscribers have bad internet connections and the quality of the stream is reduced. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.UPLOAD_LIMITED | The publisher has a bad internet connection and only audio is streamed. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.NETWORK_LIMITED | Subscribers have bad internet connections and only audio is streamed. |
Data Quality Status for Viewers
Status | Reason | Description |
---|---|---|
DataQualityStatus.NO_DATA | DataQualityReason.NONE | The subscriber has a bad internet connection and no data is being received. |
DataQualityStatus.NO_DATA | DataQualityReason.DOWNLOAD_LIMITED | The subscriber has a bad internet connection and no data is being received. |
DataQualityStatus.NO_DATA | DataQualityReason.PUBLISHER_LIMITED | The publisher has a bad internet connection and no data is being received. |
DataQualityStatus.NO_DATA | DataQualityReason.NETWORK_LIMITED | The network is limiting the quality of the stream and no data is being received. |
DataQualityStatus.ALL | DataQualityReason.NONE | Good internet connection and no quality reduction in effect. |
DataQualityStatus.ALL | DataQualityReason.DOWNLOAD_LIMITED | The subscriber has a bad internet connection and the quality of the stream is reduced. |
DataQualityStatus.ALL | DataQualityReason.PUBLISHER_LIMITED | The publisher has a bad internet connection and the quality of the stream is reduced. |
DataQualityStatus.ALL | DataQualityReason.NETWORK_LIMITED | Other subscribers have bad internet connections and the quality of the stream is reduced. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.NONE | Audio only stream, good internet connection and no quality reduction in effect. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.DOWNLOAD_LIMITED | The subscriber has a bad internet connection and is only receiving audio. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.PUBLISHER_LIMITED | The publisher has a bad internet connection and the subscriber is only receiving audio. |
DataQualityStatus.AUDIO_ONLY | DataQualityReason.NETWORK_LIMITED | The network is limiting the quality of the stream and the subscriber is only receiving audio. |
Handling Dimension Changes
Cameras may be switched at runtime and devices may be rotated. Register a handler to receive a notification whenever the video dimension changes.
1import com.phenixrts.pcast.Dimensions;2import com.phenixrts.pcast.Renderer;34// Previously obtained from media stream5Renderer renderer = ...;67renderer.setVideoDisplayDimensionsChangedCallback(8 new Renderer.VideoDisplayDimensionsChangedCallback() {9 @Override10 public void onEvent(11 Renderer renderer,12 Dimensions displayDimensions) {13 // Can get called multiple times while rendering a stream14 // Values in displayDimensions.width, displayDimensions.height15 }16 });