// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

//go:build !js
// +build !js

package webrtc

import (
	
	

	
	
)

// TrackRemote represents a single inbound source of media.
type TrackRemote struct {
	mu sync.RWMutex

	id       string
	streamID string

	payloadType PayloadType
	kind        RTPCodecType
	ssrc        SSRC
	rtxSsrc     SSRC
	codec       RTPCodecParameters
	params      RTPParameters
	rid         string

	receiver         *RTPReceiver
	peeked           []byte
	peekedAttributes interceptor.Attributes
}

func newTrackRemote( RTPCodecType, ,  SSRC,  string,  *RTPReceiver) *TrackRemote {
	return &TrackRemote{
		kind:     ,
		ssrc:     ,
		rtxSsrc:  ,
		rid:      ,
		receiver: ,
	}
}

// ID is the unique identifier for this Track. This should be unique for the
// stream, but doesn't have to globally unique. A common example would be 'audio' or 'video'
// and StreamID would be 'desktop' or 'webcam'.
func ( *TrackRemote) () string {
	.mu.RLock()
	defer .mu.RUnlock()

	return .id
}

// RID gets the RTP Stream ID of this Track
// With Simulcast you will have multiple tracks with the same ID, but different RID values.
// In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero.
func ( *TrackRemote) () string {
	.mu.RLock()
	defer .mu.RUnlock()

	return .rid
}

// PayloadType gets the PayloadType of the track.
func ( *TrackRemote) () PayloadType {
	.mu.RLock()
	defer .mu.RUnlock()

	return .payloadType
}

// Kind gets the Kind of the track.
func ( *TrackRemote) () RTPCodecType {
	.mu.RLock()
	defer .mu.RUnlock()

	return .kind
}

// StreamID is the group this track belongs too. This must be unique.
func ( *TrackRemote) () string {
	.mu.RLock()
	defer .mu.RUnlock()

	return .streamID
}

// SSRC gets the SSRC of the track.
func ( *TrackRemote) () SSRC {
	.mu.RLock()
	defer .mu.RUnlock()

	return .ssrc
}

// Msid gets the Msid of the track.
func ( *TrackRemote) () string {
	return .StreamID() + " " + .ID()
}

// Codec gets the Codec of the track.
func ( *TrackRemote) () RTPCodecParameters {
	.mu.RLock()
	defer .mu.RUnlock()

	return .codec
}

// Read reads data from the track.
func ( *TrackRemote) ( []byte) ( int,  interceptor.Attributes,  error) {
	.mu.RLock()
	 := .receiver
	 := .peeked != nil
	.mu.RUnlock()

	if  {
		.mu.Lock()
		 := .peeked
		 = .peekedAttributes

		.peeked = nil
		.peekedAttributes = nil
		.mu.Unlock()
		// someone else may have stolen our packet when we
		// released the lock.  Deal with it.
		if  != nil {
			 = copy(, )
			 = .checkAndUpdateTrack()

			return , , 
		}
	}

	// If there's a separate RTX track and an RTX packet is available, return that
	if  := .readRTX();  != nil {
		 = copy(, .pkt)
		 = .attributes
		.release()
		 = nil
	} else {
		// If there's no separate RTX track (or there's a separate RTX track but no RTX packet waiting), wait for and return
		// a packet from the main track
		, ,  = .readRTP(, )
		if  != nil {
			return , , 
		}

		 = .checkAndUpdateTrack()
	}

	return , , 
}

// checkAndUpdateTrack checks payloadType for every incoming packet
// once a different payloadType is detected the track will be updated.
func ( *TrackRemote) ( []byte) error {
	if len() < 2 {
		return errRTPTooShort
	}

	 := PayloadType([1] & rtpPayloadTypeBitmask)
	if  != .PayloadType() || len(.params.Codecs) == 0 {
		.mu.Lock()
		defer .mu.Unlock()

		,  := .receiver.api.mediaEngine.getRTPParametersByPayloadType()
		if  != nil {
			return 
		}

		.kind = .receiver.kind
		.payloadType = 
		.codec = .Codecs[0]
		.params = 
	}

	return nil
}

// ReadRTP is a convenience method that wraps Read and unmarshals for you.
func ( *TrackRemote) () (*rtp.Packet, interceptor.Attributes, error) {
	 := make([]byte, .receiver.api.settingEngine.getReceiveMTU())
	, ,  := .Read()
	if  != nil {
		return nil, nil, 
	}

	 := &rtp.Packet{}
	if  := .Unmarshal([:]);  != nil {
		return nil, nil, 
	}

	return , , nil
}

// peek is like Read, but it doesn't discard the packet read.
func ( *TrackRemote) ( []byte) ( int,  interceptor.Attributes,  error) {
	, ,  = .Read()
	if  != nil {
		return
	}

	.mu.Lock()
	// this might overwrite data if somebody peeked between the Read
	// and us getting the lock.  Oh well, we'll just drop a packet in
	// that case.
	 := make([]byte, )
	 = copy(, [:])
	.peeked = 
	.peekedAttributes = 
	.mu.Unlock()

	return
}

// SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever.
func ( *TrackRemote) ( time.Time) error {
	return .receiver.setRTPReadDeadline(, )
}

// RtxSSRC returns the RTX SSRC for a track, or 0 if track does not have a separate RTX stream.
func ( *TrackRemote) () SSRC {
	.mu.RLock()
	defer .mu.RUnlock()

	return .rtxSsrc
}

// HasRTX returns true if the track has a separate RTX stream.
func ( *TrackRemote) () bool {
	.mu.RLock()
	defer .mu.RUnlock()

	return .rtxSsrc != 0
}

func ( *TrackRemote) ( SSRC) {
	.mu.Lock()
	defer .mu.Unlock()
	.rtxSsrc = 
}