The business status of the room is used to change the behavior of the whiteboard, or to carry custom business logic. These states are included in room.state
and player.state
.
In the real-time room, we can change the value of room.state
by calling specific methods on room
, or directly assign values to some members in room.state
. If the real-time room happens to have automatic recording turned on, these actions will be recorded. During playback, some members of player.state
will also repeat the previous changes of room.state
.
You can read 《Room Business State Management》 to understand the concept and meaning of business state. This chapter only explains each field.
Take reading the globalState
field of the room
object as an example, it can be read by the following code.
var state = room.state.globalState;
For the player
object, the player.state
can be read only after loading the first frame. Otherwise, you may get the following error.
can't read state before load first frame
When this error occurs, you can check the value of player.phase
. As expected, its value should be "waitingFirstFrame"
. In this state, the player has not finished loading the first frame, so naturally it cannot obtain the player.state
object.
At this point, you need to call player.play()
or player.seekToProgressTime(timestamp)
to let the player start loading the first frame. After that, you need to wait for the onLoadFirstFrame
event to occur before reading player.state
.
The following code can ensure that player.state
can be read normally.
var player = null;
whiteWebSdk.replay({slice: "$slice"}, {
onLoadFirstFrame: function() {
// The first frame is loaded successfully, read player.state
console.log(player.state);
},
}).then(function(_player) {
player = _player;
player.play(); // Start playing from the 0th ms position and start loading the first frame
});
Construct a callback method to monitor the changes of the globalState
field.
function onStateChanged(modifyState) {
if (modifyState.globalState) {
// modifyState.globalState is not empty, indicating that globalState has changed
console.log(modifyState.modifyState);
} else {
// The other state fields have changed, we don’t care here, so we don’t deal with it
}
}
After that, we have to register this method as a callback method. For the room
object, we need to listen for the callback of onRoomStateChanged
; for the player
object, we need to listen for the callback of onPlayerStateChanged
. The signatures of these two methods are as follows.
readonly onRoomStateChanged: (modifyState: Partial<RoomState>) => void;
readonly onPlayerStateChanged: (modifyState: Partial<PlayerState>) => void;
Refer to the description in 《Callback Method|Constructing Room and Player Objects》, we know several methods to monitor them, so I won’t repeat them here. .
If you set the useMobXState
field to true
when constructing the WhiteWebSdk
object, the code is as follows.
var whiteWebSdk = new WhiteWebSdk({
appIdentifier: "$APP_IDENTIFIER",
useMobXState: true,
});
Then room.state
and player.state
will become a MobX observable object. This means that when its members change, you can use MobX to monitor its changes and respond automatically.
For example, you can monitor the changes in the globalState
field of room.state
in the following way.
var mobx = require("mobx");
mobx.reaction(function() {return room.state.globalState}, function(globalState) {
// listen to globalState has changed
});
MobX is a transparent functional responsive programming library for the JavaScript community, you can read 《@observable》 to understand what observable object means.
The types of room.state
and player.state
are defined as follows.
// business state of room.state
type RoomState = DisplayerState & {
// Member status of current user
readonly memberState: MemberState;
// current perspective mode
readonly broadcastState: Readonly<BroadcastState>;
// Current view zoom ratio (deprecated)
readonly zoomScale: number;
};
// The business state of player.state
type PlayerState = DisplayerState & {
// current observer mode
readonly observerMode: ObserverMode;
};
// The common business state of room.state and player.state
type DisplayerState = {
// public status of the room
readonly globalState: GlobalState;
// The current member status list of the room
readonly roomMembers: ReadonlyArray<RoomMember>;
// The current scene state of the room
readonly sceneState: SceneState;
// current view state
readonly cameraState: CameraState;
};
room.state.memberState
is the current user's business state, which appears when the user joins the room, and is released after the user leaves the room. Its type is defined as follows.
type MemberState = {
// Current teaching aids, modification is regarded as switching teaching aids
currentApplianceName: ApplianceNames;
// Fill color of current teaching aid
strokeColor: Color;
// The handwriting thickness of the current teaching aid
strokeWidth: number;
// Initialize the font size of the next text added
textSize: number;
// Configuration items of pencil tool
pencilOptions: PencilOptions;
};
enum ApplianceNames {
// Select tool
selector = "selector",
// Laser pointer
laserPointer = "laserPointer",
// pencil tool
pencil = "pencil",
// Rectangle tool
rectangle = "rectangle",
// Circular tool
ellipse = "ellipse",
// Rubber
eraser = "eraser",
// text tool
text = "text",
// Line tool
straight = "straight",
// arrow
arrow = "arrow",
// Hand tool
hand = "hand",
}
// An array composed of 3 to 4 components from 0 to 255, representing the values of R, G, B, and A respectively
type Color = number[];
type PencilOptions = {
// Whether to allow drawing points, after opening, click on the whiteboard with the pencil tool, a point will be drawn
enableDrawPoint: boolean;
// Prohibit bezier curve processing for handwriting
disableBezier: boolean;
// Handwriting thinning algorithm parameter, must be greater than 0.0, the larger the value, the more powerful the thinning
sparseWidth: number;
// Handwriting thinning algorithm parameter, must be greater than 0.0, the larger the value, the more powerful the thinning
sparseHump: number;
}
The memberState
of the current user can be read by others from the displayer.state.roomMembers
array.
for (var member of room.state.roomMembers) {
// Read the memberState field of a user in the room
console.log(member.memberState);
}
You can modify a field in memberState
with the following code.
room.setMembemrState({
currentApplianceName: "pencil",
});
You can also delete a field by setting it to undefined
.
room.setMembemrState({
toDeleteMe: undefined,
});
You can insert custom fields in
memberState
to store your own business information. These custom fields can be monitored/read by others in the roomroom.state.roomMembers
. At the same time, the value of the custom field and future changes will be recorded and reproduced during playback.
room.state.broadcastState
is about the business state of the current perspective, and its type BroadcastState
is defined as follows. You can read 《Anchor and Follower|Viewpoint and Coordinates》 to understand the concept of perspective tracking mode.
type BroadcastState = {
// Current perspective tracking mode
readonly mode: ViewMode;
// The ID of the host in the room, if there is no host, it is undefined
readonly broadcasterId?: number;
}
enum ViewMode {
// Free perspective, will not follow the anchor
Freedom = "freedom",
// Follower's perspective, will follow the anchor's perspective
Follower = "follower",
// From the anchor’s perspective, the followers in the room will follow me
Broadcaster = "broadcaster",
}
We can adjust the viewing angle follow mode by calling room.setViewMode
. For example, the following code can switch us to anchor mode.
room.setViewMode(ViewMode.Broadcaster);
player.state.observerMode
indicates how the whiteboard should deal with the perspective when playing back the video. Its type `ʻObserverMode`` is defined as follows.
enum ObserverMode {
// Director mode
Directory = "directory",
// free mode
Freedom = "freedom",
}
In the "free mode", the user can freely operate the viewing angle. In "Director Mode", the whiteboard will follow the person in the video according to the following rules.
0.0
, 0.0
) and the zoom ratio is 1.0
In particular, if the user adjusts the viewing angle through the device in the "director mode", it will automatically switch to the "free mode".
If you want to switch back, you can switch back to "director mode" with the following code.
player.setObserverMode(ObserverMode.Directory);
displayer.state.globalState
is the custom business state in the room. Any user in the room can read it, modify it, and monitor its changes. It is globally unique in the room. It is created since the room is created and will not be released until the room is deleted.
If displayer
is player
, you can only read it and monitor its changes, but cannot modify it.
If displayer
is room
, you can modify a field with the following code.
room.setGlobalState({
foobar: "hello world",
});
You can also delete a field by setting it to undefined
.
room.setGlobalState({
foobar: undefined,
});
displayer.state.roomMembers
is used to describe the state of all users with "write" permission in the current room. It is an array, and each element of the array is of type RoomMember
, which is defined as follows.
type RoomMember = {
// User ID
readonly memberId: number;
// user's memberState
readonly memberState: MemberState;
// user's session ID
readonly session: string;
// The payload defined when the user joins the room
readonly payload: any;
}
In particular, if a user joins the room with "writable" permission, the user himself will be included in this list. If your business logic needs to exclude users themselves, you can get the user ID by reading displayer.observerId
, and then exclude it by comparing it with the member variable memberId
of the array element. For example, the following code can exclude yourself.
for (var member of displayer.state.roomMembers) {
if (displayer.observerId !== member.memberId) {
// At this time member cannot be the user himself
}
}
displayer.state.sceneState
is used to get the state of the current scene. You can read 《Scene Management》 to understand the concept of scenes.
type SceneState = {
// List of same-level scenes under the current scene group
readonly scenes: ReadonlyArray<Scene>;
// current scene path
readonly scenePath: string;
// The name of the current scene
readonly sceneName: string;
// The address of the direct scene group to which the current scene belongs
readonly contextPath: string;
// The index number of the current scene under the current scene group
readonly index: number;
}
type Scene = {
// Scene name
readonly name: string;
// How many components are in the current scene
readonly componentsCount: number;
// PPT description contained in the current scene
readonly ppt?: PptDescription;
}
displayer.state.cameraState
is used to indicate the current state of the angle of view at this moment. You can understand the concept of perspective by reading 《Viewpoint|Viewpoint and Coordinates》.
type CameraState = {
// The point that the center of the viewing angle is aligned with, the x-axis coordinate in world coordinates
readonly centerX: number;
// The point that the center of the viewing angle is aligned with, the y-axis coordinate in world coordinates
readonly centerY: number;
// Angle of view zoom ratio
readonly scale: number;
// The width of the current whiteboard
readonly width: number;
// The height of the current whiteboard
readonly height: number;
}