1// +build !js
2
3package webrtc
4
5import (
6	"sync/atomic"
7
8	"github.com/pion/interceptor"
9	"github.com/pion/interceptor/pkg/nack"
10	"github.com/pion/interceptor/pkg/report"
11	"github.com/pion/rtp"
12)
13
14// RegisterDefaultInterceptors will register some useful interceptors.
15// If you want to customize which interceptors are loaded, you should copy the
16// code from this method and remove unwanted interceptors.
17func RegisterDefaultInterceptors(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
18	if err := ConfigureNack(mediaEngine, interceptorRegistry); err != nil {
19		return err
20	}
21
22	if err := ConfigureRTCPReports(interceptorRegistry); err != nil {
23		return err
24	}
25
26	return nil
27}
28
29// ConfigureRTCPReports will setup everything necessary for generating Sender and Receiver Reports
30func ConfigureRTCPReports(interceptorRegistry *interceptor.Registry) error {
31	reciver, err := report.NewReceiverInterceptor()
32	if err != nil {
33		return err
34	}
35
36	sender, err := report.NewSenderInterceptor()
37	if err != nil {
38		return err
39	}
40
41	interceptorRegistry.Add(reciver)
42	interceptorRegistry.Add(sender)
43	return nil
44}
45
46// ConfigureNack will setup everything necessary for handling generating/responding to nack messages.
47func ConfigureNack(mediaEngine *MediaEngine, interceptorRegistry *interceptor.Registry) error {
48	generator, err := nack.NewGeneratorInterceptor()
49	if err != nil {
50		return err
51	}
52
53	responder, err := nack.NewResponderInterceptor()
54	if err != nil {
55		return err
56	}
57
58	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack"}, RTPCodecTypeVideo)
59	mediaEngine.RegisterFeedback(RTCPFeedback{Type: "nack", Parameter: "pli"}, RTPCodecTypeVideo)
60	interceptorRegistry.Add(responder)
61	interceptorRegistry.Add(generator)
62	return nil
63}
64
65type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }
66
67func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
68	if writer, ok := i.interceptor.Load().(interceptor.RTPWriter); ok && writer != nil {
69		return writer.Write(header, payload, interceptor.Attributes{})
70	}
71
72	return 0, nil
73}
74
75func (i *interceptorToTrackLocalWriter) Write(b []byte) (int, error) {
76	packet := &rtp.Packet{}
77	if err := packet.Unmarshal(b); err != nil {
78		return 0, err
79	}
80
81	return i.WriteRTP(&packet.Header, packet.Payload)
82}
83
84func createStreamInfo(id string, ssrc SSRC, payloadType PayloadType, codec RTPCodecCapability, webrtcHeaderExtensions []RTPHeaderExtensionParameter) interceptor.StreamInfo {
85	headerExtensions := make([]interceptor.RTPHeaderExtension, 0, len(webrtcHeaderExtensions))
86	for _, h := range webrtcHeaderExtensions {
87		headerExtensions = append(headerExtensions, interceptor.RTPHeaderExtension{ID: h.ID, URI: h.URI})
88	}
89
90	feedbacks := make([]interceptor.RTCPFeedback, 0, len(codec.RTCPFeedback))
91	for _, f := range codec.RTCPFeedback {
92		feedbacks = append(feedbacks, interceptor.RTCPFeedback{Type: f.Type, Parameter: f.Parameter})
93	}
94
95	return interceptor.StreamInfo{
96		ID:                  id,
97		Attributes:          interceptor.Attributes{},
98		SSRC:                uint32(ssrc),
99		PayloadType:         uint8(payloadType),
100		RTPHeaderExtensions: headerExtensions,
101		MimeType:            codec.MimeType,
102		ClockRate:           codec.ClockRate,
103		Channels:            codec.Channels,
104		SDPFmtpLine:         codec.SDPFmtpLine,
105		RTCPFeedback:        feedbacks,
106	}
107}
108