Merge pull request #5707 from matrix-org/dbkr/audiostream
Option for audio streaming
This commit is contained in:
commit
d71999114b
4 changed files with 83 additions and 1 deletions
55
src/Livestream.ts
Normal file
55
src/Livestream.ts
Normal 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,
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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?",
|
||||
|
|
|
@ -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",
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue