[WebService] Tokbox, OpenTok API 筆記
- Tokbox Developer Center @ Official Website
- OpenTok.js reference @ Official Website
Session
串流相關
session.connect(token, completionHandler)
session.disconnect()
session.subscribe(stream, targetElement, properties, completionHandler) -> subscriber
session.unsubscribe(subscriber)
session.publish(publisher, completionHandler)
session.unpublish(publisher)
資訊取得與傳遞:
session.getSubscribersForStream(stream)
session.getPublisherForStream(stream)
session.signal(signal, completionHandler)
事件相關
session.on(type, handler, context)
session.off(type, handler, context)
可用事件
archiveStarted
,archiveStopped
connectionCreated
,connectionDestroyed
sessionConnected
,sessionDisconnected
(見備註)sessionReconnected
,sessionReconnecting
streamCreated
,streamDestroyed
streamPropertyChanged
signal
,signal:type
⚠️
sessionConnected
和sessionDisconnected
事件中的 SessionConnectEvent 已經 deprecated,因此只可用來確認事件觸發的時間點,但在 SessionConnectEvent 中得不到太多資訊。
session.on('connectionCreated', handleConnectionCreated); // 自己和他人的都同時會觸發,可以取得 connectionId
session.on('connectionDestroyed', handleConnectionDestroyed); // 只有他人的會觸發,可以取得 connectionId
session.on('streamCreated', handleStreamCreated); // 只有他人的會觸發,可以取得 stream 和 connectionId
session.on('streamDestroyed', handleStreamDestroyed); // 只有他人的會觸發,可以取得 stream 和 connectionId
// session.on('sessionDisconnected', handleSessionDisconnected); // 只有自己的會觸發,可以取得 connectionId
signal
session.on('signal', (event) => {
event.from.id; // 發送 signal 的 id
event.data; // signal 中一併傳來的 data
});
Signal
Signal 物件
{
"type": "signal:foo",
"cancelable": false,
"_defaultPrevented": false,
"data": "bar",
"from": {
/* Connection Object */
},
"target": {
/* Session Object */
}
}
發送 Signal
// signal(signal, completionHandler)
session.signal({
type: "foo",
to: recipientConnection; // a Connection object
data: "hello"
},
function(error) {
if (error) {
console.log("signal error: " + error.message);
} else {
console.log("signal sent");
}
}
);
Session 物件
// Session 物件
{
"id": "1_MX40NjQ2MTY0Mn5-MTU3NzY3...",
"sessionId": "1_MX40NjQ2MTY0Mn5-MTU3NzY3...",
"currentState": "connected",
"connection": {}, // Connection Object
"connections": {},
"streams": {},
"archives": {},
"capabilities": {
"publish": 1,
"subscribe": 1,
"forceUnpublish": 0,
"forceDisconnect": 0,
"supportsWebRTC": 1
},
"token": "T1==cGFydG5lcl9p...",
"previousState": "connecting",
"apiKey": "46461642",
"staticConfig": {},
"sessionInfo": {}
}
Connect
ConnectionEvent 物件
- Connection Event:
connectionCreated
,connectionDestroyed
ConnectionEvent 比較是從整個 session 的角度觀看,在 session 中:
- 當有新的 client(包含自己)進入 session,或者
- 自己第一次進入 session 時,原本就在 session 內的 client
都會觸發 connectionCreated
事件。當有 client 從 session 中離開時(不包含自己)會觸發 connectionDestroyed
事件。
ConnectionEvent 中會包含有 Connection Object
, cancelable
和 reason
等屬性:
// ConnectionEvent Object
{
"type": "connectionCreated",
"cancelable": false,
"connection": { /*...*/ }, // Connection Object
"reason": undefined,
"target": { /*...*/ }, // Session Object
}
Connection 物件
Connection 物件
每一個連進 session 的使用者都會有一個獨特的 connection ID。從這裡可以取得 Connection
物件:
session.connection
:在 Session 物件中有一個 Connection 屬性,可以在session.connect()
的 callback 中取得connectionId
session.connect(TOKEN_PUBLISHER, (error) => {
if (error) {
handleError(error);
} else {
// 這裡的 session 可以取得 connection 物件
console.log(session.connection);
}
});
connectCreated
事件中,在event
內包含有connect
物件:
session.on('connectionCreated', (event) => {
// 這裡的 event 可以取得 connection 物件
console.log(event.connection);
});
Connection 物件中包含:
connectionId
creationTime
:時間戳記(毫秒),可直接帶入new Date()
使用data
:在後端產生 Token 時可以定義此資料
// Connection Object
{
"id": "6bd8a316-00bf-461f-a0cd-053cab7b20b4",
"connectionId": "6bd8a316-00bf-461f-a0cd-053cab7b20b4",
"creationTime": 1580443544160,
"data": "'{\"name\":\"Hamama\",\"deviceSystemVersion\":\"ios 13.3\"}'",
"capabilities": {
"supportsWebRTC": true
},
"permissions": {
"publish": 1,
"subscribe": 1,
"forceUnpublish": 0,
"forceDisconnect": 0,
"supportsWebRTC": 1
},
"quality": null
}
SessionConnectEvent(Deprecated)
- SessionConnectEvent(deprecated):
sessionConnected
,sessionDisconnected
SessionConnectEvent 比較是從使用者個人的角度,當使用者透過 session.connect()
成功連接後,會觸發 sessionConnected
事件;當使用者透過 session.disconnect()
斷開連接後,會觸發 sessionDisconnected
事件。在 v2.2 之後此事件已經 deprecated,請改用 session.connect()
中的 completeHandler。
Stream
Stream 物件
當使用者呼叫 session.publish()
,一個新的 Stream 會被建立。
- 當一個 stream 加入到 session 時,Session 物件會觸發
streamCreated
事件 - 當一個 stream 被 destroyed 時,Session 物件會觸發
streamDestroyed
事件
// stream object
{
"id": "6713a6e6-7df0-4acc-a7e2-b60e1a83d070",
"streamId": "6713a6e6-7df0-4acc-a7e2-b60e1a83d070",
"name": "",
"creationTime": 1580375164948,
"connection": {}, // Connection 物件
"publisher": {}, // Publisher 物件
"channel": [
{
"id": "video1",
"type": "video",
"active": true,
"orientation": 0,
"width": 640,
"height": 480,
"source": "camera",
"fitMode": "cover"
},
{
"id": "audio1",
"type": "audio",
"active": true,
"orientation": -1,
"width": -1,
"height": -1,
"source": "camera",
"fitMode": "cover"
}
],
"hasAudio": true,
"hasVideo": true,
"videoType": "camera",
"defaultFitMode": "cover",
"videoDimensions": {
"width": 640,
"height": 480,
"orientation": 0
},
"destroyed": false,
"_": {}
}
在 streamCreated
和 streamDestroyed
這些事件的 event
物件中都可以取得 Stream Object
:
SteamEvent 的物件中會包含 stream
, videoType
, publisher
等等:
// StreamEvent
{
"type": "streamCreated",
"cancelable": false,
"stream": {
"id": "57e20522-698a-40f7-bb83-359d7fdde50a",
"streamId": "57e20522-698a-40f7-bb83-359d7fdde50a",
"name": "",
"creationTime": 1578304027311,
"connection": {
"id": "be7272f7-669e-4160-95b7-c216572e2348",
"connectionId": "be7272f7-669e-4160-95b7-c216572e2348",
"creationTime": 1578304022604,
"data": null,
"capabilities": {
"supportsWebRTC": true
},
"permissions": {
"publish": 1,
"subscribe": 1,
"forceUnpublish": 0,
"forceDisconnect": 0,
"supportsWebRTC": 1
},
"quality": null
},
"channel": [
{
"id": "video1",
"type": "video",
"active": true,
"orientation": 0,
"width": 640,
"height": 480,
"source": "camera",
"fitMode": "cover"
},
{
"id": "audio1",
"type": "audio",
"active": true,
"orientation": -1,
"width": -1,
"height": -1,
"source": "camera",
"fitMode": "cover"
}
],
"publisher": null,
"hasAudio": true,
"hasVideo": true,
"videoType": "camera",
"defaultFitMode": "cover",
"videoDimensions": {
"width": 640,
"height": 480,
"orientation": 0
},
"destroyed": false,
"_": {}
},
"reason": null,
"target": {
// ...
}
}
Stream Event
- StreamEvent:
streamCreated
,streamDestroyed
Stream Event 會在有使用者開始或停止將串流**發佈(publish)**到 Session 時觸發。
event.stream
event.reason
session
.on('streamCreated', function (event) {
// streamContainer is a DOM element
subscriber = session.subscribe(event.stream, targetElement);
})
.connect(token);
session
.on('streamDestroyed', function (event) {
console.log('Stream ' + event.stream.name + ' ended. ' + event.reason);
})
.connect(token);
OT
分享螢幕(Screen Sharing)
- OT.checkScreenSharingCapability
- Screen Sharing Guides @ Tokbox Developer Guides
OT.initPublisher
initPublisher @ tokbox
// (static) initPublisher([targetElement], [properties], [completionHandler]) → {Publisher}
import OT from '@opentok/client';
const publisher = OT.initPublisher('publisher', {
name: '', // 預設是空字串
/**
* Layout 相關
**/
width: '264px', // Number 或 String,初始影片寬度
height: '198px', // Number 或 String, 初始影片高度
// 當影片與 div 區塊的比例不同時要如何呈現,包含 'cover' 和 'contain'
fitMode: undefined,
// 定義 Publisher 物件如何被插到 HTML DOM 中
// 包含 replace, after, before, append,預設是 replace
insertMode: 'replace',
// 是否使用預設的 OpenTok UI,true 時可以使用額外的 fitMode, showControls 和 style
insertDefaultUI: true, // Boolean
showControls: true,
style: {
audioLevelDisplayMode: String, // "auto", "off", "on"
archiveStatusDisplayMode: String, // "auto", "off",見備註
backgroundImageURI: String,
buttonDisplayMode: String, // "auto", "off", "on"
nameDisplayMode: String, // "auto", "off", "on"
},
/**
* Audio 相關
**/
// 6,000 - 510,000. Default if 40,000.
audioBitrate: 40000,
// 這個 id 可以透過 OT.getDevices() 取得,或傳入 MediaStreamTrack 物件
audioSource: [deviceId || MediaStreamTrack Object],
audioFallbackEnabled: undefined, // Boolean
disableAudioProcessing: false,
enableStereo: false,
/**
* video 相關
**/
// String, MediaStreamTrack, Boolean, or null
videoSource: undefined, // 見備註
// 選擇要用哪個鏡頭,通常只適用於行動裝置,包含 'user', 'environment', 'left', 'right'
facingMode: 'user',
// 影片的 frame,合法的數值包含 30, 15, 7, and 1.
frameRate: undefined,
mirror: undefined, // Boolean
// 可接受的解析度包含 "1280x720", "640x480", and "320x240"
resolution: "640x480", // 見備註
// 這個設定只適用於 videoSource 屬性為 "application", "screen" 或 "window"
// 可設定的解析度介於 10 ~ 1920 之間
maxResolution: {
width: Number,
height: Number
},
/**
* publish 相關
**/
publishAudio: true, // Session.publish(publisher) 時就發佈串流
publishVideo: true, // Session.publish(publisher) 時就發佈串流
}, completionHandler);
function completionHandler(error) {
// 當使用者同意授權攝像頭和麥克風(成功)時,error 會是 null
if (error) {
// 當使用者不同意授權時,則判斷為失敗,error 會包含 code 和 message 兩個值
const { code, message } = error;
console.log({
code,
message,
})
} else {
console.log("Publisher initialized.");
}
};
- resolution:由於各瀏覽器支援的解析度可能不同,因此實際的解析度需要透過 Publisher 物件/Subscriber 物件的
videoHeight()
和videoWidth()
取得。 - style.archiveStatusDisplayMode:如果你把此值設為
off
,那麼你可以根據 Session Object 發出的archiveStarted
和archiveStopped
事件來呈現 UI 上的提示。 - videoSource:
- 可以透過
OT.getDevices()
取得後帶入,如果將此值設為null
或false
則不會要求攝像頭的權限,因此也不會有 video 被發佈,若只需要聲音的話則可以如此設定。 - 如 果要發佈共享螢幕畫面(screen-sharing stream),則將此值設為
"application"
、"screen"
、或"window"
,Firefox 需要指應為window
,其他瀏覽器則都可以。 - 可以呼叫 OT.checkScreenSharingCapability() 來確認開瀏覽器是否支援共享螢幕(screen-sharing),以及支援的 video sources(
application
,screen
和window
)。 - 在共享螢幕的串流下,預設值如下:
audioFallbackEnabled == false
,maxResolution == {width: 1920, height: 1920}
,mirror == false
,scaleMode == "fit"
、subscriber 的scaleMode
會是"fit"
。
- 可以透過
Publisher 物件
透過 OT.initPublisher()
可以取得 Publisher 物件,Publisher 物件中的 streamId
和 Stream 物件,需要在 session.publish(publishers)
後才能拿到:
// Publisher Object
{
"isWebRTC": true,
"accessAllowed": true,
"id": "OT_e42a2474-6f36-4aeb-a864-db9ff15b95f3",
"element": {},
"session": {},
"streamId": "01969ca3-7a38-4cdf-b8d3-b2ac207daf4e",
"stream": {},
}
Subscriber 物件
透過 session.subscribe(<stream>)
可以取得 Subscriber 物件:
// Subscriber 物件
{
"id": "OT_046054d4-a053-4b2d-8662-0b83f48b1392",
"widgetId": "33c88bb0-f0e1-4ebc-94ec-5c00d8ea6a61",
"session": {}, // Session Object
"stream": {}, // Stream Object
"streamId": "4e2f188a-8ecd-4916-9d94-c98a43336470",
"isWebRTC": true,
"element": DOMElement
}