Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add me stats and resolution info #207

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/me/Me.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UnmuteAlert from '../unmutealert/UnmuteAlert';
import VideoBox from '../videobox/VideoBox';
import VideoView from '../videoview/VideoView';
import Volume from '../volume/Volume';
import PeerStatsView from '../rtpquality/PeerStatsView';
import MeStatsView from '../rtpquality/MeStatsView';
import QualityIndicator from '../rtpquality/QualityIndicator';

interface MeProps {
Expand Down Expand Up @@ -39,7 +39,7 @@ const Me = ({ style }: MeProps): React.JSX.Element => {
{ micEnabled && !isMobile && <UnmuteAlert /> }

<DisplayName disabled={false} displayName={displayName} isMe />
{ !isMobile && showStats && <PeerStatsView /> }
{ !isMobile && showStats && <MeStatsView /> }
<QualityIndicator />

</VideoBox>
Expand Down
137 changes: 137 additions & 0 deletions src/components/rtpquality/MeStatsView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { useEffect, useState } from 'react';
import { useContext } from 'react';
import { ServiceContext } from '../../store/store';
import Stats from './Stats';
import { TrackStats } from '@observertc/client-monitor-js';

// import { Logger } from '../../utils/Logger';

// const logger = new Logger('MeStatsView');

type OutboundStats = {
ssrc: number;
sendingKbps?: number;
RTT?: number;
Fps?: number;
frameWidth? :number;
frameHeight? :number;
rid?: string;
}

function createOutboundStats(trackStats: TrackStats, avgRttInS?: number): OutboundStats[] {
if (trackStats.direction !== 'outbound') return [];

const result: OutboundStats[] = [];

for (const outboundRtpEntry of trackStats.outboundRtps()) {
if (!outboundRtpEntry.stats.active)
continue;
const stats = outboundRtpEntry.stats;
const item: OutboundStats = {
ssrc: stats.ssrc,
sendingKbps: Math.floor((outboundRtpEntry.sendingBitrate ?? 0) / 1000),
Fps: stats.framesPerSecond,
RTT: Math.round(Math.max(0, avgRttInS ?? 0) * 1000),
frameWidth: stats.frameWidth,
frameHeight: stats.frameHeight,
rid: stats.rid,
};

result.push(item);
}

return result;
}
// FIXME: not work on p2p mode
export const MeStatsView = () : JSX.Element => {
const { mediaService } = useContext(ServiceContext);
const [ outboundStats, setOutboundStats ] = useState<OutboundStats[]>([]);

useEffect(() => {
// this runs on mount
const monitor = mediaService.monitor;

if (!monitor) {
return;
}

let listener: () => void | undefined;
const storage = monitor.storage;

if (mediaService.mediaSenders['webcam'].track) {
listener = () => {

// Debug
/*
for (const outboundRtp of storage.outboundRtps()) {
const sender = outboundRtp.getSender();
const trackId = outboundRtp.getTrackId();
const ssrc = outboundRtp.getSsrc();
const remoteInboundRtp = outboundRtp.getRemoteInboundRtp();
const peerConnection = outboundRtp.getPeerConnection();
const transport = outboundRtp.getTransport();
const mediaSource = outboundRtp.getMediaSource();

logger.debug(trackId, ssrc,
outboundRtp.stats,
remoteInboundRtp?.stats,
sender?.stats,
peerConnection.stats,
transport?.stats,
mediaSource?.stats
);
}
*/

const trackId = mediaService.mediaSenders['webcam'].producer?.track?.id;

if (!trackId) {
return;
}
const trackStats = storage.getTrack(trackId);

if (!trackStats) {

return;
}

const newOutboundStats = createOutboundStats(trackStats, storage.avgRttInS);

setOutboundStats(newOutboundStats);
};
monitor.on('stats-collected', listener);
}

return () => {
if (!monitor) {
return;
}
if (listener) {
monitor.off('stats-collected', listener);
}
};
}, []);

return (
<Stats
orientation='vertical'
horizontalPlacement='left'
verticalPlacement='bottom'
>
{outboundStats.map((stats, index) => {

return (
<div key={index + 100010}>
<b key={index + 1}>SSRC: {stats.ssrc}</b><br />
<span key={index + 2}>sending: {stats.sendingKbps ?? -1} kbps</span><br />
<span key={index + 3}>RTT: {stats.RTT ?? -1} ms</span><br />
<span key={index + 4}>Fps: {stats.Fps ?? -1}</span><br />
<span key={index + 5}>Res: {stats.frameWidth ?? -1}x{stats.frameHeight ?? -1} ({stats.rid ?? -1})</span><br />
<br />
</div>
);
})}
</Stats>);
};

export default MeStatsView;
105 changes: 36 additions & 69 deletions src/components/rtpquality/PeerStatsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import { ServiceContext } from '../../store/store';
import Stats from './Stats';
import { TrackStats } from '@observertc/client-monitor-js';

// import { Logger } from '../../utils/Logger';

// const logger = new Logger('PeerStatsView');

interface PeerStatsViewProps {
producerId?: string;
consumerId?: string;
}

Expand All @@ -14,34 +17,8 @@ type InboundStats = {
receivedKbps?: number;
fractionLoss?: number;
meanOpinionScore?: number;
}

type OutboundStats = {
ssrc: number;
sendingKbps?: number;
RTT?: number;
Fps?: number;
}

function createOutboundStats(trackStats: TrackStats, avgRttInS?: number): OutboundStats[] {
if (trackStats.direction !== 'outbound') return [];

const result: OutboundStats[] = [];

for (const outboundRtpEntry of trackStats.outboundRtps()) {

const stats = outboundRtpEntry.stats;
const item: OutboundStats = {
ssrc: stats.ssrc,
sendingKbps: Math.floor((outboundRtpEntry.sendingBitrate ?? 0) / 1000),
Fps: stats.framesPerSecond,
RTT: Math.round(Math.max(0, avgRttInS ?? 0) * 1000),
};

result.push(item);
}

return result;
frameWidth?: number;
frameHeight?: number;
}

function createInboundStats(trackStats: TrackStats): InboundStats[] {
Expand All @@ -50,12 +27,14 @@ function createInboundStats(trackStats: TrackStats): InboundStats[] {
const result: InboundStats[] = [];

for (const inboundRtpEntry of trackStats.inboundRtps()) {
// inboundRtpStats.stats
const stats = inboundRtpEntry.stats;

const item: InboundStats = {
ssrc: inboundRtpEntry.stats.ssrc,
ssrc: stats.ssrc,
receivedKbps: Math.floor(((inboundRtpEntry.receivingBitrate ?? 0) / 1000)),
fractionLoss: Math.round((inboundRtpEntry.fractionLoss ?? 0) * 100) / 100,
frameWidth: stats.frameWidth ?? 0,
frameHeight: stats.frameHeight ?? 0,
};

result.push(item);
Expand All @@ -65,12 +44,10 @@ function createInboundStats(trackStats: TrackStats): InboundStats[] {
}

const PeerStatsView = ({
producerId,
consumerId,
}: PeerStatsViewProps): JSX.Element => {
const { mediaService } = useContext(ServiceContext);
const [ inboundStats, setInboundStats ] = useState<InboundStats [ ] >([ ]);
const [ outboundStats, setOutboundStats ] = useState<OutboundStats [ ] >([ ]);

useEffect(() => {
// this runs on mount
Expand All @@ -79,36 +56,36 @@ const PeerStatsView = ({
if (!monitor) {
return;
}
if (!producerId && !consumerId) {
return;
} else if (producerId && consumerId) {
if (!consumerId) {
return;
}

let listener: () => void | undefined;
const storage = monitor.storage;

if (mediaService.previewWebcamTrack) {

listener = () => {
const trackId = mediaService.previewWebcamTrack?.id;

if (!trackId) {
return;
}
const trackStats = storage.getTrack(trackId);

if (!trackStats) {
return;
}

const newOutboundStats = createOutboundStats(trackStats, storage.avgRttInS);

setOutboundStats(newOutboundStats);
};
monitor.on('stats-collected', listener);

} else if (consumerId) {
// Debug
/*
for (const inboundRtp of storage.inboundRtps()) {
const receiver = inboundRtp.getReceiver();
const trackId = inboundRtp.getTrackId();
const ssrc = inboundRtp.getSsrc();
const remoteOutboundRtp = inboundRtp.getRemoteOutboundRtp();
const peerConnection = inboundRtp.getPeerConnection();
const transport = inboundRtp.getTransport();
const codec = inboundRtp.getCodec();

logger.debug(trackId, ssrc,
inboundRtp.stats,
remoteOutboundRtp?.stats,
receiver?.stats,
peerConnection.stats,
transport?.stats,
codec?.stats
);
}
*/

if (consumerId) {
const consumer = mediaService.getConsumer(consumerId);

if (consumer) {
Expand Down Expand Up @@ -155,18 +132,8 @@ const PeerStatsView = ({
<span key={index + 2}>receiving: {stats.receivedKbps ?? -1} kbps</span><br />
<span key={index + 3}>FractionLoss: {stats.fractionLoss ?? -1}</span><br />
<span key={index + 4}>MOS: {stats.meanOpinionScore}</span><br />
</div>
);
})}
{outboundStats.map((stats, index) => {
return (
<div key={index + 100010}>
<b key={index + 1}>SSRC: {stats.ssrc}</b><br />
<span key={index + 2}>sending: {stats.sendingKbps ?? -1} kbps</span><br />
<span key={index + 3}>RTT: {stats.RTT ?? -1} ms</span><br />
<span key={index + 4}>Fps: {stats.Fps ?? -1}</span><br />
<span key={index + 5}>Res: {stats.frameWidth ?? -1}x{stats.frameHeight ?? -1}</span><br />
<br />

</div>
);
})}
Expand Down
2 changes: 0 additions & 2 deletions src/services/mediaService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ export class MediaService extends EventEmitter {
consumer.observer.once('close', () => this.consumers.delete(consumer.id));
consumer.once('transportclose', () => this.changeConsumer(consumer.id, 'close', false));

if (paused) this.changeConsumer(consumer.id, 'resume', true);

this.emit('consumerCreated', consumer, paused, consumerPaused, false);

this.consumerCreationState.delete(id);
Expand Down