Merge pull request #5707 from matrix-org/dbkr/audiostream

Option for audio streaming
This commit is contained in:
David Baker 2021-03-08 11:50:45 +00:00 committed by GitHub
commit d71999114b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 1 deletions

55
src/Livestream.ts Normal file
View file

@ -0,0 +1,55 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { ClientWidgetApi } from "matrix-widget-api";
import { MatrixClientPeg } from "./MatrixClientPeg";
import SdkConfig from "./SdkConfig";
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
export function getConfigLivestreamUrl() {
return SdkConfig.get()["audioStreamUrl"];
}
// Dummy rtmp URL used to signal that we want a special audio-only stream
const AUDIOSTREAM_DUMMY_URL = 'rtmp://audiostream.dummy/';
async function createLiveStream(roomId: string) {
const openIdToken = await MatrixClientPeg.get().getOpenIdToken();
const url = getConfigLivestreamUrl() + "/createStream";
const response = await window.fetch(url, {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
room_id: roomId,
openid_token: openIdToken,
}),
});
const respBody = await response.json();
return respBody['stream_id'];
}
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string) {
const streamId = await createLiveStream(roomId);
await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, {
rtmpStreamKey: AUDIOSTREAM_DUMMY_URL + streamId,
});
}

View file

@ -28,9 +28,11 @@ import dis from "../../../dispatcher/dispatcher";
import SettingsStore from "../../../settings/SettingsStore";
import Modal from "../../../Modal";
import QuestionDialog from "../dialogs/QuestionDialog";
import ErrorDialog from "../dialogs/ErrorDialog";
import {WidgetType} from "../../../widgets/WidgetType";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
import { getConfigLivestreamUrl, startJitsiAudioLivestream } from "../../../Livestream";
interface IProps extends React.ComponentProps<typeof IconizedContextMenu> {
app: IApp;
@ -54,6 +56,27 @@ const WidgetContextMenu: React.FC<IProps> = ({
const widgetMessaging = WidgetMessagingStore.instance.getMessagingForId(app.id);
const canModify = userWidget || WidgetUtils.canUserModifyWidgets(roomId);
let streamAudioStreamButton;
if (getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
const onStreamAudioClick = async () => {
try {
await startJitsiAudioLivestream(widgetMessaging, roomId);
} catch (err) {
console.error("Failed to start livestream", err);
// XXX: won't i18n well, but looks like widget api only support 'message'?
const message = err.message || _t("Unable to start audio streaming.");
Modal.createTrackedDialog('WidgetContext Menu', 'Livestream failed', ErrorDialog, {
title: _t('Failed to start livestream'),
description: message,
});
}
onFinished();
};
streamAudioStreamButton = <IconizedContextMenuOption
onClick={onStreamAudioClick} label={_t("Start audio stream")}
/>;
}
let unpinButton;
if (showUnpin) {
const onUnpinClick = () => {
@ -163,6 +186,7 @@ const WidgetContextMenu: React.FC<IProps> = ({
return <IconizedContextMenu {...props} chevronFace={ChevronFace.None} onFinished={onFinished}>
<IconizedContextMenuOptionList>
{ streamAudioStreamButton }
{ editButton }
{ revokeButton }
{ deleteButton }
@ -175,4 +199,3 @@ const WidgetContextMenu: React.FC<IProps> = ({
};
export default WidgetContextMenu;

View file

@ -2410,6 +2410,9 @@
"Set status": "Set status",
"Set a new status...": "Set a new status...",
"View Community": "View Community",
"Unable to start audio streaming.": "Unable to start audio streaming.",
"Failed to start livestream": "Failed to start livestream",
"Start audio stream": "Start audio stream",
"Take a picture": "Take a picture",
"Delete Widget": "Delete Widget",
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?",

View file

@ -19,6 +19,7 @@ import { IWidgetApiRequest } from "matrix-widget-api";
export enum ElementWidgetActions {
ClientReady = "im.vector.ready",
HangupCall = "im.vector.hangup",
StartLiveStream = "im.vector.start_live_stream",
OpenIntegrationManager = "integration_manager_open",
/**