TypeError: duplicated codec.preferredPayloadType

Hi! I’m trying to use a Router that handles all default codecs supported by mediasoup; for this, the docs are not too explicit (or I’m blind and didn’t see it) because they always show examples where some specific codecs are passed to worker.createRouter(RouterOptions), but I wasn’t able to find some example where no codecs are specified (“use everything you can”)

First attempt: worker.createRouter({})

So first I saw that RouterOptions.mediaCodecs is optional, but RouterOptions itself is required in worker.createRouter(RouterOptions), hence I pass an empty object:

let router = await worker.createRouter({});

This doesn’t work; what it does is the same as if an empty array had been passed, i.e. it is equivalent to this:

let router = await worker.createRouter({ mediaCodecs: [] });

which means the opposite of what I wanted: now mediasoup is configured to work without any codec.

This causes an error later down the way, while trying to produce on some transport:

  mediasoup:Transport produce()
  mediasoup:Channel request() [method:transport.produce, id:4]
  mediasoup:ERROR:Channel [pid:75547 RTC::RtpParameters::RtpParameters() | throwing MediaSoupTypeError: empty codecs
  mediasoup:ERROR:Channel [pid:75547 Worker::OnChannelRequest() | throwing MediaSoupTypeError: empty codecs [method:transport.produce]
  mediasoup:WARN:Channel request failed [method:transport.produce, id:4]:  [method:transport.produce]

Notice the error: empty codecs.

  • Q: Is that how it should work? I expected that the mediaCodecs field is not required precisely to be able to not restrict the set of codecs used by mediasoup. If this is however working as expected, maybe a line in the docs could be helpful to clarify that.

Second attempt: getSupportedRtpCapabilities()

I found this function, so now I’m trying to call

worker.createRouter({
  mediaCodecs: Mediasoup.getSupportedRtpCapabilities().codecs
});

but it throws an error:

  mediasoup:Worker createRouter()
  TypeError: duplicated codec.preferredPayloadType: 13

(the original code doesn’t print the problematic value, that’s something I added to the .js)

Fair enough, as I know the default capabilities come with some repeated PTs.

However, removing all preferredPayloadType fields also causes the same error, with the same PT number:

worker.createRouter({
  mediaCodecs: Mediasoup.getSupportedRtpCapabilities().codecs?.map((c) => {
    delete c.preferredPayloadType;
    return c;
  })
});
  mediasoup:Worker createRouter()
  TypeError: duplicated codec.preferredPayloadType: 13

(and the resulting object doesn’t contain any PTs, I verified)

So this also doesn’t work :frowning:

  • Q: Is there a recommended way to tell mediasoup “just use everything” instead of having to be explicit about the codecs that should be used? Is it maybe considered a bad practice to do so?

Thanks

A Router could just be used for DataChannels, that’s why mediaCodecs are no longer required.

Regarding “use everything”, payload types are limited (yes, due to weird SDP syntax limitations) so we cannot make your wish work. It wouldn’t scale plus probably it already fails if you try to load all supported codecs due to lack of available payload types. I mean, even if you don’t sent a preferredPayloadType, mediasoup needs to assign one to each codec, and these are super limited. So let’s assume this is not possible and it would be worse as far as we introduce more codecs (AV1, etc).

Oh so that’s why there isn’t an obvious way to just not having to specify any codec.

But it feels weird, I mean, when you ask other WebRTC implementations (i.e. some browser) about what are their capabilities, they just respond with a default set without any user or developer intervention. Wouldn’t that make sense for mediasoup?

Right now it’s like if I had to generate a test SDP Offer with Chrome, copy the result in a text file somewhere, and then use that to configure the PeerConnection in the actual app. Translated to mediasoup terms: call getSupportedRtpCapabilities(), copy the resulting array in some file, then use it for future calls to my application’s createRouter().

This has of course the disadvantage that I’d need to periodically print the getSupportedRtpCapabilities() with newer versions of mediasoup, to see if there are new stuff in there. Meanwhile, the newest Chrome introduced AV1 in their default SDP Offer, and didn’t see any issue there. So I’m a bit confused about what would really break.

I understand though, that PTs go from 96 to 127 to there are only 32 possible values. mediasoup v3.8 currently has 27 in its default array. The max number is indeed a potential problem in the future, but I also see that default mediasoup array contains a lot more codecs than most browsers, mainly because of minor combinatorial differences between audio ones.

Confirmed The error duplicated codec.preferredPayloadType was being caused by too many elements in the array returned by getSupportedRtpCapabilities(). Thanks for that tip!

This works; it just removes some of the most repeated codecs which are not that interesting for WebRTC usage with current web browsers:

worker.createRouter({
  mediaCodecs: Mediasoup.getSupportedRtpCapabilities()
    .codecs?.filter(
      (c) =>
        c.mimeType !== "audio/SILK" &&
        c.mimeType !== "audio/CN" &&
        c.mimeType !== "audio/telephone-event"
    )
    .map((c) => {
      delete c.preferredPayloadType;
      return c;
    }),
});

Then add a new more for every video codec (RTX codec).

Ooops! right :slight_smile: well for now it seemed to be enough by removing the most repeated audio codec combinations. In reality I just want something simple: that when mediasoup implements AV1, the app doesn’t need to be changed, that’s all.

I see, but it’s not really possible. There could be some helper utils that return nice set of media codecs.

1 Like

I marked that comment :point_up_2: as solution because that’s basically what it is. Maybe mediasoup is missing a small helper tool that provides all the latest and greatest capabilities in some useful shape that can be used directly by application, kind of how web browsers do when you ask them to generate a default SDP Offer without any other parameter. But then that’d be a proper feature request. For now, each app wanting such behavior needs to build such utility by itself.

Note for anyone finding this thread in the future: something simple like this is working fine for my particular needs (TypeError: duplicated codec.preferredPayloadType - #4 by j1elo) (yours might vary)

The thing is that, honestly, I don’t feel comfortable with mediasoup providing with those kind of helpers. I don’t want to make those decisions about which codecs are preferable, plus it’s impossible to decide a proper H264 codec since there are tons of configurations with different profile-level-id and other codec params.

Yeah I agree that maybe each app should worry about what to do for its own needs. Although maybe it turns out that majority of users just would like to do like me, and use whatever can be used! (maybe it’s a good topic for a survey)

I must confess initially it was very confusing to me, like “why does mediasoup make me write the explicit params to be used? I don’t even know which ones I need!”. Later I found the getSupportedRtpCapabilities() method, printed it, and copied some of the entries by hand. The docs mention this in passing, but maybe a more in depth section about this (kind of a “first steps” thing to do) would help new users (and not so new).

To close, let me nitpick about this:

it’s impossible to decide a proper H264 codec since there are tons of configurations with different profile-level-id and other codec params.

not exactly impossible for mediasoup, is it? I mean, everyone has the same issue, not only mediasoup. Web browsers indeed just solve it with a very simple solution, proposing multiple H264 payload types in their SDP offers. I mean if Chrome can get by with doing this… all of us can too, right? :slight_smile:

The simple answer is that I don’t want to decide which H264 codec configurations are better or most suitable for common use cases. And yes, users must be aware of how codec params work, this is not something they can bypass.

1 Like