package rtsp

import (
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"net"
	"reflect"
	"strings"
	"time"

	"github.com/deepch/vdk/codec/aacparser"
	"github.com/deepch/vdk/codec/h264parser"
	"github.com/deepch/vdk/codec/h265parser"
	"github.com/pion/rtcp"
	"github.com/pion/rtp"
	"github.com/pion/webrtc/v4"
	"m7s.live/v5"
	"m7s.live/v5/pkg"
	"m7s.live/v5/pkg/codec"
	mrtp "m7s.live/v5/plugin/rtp/pkg"
)

type Sender struct {
	*m7s.Subscriber
	Stream
	UDPPorts          map[int][]int          // 保存媒体索引对应的UDP端口 [clientRTP, clientRTCP, serverRTP, serverRTCP]
	UDPConns          map[int][]*net.UDPConn // 保存媒体索引对应的UDP连接 [RTP发送连接, RTCP发送连接]
	AllocatedUDPPorts []uint16               // 记录从端口池分配的UDP端口，用于连接结束时释放回池
}

type Receiver struct {
	*m7s.Publisher
	Stream
	AudioCodecParameters *webrtc.RTPCodecParameters
	VideoCodecParameters *webrtc.RTPCodecParameters
}

func (s *Sender) GetMedia() (medias []*Media, err error) {
	if s.SubAudio && s.Publisher.PubAudio && s.Publisher.HasAudioTrack() {
		audioTrack := s.Publisher.GetAudioTrack(reflect.TypeOf((*mrtp.AudioFrame)(nil)))
		if err = audioTrack.WaitReady(); err != nil {
			return
		}
		parameter := audioTrack.ICodecCtx.(mrtp.IRTPCtx).GetRTPCodecParameter()
		media := &Media{
			Kind:      "audio",
			Direction: DirectionRecvonly,
			Codecs: []*Codec{{
				Name:        parameter.MimeType[6:],
				ClockRate:   parameter.ClockRate,
				Channels:    parameter.Channels,
				FmtpLine:    parameter.SDPFmtpLine,
				PayloadType: uint8(parameter.PayloadType),
			}},
			ID: fmt.Sprintf("trackID=%d", len(medias)),
		}
		s.AudioChannelID = len(medias) << 1
		medias = append(medias, media)
	}

	if s.SubVideo && s.Publisher.PubVideo && s.Publisher.HasVideoTrack() {
		videoTrack := s.Publisher.GetVideoTrack(reflect.TypeOf((*mrtp.VideoFrame)(nil)))
		if err = videoTrack.WaitReady(); err != nil {
			return
		}
		parameter := videoTrack.ICodecCtx.(mrtp.IRTPCtx).GetRTPCodecParameter()
		c := Codec{
			Name:        parameter.MimeType[6:],
			ClockRate:   parameter.ClockRate,
			Channels:    parameter.Channels,
			FmtpLine:    parameter.SDPFmtpLine,
			PayloadType: uint8(parameter.PayloadType),
		}
		media := &Media{
			Kind:      "video",
			Direction: DirectionRecvonly,
			Codecs:    []*Codec{&c},
			ID:        fmt.Sprintf("trackID=%d", len(medias)),
		}
		s.VideoChannelID = len(medias) << 1
		medias = append(medias, media)
	}
	return
}

func (s *Sender) sendRTP(pack *mrtp.RTPData, channel int) (err error) {
	mediaIndex := channel / 2 // 计算媒体索引

	// 检查是否使用UDP传输
	if s.Transport == "UDP" && s.UDPPorts != nil {
		if ports, ok := s.UDPPorts[mediaIndex]; ok {
			// 确保UDP连接已经建立
			if s.UDPConns == nil || s.UDPConns[mediaIndex] == nil {
				// 创建UDP连接
				if err = s.setupUDPConnection(mediaIndex); err != nil {
					s.Stream.Error("Failed to setup UDP connection", "error", err, "mediaIndex", mediaIndex)
					goto TCP_FALLBACK // 如果UDP连接失败，回退到TCP
				}
			}

			// 再次检查UDP连接是否已正确建立，以及是否有足够的连接
			if s.UDPConns == nil || len(s.UDPConns[mediaIndex]) < 1 {
				s.Stream.Error("UDP connections not properly established", "mediaIndex", mediaIndex)
				goto TCP_FALLBACK // 如果UDP连接不完整，回退到TCP
			}

			// 获取UDP连接
			rtpConn := s.UDPConns[mediaIndex][0]
			if rtpConn == nil {
				s.Stream.Error("RTP UDP connection is nil", "mediaIndex", mediaIndex)
				goto TCP_FALLBACK
			}

			// 获取客户端IP地址，正确处理IPv6
			remoteIP := s.Conn.RemoteAddr().(*net.TCPAddr).IP
			var clientAddr *net.UDPAddr
			if remoteIP.To4() == nil {
				// IPv6地址需要使用[ip]:port格式
				clientAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("[%s]:%d", remoteIP.String(), ports[0]))
			} else {
				// IPv4地址
				clientAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", remoteIP.String(), ports[0]))
			}

			if err != nil {
				s.Stream.Error("Failed to resolve UDP address", "error", err, "ip", remoteIP.String(), "port", ports[0])
				goto TCP_FALLBACK
			}

			// 发送RTP包
			for packet := range pack.Packets.RangePoint {
				buf := s.MemoryAllocator.Borrow(packet.MarshalSize())
				_, err := packet.MarshalTo(buf)
				if err != nil {
					return err
				}
				_, err = rtpConn.WriteToUDP(buf, clientAddr)
				if err != nil {
					s.Stream.Error("UDP send failed", "error", err, "addr", clientAddr.String())
					goto TCP_FALLBACK
				}
			}

			return nil
		}
	}

TCP_FALLBACK:
	// 使用TCP传输（优化版本：一次性分配内存并发送）
	s.StartWrite()
	defer s.StopWrite()

	// 直接使用 pack.GetSize() 获取总大小，并加上TCP头部大小
	totalSize := pack.GetSize() + 4*len(pack.Packets) // 每个包需要4字节TCP头部

	// 一次性分配内存
	chunk := s.MemoryAllocator.Borrow(totalSize)

	// 序列化所有包到内存中
	offset := 0
	for packet := range pack.Packets.RangePoint {
		size := packet.MarshalSize()
		chunk[offset] = '$'
		chunk[offset+1] = byte(channel)
		chunk[offset+2] = byte(size >> 8)
		chunk[offset+3] = byte(size)
		if _, err = packet.MarshalTo(chunk[offset+4 : offset+4+size]); err != nil {
			return
		}
		offset += size + 4
	}

	// 一次性写入
	if _, err = s.Write(chunk); err != nil {
		return
	}
	return
}

// 建立UDP连接
func (s *Sender) setupUDPConnection(mediaIndex int) error {
	ports, ok := s.UDPPorts[mediaIndex]
	if !ok {
		return fmt.Errorf("no UDP ports configured for media %d", mediaIndex)
	}

	// 服务器端RTP和RTCP端口
	serverRTPPort := ports[2]
	serverRTCPPort := ports[3]

	s.Stream.Debug("Setting up UDP connections", "mediaIndex", mediaIndex,
		"serverRTPPort", serverRTPPort, "serverRTCPPort", serverRTCPPort)

	// 尝试创建RTP连接，支持重试几次
	var rtpConn *net.UDPConn
	var rtcpConn *net.UDPConn
	var err error
	maxRetries := 3

	// 创建RTP连接
	for i := 0; i < maxRetries; i++ {
		rtpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", serverRTPPort+i*2))
		if err != nil {
			s.Stream.Error("Failed to resolve RTP UDP address", "error", err, "port", serverRTPPort+i*2)
			continue
		}

		rtpConn, err = net.ListenUDP("udp", rtpAddr)
		if err != nil {
			s.Stream.Error("Failed to listen on RTP UDP port", "error", err, "port", serverRTPPort+i*2)
			continue
		}

		// 成功创建RTP连接
		serverRTPPort = serverRTPPort + i*2
		serverRTCPPort = serverRTPPort + 1 // 更新RTCP端口为RTP+1
		break
	}

	if rtpConn == nil {
		return fmt.Errorf("failed to create RTP UDP connection after %d retries", maxRetries)
	}

	// 创建RTCP连接
	rtcpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", serverRTCPPort))
	if err != nil {
		rtpConn.Close()
		return fmt.Errorf("failed to resolve RTCP UDP address: %w", err)
	}

	rtcpConn, err = net.ListenUDP("udp", rtcpAddr)
	if err != nil {
		rtpConn.Close()
		return fmt.Errorf("failed to listen on RTCP UDP port %d: %w", serverRTCPPort, err)
	}

	// 初始化UDP连接映射
	if s.UDPConns == nil {
		s.UDPConns = make(map[int][]*net.UDPConn)
	}

	// 保存连接
	s.UDPConns[mediaIndex] = []*net.UDPConn{rtpConn, rtcpConn}

	// 更新端口信息（如果有变化）
	if ports[2] != serverRTPPort || ports[3] != serverRTCPPort {
		s.UDPPorts[mediaIndex][2] = serverRTPPort
		s.UDPPorts[mediaIndex][3] = serverRTCPPort
	}

	s.Stream.Info("UDP connections established", "mediaIndex", mediaIndex,
		"rtpPort", serverRTPPort, "rtcpPort", serverRTCPPort)

	return nil
}

// 发送RTCP包
func (s *Sender) sendRTCP(packet rtcp.Packet, mediaIndex int) error {
	// 检查是否使用UDP传输
	if s.Transport == "UDP" && s.UDPPorts != nil && s.UDPConns != nil {
		// 检查mediaIndex是否存在于UDPPorts和UDPConns中
		ports, portsOk := s.UDPPorts[mediaIndex]
		conns, connsOk := s.UDPConns[mediaIndex]

		if portsOk && connsOk && len(conns) > 1 && conns[1] != nil {
			rtcpConn := conns[1]

			// 获取客户端IP地址，正确处理IPv6
			remoteIP := s.Conn.RemoteAddr().(*net.TCPAddr).IP
			var clientAddr *net.UDPAddr
			var err error

			if remoteIP.To4() == nil {
				// IPv6地址需要使用[ip]:port格式
				clientAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("[%s]:%d", remoteIP.String(), ports[1]))
			} else {
				// IPv4地址
				clientAddr, err = net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", remoteIP.String(), ports[1]))
			}

			if err != nil {
				s.Stream.Error("Failed to resolve RTCP UDP address", "error", err, "ip", remoteIP.String(), "port", ports[1])
				return err
			}

			// 序列化并发送RTCP包
			buf, err := packet.Marshal()
			if err != nil {
				return err
			}

			_, err = rtcpConn.WriteToUDP(buf, clientAddr)
			if err != nil {
				s.Stream.Error("UDP RTCP send failed", "error", err, "addr", clientAddr.String())
				return err
			}

			return nil
		} else {
			connsLen := 0
			if connsOk {
				connsLen = len(conns)
			}

			s.Stream.Debug("RTCP UDP connection not available", "mediaIndex", mediaIndex,
				"portsOk", portsOk, "connsOk", connsOk, "connsLen", connsLen)
		}
	}

	// TCP模式发送RTCP或UDP不可用（这里可以根据需要实现）
	return nil
}

func (s *Sender) Send() (err error) {
	// 启动音视频发送协程
	go m7s.PlayBlock(s.Subscriber, func(audio *mrtp.AudioFrame) error {
		return s.sendRTP(&audio.RTPData, s.AudioChannelID)
	}, func(video *mrtp.VideoFrame) error {
		return s.sendRTP(&video.RTPData, s.VideoChannelID)
	})

	// 如果是UDP模式，需要在这里启动一个RTCP处理协程
	if s.Transport == "UDP" {
		done := s.Subscriber.Done()
		go func() {
			rtcpTicker := time.NewTicker(5 * time.Second)
			defer rtcpTicker.Stop()

			// 创建RTCP SR包
			sr := &rtcp.SenderReport{
				SSRC:        0, // 将在实际发送时设置
				NTPTime:     0,
				RTPTime:     0,
				PacketCount: 0,
				OctetCount:  0,
			}

			// 创建SDES包
			sdes := &rtcp.SourceDescription{
				Chunks: []rtcp.SourceDescriptionChunk{
					{
						Source: 0, // 将在实际发送时设置
						Items: []rtcp.SourceDescriptionItem{
							{Type: rtcp.SDESCNAME, Text: "monibuca"},
						},
					},
				},
			}

			for {
				select {
				case <-rtcpTicker.C:
					// 更新NTP时间 (RFC3550中定义的格式)
					now := time.Now()
					seconds := uint32(now.Unix() + 0x83AA7E80) // 从1900年开始的秒数，加上从1900到1970的秒数
					fraction := uint32(now.Nanosecond() * 0x100000000 / 1000000000)
					ntp := uint64(seconds)<<32 | uint64(fraction)
					sr.NTPTime = ntp

					// 向所有媒体轨道发送RTCP
					if s.AudioChannelID >= 0 {
						mediaIndex := s.AudioChannelID / 2
						s.sendRTCP(sr, mediaIndex)
						s.sendRTCP(sdes, mediaIndex)
					}

					if s.VideoChannelID >= 0 {
						mediaIndex := s.VideoChannelID / 2
						s.sendRTCP(sr, mediaIndex)
						s.sendRTCP(sdes, mediaIndex)
					}

				case <-done:
					return
				}
			}
		}()
	}

	// 接收处理（处理客户端发来的消息）
	return s.NetConnection.Receive(true, nil, nil)
}

func (r *Receiver) SetMedia(medias []*Media) (err error) {
	r.AudioChannelID = -1
	r.VideoChannelID = -1
	var hasAudio, hasVideo bool // 新增标志位
	for i, media := range medias {
		if codec := media.Codecs[0]; codec.IsAudio() {
			r.AudioCodecParameters = &webrtc.RTPCodecParameters{
				RTPCodecCapability: webrtc.RTPCodecCapability{
					MimeType:     "audio/" + codec.Name,
					ClockRate:    codec.ClockRate,
					Channels:     codec.Channels,
					SDPFmtpLine:  codec.FmtpLine,
					RTCPFeedback: nil,
				},
				PayloadType: webrtc.PayloadType(codec.PayloadType),
			}
			r.AudioChannelID = i << 1
			hasAudio = true // 标记找到音频
		} else if codec.IsVideo() {
			r.VideoChannelID = i << 1
			r.VideoCodecParameters = &webrtc.RTPCodecParameters{
				RTPCodecCapability: webrtc.RTPCodecCapability{
					MimeType:     "video/" + codec.Name,
					ClockRate:    codec.ClockRate,
					Channels:     codec.Channels,
					SDPFmtpLine:  codec.FmtpLine,
					RTCPFeedback: nil,
				},
				PayloadType: webrtc.PayloadType(codec.PayloadType),
			}
			hasVideo = true // 标记找到视频
		} else {
			r.Stream.Warn("media kind not support", "kind", codec.Kind())
		}
	}

	// 在遍历后检查，如果 Publisher 存在且未找到对应媒体，则调用 NoAudio/NoVideo
	if r.Publisher != nil {
		if !hasAudio {
			r.Publisher.NoAudio()
			r.Stream.Info("SDP does not contain audio, calling Publisher.NoAudio()")
		}
		if !hasVideo {
			r.Publisher.NoVideo()
			r.Stream.Info("SDP does not contain video, calling Publisher.NoVideo()")
		}
	}
	return
}

func (r *Receiver) Receive() (err error) {
	var audioPacket, videoPacket *rtp.Packet
	var audioClockRate uint32
	var rtcpTS time.Time
	sdes := &rtcp.SourceDescription{
		Chunks: []rtcp.SourceDescriptionChunk{
			{
				Source: 0, // Set appropriate SSRC
				Items: []rtcp.SourceDescriptionItem{
					{Type: rtcp.SDESCNAME, Text: "monibuca"}, // Set appropriate CNAME
				},
			},
		},
	}
	rr := &rtcp.ReceiverReport{
		Reports: []rtcp.ReceptionReport{
			{
				SSRC:               0, // Set appropriate SSRC
				FractionLost:       0, // Set appropriate fraction lost
				TotalLost:          0, // Set total packets lost
				LastSequenceNumber: 0, // Set last sequence number
				Jitter:             0, // Set jitter
				LastSenderReport:   0, // Set last SR timestamp
				Delay:              0, // Set delay since last SR
			},
		},
	}
	var writer m7s.PublishWriter[*mrtp.AudioFrame, *mrtp.VideoFrame]
	if r.AudioCodecParameters != nil && r.PubAudio {
		writer.PublishAudioWriter = m7s.NewPublishAudioWriter[*mrtp.AudioFrame](r.Publisher, r.MemoryAllocator)
		switch r.AudioCodecParameters.MimeType {
		case webrtc.MimeTypeOpus:
			var ctx mrtp.OPUSCtx
			ctx.OPUSCtx = &codec.OPUSCtx{}
			ctx.ParseFmtpLine(r.AudioCodecParameters)
			ctx.OPUSCtx.Channels = int(ctx.RTPCodecParameters.Channels)
			audioClockRate = ctx.RTPCodecParameters.ClockRate
			writer.AudioFrame.ICodecCtx = &ctx
		case webrtc.MimeTypePCMA:
			var ctx mrtp.PCMACtx
			ctx.PCMACtx = &codec.PCMACtx{}
			ctx.ParseFmtpLine(r.AudioCodecParameters)
			ctx.AudioCtx.SampleRate = int(r.AudioCodecParameters.ClockRate)
			ctx.AudioCtx.Channels = int(ctx.RTPCodecParameters.Channels)
			audioClockRate = ctx.RTPCodecParameters.ClockRate
			writer.AudioFrame.ICodecCtx = &ctx
		case webrtc.MimeTypePCMU:
			var ctx mrtp.PCMUCtx
			ctx.PCMUCtx = &codec.PCMUCtx{}
			ctx.ParseFmtpLine(r.AudioCodecParameters)
			ctx.AudioCtx.SampleRate = int(r.AudioCodecParameters.ClockRate)
			ctx.AudioCtx.Channels = int(ctx.RTPCodecParameters.Channels)
			audioClockRate = ctx.RTPCodecParameters.ClockRate
			writer.AudioFrame.ICodecCtx = &ctx
		case "audio/MP4A-LATM":
			ctx := mrtp.AACCtx{
				AACCtx: &codec.AACCtx{},
			}
			ctx.ParseFmtpLine(r.AudioCodecParameters)
			if conf, ok := ctx.Fmtp["config"]; ok {
				if ctx.AACCtx.ConfigBytes, err = hex.DecodeString(conf); err == nil {
					if ctx.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(ctx.AACCtx.ConfigBytes); err != nil {
						return err
					}
				}
			}
			audioClockRate = ctx.RTPCodecParameters.ClockRate
			writer.AudioFrame.ICodecCtx = &ctx
		case "audio/MPEG4-GENERIC":
			ctx := mrtp.AACCtx{AACCtx: &codec.AACCtx{}}
			ctx.ParseFmtpLine(r.AudioCodecParameters)
			ctx.IndexLength = 3
			ctx.IndexDeltaLength = 3
			ctx.SizeLength = 13
			if conf, ok := ctx.Fmtp["config"]; ok {
				if ctx.AACCtx.ConfigBytes, err = hex.DecodeString(conf); err == nil {
					if ctx.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(ctx.AACCtx.ConfigBytes); err != nil {
						return err
					}
				}
			}
			audioClockRate = ctx.RTPCodecParameters.ClockRate
			writer.AudioFrame.ICodecCtx = &ctx
		}
		audioPacket = writer.AudioFrame.Packets.GetNextPointer()
	}
	if r.VideoCodecParameters != nil && r.PubVideo {
		writer.PublishVideoWriter = m7s.NewPublishVideoWriter[*mrtp.VideoFrame](r.Publisher, r.MemoryAllocator)
		switch r.VideoCodecParameters.MimeType {
		case webrtc.MimeTypeH264:
			ctx := &mrtp.H264Ctx{
				H264Ctx: &codec.H264Ctx{},
			}
			ctx.ParseFmtpLine(r.VideoCodecParameters)
			var sps, pps []byte
			//packetization-mode=1; sprop-parameter-sets=J2QAKaxWgHgCJ+WagICAgQ==,KO48sA==; profile-level-id=640029
			if sprop, ok := ctx.Fmtp["sprop-parameter-sets"]; ok {
				if sprops := strings.Split(sprop, ","); len(sprops) == 2 {
					if sps, err = base64.StdEncoding.DecodeString(sprops[0]); err != nil {
						return err
					}
					if pps, err = base64.StdEncoding.DecodeString(sprops[1]); err != nil {
						return err
					}
					if len(sps) < 4 {
						return errors.New("sps too short")
					}
				}
				if ctx.CodecData, err = h264parser.NewCodecDataFromSPSAndPPS(sps, pps); err != nil {
					return err
				}
			}
			writer.VideoFrame.ICodecCtx = ctx
		case webrtc.MimeTypeH265:
			ctx := &mrtp.H265Ctx{
				H265Ctx: &codec.H265Ctx{},
			}
			ctx.ParseFmtpLine(r.VideoCodecParameters)
			var vps, sps, pps []byte
			if sprop_sps, ok := ctx.Fmtp["sprop-sps"]; ok {
				if sps, err = base64.StdEncoding.DecodeString(sprop_sps); err != nil {
					return err
				}
			}
			if sprop_pps, ok := ctx.Fmtp["sprop-pps"]; ok {
				if pps, err = base64.StdEncoding.DecodeString(sprop_pps); err != nil {
					return err
				}
			}
			if sprop_vps, ok := ctx.Fmtp["sprop-vps"]; ok {
				if vps, err = base64.StdEncoding.DecodeString(sprop_vps); err != nil {
					return err
				}
			}
			if len(vps) > 0 && len(sps) > 0 && len(pps) > 0 {
				if ctx.CodecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(vps, sps, pps); err != nil {
					return err
				}
			}
			if sprop_donl, ok := ctx.Fmtp["sprop-max-don-diff"]; ok {
				if sprop_donl != "0" {
					ctx.DONL = true
				}
			}
			writer.VideoFrame.ICodecCtx = ctx
		}
		videoPacket = writer.VideoFrame.Packets.GetNextPointer()
	}
	return r.NetConnection.Receive(false, func(channelID byte, buf []byte) error {
		if r.Publisher != nil && r.Publisher.Paused != nil {
			r.Stream.Pause()
			r.Publisher.Paused.Await()
			r.Stream.Play()
		}
		if time.Since(rtcpTS) > 5*time.Second {
			rtcpTS = time.Now()
			// Serialize RTCP packets
			rawRR, err := rr.Marshal()
			if err != nil {
				return err
			}
			rawSDES, err := sdes.Marshal()
			if err != nil {
				return err
			}
			length := len(rawRR) + len(rawSDES)
			rtcp := append([]byte{'$', 0x03, byte(length >> 8), byte(length)}, rawRR...)
			rtcp = append(rtcp, rawSDES...)
			// Send RTCP packets
			if _, err = r.NetConnection.Write(rtcp); err != nil {
				return err
			}
		}
		if r.Publisher == nil {
			return pkg.ErrMuted
		}
		switch int(channelID) {
		case r.AudioChannelID:
			if !r.PubAudio || writer.PublishAudioWriter == nil {
				return pkg.ErrMuted
			}
			if err = audioPacket.Unmarshal(buf); err != nil {
				return err
			}

			rr.SSRC = audioPacket.SSRC
			sdes.Chunks[0].Source = audioPacket.SSRC
			rr.Reports[0].SSRC = audioPacket.SSRC
			rr.Reports[0].LastSequenceNumber = uint32(audioPacket.SequenceNumber)

			if audioPacket.Timestamp == writer.AudioFrame.Packets[0].Timestamp {
				writer.AudioFrame.AddRecycleBytes(buf)
				audioPacket = writer.AudioFrame.Packets.GetNextPointer()
				return pkg.ErrDiscard
			} else {
				// if err = r.WriteAudio(audioFrame); err != nil {
				// 	return err
				// }
				writer.AudioFrame.Timestamp = time.Duration(audioPacket.Timestamp) * time.Second / time.Duration(audioClockRate)
				newFrameFirstPacket := *audioPacket
				writer.AudioFrame.Packets.Reduce()
				if err = writer.NextAudio(); err != nil {
					return err
				}
				writer.AudioFrame.AddRecycleBytes(buf)
				*writer.AudioFrame.Packets.GetNextPointer() = newFrameFirstPacket
				audioPacket = writer.AudioFrame.Packets.GetNextPointer()
				return pkg.ErrDiscard
			}
		case r.VideoChannelID:
			if !r.PubVideo || writer.VideoFrame == nil {
				return pkg.ErrMuted
			}
			if err = videoPacket.Unmarshal(buf); err != nil {
				return err
			}

			rr.Reports[0].SSRC = videoPacket.SSRC
			sdes.Chunks[0].Source = videoPacket.SSRC
			rr.Reports[0].LastSequenceNumber = uint32(videoPacket.SequenceNumber)

			if videoPacket.Timestamp == writer.VideoFrame.Packets[0].Timestamp {
				writer.VideoFrame.AddRecycleBytes(buf)
				videoPacket = writer.VideoFrame.Packets.GetNextPointer()
				return pkg.ErrDiscard
			} else {
				// t := time.Now()
				// fmt.Println("write video1", t)
				writer.VideoFrame.SetDTS(time.Duration(videoPacket.Timestamp))
				newFrameFirstPacket := *videoPacket
				writer.VideoFrame.Packets.Reduce()
				if err = writer.NextVideo(); err != nil {
					return err
				}
				writer.VideoFrame.AddRecycleBytes(buf)
				*writer.VideoFrame.Packets.GetNextPointer() = newFrameFirstPacket
				videoPacket = writer.VideoFrame.Packets.GetNextPointer()
				return pkg.ErrDiscard
			}
		}
		return pkg.ErrUnsupportCodec
	}, func(channelID byte, buf []byte) error {
		msg := &RTCP{Channel: channelID}
		if err = msg.Header.Unmarshal(buf); err != nil {
			return err
		}
		if msg.Packets, err = rtcp.Unmarshal(buf); err != nil {
			return err
		}
		r.Stream.Debug("rtcp", "type", msg.Header.Type, "length", msg.Header.Length)
		if msg.Header.Type == rtcp.TypeSenderReport {
			for _, report := range msg.Packets {
				if report, ok := report.(*rtcp.SenderReport); ok {
					rr.Reports[0].LastSenderReport = uint32(report.NTPTime)
				}
			}

		}
		return pkg.ErrDiscard
	})
}

// 添加Dispose方法，清理资源
func (r *Receiver) Dispose() {
	// 清理可能持有的帧资源
	if r.Publisher != nil {
		// 如果必要，这里可以添加额外的Publisher清理代码
	}

	// 调用基类Dispose
	r.Stream.Dispose()
	r.Stream.Info("Receiver disposed and resources cleaned up")
}

// 添加Dispose方法，清理UDP资源
func (s *Sender) Dispose() {
	// 释放UDP连接资源
	if s.UDPConns != nil {
		for mediaIndex, conns := range s.UDPConns {
			for i, conn := range conns {
				if conn != nil {
					connType := "RTP"
					if i == 1 {
						connType = "RTCP"
					}

					err := conn.Close()
					if err != nil {
						s.Stream.Error("Error closing UDP connection", "error", err,
							"mediaIndex", mediaIndex, "type", connType)
					} else {
						s.Stream.Debug("Closed UDP connection", "mediaIndex", mediaIndex, "type", connType)
					}
				}
			}
		}
		s.UDPConns = nil
	}

	// 调用基类Dispose
	s.Stream.Dispose()
}
