removed incomplete active speaker demo
This commit is contained in:
parent
7450f51269
commit
0829203d78
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"presets": ["next/babel"],
|
||||
"plugins": ["inline-react-svg"]
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# Active Speaker
|
||||
|
||||

|
||||
|
||||
### Live example
|
||||
|
||||
**[See it in action here ➡️](https://dailyjs-active-speaker.vercel.app)**
|
||||
|
||||
---
|
||||
|
||||
## What does this demo do?
|
||||
|
||||
- Uses an active speaker view mode that shows the currently talking participant (or active screen share) in a larger tile
|
||||
- Introduces the `ParticipantBar` column that virtually scrolls through all call participants
|
||||
- Uses manual subscriptions to paginate between tiles that are currently in view. For more information about how this works, please refer to the [pagination demo](../pagination)
|
||||
|
||||
Please note: this demo is not currently mobile optimised
|
||||
|
||||
### Getting started
|
||||
|
||||
```
|
||||
# set both DAILY_API_KEY and DAILY_DOMAIN
|
||||
mv env.example .env.local
|
||||
|
||||
yarn
|
||||
yarn workspace @dailyjs/active-speaker dev
|
||||
```
|
||||
|
||||
## Deploy your own on Vercel
|
||||
|
||||
[](https://vercel.com/new/daily-co/clone-flow?repository-url=https%3A%2F%2Fgithub.com%2Fdaily-demos%2Fexamples.git&env=DAILY_DOMAIN%2CDAILY_API_KEY&envDescription=Your%20Daily%20domain%20and%20API%20key%20can%20be%20found%20on%20your%20account%20dashboard&envLink=https%3A%2F%2Fdashboard.daily.co&project-name=daily-examples&repo-name=daily-examples)
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import App from '@dailyjs/basic-call/components/App';
|
||||
import Room from '../Room';
|
||||
|
||||
// Extend our basic call app component with our custom Room componenet
|
||||
export const AppWithSpeakerViewRoom = () => (
|
||||
<App
|
||||
customComponentForState={{
|
||||
room: () => <Room />,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export default AppWithSpeakerViewRoom;
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { AppWithSpeakerViewRoom as default } from './App';
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
import { SpeakerView } from '../SpeakerView';
|
||||
|
||||
export const Room = () => <SpeakerView />;
|
||||
|
||||
export default Room;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { Room as default } from './Room';
|
||||
export { Room } from './Room';
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Tile } from '@dailyjs/shared/components/Tile';
|
||||
import { DEFAULT_ASPECT_RATIO } from '@dailyjs/shared/constants';
|
||||
import { useResize } from '@dailyjs/shared/hooks/useResize';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const MAX_RATIO = DEFAULT_ASPECT_RATIO;
|
||||
const MIN_RATIO = 4 / 3;
|
||||
|
||||
export const SpeakerTile = ({ participant, screenRef }) => {
|
||||
const [ratio, setRatio] = useState(MAX_RATIO);
|
||||
const [nativeAspectRatio, setNativeAspectRatio] = useState(null);
|
||||
const [screenHeight, setScreenHeight] = useState(1);
|
||||
|
||||
const updateRatio = useCallback(() => {
|
||||
const rect = screenRef.current?.getBoundingClientRect();
|
||||
setRatio(rect.width / rect.height);
|
||||
setScreenHeight(rect.height);
|
||||
}, [screenRef]);
|
||||
|
||||
useResize(() => {
|
||||
updateRatio();
|
||||
}, [updateRatio]);
|
||||
|
||||
useEffect(() => updateRatio(), [updateRatio]);
|
||||
|
||||
/**
|
||||
* Only use the video's native aspect ratio if it's in portrait mode
|
||||
* (e.g. mobile) to update how we crop videos. Otherwise, use landscape
|
||||
* defaults.
|
||||
*/
|
||||
const handleNativeAspectRatio = (r) => {
|
||||
const isPortrait = r < 1;
|
||||
setNativeAspectRatio(isPortrait ? r : null);
|
||||
};
|
||||
|
||||
const { height, finalRatio, videoFit } = useMemo(
|
||||
() =>
|
||||
// Avoid cropping mobile videos, which have the nativeAspectRatio set
|
||||
({
|
||||
height: (nativeAspectRatio ?? ratio) >= MIN_RATIO ? '100%' : null,
|
||||
finalRatio:
|
||||
nativeAspectRatio || (ratio <= MIN_RATIO ? MIN_RATIO : MAX_RATIO),
|
||||
videoFit: ratio >= MAX_RATIO || nativeAspectRatio ? 'contain' : 'cover',
|
||||
}),
|
||||
[nativeAspectRatio, ratio]
|
||||
);
|
||||
|
||||
const style = {
|
||||
height,
|
||||
maxWidth: screenHeight * finalRatio,
|
||||
overflow: 'hidden',
|
||||
};
|
||||
|
||||
return (
|
||||
<Tile
|
||||
aspectRatio={finalRatio}
|
||||
participant={participant}
|
||||
style={style}
|
||||
videoFit={videoFit}
|
||||
showActiveSpeaker={false}
|
||||
onVideoResize={handleNativeAspectRatio}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
SpeakerTile.propTypes = {
|
||||
participant: PropTypes.object,
|
||||
screenRef: PropTypes.object,
|
||||
};
|
||||
|
||||
export default SpeakerTile;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { SpeakerTile as default } from './SpeakerTile';
|
||||
export { SpeakerTile } from './SpeakerTile';
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import RoomContainer from '@dailyjs/basic-call/components/Room/RoomContainer';
|
||||
import ParticipantBar from '@dailyjs/shared/components/ParticipantBar/ParticipantBar';
|
||||
import VideoContainer from '@dailyjs/shared/components/VideoContainer/VideoContainer';
|
||||
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
||||
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||
import { useTracks } from '@dailyjs/shared/contexts/TracksProvider';
|
||||
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||
import { isScreenId } from '@dailyjs/shared/contexts/participantsState';
|
||||
import SpeakerTile from './SpeakerTile';
|
||||
|
||||
const SIDEBAR_WIDTH = 186;
|
||||
|
||||
export const SpeakerView = () => {
|
||||
const { currentSpeaker, localParticipant, participants, screens } =
|
||||
useParticipants();
|
||||
const { updateCamSubscriptions } = useTracks();
|
||||
const { showLocalVideo } = useCallState();
|
||||
const { pinnedId } = useUIState();
|
||||
const activeRef = useRef();
|
||||
|
||||
const screensAndPinned = useMemo(
|
||||
() => [...screens, ...participants.filter(({ id }) => id === pinnedId)],
|
||||
[participants, pinnedId, screens]
|
||||
);
|
||||
|
||||
const otherParticipants = useMemo(
|
||||
() => participants.filter(({ isLocal }) => !isLocal),
|
||||
[participants]
|
||||
);
|
||||
|
||||
const showSidebar = useMemo(() => {
|
||||
const hasScreenshares = screens.length > 0;
|
||||
|
||||
if (isScreenId(pinnedId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return participants.length > 1 || hasScreenshares;
|
||||
}, [participants, pinnedId, screens]);
|
||||
|
||||
/* const screenShareTiles = useMemo(
|
||||
() => <ScreensAndPins items={screensAndPinned} />,
|
||||
[screensAndPinned]
|
||||
); */
|
||||
|
||||
const hasScreenshares = useMemo(() => screens.length > 0, [screens]);
|
||||
|
||||
const fixedItems = useMemo(() => {
|
||||
const items = [];
|
||||
if (showLocalVideo) {
|
||||
items.push(localParticipant);
|
||||
}
|
||||
if (hasScreenshares && otherParticipants.length > 0) {
|
||||
items.push(otherParticipants[0]);
|
||||
}
|
||||
return items;
|
||||
}, [hasScreenshares, localParticipant, otherParticipants, showLocalVideo]);
|
||||
|
||||
const otherItems = useMemo(() => {
|
||||
if (otherParticipants.length > 1) {
|
||||
return otherParticipants.slice(hasScreenshares ? 1 : 0);
|
||||
}
|
||||
return [];
|
||||
}, [hasScreenshares, otherParticipants]);
|
||||
|
||||
/**
|
||||
* Update cam subscriptions, in case ParticipantBar is not shown.
|
||||
*/
|
||||
useEffect(() => {
|
||||
// Sidebar takes care of cam subscriptions for all displayed participants.
|
||||
if (showSidebar) return;
|
||||
updateCamSubscriptions([
|
||||
currentSpeaker?.id,
|
||||
...screensAndPinned.map((p) => p.id),
|
||||
]);
|
||||
}, [currentSpeaker, screensAndPinned, showSidebar, updateCamSubscriptions]);
|
||||
|
||||
return (
|
||||
<div className="speaker-view">
|
||||
<RoomContainer>
|
||||
<VideoContainer>
|
||||
<div ref={activeRef} className="active">
|
||||
<SpeakerTile participant={currentSpeaker} screenRef={activeRef} />
|
||||
</div>
|
||||
</VideoContainer>
|
||||
</RoomContainer>
|
||||
{showSidebar && (
|
||||
<ParticipantBar
|
||||
fixed={fixedItems}
|
||||
others={otherItems}
|
||||
width={SIDEBAR_WIDTH}
|
||||
/>
|
||||
)}
|
||||
|
||||
<style jsx>{`
|
||||
.speaker-view {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpeakerView;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export { SpeakerView as default } from './SpeakerView';
|
||||
export { SpeakerView } from './SpeakerView';
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Domain excluding 'https://' and 'daily.co' e.g. 'somedomain'
|
||||
DAILY_DOMAIN=
|
||||
|
||||
# Obtained from https://dashboard.daily.co/developers
|
||||
DAILY_API_KEY=
|
||||
|
||||
# Daily REST API endpoint
|
||||
DAILY_REST_DOMAIN=https://api.daily.co/v1
|
||||
|
||||
|
||||
# Enable manual track subscriptions
|
||||
MANUAL_TRACK_SUBS=1
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 143 KiB |
|
|
@ -1 +0,0 @@
|
|||
// Note: I am here because next-transpile-modules requires a mainfile
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
const withPlugins = require('next-compose-plugins');
|
||||
const withTM = require('next-transpile-modules')([
|
||||
'@dailyjs/shared',
|
||||
'@dailyjs/basic-call',
|
||||
]);
|
||||
|
||||
const packageJson = require('./package.json');
|
||||
|
||||
module.exports = withPlugins([withTM], {
|
||||
env: {
|
||||
PROJECT_TITLE: packageJson.description,
|
||||
},
|
||||
});
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "@dailyjs/active-speaker",
|
||||
"description": "Basic Call + Active Speaker",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dailyjs/basic-call": "*",
|
||||
"@dailyjs/shared": "*",
|
||||
"next": "^11.0.0",
|
||||
"pluralize": "^8.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-module-resolver": "^4.1.0",
|
||||
"next-compose-plugins": "^2.2.1",
|
||||
"next-transpile-modules": "^8.0.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import React from 'react';
|
||||
import App from '@dailyjs/basic-call/pages/_app';
|
||||
import AppWithSpeakerViewRoom from '../components/App';
|
||||
|
||||
App.customAppComponent = <AppWithSpeakerViewRoom />;
|
||||
|
||||
export default App;
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../basic-call/pages/api
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import Index from '@dailyjs/basic-call/pages';
|
||||
import getDemoProps from '@dailyjs/shared/lib/demoProps';
|
||||
|
||||
export async function getStaticProps() {
|
||||
const defaultProps = getDemoProps();
|
||||
|
||||
// Pass through domain as prop
|
||||
return {
|
||||
props: defaultProps,
|
||||
};
|
||||
}
|
||||
|
||||
export default Index;
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<svg width="80" height="32" viewBox="0 0 80 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.5886 27.0149C23.8871 27.0149 25.7976 25.6716 26.6035 24.0896V26.6866H30.9021V4H26.6035V13.403C25.7379 11.8209 24.1856 10.7164 21.6782 10.7164C17.7677 10.7164 14.8125 13.7313 14.8125 18.8657V19.1045C14.8125 24.2985 17.7976 27.0149 21.5886 27.0149ZM22.8722 23.6418C20.7229 23.6418 19.2304 22.1194 19.2304 19.0149V18.7761C19.2304 15.6716 20.5737 14.0299 22.9916 14.0299C25.3498 14.0299 26.7229 15.6119 26.7229 18.7164V18.9552C26.7229 22.1194 25.1409 23.6418 22.8722 23.6418Z" fill="#121A24"/>
|
||||
<path d="M37.9534 27.0149C40.4011 27.0149 41.7743 26.0597 42.6698 24.806V26.6866H46.8787V16.5075C46.8787 12.2687 44.1623 10.7164 40.3414 10.7164C36.5205 10.7164 33.5951 12.3582 33.3265 16.0597H37.416C37.5951 14.7164 38.3713 13.8507 40.0728 13.8507C42.0429 13.8507 42.6101 14.8657 42.6101 16.7164V17.3433H40.8489C36.0728 17.3433 32.7295 18.7164 32.7295 22.3582C32.7295 25.6418 35.1175 27.0149 37.9534 27.0149ZM39.2369 24C37.6548 24 36.9683 23.2537 36.9683 22.1194C36.9683 20.4478 38.431 19.9104 40.9384 19.9104H42.6101V21.2239C42.6101 22.9552 41.1474 24 39.2369 24Z" fill="#121A24"/>
|
||||
<path d="M49.647 26.6866H53.9456V11.0746H49.647V26.6866ZM51.7665 8.95522C53.1694 8.95522 54.2441 7.9403 54.2441 6.59702C54.2441 5.25373 53.1694 4.23881 51.7665 4.23881C50.3933 4.23881 49.3187 5.25373 49.3187 6.59702C49.3187 7.9403 50.3933 8.95522 51.7665 8.95522Z" fill="#121A24"/>
|
||||
<path d="M56.9765 26.6866H61.275V4H56.9765V26.6866Z" fill="#121A24"/>
|
||||
<path d="M70.5634 32L78.9917 11.0746H74.8711L71.3499 20.4478L67.5589 11.0746H62.9021L69.1523 25.1953L66.3779 32H70.5634Z" fill="#121A24"/>
|
||||
<path d="M0 32H4.1875L17.0766 0H12.9916L0 32Z" fill="url(#paint0_linear)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="8.88727" y1="-0.222885" x2="8.88727" y2="30" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BEBB9"/>
|
||||
<stop offset="1" stop-color="#FF9254"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
|
@ -1,14 +0,0 @@
|
|||
<svg width="80" height="32" viewBox="0 0 80 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.5886 27.0149C23.8871 27.0149 25.7976 25.6716 26.6035 24.0896V26.6866H30.9021V4H26.6035V13.403C25.7379 11.8209 24.1856 10.7164 21.6782 10.7164C17.7677 10.7164 14.8125 13.7313 14.8125 18.8657V19.1045C14.8125 24.2985 17.7976 27.0149 21.5886 27.0149ZM22.8722 23.6418C20.7229 23.6418 19.2304 22.1194 19.2304 19.0149V18.7761C19.2304 15.6716 20.5737 14.0299 22.9916 14.0299C25.3498 14.0299 26.7229 15.6119 26.7229 18.7164V18.9552C26.7229 22.1194 25.1409 23.6418 22.8722 23.6418Z" fill="white"/>
|
||||
<path d="M37.9534 27.0149C40.4011 27.0149 41.7743 26.0597 42.6698 24.806V26.6866H46.8787V16.5075C46.8787 12.2687 44.1623 10.7164 40.3414 10.7164C36.5205 10.7164 33.5951 12.3582 33.3265 16.0597H37.416C37.5951 14.7164 38.3713 13.8507 40.0728 13.8507C42.0429 13.8507 42.6101 14.8657 42.6101 16.7164V17.3433H40.8489C36.0728 17.3433 32.7295 18.7164 32.7295 22.3582C32.7295 25.6418 35.1175 27.0149 37.9534 27.0149ZM39.2369 24C37.6548 24 36.9683 23.2537 36.9683 22.1194C36.9683 20.4478 38.431 19.9104 40.9384 19.9104H42.6101V21.2239C42.6101 22.9552 41.1474 24 39.2369 24Z" fill="white"/>
|
||||
<path d="M49.647 26.6866H53.9456V11.0746H49.647V26.6866ZM51.7665 8.95522C53.1694 8.95522 54.2441 7.9403 54.2441 6.59702C54.2441 5.25373 53.1694 4.23881 51.7665 4.23881C50.3933 4.23881 49.3187 5.25373 49.3187 6.59702C49.3187 7.9403 50.3933 8.95522 51.7665 8.95522Z" fill="white"/>
|
||||
<path d="M56.9765 26.6866H61.275V4H56.9765V26.6866Z" fill="white"/>
|
||||
<path d="M70.5634 32L78.9917 11.0746H74.8711L71.3499 20.4478L67.5589 11.0746H62.9021L69.1523 25.1953L66.3779 32H70.5634Z" fill="white"/>
|
||||
<path d="M0 32H4.1875L17.0766 0H12.9916L0 32Z" fill="url(#paint0_linear)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="8.88727" y1="-0.222885" x2="8.88727" y2="30" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BEBB9"/>
|
||||
<stop offset="1" stop-color="#FF9254"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB |
Loading…
Reference in New Issue