Open shripad-agashe opened 6 years ago
Do you want to set the subscriber/publisher controls to false?, I mean to hide the controls?
No. I want to be able to supply a custom UI for subscriber. The basic use case is to make it change size based on who is speaking etc. The fix is exactly like the one mentioned in issue above.
Hello, I am also having this issue. I want to get the video element triggered on videoElementCreated
event when insertDefaultUI = false
Any news about this issue? Publisher is properly working.
I am having the same issue. Any news?
Edit: I don't have enough time to wait for updates, so I've modified the OTSubscriber component until this bug is fixed.
Here's my component in case someone else is having the same issue:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import uuid from 'uuid';
export class OTSubscriber extends Component {
constructor(props, context) {
super(props);
this.state = {
subscriber: null,
stream: props.stream || context.stream || null,
session: props.session || context.session || null,
};
}
componentDidMount() {
this.createSubscriber();
}
componentDidUpdate(prevProps, prevState) {
const cast = (value, Type, defaultValue) => (value === undefined ? defaultValue : Type(value));
const updateSubscriberProperty = (key) => {
const previous = cast(prevProps.properties[key], Boolean, true);
const current = cast(this.props.properties[key], Boolean, true);
if (previous !== current) {
this.state.subscriber[key](current);
}
};
updateSubscriberProperty('subscribeToAudio');
updateSubscriberProperty('subscribeToVideo');
if (prevState.session !== this.state.session || prevState.stream !== this.state.stream) {
this.destroySubscriber(prevState.session);
this.createSubscriber();
}
}
componentWillUnmount() {
this.destroySubscriber();
}
getSubscriber() {
return this.state.subscriber;
}
createSubscriber() {
if (!this.state.session || !this.state.stream) {
this.setState({ subscriber: null });
return;
}
let container = null;
const { properties } = this.props;
if (!properties || properties.insertDefaultUI || properties.insertDefaultUI === undefined) {
container = document.createElement('div');
container.setAttribute('class', 'OTSubscriberContainer');
this.node.appendChild(container);
}
this.subscriberId = uuid();
const { subscriberId } = this;
const subscriber = this.state.session.subscribe(
this.state.stream,
container,
this.props.properties,
(err) => {
if (subscriberId !== this.subscriberId) {
// Either this subscriber has been recreated or the
// component unmounted so don't invoke any callbacks
return;
}
if (err && typeof this.props.onError === 'function') {
this.props.onError(err);
} else if (!err && typeof this.props.onSubscribe === 'function') {
this.props.onSubscribe();
}
},
);
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
subscriber.on(this.props.eventHandlers);
}
this.setState({ subscriber });
}
destroySubscriber(session = this.props.session) {
delete this.subscriberId;
if (this.state.subscriber) {
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
this.state.subscriber.once('destroyed', () => {
this.state.subscriber.off(this.props.eventHandlers);
});
}
if (session) {
session.unsubscribe(this.state.subscriber);
}
}
}
render() {
return <div ref={(node) => { this.node = node; }} />;
}
}
OTSubscriber.propTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
properties: PropTypes.object, // eslint-disable-line react/forbid-prop-types
eventHandlers: PropTypes.objectOf(PropTypes.func),
onSubscribe: PropTypes.func,
onError: PropTypes.func,
};
OTSubscriber.defaultProps = {
stream: null,
session: null,
properties: {},
eventHandlers: null,
onSubscribe: null,
onError: null,
};
OTSubscriber.contextTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
};
session: props.session || context.session || null,
};
}
componentDidMount() {
this.createSubscriber();
}
componentDidUpdate(prevProps, prevState) {
const cast = (value, Type, defaultValue) => (value === undefined ? defaultValue : Type(value));
const updateSubscriberProperty = (key) => {
const previous = cast(prevProps.properties[key], Boolean, true);
const current = cast(this.props.properties[key], Boolean, true);
if (previous !== current) {
this.state.subscriber[key](current);
}
};
updateSubscriberProperty('subscribeToAudio');
updateSubscriberProperty('subscribeToVideo');
if (prevState.session !== this.state.session || prevState.stream !== this.state.stream) {
this.destroySubscriber(prevState.session);
this.createSubscriber();
}
}
componentWillUnmount() {
this.destroySubscriber();
}
getSubscriber() {
return this.state.subscriber;
}
createSubscriber() {
if (!this.state.session || !this.state.stream) {
this.setState({ subscriber: null });
return;
}
let container = null;
if (!this.props.properties || this.props.properties.insertDefaultUI) {
container = document.createElement('div');
container.setAttribute('class', 'OTSubscriberContainer');
this.node.appendChild(container);
}
this.subscriberId = uuid();
const { subscriberId } = this;
const subscriber = this.state.session.subscribe(
this.state.stream,
container,
this.props.properties,
(err) => {
if (subscriberId !== this.subscriberId) {
// Either this subscriber has been recreated or the
// component unmounted so don't invoke any callbacks
return;
}
if (err && typeof this.props.onError === 'function') {
this.props.onError(err);
} else if (!err && typeof this.props.onSubscribe === 'function') {
this.props.onSubscribe();
}
},
);
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
subscriber.on(this.props.eventHandlers);
}
this.setState({ subscriber });
}
destroySubscriber(session = this.props.session) {
delete this.subscriberId;
if (this.state.subscriber) {
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
this.state.subscriber.once('destroyed', () => {
this.state.subscriber.off(this.props.eventHandlers);
});
}
if (session) {
session.unsubscribe(this.state.subscriber);
}
}
}
render() {
return <div ref={(node) => { this.node = node; }} />;
}
}
OTSubscriber.propTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
properties: PropTypes.object, // eslint-disable-line react/forbid-prop-types
eventHandlers: PropTypes.objectOf(PropTypes.func),
onSubscribe: PropTypes.func,
onError: PropTypes.func,
};
OTSubscriber.defaultProps = {
stream: null,
session: null,
properties: {},
eventHandlers: null,
onSubscribe: null,
onError: null,
};
OTSubscriber.contextTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
};
Would love to see this fixe being merged.
Because the fix above seems old and has a duplication on the copy/paste (it should be around 180 lines) here is my hot fix where the only change is
let container;
if (!this.props.properties || this.props.properties.insertDefaultUI) {
container = document.createElement('div');
container.setAttribute('class', 'OTSubscriberContainer');
this.node.appendChild(container);
}
Complete file:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import uuid from 'uuid';
export default class OTSubscriber extends Component {
constructor(props, context) {
super(props);
this.state = {
subscriber: null,
stream: props.stream || context.stream || null,
session: props.session || context.session || null,
currentRetryAttempt: 0,
};
this.maxRetryAttempts = props.maxRetryAttempts || 5;
this.retryAttemptTimeout = props.retryAttemptTimeout || 1000;
}
componentDidMount() {
this.createSubscriber();
}
componentDidUpdate(prevProps, prevState) {
const cast = (value, Type, defaultValue) => (value === undefined ? defaultValue : Type(value));
const updateSubscriberProperty = (key) => {
const previous = cast(prevProps.properties[key], Boolean, true);
const current = cast(this.props.properties[key], Boolean, true);
if (previous !== current) {
this.state.subscriber[key](current);
}
};
updateSubscriberProperty('subscribeToAudio');
updateSubscriberProperty('subscribeToVideo');
if (prevState.session !== this.state.session || prevState.stream !== this.state.stream) {
this.destroySubscriber(prevState.session);
this.createSubscriber();
}
}
componentWillUnmount() {
this.destroySubscriber();
}
getSubscriber() {
return this.state.subscriber;
}
createSubscriber() {
if (!this.state.session || !this.state.stream) {
this.setState({ subscriber: null });
return;
}
let container;
if (!this.props.properties || this.props.properties.insertDefaultUI) {
container = document.createElement('div');
container.setAttribute('class', 'OTSubscriberContainer');
this.node.appendChild(container);
}
this.subscriberId = uuid();
const { subscriberId } = this;
const subscriber = this.state.session.subscribe(
this.state.stream,
container,
this.props.properties,
(err) => {
if (subscriberId !== this.subscriberId) {
// Either this subscriber has been recreated or the
// component unmounted so don't invoke any callbacks
return;
}
if (err &&
this.props.retry &&
this.state.currentRetryAttempt < (this.maxRetryAttempts - 1)) {
// Error during subscribe function
this.handleRetrySubscriber();
// If there is a retry action, do we want to execute the onError props function?
// return;
}
if (err && typeof this.props.onError === 'function') {
this.props.onError(err);
} else if (!err && typeof this.props.onSubscribe === 'function') {
this.props.onSubscribe();
}
},
);
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
subscriber.on(this.props.eventHandlers);
}
this.setState({ subscriber });
}
handleRetrySubscriber() {
setTimeout(() => {
this.setState(state => ({
currentRetryAttempt: state.currentRetryAttempt + 1,
subscriber: null,
}));
this.createSubscriber();
}, this.retryAttemptTimeout);
}
destroySubscriber(session = this.props.session) {
delete this.subscriberId;
if (this.state.subscriber) {
if (
this.props.eventHandlers &&
typeof this.props.eventHandlers === 'object'
) {
this.state.subscriber.once('destroyed', () => {
this.state.subscriber.off(this.props.eventHandlers);
});
}
if (session) {
session.unsubscribe(this.state.subscriber);
}
}
}
render() {
const { className, style } = this.props;
return <div className={className} style={style} ref={(node) => { this.node = node; }} />;
}
}
OTSubscriber.propTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
className: PropTypes.string,
style: PropTypes.object, // eslint-disable-line react/forbid-prop-types
properties: PropTypes.object, // eslint-disable-line react/forbid-prop-types
retry: PropTypes.bool,
maxRetryAttempts: PropTypes.number,
retryAttemptTimeout: PropTypes.number,
eventHandlers: PropTypes.objectOf(PropTypes.func),
onSubscribe: PropTypes.func,
onError: PropTypes.func,
};
OTSubscriber.defaultProps = {
stream: null,
session: null,
className: '',
style: {},
properties: {},
retry: false,
maxRetryAttempts: 5,
retryAttemptTimeout: 1000,
eventHandlers: null,
onSubscribe: null,
onError: null,
};
OTSubscriber.contextTypes = {
stream: PropTypes.shape({
streamId: PropTypes.string,
}),
session: PropTypes.shape({
subscribe: PropTypes.func,
unsubscribe: PropTypes.func,
}),
};
I guess the fix is similar to issue mentioned below. https://github.com/opentok/opentok-react/issues/3