...
REST-methods and response statuses
REST-method | Example of REST query | Example of response | Response statuses | Description | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
/mixer/startup |
| 200 - OK 400 - Bad request 409 - Conflict 500 - Internal error | Creates a mixer the provided stream is published for | ||||||||
/mixer/add |
| 200 - OK 404 - Mixer not found 404 - Stream not found 500 - Internal error | Add the RTMP stream to the mixer | ||||||||
/mixer/remove |
| 200 - OK 404 - Mixer not found 404 - Stream not found 500 - Internal error | Remove the RTMP stream from the mixer | ||||||||
/mixer/find_all |
| 200 - OK 404 - Not found 500 - Internal error | Find all mixers | ||||||||
/mixer/terminate |
| 200 - OK 404 - Not found 500 - Internal error | Terminate operation of the mixer | ||||||||
/stream/startRecording |
| 200 - OK 404 - Not found 500 - Internal error | Start recording of the stream in the given media session | ||||||||
/stream/stopRecording |
| 200 - OK 404 - Not found 500 - Internal error | Stop recording the stream in the given media session | ||||||||
/mixer/setAudioVideo |
| 200 - OK 400 - Bad request 404 - Not found 500 - Internal error | Mute/unmute video or change audio level for mexer incoming stream |
Parameters
...
Parameter name
...
Description
...
Example
...
uri
...
Unique identifier of the mixer
...
...
localStreamName
...
Name of the output stream of the mixer
...
stream3
...
remoteStreamName
...
Name of the stream added to the mixer
...
stream1
rtmp://rtmp.flashphoner.com:1935/live/rtmp_stream1
...
mediaSessionId
...
Media session identifier
...
ce92b134-2468-4460-8d06-1ea3c5aabace
...
status
...
Stream status
...
PROCESSED_LOCAL
...
^stream.*
["stream1", "stream2"]
...
Mixer configuration while creating the instance using REST API
Since build 5.2.872 it is possible to pass most of mixer parameters corresponding to flashphoner.properties mixer settings while creating the mixer using /mixer/startup REST query. In this case, parameters will be applied to the created mixer instance only. For example, the following query
Code Block | ||||
---|---|---|---|---|
| ||||
{
"uri": "mixer://mixer1",
"localStreamName": "stream3",
"mixerVideoWidth": 640,
"mixerVideoHeight": 360,
"mixerVideoFps": 24,
"mixerVideoBitrateKbps": 500
} |
will create the mixer with output stream resolution 640x360, fps 24 and bitrate 500 kbps, no matter what settings are set in flashphoner.properties file
The mixer parameters fukll list can be retrieved using /mixer/find_all REST query, for example
...
language | js |
---|---|
theme | RDark |
title | Mixer parameters full list |
collapse | true |
...
/mixer/set_body_watermark |
| 200 - OK 400 - Bad request 404 - Not found | Add watermark to mixer output stream picture | ||||||||
/mixer/set_stream_watermark |
| 200 - OK 400 - Bad request 404 - Not found | Add watermark to one of the mixer input streams pictures in the mixer output stream |
Parameters
Parameter name | Description | Example |
---|---|---|
uri | Unique identifier of the mixer | |
localStreamName | Name of the output stream of the mixer | stream3 |
hasVideo | Mix video | true |
hasAudio | Mix audio | true |
remoteStreamName | Name of the stream added to the mixer | stream1 |
mediaSessionId | Media session identifier | ce92b134-2468-4460-8d06-1ea3c5aabace |
status | Stream status | PROCESSED_LOCAL |
background | Mixer background | background.png |
watermark | Mixer watermark | watermark.png |
mixerLayoutClass | Mixer layout | com.flashphoner.mixerlayout.TestLayout |
streams | Streams list or regular expression for search | ^stream.* ["stream1", "stream2"] |
audioLevel | Incoming stream audio level | 0 |
videoMuted | Mute video | true |
Mixer configuration while creating the instance using REST API
Since build 5.2.872 it is possible to pass most of mixer parameters corresponding to flashphoner.properties mixer settings while creating the mixer using /mixer/startup REST query. In this case, parameters will be applied to the created mixer instance only. For example, the following query
Code Block | ||||
---|---|---|---|---|
| ||||
{
"uri": "mixer://mixer1",
"localStreamName": "stream3",
"mixerVideoWidth": 640,
"mixerVideoHeight": 360,
"mixerVideoFps": 24,
"mixerVideoBitrateKbps": 500
} |
will create the mixer with output stream resolution 640x360, fps 24 and bitrate 500 kbps, no matter what settings are set in flashphoner.properties file
The mixer parameters fukll list can be retrieved using /mixer/find_all REST query, for example
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
[ { "localMediaSessionId": "7c9e5353-8680-4ad2-8a47-1a366091785c", "localStreamName": "m1", "uri": "mixer://m1", "status": "PROCESSED_LOCAL", "hasAudio": true, "hasVideo": true, "record": false, "mediaSessions": [], "mixerLayoutClass": "com.flashphoner.media.mixer.video.presentation.GridLayout", "mixerLayoutDir": "/opt/mixer1-layout", "mixerActivityTimerCoolOffPeriod": 1, "mixerActivityTimerTimeout": -1, "mixerAppName": "defaultApp", "mixerAudioOpusFloatCoding": false, "mixerOutBufferInitialSizemixerAudioSilenceThreshold": 2000-50, "mixerOutBufferStartSizemixerAudioThreads": 1504, "mixerOutBufferPollingTimemixerAutoScaleDesktop": 100true, "mixerOutBufferMaxBufferingsAllowedmixerDebugMode": -1false, "mixerShowSeparateAudioFramemixerDesktopAlign": true"TOP", "mixerTextAutoscalemixerDisplayStreamName": truefalse, "mixerTextColourmixerFontSize": "0xFFFFFF"20, "mixerTextBulkWriteWithBuffermixerFontSizeAudioOnly": true40, "mixerTextBulkWritemixerIdleTimeout": true20000, "mixerTextBackgroundOpacitymixerInBufferingMs": 100200, "mixerTextBackgroundColourmixerIncomingTimeRateLowerThreshold": "0x2B2A2B"0.95, "mixerTextPaddingLeftmixerIncomingTimeRateUpperThreshold": 51.05, "mixerVoiceActivitySwitchDelaymixerMcuAudio": 0false, "mixerVoiceActivityFrameThicknessmixerMcuVideo": 6false, "mixerVoiceActivityFramePositionInnermixerMcuMultithreadedMix": false, "mixerVoiceActivityColourmixerMinimalFontSize": "0x00CC66"1, "mixerVoiceActivitymixerMcuMultithreadedDelivery": truefalse, "mixerVideoWidthmixerOutBufferEnabled": 1280false, "mixerVideoThreadsmixerOutBufferInitialSize": 42000, "mixerVideoStableFpsThresholdmixerOutBufferStartSize": 15150, "mixerVideoQualitymixerOutBufferPollingTime": 24100, "mixerVideoProfileLevelmixerOutBufferMaxBufferingsAllowed": "42c02a"-1, "mixerVideoLayoutDesktopKeyWordmixerShowSeparateAudioFrame": "desktop"true, "mixerVideoHeightmixerTextAutoscale": 720true, "mixerVideoGridLayoutPaddingmixerTextColour": 30"0xFFFFFF", "mixerVideoGridLayoutMiddlePaddingmixerTextBulkWriteWithBuffer": 10true, "mixerVideoFpsmixerTextBulkWrite": 30true, "mixerVideoDesktopLayoutPaddingmixerTextBackgroundOpacity": 30100, "mixerVideoDesktopLayoutInlinePaddingmixerTextBackgroundColour": 10"0x2B2A2B", "mixerVideoBufferLengthmixerTextPaddingLeft": 10005, "mixerVoiceActivitySwitchDelay": 0, "mixerVideoBitrateKbpsmixerVoiceActivityFrameThickness": 20006, "mixerUseSdpStatemixerVoiceActivityFramePositionInner": truefalse, "mixerTypemixerVoiceActivityColour": "NATIVE0x00CC66", "mixerThreadTimeoutMsmixerVoiceActivity": 33true, "mixerTextPaddingTopmixerVideoWidth": 51280, "mixerTextPaddingRightmixerVideoThreads": 4, "mixerTextFontmixerVideoStableFpsThreshold": "Serif"15, "mixerVideoQuality": 24, "mixerTextPaddingBottommixerVideoProfileLevel": 5"42c02a", "mixerTextDisplayRoommixerVideoLayoutDesktopKeyWord": true"desktop", "mixerTextCutTopmixerVideoHeight": 3720, "mixerRealtimemixerVideoGridLayoutPadding": true30, "mixerPruneStreamsmixerVideoGridLayoutMiddlePadding": false10, "audioMixerOutputCodecmixerVideoFps": "alaw"30, "audioMixerOutputSampleRatemixerVideoDesktopLayoutPadding": 4800030, "audioMixerMaxDelaymixerVideoDesktopLayoutInlinePadding": 30010, "mixerAudioOnlyHeightmixerVideoBufferLength": 3601000, "mixerAudioOnlyWidthmixerVideoBitrateKbps": 6402000, "videoOutputCodecmixerUseSdpState":"vp8" true, "mixerTextAlignmixerType": "TOP_CENTERNATIVE", } "mixerThreadTimeoutMs": 33, "mixerTextPaddingTop": 5, "mixerTextPaddingRight": 4, "mixerTextFont": "Serif", "mixerTextPaddingBottom": 5, "mixerTextDisplayRoom": true, "mixerTextCutTop": 3, "mixerRealtime": true, "mixerPruneStreams": false, "audioMixerOutputCodec": "alaw", "audioMixerOutputSampleRate": 48000, "audioMixerMaxDelay": 300, "mixerAudioOnlyHeight": 360, "mixerAudioOnlyWidth": 640, "videoOutputCodec":"vp8", "mixerTextAlign": "TOP_CENTER" } ] |
Sending the REST query to the WCS server
...
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public enum BoxPosition { //attach box to the left LEFT, //attach box to the right RIGHT, //attach box to the top TOP, //attach box to the bottom BOTTOM, //center box in the parent box CENTER, //bottom and center box in the parent box BOTTOM_CENTER, //top and center box in the parent box TOP_CENTER, //attach box to the right-top corner of left adjoining box (in the same parent box) INLINE_HORIZONTAL, //same as INLINE_HORIZONTAL but additionally adds vertical CENTER INLINE_HORIZONTAL_CENTER, //attach box to the left-bottom corner of upper adjoining box (in the same parent box) INLINE_VERTICAL, //same as INLINE_VERTICAL but additionally adds horizontal CENTER INLINE_VERTICAL, //same as INLINE_VERTICAL but additionally adds horizontal CENTER INLINE_VERTICAL_CENTER } |
Then the class should be complied into byte code. To do this, create folder tree accordind to TestLayout class package name
Code Block | ||||
---|---|---|---|---|
| ||||
mkdir -p com/flashphoner/mixerlayout |
and execute the command
Code Block | ||||
---|---|---|---|---|
| ||||
javac -cp /usr/local/FlashphonerWebCallServer/lib/wcs-core.jar ./com/flashphoner/mixerlayout/TestLayout.java |
Now, pack the code compiled to jar file
Code Block | ||||
---|---|---|---|---|
| ||||
jar -cf testlayout.jar ./com/flashphoner/mixerlayout/TestLayout.class |
and copy this file to WCS libraries folder
Code Block | ||||
---|---|---|---|---|
| ||||
cp testlayout.jar /usr/local/FlashphonerWebCallServer/lib |
To use custom mixer layout class, set it to the following parameter in flashphoner.properties file
Code Block | ||
---|---|---|
| ||
mixer_layout_class=com.flashphoner.mixerlayout.TestLayout |
and restart WCS.
With this custom layout, mixer output stream for three input streams will look like:
Cropping pictures in custom layout
To crop a picture around a central point like CropNoPaddingGridLayout, use Box.fillParentNoScale() instead of Box.fillParent() method. The following example places two pictures by name with cropping around center:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
package com.flashphoner.mixerlayout; // Import mixer layout interface import com.flashphoner.media.mixer.video.presentation.BoxPosition; import com.flashphoner.sdk.media.IVideoMixerLayout; // Import YUV frame description import com.flashphoner.sdk.media.YUVFrame; // Import Box class for picture operations import com.flashphoner.media.mixer.video.presentation.Box; // Uncomment this if using build 5.2.878-5.2.976 // import com.flashphoner.server.commons.rmi.data.impl.MixerConfig; // Import Java packages to use import java.awt.*; import java.util.ArrayList; public class SideBySideLayout implements IVideoMixerLayout { // Owner's stream name private static final String USERFOR = "user_for"; // Challenger's stream name private static final String USERAGAINST = "user_against"; /** * Function to compute layout, will be called by mixer before encoding output stream picture * This example computes grid layout * @param yuvFrames - incoming streams raw pictures array in YUV format * @param strings - incoming streams names array * @param canvasWidth - mixer output picture canwas width * @param canvasHeight - mixer output picture canwas heigth * @return array of pictures layouts */ @Override public Layout[] computeLayout(YUVFrame[] yuvFrames, String[] strings, int canvasWidth, int canvasHeight) { // This object represents mixer canvas Box mainBox = new Box(null, canvasWidth, canvasHeight); _CENTER } |
Then the class should be complied into byte code. To do this, create folder tree accordind to TestLayout class package name
Code Block | ||||
---|---|---|---|---|
| ||||
mkdir -p com/flashphoner/mixerlayout |
and execute the command
Code Block | ||||
---|---|---|---|---|
| ||||
javac -cp /usr/local/FlashphonerWebCallServer/lib/wcs-core.jar ./com/flashphoner/mixerlayout/TestLayout.java |
Now, pack the code compiled to jar file
Code Block | ||||
---|---|---|---|---|
| ||||
jar -cf testlayout.jar ./com/flashphoner/mixerlayout/TestLayout.class |
and copy this file to WCS libraries folder
Code Block | ||||
---|---|---|---|---|
| ||||
cp testlayout.jar /usr/local/FlashphonerWebCallServer/lib |
To use custom mixer layout class, set it to the following parameter in flashphoner.properties file
Code Block | ||
---|---|---|
| ||
mixer_layout_class=com.flashphoner.mixerlayout.TestLayout |
and restart WCS.
With this custom layout, mixer output stream for three input streams will look like:
Cropping pictures in custom layout
To crop a picture around a central point like CropNoPaddingGridLayout, use Box.fillParentNoScale() instead of Box.fillParent() method. The following example places two pictures by name with cropping around center:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
package com.flashphoner.mixerlayout; // Import mixer layout interface import com.flashphoner.media.mixer.video.presentation.BoxPosition; import com.flashphoner.sdk.media.IVideoMixerLayout; // Import YUV frame description import com.flashphoner.sdk.media.YUVFrame; // Import Box class for picture operations import com.flashphoner.media.mixer.video.presentation.Box; // Uncomment this if using build 5.2.878-5.2.976 // import com.flashphoner.server.commons.rmi.data.impl.MixerConfig; // Import Java packages to use import java.awt.*; import java.util.ArrayList; public class SideBySideLayout implements IVideoMixerLayout { // Owner's stream name private static final String USERFOR = "user_for"; // Challenger's stream name private static final String USERAGAINST = "user_against"; /** * Function to compute layout, will be called by mixer before encoding output stream picture * This example computes grid layout * @param yuvFrames - incoming streams raw pictures array in YUV format * @param strings - incoming streams names array * @param canvasWidth - mixer output picture canwas width * @param canvasHeight - mixer output picture canwas heigth * @return array of pictures layouts */ @Override public Layout[] computeLayout(YUVFrame[] yuvFrames, String[] strings, int canvasWidth, int canvasHeight) { // This object represents mixer canvas Box mainBox = new Box(null, canvasWidth, canvasHeight); // Container to place CHALLENGER stream pictures Box userForContainer = new Box(mainBox, canvasWidth / 2, canvasHeight); userForContainer.setPosition(BoxPosition.LEFT); // Container to place OWNER stream pictures Box userAgainstContainer = new Box(mainBox, canvasWidth / 2, canvasHeight); userAgainstContainer.setPosition(BoxPosition.RIGHT); // Iterate through incoming stream pictures array for (int c = 0; c < yuvFrames.length; c++) { String name = strings[c]; // Container to place CHALLENGER stream picturesBox container; Box userForContainer = new Box(mainBox, canvasWidth / 2, canvasHeight); userForContainer.setPosition(BoxPosition.LEFT); // ContainerChhose tocontainer placedepending OWNERon stream picturesname Box userAgainstContainer = new Box(mainBox, canvasWidth / 2, canvasHeight);if (name.contains(USERFOR)) { userAgainstContainer.setPosition(BoxPosition.RIGHT); // Iterate through incoming streamcontainer pictures= arrayuserForContainer; for (int c = 0;} celse <if yuvFrames.length; c++(name.contains(USERAGAINST)) { String namecontainer = strings[c]userAgainstContainer; Box container;} else { // Wrong stream name // Chhose container depending on stream name continue; if (name.contains(USERFOR)) { } // containerFill =the userForContainer; container by the stream picture } else if (name.contains(USERAGAINST)) { Box frameBox = Box.computeBoxWithFrame(container, yuvFrames[c]); container = userAgainstContainerframeBox.fillParentNoScale(); } else { // WrongPrepare streaman name array to return layout calculated ArrayList<IVideoMixerLayout.Layout> layout = new continueArrayList<>(); // Calculate mixer }layout mainBox.computeLayout(layout); // Fill the container// byReturn the stream pictureresult Box frameBox = Box.computeBoxWithFrame(container, yuvFrames[creturn layout.toArray(new IVideoMixerLayout.Layout[layout.size()]); frameBox.fillParentNoScale(); } /** } * The function for internal use. * Uncomment this if //using Prepare an array to return layout calculatedbuild 5.2.878-5.2.976 */ //@Override ArrayList<IVideoMixerLayout.Layout> layout = new ArrayList<>(); // Calculate mixer layout mainBox.computeLayout(layout); // Return the result return layout.toArray(new IVideoMixerLayout.Layout[layout.size()]); } /** * The function for internal use. * Uncomment this if using build 5.2.878-5.2.976 */ //@Override //public void setConfig(MixerConfig mixerConfig) { //} } |
Mixer layout management while creating mixer
...
//public void setConfig(MixerConfig mixerConfig) {
//}
}
|
Mixer layout management while creating mixer
Since build 5.2.693 mixer layout can be defined when creating mixer with REST API, for example
Code Block | ||||
---|---|---|---|---|
| ||||
{
"uri": "mixer://mixer1",
"localStreamName": "mixer1",
"mixerLayoutClass": "com.flashphoner.mixerlayout.TestLayout"
} |
Then, layout can be defib=ned for every mixer separately
Mixer output stream encoding profile management
Some browsers do not support playback for H264 streams encoded by certain profiles. To solve it, the following parameter is added since build 5.2.414 to set mixer output stream encoding profile
Code Block | ||
---|---|---|
| ||
mixer_video_profile_level=42c02a |
By default, constrainted baseline level 4.2 profile is set.
Mixer background management and watermarking
Since build 5.2.693 mixer backgroung can be defined and watermark can be added when creating mixer with REST API, for example
Code Block | ||||
---|---|---|---|---|
| ||||
{
"uri": "mixer://mixer1",
"localStreamName": "mixer1",
"watermark": "watermark.png",
"background": "background.png"
} |
By default, files should be placed to /usr/local/FlashphonerWebCallServer/conf folder. Full path to the files can also be set, for example
Code Block | ||||
---|---|---|---|---|
| ||||
{
"uri": "mixer://mixer1",
"localStreamName": "mixer1",
"watermark": "/opt/media/watermark.png",
"background": "/opt/media/background.png"
} |
Adding and changing stream watermark dynamically
Since build 5.2.1349 in is possible to dynamically add or change stream watermark without stopping the mixer. A watermark can be added, changed or moved to another picture location according to coordinates defined using REST API queries:
/mixer/set_body_watermark
- to the whole mixer output stream picture
Code Block | ||||
---|---|---|---|---|
| ||||
{ "uri": "mixer://mixer1m1", "localStreamNamewatermark":"/opt/media/logo.png", "mixer1x":0, "mixerLayoutClassy":0, "com.flashphoner.mixerlayout.TestLayout" } |
Then, layout can be defib=ned for every mixer separately
Mixer output stream encoding profile management
Some browsers do not support playback for H264 streams encoded by certain profiles. To solve it, the following parameter is added since build 5.2.414 to set mixer output stream encoding profile
Code Block | ||
---|---|---|
| ||
mixer_video_profile_level=42c02a |
By default, constrainted baseline level 4.2 profile is set.
Mixer background management and watermarking
...
marginTop":0,
"marginLeft":0,
"marginBottom":0,
"marginRight":0
} |
/mixer/set_stream_watermark
- to a certain input stream picture
Code Block | ||||
---|---|---|---|---|
| ||||
{ "uri":"mixer://m1", "watermark"mixer:"/opt//mixer1media/logo.png", "mediaSessionId": "030bb470-185c-11ed-9fad-918e05233ae9", "localStreamNamex":0, "mixer1y":0, "watermarkmarginTop":0, "watermark.pngmarginLeft":0, "backgroundmarginBottom":0, "background.png" } |
...
marginRight":0
} |
Where
- watermark - watermark file name
- x, y - top left watermark corner coordinates on the stream picture
- marginTop, marginLeft, marginBottom, marginRignt - watermark margins from stream picture borders
If watermark coordinates are out of stream picture bounds, the watermark will be scaled to the bounds using margins.
To move watermark to another location on the stream picture, send the query with the same file name and a new coordinates. To remove watermark from the stream picture, send the query with empty watermark
field
Code Block | ||||
---|---|---|---|---|
| ||||
{ "uri": "mixer://mixer1m1", "localStreamName": "mixer1", "watermark": "/opt/media/watermark.png", "background": "/opt/media/background.png" } |
Stereo sound in mixer output stream
...