Protocol spec: better readability

This commit is contained in:
Stéphane L 2017-04-20 23:26:41 +02:00 committed by GitHub
parent dd487a5055
commit 20a8853854

View File

@ -6,77 +6,129 @@ Messages exchanged between the client and the server are JSON objects.
The protocol in general is based on the OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio. The protocol in general is based on the OBS Remote protocol created by Bill Hamilton, with new commands specific to OBS Studio.
### Table of contents ### Table of contents
* [Authentication](#authentication)
* [Events](#events) * [Events](#events)
- [Description](#description) - [Description](#description)
- [Event Types](#event-types) - [Event Types](#event-types)
- ["SwitchScenes"](#switchscenes) - **Scenes**
- ["ScenesChanged"](#sceneschanged) - ["SwitchScenes"](#switchscenes)
- ["SourceOrderChanged"](#sourceorderchanged) - ["ScenesChanged"](#sceneschanged)
- ["SceneItemAdded"](#sceneitemadded) - **Sources / Scene Items**
- ["SceneItemRemoved"](#sceneitemremoved) - ["SourceOrderChanged"](#sourceorderchanged)
- ["SceneItemVisibilityChanged"](#sceneitemvisibilitychanged) - ["SceneItemAdded"](#sceneitemadded)
- ["SceneCollectionChanged"](#scenecollectionchanged) - ["SceneItemRemoved"](#sceneitemremoved)
- ["SceneCollectionListChanged"](#scenecollectionlistchanged) - ["SceneItemVisibilityChanged"](#sceneitemvisibilitychanged)
- ["SwitchTransition"](#switchtransition) - **Scene Collections**
- ["TransitionDurationChanged"](#transitiondurationchanged) - ["SceneCollectionChanged"](#scenecollectionchanged)
- ["TransitionListChanged"](#transitionlistchanged) - ["SceneCollectionListChanged"](#scenecollectionlistchanged)
- ["TransitionBegin"](#transitionbegin) - **Transitions**
- ["PreviewSceneChanged"](#previewscenechanged) - ["SwitchTransition"](#switchtransition)
- ["StudioModeSwitched"](#studiomodeswitched) - ["TransitionDurationChanged"](#transitiondurationchanged)
- ["ProfileChanged"](#profilechanged) - ["TransitionListChanged"](#transitionlistchanged)
- ["ProfileListChanged"](#profilelistchanged) - ["TransitionBegin"](#transitionbegin)
- ["StreamStarting"](#streamstarting) - **Studio Mode**
- ["StreamStarted"](#streamstarted) - ["PreviewSceneChanged"](#previewscenechanged)
- ["StreamStopping"](#streamstopping) - ["StudioModeSwitched"](#studiomodeswitched)
- ["StreamStopped"](#streamstopped) - **Profiles**
- ["RecordingStarting"](#recordingstarting) - ["ProfileChanged"](#profilechanged)
- ["RecordingStarted"](#recordingstarted) - ["ProfileListChanged"](#profilelistchanged)
- ["RecordingStopping"](#recordingstopping) - **Streaming**
- ["RecordingStopped"](#recordingstopped) - ["StreamStarting"](#streamstarting)
- ["StreamStatus"](#streamstatus) - ["StreamStarted"](#streamstarted)
- ["Exiting"](#exiting) - ["StreamStopping"](#streamstopping)
- ["StreamStopped"](#streamstopped)
- ["StreamStatus"](#streamstatus)
- **Recording**
- ["RecordingStarting"](#recordingstarting)
- ["RecordingStarted"](#recordingstarted)
- ["RecordingStopping"](#recordingstopping)
- ["RecordingStopped"](#recordingstopped)
- **Other**
- ["Exiting"](#exiting)
* [Requests](#requests) * [Requests](#requests)
- [Description](#description-1) - [Description](#description-1)
- [Request Types](#request-types) - [Request Types](#request-types)
- ["GetVersion"](#getversion) - **General**
- ["GetAuthRequired"](#getauthrequired) - ["GetVersion"](#getversion)
- ["Authenticate"](#authenticate) - ["GetAuthRequired"](#getauthrequired)
- ["GetCurrentScene"](#getcurrentscene) - ["Authenticate"](#authenticate)
- ["SetCurrentScene"](#setcurrentscene) - **Scenes**
- ["GetSceneList"](#getscenelist) - ["GetCurrentScene"](#getcurrentscene)
- ["SetSourceRender"](#setsourcerender) - ["SetCurrentScene"](#setcurrentscene)
- ["GetStudioModeStatus"](#getstudiomodestatus) - ["GetSceneList"](#getscenelist)
- ["SetPreviewScene"](#setpreviewscene) - **Studio Mode**
- ["TransitionToProgram"](#transitiontoprogram) - ["GetStudioModeStatus"](#getstudiomodestatus)
- ["EnableStudioMode"](#enablestudiomode) - ["SetPreviewScene"](#setpreviewscene)
- ["DisableStudioMode"](#disablestudiomode) - ["TransitionToProgram"](#transitiontoprogram)
- ["ToggleStudioMode"](#togglestudiomode) - ["EnableStudioMode"](#enablestudiomode)
- ["StartStopStreaming"](#startstopstreaming) - ["DisableStudioMode"](#disablestudiomode)
- ["StartStopRecording"](#startstoprecording) - ["ToggleStudioMode"](#togglestudiomode)
- ["StartStreaming"](#startstreaming) - **Streaming**
- ["StopStreaming"](#stopstreaming) - ["StartStopStreaming"](#startstopstreaming)
- ["StartRecording"](#startrecording) - ["StartStreaming"](#startstreaming)
- ["StopRecording"](#stoprecording) - ["StopStreaming"](#stopstreaming)
- ["GetStreamingStatus"](#getstreamingstatus) - ["GetStreamingStatus"](#getstreamingstatus)
- ["GetTransitionList"](#gettransitionlist) - **Recording**
- ["GetCurrentTransition"](#getcurrenttransition) - ["StartStopRecording"](#startstoprecording)
- ["SetCurrentTransition"](#setcurrenttransition) - ["StartRecording"](#startrecording)
- ["SetTransitionDuration"](#settransitionduration) - ["StopRecording"](#stoprecording)
- ["GetTransitionDuration"](#gettransitionduration) - ["GetStreamingStatus"](#getstreamingstatus)
- ["SetVolume"](#setvolume) - **Transitions**
- ["GetVolume"](#getvolume) - ["GetTransitionList"](#gettransitionlist)
- ["SetMute"](#setmute) - ["GetCurrentTransition"](#getcurrenttransition)
- ["ToggleMute"](#togglemute) - ["SetCurrentTransition"](#setcurrenttransition)
- ["SetSceneItemPosition"](#setsceneitemposition) - ["GetTransitionDuration"](#gettransitionduration)
- ["SetSceneItemTransform"](#setsceneitemtransform) - ["SetTransitionDuration"](#settransitionduration)
- ["SetSceneItemCrop"](#setsceneitemcrop) - **Sources**
- ["SetCurrentSceneCollection"](#setcurrentscenecollection) - ["GetCurrentScene"](#getcurrentscene)
- ["GetCurrentSceneCollection"](#getcurrentscenecollection) - ["GetSceneList"](#getscenelist)
- ["ListSceneCollections"](#listscenecollections) - ["SetVolume"](#setvolume)
- ["SetCurrentProfile"](#setcurrentprofile) - ["GetVolume"](#getvolume)
- ["GetCurrentProfile"](#getcurrentprofile) - ["SetMute"](#setmute)
- ["ListProfiles"](#listprofiles) - ["ToggleMute"](#togglemute)
* [Authentication](#authentication) - ["SetSourceRender"](#setsourcerender)
- ["SetSceneItemPosition"](#setsceneitemposition)
- ["SetSceneItemTransform"](#setsceneitemtransform)
- ["SetSceneItemCrop"](#setsceneitemcrop)
- **Scene Collections**
- ["ListSceneCollections"](#listscenecollections)
- ["SetCurrentSceneCollection"](#setcurrentscenecollection)
- ["GetCurrentSceneCollection"](#getcurrentscenecollection)
- **Profiles**
- ["ListProfiles"](#listprofiles)
- ["SetCurrentProfile"](#setcurrentprofile)
- ["GetCurrentProfile"](#getcurrentprofile)
## Authentication
A call to [`GetAuthRequired`](#getauthrequired) gives the client two elements :
- A challenge : a random string that will be used to generate the auth response
- A salt : applied to the password when generating the auth response
The client knows a password and must it to authenticate itself to the server.
However, it must keep this password secret, and it is the purpose of the authentication mecanism used by obs-websocket.
After a call to [`GetAuthRequired`](#getauthrequired), the client knows a password (kept secret), a challenge and a salt (sent by the server).
To generate the answer to the auth challenge, follow this procedure :
- Concatenate the password with the salt sent by the server (in this order : password + server salt), then generate a binary SHA256 hash of the result and encode the resulting SHA256 binary hash to base64.
- Concatenate the base64 secret with the challenge sent by the server (in this order : base64 secret + server challenge), then generate a binary SHA256 hash of the result and encode it to base64.
- Voilà, this last base64 string is the auth response. You may now use it to authenticate to the server with the `Authenticate` request.
Here's how it looks in pseudocode :
```
password = "supersecretpassword"
challenge = "ztTBnnuqrqaKDzRM3xcVdbYm"
salt = "PZVbYpvAnZut2SS6JNJytDm9"
secret_string = password + salt
secret_hash = binary_sha256(secret_string)
secret = base64_encode(secret_hash)
auth_response_string = secret + challenge
auth_response_hash = binary_sha256(auth_response_string)
auth_response = base64_encode(auth_response_hash)
```
A client can then authenticate to the server by calling [`Authenticate`](#authenticate) with the computed challenge response.
## Events ## Events
### Description ### Description
@ -701,32 +753,3 @@ __Response__ : OK with the additional fields :
- **"profiles"** (array of objects) : names of available profiles - **"profiles"** (array of objects) : names of available profiles
--- ---
### Authentication
A call to `GetAuthRequired` gives the client two elements :
- A challenge : a random string that will be used to generate the auth response
- A salt : applied to the password when generating the auth response
The client knows a password and must it to authenticate itself to the server.
However, it must keep this password secret, and it is the purpose of the authentication mecanism used by obs-websocket.
After a call to `GetAuthRequired`, the client knows a password (kept secret), a challenge and a salt (sent by the server).
To generate the answer to the auth challenge, follow this procedure :
- Concatenate the password with the salt sent by the server (in this order : password + server salt), then generate a binary SHA256 hash of the result and encode the resulting SHA256 binary hash to base64.
- Concatenate the base64 secret with the challenge sent by the server (in this order : base64 secret + server challenge), then generate a binary SHA256 hash of the result and encode it to base64.
- Voilà, this last base64 string is the auth response. You may now use it to authenticate to the server with the `Authenticate` request.
Here's how it looks in pseudocode :
```
password = "supersecretpassword"
challenge = "ztTBnnuqrqaKDzRM3xcVdbYm"
salt = "PZVbYpvAnZut2SS6JNJytDm9"
secret_string = password + salt
secret_hash = binary_sha256(secret_string)
secret = base64_encode(secret_hash)
auth_response_string = secret + challenge
auth_response_hash = binary_sha256(auth_response_string)
auth_response = base64_encode(auth_response_hash)
```