New consumer added missing MediaStreamTrack object info

In this.protooPeer.on('request', async (request, accept, reject) => {... I’m handling the newConsumer value for request.method in a switch statement using the below code.

case 'newConsumer': {

          const {
            peerId,
            producerId,
            id,
            kind,
            rtpParameters,
            type,
            appData,
            producerPaused,
          } = request.data

          try {
            const consumer = await this.recvTransport?.consume({
              id,
              producerId,
              kind,
              rtpParameters,
              appData: { ...appData, peerId },
            })!

            // Store in the map.
            this.consumers.set(consumer.id, consumer)

            consumer.on('transportclose', () => {
              this.consumers.delete(consumer.id)
            })

            const consumerRtpParams = consumer.rtpParameters
            const consumerScalabilityMode = consumerRtpParams.encodings![0]
              ?.scalabilityMode!

            const {
              spatialLayers,
              temporalLayers,
            } = mediasoupClient.parseScalabilityMode(consumerScalabilityMode)

// Gathering data here regarding the consumer, layers, etc...see JSON below 

Here’s the data I gather with the consumer.track: MediaStreamTrack property which I need to bind to the HTML element and enable the video/audio stream.

{
  "id": "4fb46745-7cff-4f3e-a6fa-b0ff626e62f3",
  "peerId": "mitch-12345",
  "type": "simulcast",
  "locallyPaused": false,
  "remotelyPaused": false,
  "rtpParameters": {
    "codecs": [
      {
        "mimeType": "video/H264",
        "payloadType": 105,
        "clockRate": 90000,
        "parameters": {
          "level-asymmetry-allowed": 1,
          "packetization-mode": 1,
          "profile-level-id": "4d0032"
        },
        "rtcpFeedback": [
          {
            "type": "transport-cc",
            "parameter": ""
          },
          {
            "type": "ccm",
            "parameter": "fir"
          },
          {
            "type": "nack",
            "parameter": ""
          },
          {
            "type": "nack",
            "parameter": "pli"
          }
        ]
      },
      {
        "mimeType": "video/rtx",
        "payloadType": 106,
        "clockRate": 90000,
        "parameters": {
          "apt": 105
        },
        "rtcpFeedback": [
          
        ]
      }
    ],
    "headerExtensions": [
      {
        "uri": "urn:ietf:params:rtp-hdrext:sdes:mid",
        "id": 1,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
        "id": 4,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
        "id": 5,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07",
        "id": 6,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "urn:3gpp:video-orientation",
        "id": 11,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "urn:ietf:params:rtp-hdrext:toffset",
        "id": 12,
        "encrypt": false,
        "parameters": {
          
        }
      }
    ],
    "encodings": [
      {
        "ssrc": 340544270,
        "rtx": {
          "ssrc": 130972761
        },
        "scalabilityMode": "S3T3",
        "maxBitrate": 5000000,
        "dtx": false
      }
    ],
    "rtcp": {
      "cname": "u0ZvBggNCA3Sw0xS",
      "reducedSize": true,
      "mux": true
    },
    "mid": "1"
  },
  "spatialLayers": 3,
  "temporalLayers": 3,
  "preferredSpatialLayer": 2,
  "preferredTemporalLayer": 2,
  "priority": 1,
  "codec": "H264",
  "track": {
    
  },
  "consumerClosed": false,
  "consumerPaused": false,
  "consumerLocalId": "1"
}

I also receive the consumerScore notification
protooPeer notification consumerScore 4fb46745-7cff-4f3e-a6fa-b0ff626e62f3 - {"producerScore":0,"producerScores":[0,0,0],"score":10}

Any ideas on how can I debug this to grab the MediaStreamTrack?

No idea what’s wrong in your code, but consumer.track is a getter that returns the remote MediaStreamTrack instance, and not the object you have printed above.

Sorry for the confusion the object I printed above is just a custom object I gather info like the below and pass to components listening for events. See example below.

{
              eventName: RoomClientEvents.ConsumerAdded,
              data: {
                id: consumer.id,
                peerId: peerId,
                type: type,
                locallyPaused: false,
                remotelyPaused: producerPaused,
                rtpParameters: consumer.rtpParameters,
                spatialLayers: spatialLayers,
                temporalLayers: temporalLayers,
                preferredSpatialLayer: spatialLayers - 1,
                preferredTemporalLayer: temporalLayers - 1,
                priority: 1,
                codec: consumer.rtpParameters.codecs[0].mimeType.split('/')[1],
                track: consumer.track,
                consumerClosed: consumer.closed,
                consumerPaused: consumer.paused,
                consumerLocalId: consumer.localId,
              },

My problem is still the same and I guess I’m right I need the remote MediaStreamTrack instance to show video of the consumer in my reactjs component;

consumer.track is empty object.

"track": {
    
  },

Server logs show 2 peers and 4 transports so it looks like it is working fine.

The code server side.

await consumerPeer.request(
				'newConsumer',
				{
					peerId: producerPeer.id,
					producerId: producer.id,
					id: consumer.id,
					kind: consumer.kind,
					rtpParameters: consumer.rtpParameters,
					type: consumer.type,
					appData: producer.appData,
					producerPaused: consumer.producerPaused
				})

No idea what is wrong, honestly. But obviously consumer.track does work.

  • After consumer = await this.recvTransport?.consume(...) print the obtained consumer.
  • Then print the consumer.track. It cannot be an empty object at all. I mean, it’s impossible, so this is something additional in your code.

After

const consumer = await this.recvTransport?.consume({
              id,
              producerId,
              kind,
              rtpParameters,
              appData: { ...appData, peerId }, 
            })!

Here’s the new consumer object…

{
  "_events": {
    
  },
  "_eventsCount": 2,
  "_maxListeners": null,
  "_closed": false,
  "_id": "ab93245c-3d7b-4ea1-91bb-be69e4032e99",
  "_localId": "1",
  "_producerId": "4aab5f2d-91d9-4527-b913-f96be4477599",
  "_rtpReceiver": {
    
  },
  "_track": {
    
  },
  "_rtpParameters": {
    "codecs": [
      {
        "mimeType": "video/H264",
        "payloadType": 105,
        "clockRate": 90000,
        "parameters": {
          "level-asymmetry-allowed": 1,
          "packetization-mode": 1,
          "profile-level-id": "4d0032"
        },
        "rtcpFeedback": [
          {
            "type": "transport-cc",
            "parameter": ""
          },
          {
            "type": "ccm",
            "parameter": "fir"
          },
          {
            "type": "nack",
            "parameter": ""
          },
          {
            "type": "nack",
            "parameter": "pli"
          }
        ]
      },
      {
        "mimeType": "video/rtx",
        "payloadType": 106,
        "clockRate": 90000,
        "parameters": {
          "apt": 105
        },
        "rtcpFeedback": [
          
        ]
      }
    ],
    "headerExtensions": [
      {
        "uri": "urn:ietf:params:rtp-hdrext:sdes:mid",
        "id": 1,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
        "id": 4,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
        "id": 5,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07",
        "id": 6,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "urn:3gpp:video-orientation",
        "id": 11,
        "encrypt": false,
        "parameters": {
          
        }
      },
      {
        "uri": "urn:ietf:params:rtp-hdrext:toffset",
        "id": 12,
        "encrypt": false,
        "parameters": {
          
        }
      }
    ],
    "encodings": [
      {
        "ssrc": 690200973,
        "rtx": {
          "ssrc": 104632687
        },
        "scalabilityMode": "S3T3",
        "maxBitrate": 5000000,
        "dtx": false
      }
    ],
    "rtcp": {
      "cname": "CivOzxR9LYsGl6zy",
      "reducedSize": true,
      "mux": true
    },
    "mid": "1"
  },
  "_paused": false,
  "_appData": {
    "peerId": "mitch-12345"
  }
}

And consumer.track
{}

This cannot happen when in a browser. You didn’t tell about your device BTW.

Anyway, take the perconnection of the recvTransport (using recvTransport._handler._pc) and iterate its RTCRtpReceivers using pc.getReceivers() and check their track property.

hmmm, I was actually using Chrome on macOS and debugging as iPhone which could raise issues but changed to just responsive and still the same result.

recvTransport._handler._pc is private and inaccessible recvTransport.handler._pc doesn’t exist. I am using reactjs TypeScript and maybe prevents accessing the variables.

Another interesting part is I receive two newConsumer events for the same peer with different IDs.


First has producer score and the second doesn’t.

Use @ts-ignore to prevent TS errors. transport._handler._pc does exist even if it’s private at TS level.

I don’t know what else I can tell. consumer.track obviously works, otherwise no mediasoup-client based app would work.

I understand but clearly something is wrong either with my code, maybe because I am using Chrome but it doesn’t look like there’s an issue, I’ve tried one tab in Safari and one in Chrome (usually I just use two tabs in Chrome.

const pc = this.recvTransport._handler._pc
const receivers = pc.getReceivers()
receivers.forEach((element) => {
    logger.info(`receiver track: ${JSON.stringify(element.track)}`)
})

No luck :confused:
3 times [core.RoomClient] receiver track: {}

Just room the mediasoup-demo with two peers and print the same by accessing CC.recvTransport._handler._pc

@ibc I enabled mediasoup-client logging and print the console trying to consume a newPeer joined the room. https://gist.github.com/xplatsolutions/bdb2454543dc2f7a1be5c8596314a13c

I noticed this weird trackId in line mediasoup-client:Chrome74 receive() [trackId:probator, kind:video] +75ms

Let me know if you see anything interesting.

Nothing wrong in that log

Why do I get 3 receive() with the last one to be video and id probator?

For RTP probation purposes.

One advice: if you take a look to the logs for the first time, everything will look the cause of your current issue.

You may have something in your app (another library) that is overriding the PeerConnection and/or MediaStreamTrack classes. No idea.

To clarify: consumer.track is the MediaStreamTrack that mediasoup-client reads from the corresponding Transceiver in the PeerConnection. It’s completely impossible that it’s an empty object. Mediasoup-client does not mangle/modify the track object at all.

If your PC has empty objects as tracks in getReceivers() then the problem is elsewhere.

BTW: don’t print the track with JSON.stringify, please, that will just take public properties of the track. Do a simple console.log(“track:”, consumer.track)

OK, I will debug with a fresh Chrome browser restarted. Mediasoup demo though works fine when I use two tabs opened for the same browser window.

I don’t use any other library and following pretty much what mediasoup-demo implementation does. I do use though two RoomClient instances which I believe is just fine.

We’re using "mediasoup-client": "^3.6.12".

Do you think calling multiple times navigator.mediaDevices.getUserMedia could cause such an issue?

OK I might have been chasing ghosts before I even bind the MediaStreamTrack object to an HTML element because I was working in the business layer and freaking out that the object is empty, little I know about JSON.stringify printing only public properties! I have to work on the logger I use, printing the object with console.log show the MediaStreamTrack in muted state at the moment.

consumer track: 
MediaStreamTrack {kind: "video", id: "4c6c5831-677b-4c36-8a6e-2fc3e7297102", label: "4c6c5831-677b-4c36-8a6e-2fc3e7297102", enabled: true, muted: false, …}
contentHint: ""
enabled: true
id: "4c6c5831-677b-4c36-8a6e-2fc3e7297102"
kind: "video"
label: "4c6c5831-677b-4c36-8a6e-2fc3e7297102"
muted: true
onended: null
onmute: null
onunmute: null
readyState: "live"
__proto__: MediaStreamTrack

:point_up_2:

I won’t enter into strange hypotheses. The only issue I see in your code is that you print a MediaStreamTrack with JSON.stringify(). If you do that it will print just {} as I explained above. You are assuming that there is a bug just because JSON.stringify(track) returns {} (as expected).

I replied at the same time…and yes I assumed there is a bug but in reality doesn’t look like there’s any issue :slight_smile:

I will continue with the UI to verify but definitely everything looks good ! Thanks @ibc, your help is appreciated!