Skip to content

Commit 6cd92ba

Browse files
committed
Custom local video stream injection in a call
Signed-off-by: Mohtasim Bellah <[email protected]>
1 parent 9d79be1 commit 6cd92ba

File tree

1 file changed

+109
-83
lines changed

1 file changed

+109
-83
lines changed
Lines changed: 109 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,109 @@
1-
// Copyright (c) Microsoft Corporation.
2-
// Licensed under the MIT License.
3-
4-
import { CallAgent } from '@azure/communication-calling';
5-
import {
6-
CommunicationIdentifier,
7-
CommunicationUserIdentifier,
8-
isMicrosoftTeamsUserIdentifier,
9-
isPhoneNumberIdentifier,
10-
MicrosoftTeamsUserIdentifier,
11-
PhoneNumberIdentifier
12-
} from '@azure/communication-common';
13-
import { Dialpad, fromFlatCommunicationIdentifier } from '@azure/communication-react';
14-
15-
import { IncomingCallStack, usePropsFor } from '@azure/communication-react';
16-
import { PrimaryButton, Stack, TextField, Image } from '@fluentui/react';
17-
import React, { useState } from 'react';
18-
import { imgStyle } from '../styles/HomeScreen.styles';
19-
20-
export interface HomeScreenProps {
21-
callAgent: CallAgent;
22-
headerImageProps?: {
23-
src?: string;
24-
};
25-
}
26-
27-
export const HomeScreen = (props: HomeScreenProps): JSX.Element => {
28-
const { callAgent, headerImageProps } = props;
29-
const [targetParticipants, setTargetParticipants] = useState<CommunicationIdentifier[]>();
30-
const [alternateCallerId, setAlternateCallerId] = useState<string>();
31-
32-
const incomingCallStackProps = usePropsFor(IncomingCallStack);
33-
return (
34-
<Stack horizontal tokens={{ childrenGap: '1rem' }}>
35-
<Stack style={{ position: 'absolute', top: '0', right: '0' }}>
36-
{<IncomingCallStack {...incomingCallStackProps} tabIndex={1} />}
37-
</Stack>
38-
<Stack verticalAlign="center">
39-
<Image alt="Welcome to the ACS Calling sample app" className={imgStyle} {...headerImageProps} />
40-
</Stack>
41-
<Stack tokens={{ childrenGap: '1rem' }} style={{ minWidth: '20rem', margin: 'auto' }}>
42-
<TextField
43-
label="ACS or Teams user ID"
44-
placeholder="Enter the userId you want to call"
45-
onChange={(_, value: string | undefined) => {
46-
const ids: string[] = value ? value.split(',') : [];
47-
let newParticipants: CommunicationIdentifier[] = [];
48-
ids.forEach((id) => {
49-
newParticipants = newParticipants.concat([fromFlatCommunicationIdentifier(id)]);
50-
});
51-
setTargetParticipants(newParticipants);
52-
}}
53-
></TextField>
54-
<TextField
55-
label="Alternate Caller Id"
56-
placeholder="Enter the alternate caller id"
57-
onChange={(_, value: string | undefined) => setAlternateCallerId(value || '')}
58-
></TextField>
59-
<Dialpad onChange={(value) => setTargetParticipants([{ phoneNumber: value }])}></Dialpad>
60-
<PrimaryButton
61-
onClick={() => {
62-
console.log('targetParticipants', targetParticipants);
63-
if (targetParticipants && targetParticipants[0]) {
64-
if (isPhoneNumberIdentifier(targetParticipants[0]) && alternateCallerId) {
65-
(callAgent as CallAgent).startCall(targetParticipants as PhoneNumberIdentifier[], {
66-
alternateCallerId: { phoneNumber: alternateCallerId }
67-
});
68-
} else {
69-
if (isMicrosoftTeamsUserIdentifier(targetParticipants[0])) {
70-
(callAgent as CallAgent).startCall(targetParticipants as MicrosoftTeamsUserIdentifier[]);
71-
} else {
72-
(callAgent as CallAgent).startCall(targetParticipants as CommunicationUserIdentifier[]);
73-
}
74-
}
75-
}
76-
}}
77-
>
78-
Start Call
79-
</PrimaryButton>
80-
</Stack>
81-
</Stack>
82-
);
83-
};
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
import { CallAgent, LocalVideoStream } from '@azure/communication-calling';
5+
import {
6+
CommunicationIdentifier,
7+
CommunicationUserIdentifier,
8+
isMicrosoftTeamsUserIdentifier,
9+
isPhoneNumberIdentifier,
10+
MicrosoftTeamsUserIdentifier,
11+
PhoneNumberIdentifier
12+
} from '@azure/communication-common';
13+
import { Dialpad, fromFlatCommunicationIdentifier } from '@azure/communication-react';
14+
15+
import { IncomingCallStack, usePropsFor } from '@azure/communication-react';
16+
import { PrimaryButton, Stack, TextField, Image } from '@fluentui/react';
17+
import React, { useState } from 'react';
18+
import { imgStyle } from '../styles/HomeScreen.styles';
19+
20+
export interface HomeScreenProps {
21+
callAgent: CallAgent;
22+
headerImageProps?: {
23+
src?: string;
24+
};
25+
}
26+
27+
export const HomeScreen = (props: HomeScreenProps): JSX.Element => {
28+
const { callAgent, headerImageProps } = props;
29+
const [targetParticipants, setTargetParticipants] = useState<CommunicationIdentifier[]>();
30+
const [alternateCallerId, setAlternateCallerId] = useState<string>();
31+
32+
const createVideoMediaStreamToSend = () => {
33+
const canvas = document.createElement('canvas');
34+
const ctx = canvas.getContext('2d');
35+
canvas.width = 1500;
36+
canvas.height = 845;
37+
if (ctx) {
38+
ctx.fillStyle = 'blue';
39+
ctx.fillRect(0, 0, canvas.width, canvas.height);
40+
const colors = ['red', 'yellow'];
41+
window.setInterval(() => {
42+
ctx.fillStyle = colors[Math.floor(Math.random() * colors.length)] || 'black';
43+
const x = Math.floor(Math.random() * canvas.width);
44+
const y = Math.floor(Math.random() * canvas.height);
45+
const size = 100;
46+
ctx.fillRect(x, y, size, size);
47+
}, 1000 / 30);
48+
}
49+
50+
return canvas.captureStream(30);
51+
};
52+
53+
const mediaStream = createVideoMediaStreamToSend();
54+
const localStream = new LocalVideoStream(mediaStream);
55+
56+
const incomingCallStackProps = usePropsFor(IncomingCallStack);
57+
return (
58+
<Stack horizontal tokens={{ childrenGap: '1rem' }}>
59+
<Stack style={{ position: 'absolute', top: '0', right: '0' }}>
60+
{<IncomingCallStack {...incomingCallStackProps} tabIndex={1} />}
61+
</Stack>
62+
<Stack verticalAlign="center">
63+
<Image alt="Welcome to the ACS Calling sample app" className={imgStyle} {...headerImageProps} />
64+
</Stack>
65+
<Stack tokens={{ childrenGap: '1rem' }} style={{ minWidth: '20rem', margin: 'auto' }}>
66+
<TextField
67+
label="ACS or Teams user ID"
68+
placeholder="Enter the userId you want to call"
69+
onChange={(_, value: string | undefined) => {
70+
const ids: string[] = value ? value.split(',') : [];
71+
let newParticipants: CommunicationIdentifier[] = [];
72+
ids.forEach((id) => {
73+
newParticipants = newParticipants.concat([fromFlatCommunicationIdentifier(id)]);
74+
});
75+
setTargetParticipants(newParticipants);
76+
}}
77+
></TextField>
78+
<TextField
79+
label="Alternate Caller Id"
80+
placeholder="Enter the alternate caller id"
81+
onChange={(_, value: string | undefined) => setAlternateCallerId(value || '')}
82+
></TextField>
83+
<Dialpad onChange={(value) => setTargetParticipants([{ phoneNumber: value }])}></Dialpad>
84+
<PrimaryButton
85+
onClick={() => {
86+
console.log('targetParticipants', targetParticipants);
87+
if (targetParticipants && targetParticipants[0]) {
88+
if (isPhoneNumberIdentifier(targetParticipants[0]) && alternateCallerId) {
89+
(callAgent as CallAgent).startCall(targetParticipants as PhoneNumberIdentifier[], {
90+
alternateCallerId: { phoneNumber: alternateCallerId }
91+
});
92+
} else {
93+
if (isMicrosoftTeamsUserIdentifier(targetParticipants[0])) {
94+
(callAgent as CallAgent).startCall(targetParticipants as MicrosoftTeamsUserIdentifier[]);
95+
} else {
96+
(callAgent as CallAgent).startCall(targetParticipants as CommunicationUserIdentifier[], {
97+
videoOptions: { localVideoStreams: [localStream] }
98+
});
99+
}
100+
}
101+
}
102+
}}
103+
>
104+
Start Call
105+
</PrimaryButton>
106+
</Stack>
107+
</Stack>
108+
);
109+
};

0 commit comments

Comments
 (0)