Repository: pion/webrtc (go)

Issue:
conflict extmap id of header extensions
<!--
  Come join our community on Slack https://pion.ly/slack for quicker support and more resources

  We also provide a Knowledge Base https://pion.ly/knowledge-base that covers Pion and general WebRTC
  
  We maintain a FAQ of common issues and questions https://pion.ly/knowledge-base/pion-basics/faq/

 Please answer these questions before submitting your issue. Thanks!
-->

### Your environment.
  - Version: *Release or SHA* 
  - Browser: *include version*
  - Other Information - *stacktraces, related issues, suggestions how to fix, links for us to have context*

### What did you do?
<!--
If possible, provide an example for reproducing the error.
A complete runnable program is good.
-->

#2220 will generate duplicate extmap id for different uri, it can't pass this test case:

```
	t.Run("unique extmapid with different codec", func(t *testing.T) {
		m := &MediaEngine{}
		registerCodec(m)
		assert.NoError(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test"}, RTPCodecTypeAudio))
		assert.NoError(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test2"}, RTPCodecTypeVideo))

		audio := m.getRTPParametersByKind(RTPCodecTypeAudio, []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly})
		video := m.getRTPParametersByKind(RTPCodecTypeVideo, []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly})

		assert.Equal(t, 1, len(audio.HeaderExtensions))
		assert.Equal(t, 1, len(video.HeaderExtensions))
		assert.NotEqual(t, audio.HeaderExtensions[0].ID, video.HeaderExtensions[0].ID)
	})
```


### What did you expect?

generate unique extmap id for different extension uri in all media sections

### What happened?


Pull request description:
Generate unique extmap id for extensions
Generate unique extmap id for extesions with different uri

fix #2235 

#### Description

#### Reference issue
Fixes #...


Patch:
diff --git a/mediaengine.go b/mediaengine.go
index ad2ee7f4..cfe4e471 100644
--- a/mediaengine.go
+++ b/mediaengine.go
@@ -569,33 +569,35 @@ func (m *MediaEngine) getRTPParametersByKind(typ RTPCodecType, directions []RTPT
 			}
 		}
 	} else {
+		mediaHeaderExtensions := make(map[int]mediaEngineHeaderExtension)
 		for _, e := range m.headerExtensions {
-			if haveRTPTransceiverDirectionIntersection(e.allowedDirections, directions) && (e.isAudio && typ == RTPCodecTypeAudio || e.isVideo && typ == RTPCodecTypeVideo) {
-				usingNegotiatedID := false
-				for id := range m.negotiatedHeaderExtensions {
-					if m.negotiatedHeaderExtensions[id].uri == e.uri {
-						usingNegotiatedID = true
-						headerExtensions = append(headerExtensions, RTPHeaderExtensionParameter{ID: id, URI: e.uri})
-						break
-					}
+			usingNegotiatedID := false
+			for id := range m.negotiatedHeaderExtensions {
+				if m.negotiatedHeaderExtensions[id].uri == e.uri {
+					usingNegotiatedID = true
+					mediaHeaderExtensions[id] = e
+					break
 				}
-				if !usingNegotiatedID {
-					for id := 1; id < 15; id++ {
-						idAvailable := true
-						for checkID := range headerExtensions {
-							if headerExtensions[checkID].ID == id {
-								idAvailable = false
-								break
-							}
-						}
-						if _, taken := m.negotiatedHeaderExtensions[id]; idAvailable && !taken {
-							headerExtensions = append(headerExtensions, RTPHeaderExtensionParameter{ID: id, URI: e.uri})
-							break
-						}
+			}
+			if !usingNegotiatedID {
+				for id := 1; id < 15; id++ {
+					idAvailable := true
+					if _, ok := mediaHeaderExtensions[id]; ok {
+						idAvailable = false
+					}
+					if _, taken := m.negotiatedHeaderExtensions[id]; idAvailable && !taken {
+						mediaHeaderExtensions[id] = e
+						break
 					}
 				}
 			}
 		}
+
+		for id, e := range mediaHeaderExtensions {
+			if haveRTPTransceiverDirectionIntersection(e.allowedDirections, directions) && (e.isAudio && typ == RTPCodecTypeAudio || e.isVideo && typ == RTPCodecTypeVideo) {
+				headerExtensions = append(headerExtensions, RTPHeaderExtensionParameter{ID: id, URI: e.uri})
+			}
+		}
 	}
 
 	return RTPParameters{


Test patch:
diff --git a/mediaengine_test.go b/mediaengine_test.go
index 58e81ca6..5761f98e 100644
--- a/mediaengine_test.go
+++ b/mediaengine_test.go
@@ -415,6 +415,20 @@ func TestMediaEngineHeaderExtensionDirection(t *testing.T) {
 		assert.ErrorIs(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test"}, RTPCodecTypeAudio, RTPTransceiverDirectionInactive), ErrRegisterHeaderExtensionInvalidDirection)
 		assert.ErrorIs(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test"}, RTPCodecTypeAudio, RTPTransceiverDirection(0)), ErrRegisterHeaderExtensionInvalidDirection)
 	})
+
+	t.Run("Unique extmapid with different codec", func(t *testing.T) {
+		m := &MediaEngine{}
+		registerCodec(m)
+		assert.NoError(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test"}, RTPCodecTypeAudio))
+		assert.NoError(t, m.RegisterHeaderExtension(RTPHeaderExtensionCapability{"pion-header-test2"}, RTPCodecTypeVideo))
+
+		audio := m.getRTPParametersByKind(RTPCodecTypeAudio, []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly})
+		video := m.getRTPParametersByKind(RTPCodecTypeVideo, []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly})
+
+		assert.Equal(t, 1, len(audio.HeaderExtensions))
+		assert.Equal(t, 1, len(video.HeaderExtensions))
+		assert.NotEqual(t, audio.HeaderExtensions[0].ID, video.HeaderExtensions[0].ID)
+	})
 }
 
 // If a user attempts to register a codec twice we should just discard duplicate calls