1
votes

enter image description hereI created a project with angular 9 and that allow create a video calls using a library Twilio Video chat room. but unable to connect remote participant in video chat room, due to track.attach is not a function.

ERROR TypeError: track.attach is not a function
1

1 Answers

-2
votes

Please check this you will get your solution.

import { Injectable, EventEmitter, ElementRef, Renderer2, RendererFactory2 } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs';
import { connect, createLocalTracks, createLocalVideoTrack } from 'twilio-video';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Http } from '@angular/http';
import { Router } from '@angular/router';
import { BaCustomPreLoader } from './baCustomPreloader.service';


@Injectable()
export class TwilioService {

  remoteVideo: ElementRef;
  localVideo: ElementRef;
  previewing: boolean;
  msgSubject = new BehaviorSubject("");
  roomObj: any;

  roomParticipants;

  private renderer: Renderer2;
  constructor(
    private http: Http,
    private router: Router,
    private rendererFactory: RendererFactory2,
    private baCustomPreLoader: BaCustomPreLoader) {
    this.renderer = rendererFactory.createRenderer(null, null);
  }
  microphone = true;

  mute() {
    this.roomObj.localParticipant.audioTracks.forEach(function (
      audioTrack
    ) {
      audioTrack.track.disable();
    });
    this.microphone = false;
  }


  unmute() {
    this.roomObj.localParticipant.audioTracks.forEach(function (
      audioTrack
    ) {
      audioTrack.track.enable();
    });
    this.microphone = true;
  }


  connectToRoom(accessToken: string, options): void {
    connect(accessToken, options).then(room => {
      this.roomObj = room;

      if (!this.previewing && options['video']) {
        this.startLocalVideo();
        this.previewing = true;
      }

      this.roomParticipants = room.participants;
      room.participants.forEach(participant => {
        this.attachParticipantTracks(participant);
      });

      room.on('participantDisconnected', (participant) => {
        this.detachParticipantTracks(participant);
      });

      room.on('participantConnected', (participant) => {
        this.roomParticipants = room.participants;
        this.attachParticipantTracks(participant);

        participant.on('trackPublished', track => {

          const element = track.attach();
          this.renderer.data.id = track.sid;
          this.renderer.setStyle(element, 'height', '100%');
          this.renderer.setStyle(element, 'max-width', '100%');
          this.renderer.appendChild(this.remoteVideo.nativeElement, element);
          this.baCustomPreLoader.hide();
        });
      });

      // When a Participant adds a Track, attach it to the DOM.
      room.on('trackPublished', (track, participant) => {
        this.attachTracks([track]);
      });

      // When a Participant removes a Track, detach it from the DOM.
      room.on('trackRemoved', (track, participant) => {
        this.detachTracks([track]);
      });

      room.once('disconnected', room => {
        room.localParticipant.tracks.forEach(track => {
          track.track.stop();
          const attachedElements = track.track.detach();
          attachedElements.forEach(element => element.remove());
          room.localParticipant.videoTracks.forEach(video => {
            const trackConst = [video][0].track;
            trackConst.stop();

            trackConst.detach().forEach(element => element.remove());

            room.localParticipant.unpublishTrack(trackConst);
          });



          let element = this.remoteVideo.nativeElement;
          while (element.firstChild) {
            element.removeChild(element.firstChild);
          }
          let localElement = this.localVideo.nativeElement;
          while (localElement.firstChild) {
            localElement.removeChild(localElement.firstChild);
          }
          this.router.navigate(['thanks']);
          setTimeout(() => {
            window.location.reload();
          }, 1000)
        });

      });
    }, (error) => {
      alert(error.message);
    });
  }

  attachParticipantTracks(participant): void {
    participant.tracks.forEach(part => {
      this.trackPublished(part);
    });
  }

  trackPublished(publication) {

    if (publication.isSubscribed)
      this.attachTracks(publication.track);

    if (!publication.isSubscribed)
      publication.on('subscribed', track => {
        this.attachTracks(track);
      });
  }

  attachTracks(tracks) {
    const element = tracks.attach();
    this.renderer.data.id = tracks.sid;
    this.renderer.setStyle(element, 'height', '100%');
    this.renderer.setStyle(element, 'max-width', '100%');
    this.renderer.appendChild(this.remoteVideo.nativeElement, element);
    this.baCustomPreLoader.hide();
  }

  startLocalVideo(): void {
    createLocalVideoTrack({
      video: { width: 1280, height: 720 },
    }).then(track => {
      if (this.localVideo) {
        const element = track.attach();
        this.renderer.data.id = track.sid;
        this.renderer.setStyle(element, 'width', '25%');
        this.renderer.appendChild(this.localVideo.nativeElement, element);
      }
    });
  }

  detachParticipantTracks(participant) {
    this.detachTracks(participant);
  }

  detachTracks(tracks): void {
    tracks.tracks.forEach(track => {
      let element = this.remoteVideo.nativeElement;
      while (element.firstChild) {
        element.removeChild(element.firstChild);
      }
    });
  }
}