Skip to content

Commit

Permalink
fix: bug-solve and addressed feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Saelmala committed Sep 20, 2024
1 parent 96e6907 commit 0a0fb25
Show file tree
Hide file tree
Showing 14 changed files with 222 additions and 184 deletions.
34 changes: 20 additions & 14 deletions src/api/ateliereLive/pipelines/streams/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export async function createStream(
return pipeline.uuid;
})
);

const ingestUuid = await getUuidFromIngestName(
source.ingest_name,
false
Expand All @@ -79,13 +80,15 @@ export async function createStream(
source.ingest_source_name,
false
);

const audioMapping =
source.audio_stream.audio_mapping &&
source.audio_stream.audio_mapping.length > 0
? source.audio_stream.audio_mapping
: [[0, 1]];

await initDedicatedPorts();

for (const pipeline of production_settings.pipelines) {
const availablePorts = getAvailablePortsForIngest(
source.ingest_name,
Expand All @@ -101,28 +104,29 @@ export async function createStream(
Log().info(
`Allocated port ${availablePort} on '${source.ingest_name}' for ${source.ingest_source_name}`
);

const stream: PipelineStreamSettings = {
ingest_id: ingestUuid,
source_id: sourceId,
pipeline_id: pipeline.pipeline_id!,
input_slot: input_slot,
alignment_ms: pipeline.alignment_ms,
audio_format: pipeline.audio_format,
audio_sampling_frequency: pipeline.audio_sampling_frequency,
bit_depth: pipeline.bit_depth,
convert_color_range: pipeline.convert_color_range,
encoder: pipeline.encoder,
encoder_device: pipeline.encoder_device,
format: pipeline.format,
max_network_latency_ms: pipeline.max_network_latency_ms,
width: pipeline.width,
height: pipeline.height,
frame_rate_d: pipeline.frame_rate_d,
frame_rate_n: pipeline.frame_rate_n,
format: pipeline.format,
encoder: pipeline.encoder,
encoder_device: pipeline.encoder_device,
gop_length: pipeline.gop_length,
height: pipeline.height,
max_network_latency_ms: pipeline.max_network_latency_ms,
pic_mode: pipeline.pic_mode,
speed_quality_balance: pipeline.speed_quality_balance,
video_kilobit_rate: pipeline.video_kilobit_rate,
width: pipeline.width,
ingest_id: ingestUuid,
source_id: sourceId,
input_slot,
bit_depth: pipeline.bit_depth,
speed_quality_balance: pipeline.speed_quality_balance,
convert_color_range: pipeline.convert_color_range,
audio_sampling_frequency: pipeline.audio_sampling_frequency,
audio_format: pipeline.audio_format,
audio_mapping: JSON.stringify(audioMapping),
interfaces: [
{
Expand All @@ -131,6 +135,7 @@ export async function createStream(
}
]
};

try {
Log().info(
`Connecting '${source.ingest_name}/${ingestUuid}}:${source.ingest_source_name}' to '${pipeline.pipeline_name}/${pipeline.pipeline_id}'`
Expand All @@ -147,6 +152,7 @@ export async function createStream(
Log().info(
`Stream '${result.stream_uuid}' from '${source.ingest_name}/${ingestUuid}' to '${pipeline.pipeline_name}/${pipeline.pipeline_id}' connected`
);

sourceToPipelineStreams.push({
source_id: source._id.toString(),
stream_uuid: result.stream_uuid,
Expand Down
2 changes: 1 addition & 1 deletion src/api/manager/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ async function connectIngestSources(
width: pipeline.width,
ingest_id: ingestUuid,
source_id: sourceId,
input_slot,
input_slot: input_slot,
audio_mapping: JSON.stringify(audioMapping),
interfaces: [
{
Expand Down
1 change: 0 additions & 1 deletion src/app/api/manager/streams/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
status: 403
});
}

const data = await request.json();
const createStreamRequest = data as CreateStreamRequestBody;
return await createStream(
Expand Down
38 changes: 38 additions & 0 deletions src/app/api/manager/websocket/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NextResponse } from 'next/server';

const wsUrl = `ws://${process.env.CONTROL_PANEL_WS}`;

export async function POST(request: Request) {
const { action, inputSlot } = await request.json();

if (!wsUrl) {
return NextResponse.json(
{ message: 'WebSocket URL is not defined' },
{ status: 500 }
);
}

return new Promise((resolve) => {
const ws = new WebSocket(wsUrl);

ws.onopen = () => {
if (action === 'closeHtml') {
ws.send(`html close ${inputSlot}`);
ws.send('html reset');
} else if (action === 'closeMediaplayer') {
ws.send(`media close ${inputSlot}`);
ws.send('media reset');
}
ws.close();
};

ws.onerror = (error) => {
resolve(
NextResponse.json(
{ message: 'WebSocket error', error },
{ status: 500 }
)
);
};
});
}
112 changes: 50 additions & 62 deletions src/app/production/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
'use client';

import React, { useEffect, useState, KeyboardEvent, useContext } from 'react';
import { PageProps } from '../../../../.next/types/app/production/[id]/page';
import SourceListItem from '../../../components/sourceListItem/SourceListItem';
import FilterOptions from '../../../components/filter/FilterOptions';
import { AddInput } from '../../../components/addInput/AddInput';
import { IconX } from '@tabler/icons-react';
import { useSources } from '../../../hooks/sources/useSources';
import {
AddSourceStatus,
Expand All @@ -19,8 +17,6 @@ import { updateSetupItem } from '../../../hooks/items/updateSetupItem';
import { removeSetupItem } from '../../../hooks/items/removeSetupItem';
import { addSetupItem } from '../../../hooks/items/addSetupItem';
import HeaderNavigation from '../../../components/headerNavigation/HeaderNavigation';
import styles from './page.module.scss';
import FilterProvider from '../../../contexts/FilterContext';
import { useGetPresets } from '../../../hooks/presets';
import { Preset } from '../../../interfaces/preset';
import SourceCards from '../../../components/sourceCards/SourceCards';
Expand All @@ -46,6 +42,9 @@ import SourceList from '../../../components/sourceList/SourceList';
import { LockButton } from '../../../components/lockButton/LockButton';
import { GlobalContext } from '../../../contexts/GlobalContext';
import { Select } from '../../../components/select/Select';
import { useAddSource } from '../../../hooks/sources/useAddSource';
import { useGetFirstEmptySlot } from '../../../hooks/useGetFirstEmptySlot';
import { useWebsocket } from '../../../hooks/useWebsocket';

export default function ProductionConfiguration({ params }: PageProps) {
const t = useTranslate();
Expand Down Expand Up @@ -95,6 +94,13 @@ export default function ProductionConfiguration({ params }: PageProps) {
const [deleteSourceStatus, setDeleteSourceStatus] =
useState<DeleteSourceStatus>();

// Create source
const [firstEmptySlot] = useGetFirstEmptySlot();
const [addSource] = useAddSource();

// Websocket
const [closeWebsocket] = useWebsocket();

const { locked } = useContext(GlobalContext);

const isAddButtonDisabled =
Expand Down Expand Up @@ -398,65 +404,29 @@ export default function ProductionConfiguration({ params }: PageProps) {
</li>
);
}
function getSourcesToDisplay(
filteredSources: Map<string, SourceWithId>
): React.ReactNode[] {
return Array.from(filteredSources.values()).map((source, index) => {
return (
<SourceListItem
key={`${source.ingest_source_name}-${index}`}
source={source}
disabled={selectedProductionItems?.includes(source._id.toString())}
action={(source: SourceWithId) => {
if (productionSetup && productionSetup.isActive) {
setSelectedSource(source);
setAddSourceModal(true);
} else if (productionSetup) {
const updatedSetup = addSetupItem(
{
_id: source._id.toString(),
type: 'ingest_source',
label: source.ingest_source_name,
// Byt till hook
input_slot: getFirstEmptySlot()
},
productionSetup
);
if (!updatedSetup) return;
setProductionSetup(updatedSetup);
putProduction(updatedSetup._id.toString(), updatedSetup).then(
() => {
setAddSourceModal(false);
setSelectedSource(undefined);
}
);
}
}}
/>
);
});
}

const getFirstEmptySlot = () => {
if (!productionSetup) throw 'no_production';
let firstEmptySlot = productionSetup.sources.length + 1;
if (productionSetup.sources.length === 0) {
return firstEmptySlot;
}
for (
let i = 0;
i <
productionSetup.sources[productionSetup.sources.length - 1].input_slot;
i++
) {
if (
!productionSetup.sources.some((source) => source.input_slot === i + 1)
) {
firstEmptySlot = i + 1;
break;
}
const addSourceAction = (source: SourceWithId) => {
if (productionSetup && productionSetup.isActive) {
setSelectedSource(source);
setAddSourceModal(true);
} else if (productionSetup) {
const input: SourceReference = {
_id: source._id.toString(),
type: 'ingest_source',
label: source.ingest_source_name,
input_slot: firstEmptySlot(productionSetup)
};
addSource(input, productionSetup).then((updatedSetup) => {
if (!updatedSetup) return;
setProductionSetup(updatedSetup);
setAddSourceModal(false);
setSelectedSource(undefined);
});
}
return firstEmptySlot;
};

const isDisabledFunction = (source: SourceWithId): boolean => {
return selectedProductionItems?.includes(source._id.toString());
};

const handleAddSource = async () => {
Expand Down Expand Up @@ -615,7 +585,25 @@ export default function ProductionConfiguration({ params }: PageProps) {
return;
}
}

if (
selectedSourceRef.type === 'html' ||
selectedSourceRef.type === 'mediaplayer'
) {
// Action specifies what websocket method to call
const action =
selectedSourceRef.type === 'html' ? 'closeHtml' : 'closeMediaplayer';
const inputSlot = productionSetup.sources.find(
(source) => source._id === selectedSourceRef._id
)?.input_slot;

if (!inputSlot) return;

closeWebsocket(action, inputSlot);
}

const updatedSetup = removeSetupItem(selectedSourceRef, productionSetup);

if (!updatedSetup) return;
setProductionSetup(updatedSetup);
putProduction(updatedSetup._id.toString(), updatedSetup).then(() => {
Expand Down
Loading

0 comments on commit 0a0fb25

Please sign in to comment.