Reputation: 2174
I'm using Twillio JS API in my project to display video outputs from multiple sources. This API generates enumeration of DOM video/audio elements that can be attached to the page as follows:
let tracks = TwillioVideo.createLocalTracks({
video: { deviceId: this.state.selectedVideoInput.deviceId },
audio: { deviceId: this.state.selectedAudioInput.deviceId }
}
//Find dom element to attach tracks to
let previewContainer = document.getElementById('local-media')
//Attach all tracks
this.setState({localTracks: tracks})
tracks.forEach(track => previewContainer.appendChild(track.attach()))
track.attach()
generates a dom element that can be appended but its not something i can put in React state so it can be rendered like so:
<div id="local-media">{this.state.localTracks.map(track => track.attach()}</div>
If I in fact try to do it i get:
Unhandled Rejection (Invariant Violation): Objects are not valid as a React child (found: [object HTMLAudioElement]). If you meant to render a collection of children, use an array instead.
EDIT 1: I was able to get rid of error by doing this:
{this.state.localTracks.map(track => track.attach().Element)}
but it's not returning renderable html but undefined
instead
Upvotes: 1
Views: 1608
Reputation: 73057
Twilio developer evangelist here.
The attach
method in Twilio Video can take an argument, which is an HTMLMediaElement
, and will attach the media to that element.
I would recommend that you create a component you can use to render the media for each media track and then use React refs to get a pointer to the DOM element.
Something like this:
import React, { Component, createRef } from 'react';
class Participant extends Component {
constructor(props) {
super(props);
this.video = createRef();
this.audio = createRef();
this.trackAdded = this.trackAdded.bind(this);
}
trackAdded(track) {
if (track.kind === 'video') {
track.attach(this.video.current);
} else if (track.kind === 'audio') {
track.attach(this.audio.current);
}
}
componentDidMount() {
const videoTrack = Array.from(
this.props.participant.videoTracks.values()
)[0];
if (videoTrack) {
videoTrack.attach(this.video.current);
}
const audioTrack = Array.from(
this.props.participant.audioTracks.values()
)[0];
if (audioTrack) {
audioTrack.attach(this.audio.current);
}
this.props.participant.on('trackAdded', this.trackAdded);
}
render() {
return (
<div className="participant">
<h3>{this.props.participant.identity}</h3>
<video ref={this.video} autoPlay={true} muted={true} />
<audio ref={this.audio} autoPlay={true} muted={true} />
</div>
);
}
}
export default Participant;
Then, for every participant in your chat, you can render one of these component.
Let me know if this helps at all.
Upvotes: 1