Skip to content

Commit

Permalink
implement delay control
Browse files Browse the repository at this point in the history
  • Loading branch information
fredemmott committed Oct 18, 2018
1 parent 48a4d5e commit 76d73b0
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 3 deletions.
22 changes: 22 additions & 0 deletions plugins/base/ClientHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,28 @@ void ClientHandler::plaintextRpcMessageReceived(const QByteArray& message) {
encryptThenSendMessage(doc.toJson());
return;
}

if (method == "outputs/setDelay") {
const bool success = software->setOutputDelay(
jsonrpc["params"].toObject()["id"].toString(),
jsonrpc["params"].toObject()["seconds"].toInt()
);
QJsonObject json {
{ "jsonrpc", "2.0" },
{ "id", jsonrpc["id"] },
};
if (success) {
json["result"] = QJsonObject {};
} else {
json["error"] = QJsonObject {
{ "code", 0 },
{ "message", "The software failed to set the delay" }
};
}
encryptThenSendMessage(QJsonDocument(json).toJson());
return;
}

}

namespace {
Expand Down
7 changes: 7 additions & 0 deletions plugins/base/StreamingSoftware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ StreamingSoftware::StreamingSoftware(QObject* parent) : QObject(parent) {

StreamingSoftware::~StreamingSoftware() {
}

bool StreamingSoftware::setOutputDelay(
const QString& name,
int64_t seconds
) {
return false;
}
1 change: 1 addition & 0 deletions plugins/base/StreamingSoftware.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class StreamingSoftware: public QObject {
public slots:
virtual void startOutput(const QString& id) = 0;
virtual void stopOutput(const QString& id) = 0;
virtual bool setOutputDelay(const QString& id, int64_t seconds);
signals:
void outputStateChanged(const QString& id, OutputState newState);
void configurationChanged(const Config& config);
Expand Down
13 changes: 13 additions & 0 deletions plugins/obs/OBS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ Config OBS::getConfiguration() const {
return config;
}

bool OBS::setOutputDelay(const QString& id, int64_t seconds) {
if (id != s_streaming) {
return false;
}
auto config = obs_frontend_get_profile_config();
config_set_bool(config, "Output", "DelayEnable", seconds > 0);
if (seconds <= 0) {
return true;
}
config_set_int(config, "Output", "DelaySec", seconds);
return true;
}

void OBS::setConfiguration(const Config& config) {
auto obs_config = obs_frontend_get_global_config();
assert(obs_config);
Expand Down
1 change: 1 addition & 0 deletions plugins/obs/OBS.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class OBS : public StreamingSoftware {
public slots:
void startOutput(const QString& id);
void stopOutput(const QString& id);
bool setOutputDelay(const QString& id, int64_t seconds);
private:
Config getInitialConfiguration();
void setConfiguration(const Config& config);
Expand Down
29 changes: 29 additions & 0 deletions rpc_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,32 @@ Example response and notifications:
```

There is likely to be a significant amount of time between receiving success and receiving the notifications.

### `outputs/setDelay`

This method is sent by the client when it wants to set a delay on an output.

This method takes `{ id: string; seconds: int}` for its' parameters. If 0, the
delay is disabled.

Clients *should not* send this message unless the output is stopped.

Example request:

```
{
"jsonrpc": "2.0",
"method": "outputs/setDelay",
"id": "setDelay/1",
"params": { "id": "twitch://fredemmott", "seconds": 300 }
}
```

Example response:

```
{
"jsonrpc": "2.0",
"id": "setDelay/1",
"result": { "seconds": 300 }
}
1 change: 1 addition & 0 deletions webui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ <h2>HOST</h2>
" transform="rotate(180, 100, 100)" />
</svg>
<span class="state">UNKNOWN</span>
<span class="delay"></span>
<a href='#' class="remove">remove this output</a>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions webui/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,11 @@ input#name::placeholder {
#addConnection:hover {
color: #fff;
}

.delay {
cursor: pointer;
}

.delay:hover {
text-decoration: underline;
}
4 changes: 4 additions & 0 deletions webui/src/RPCClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ export default class RPCClient {
return await this.sendRequest('outputs/get', null);
}

public async setDelay(id: string, seconds: number): Promise<void> {
await this.sendRequest('outputs/setDelay', { id, seconds });
}

public async startOutput(id: string): Promise<void> {
await this.sendRequest("outputs/start", { id });
}
Expand Down
1 change: 1 addition & 0 deletions webui/src/RPCTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ export interface Output {
name: string,
type: OutputType,
state: OutputState,
delaySeconds?: number,
}
35 changes: 32 additions & 3 deletions webui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class WebUIClient {
const container = document.querySelector('#outputContainer') as HTMLDivElement;
for (const key in this.outputs) {
container.removeChild(this.outputs[key]);
delete this.outputs[key];
}
this.outputs = {};

for (const id in outputs) {
this.addOutputElement(container, outputs[id]);
Expand All @@ -99,14 +99,43 @@ class WebUIClient {
private addOutputElement(container: HTMLDivElement, output: Output): void {
const recordingTemplate = document.querySelector('#recordingTemplate');
const streamingTemplate = document.querySelector('#streamingTemplate');
const { id, name, type, state } = output;
const { id, name, type, state, delaySeconds } = output;
const template = (type === OutputType.LOCAL_RECORDING)
? recordingTemplate : streamingTemplate;
const elem = template.cloneNode(/* deep = */ true) as HTMLDivElement;
this.outputs[id] = elem;
elem.removeAttribute('id');
elem.dataset.outputId = id;
elem.dataset.host = this.config.host;
this.outputs[id] = elem;
if (delaySeconds != undefined) {
const delayMsg = elem.querySelector('.delay') as HTMLSpanElement;
if (delaySeconds == 0) {
delayMsg.innerText = 'no delay';
} else {
delayMsg.innerText = delaySeconds.toString() + 's delay';
}
delayMsg.addEventListener(
'click',
async e => {
e.preventDefault();
const input = window.prompt(
"Enter the number of seconds to delay the stream, or '0' to " +
"disable delay",
'0'
);
const seconds = parseInt(input);
if (isNaN(seconds) || seconds < 0) {
return;
}
await this.rpc.setDelay(output.id, seconds);
if (seconds == 0) {
delayMsg.innerText = 'no delay';
} else {
delayMsg.innerText = input + 's delay';
}
}
);
}
this.setOutputElementState(elem, state);
elem.querySelector('.button').addEventListener('click', e => {
e.preventDefault();
Expand Down

0 comments on commit 76d73b0

Please sign in to comment.