mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-07 14:25:17 +03:00
200 lines
3.5 KiB
Go
200 lines
3.5 KiB
Go
package tunnel
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"sync"
|
|
)
|
|
|
|
type MultiTrackTunnel struct {
|
|
tunnels []*VP8DataTunnel
|
|
|
|
mu sync.Mutex
|
|
onData func([]byte)
|
|
onClose func()
|
|
onPeerRestart func()
|
|
isClosed bool
|
|
fps int
|
|
batch int
|
|
}
|
|
|
|
func NewMultiTrackTunnel(tunnels []*VP8DataTunnel) *MultiTrackTunnel {
|
|
m := &MultiTrackTunnel{tunnels: tunnels}
|
|
for i, tun := range tunnels {
|
|
m.wireSubTunnel(tun, i == 0)
|
|
}
|
|
return m
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) AddSubTunnel(tun *VP8DataTunnel) {
|
|
m.mu.Lock()
|
|
if m.isClosed {
|
|
m.mu.Unlock()
|
|
tun.Stop()
|
|
return
|
|
}
|
|
m.tunnels = append(m.tunnels, tun)
|
|
fps := m.fps
|
|
batch := m.batch
|
|
m.mu.Unlock()
|
|
m.wireSubTunnel(tun, false)
|
|
if fps > 0 && batch > 0 {
|
|
tun.Start(fps, batch)
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) RemoveLastSubTunnel() *VP8DataTunnel {
|
|
m.mu.Lock()
|
|
if len(m.tunnels) <= 1 {
|
|
m.mu.Unlock()
|
|
return nil
|
|
}
|
|
last := m.tunnels[len(m.tunnels)-1]
|
|
m.tunnels = m.tunnels[:len(m.tunnels)-1]
|
|
m.mu.Unlock()
|
|
last.Stop()
|
|
return last
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SubTunnelCount() int {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
return len(m.tunnels)
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SendData(data []byte) {
|
|
m.mu.Lock()
|
|
tunnels := m.tunnels
|
|
m.mu.Unlock()
|
|
if len(tunnels) == 0 {
|
|
return
|
|
}
|
|
var connID uint32
|
|
if len(data) >= 8 {
|
|
connID = binary.BigEndian.Uint32(data[4:8])
|
|
}
|
|
idx := connID % uint32(len(tunnels))
|
|
tunnels[idx].SendData(data)
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) DeliverData(data []byte) {
|
|
m.mu.Lock()
|
|
handler := m.onData
|
|
m.mu.Unlock()
|
|
if handler != nil {
|
|
handler(data)
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SubTunnels() []*VP8DataTunnel {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
subs := make([]*VP8DataTunnel, len(m.tunnels))
|
|
copy(subs, m.tunnels)
|
|
return subs
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SetOnData(fn func([]byte)) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.onData = fn
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SetOnClose(fn func()) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.onClose = fn
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) SetOnPeerRestart(fn func()) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.onPeerRestart = fn
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) Reconfigure(fps, batch int) {
|
|
m.mu.Lock()
|
|
m.fps = fps
|
|
m.batch = batch
|
|
tunnels := m.tunnels
|
|
m.mu.Unlock()
|
|
for _, tun := range tunnels {
|
|
tun.Reconfigure(fps, batch)
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) Start(fps, batch int) {
|
|
m.mu.Lock()
|
|
m.fps = fps
|
|
m.batch = batch
|
|
tunnels := m.tunnels
|
|
m.mu.Unlock()
|
|
for _, tun := range tunnels {
|
|
tun.Start(fps, batch)
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) Stop() {
|
|
m.mu.Lock()
|
|
if m.isClosed {
|
|
m.mu.Unlock()
|
|
return
|
|
}
|
|
m.isClosed = true
|
|
tunnels := m.tunnels
|
|
m.mu.Unlock()
|
|
for _, tun := range tunnels {
|
|
tun.Stop()
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) HandleFrame(frame []byte) {
|
|
m.mu.Lock()
|
|
var first *VP8DataTunnel
|
|
if len(m.tunnels) > 0 {
|
|
first = m.tunnels[0]
|
|
}
|
|
m.mu.Unlock()
|
|
if first != nil {
|
|
first.HandleFrame(frame)
|
|
}
|
|
}
|
|
|
|
func (m *MultiTrackTunnel) wireSubTunnel(tun *VP8DataTunnel, isCamera bool) {
|
|
tun.SetOnData(func(data []byte) {
|
|
m.mu.Lock()
|
|
handler := m.onData
|
|
m.mu.Unlock()
|
|
if handler != nil {
|
|
handler(data)
|
|
}
|
|
})
|
|
if !isCamera {
|
|
return
|
|
}
|
|
tun.SetOnPeerRestart(func() {
|
|
m.mu.Lock()
|
|
handler := m.onPeerRestart
|
|
m.mu.Unlock()
|
|
if handler != nil {
|
|
handler()
|
|
}
|
|
})
|
|
tun.SetOnClose(func() {
|
|
m.mu.Lock()
|
|
if m.isClosed {
|
|
m.mu.Unlock()
|
|
return
|
|
}
|
|
m.isClosed = true
|
|
closeHandler := m.onClose
|
|
subTunnels := m.tunnels
|
|
m.mu.Unlock()
|
|
for _, t := range subTunnels {
|
|
t.Stop()
|
|
}
|
|
if closeHandler != nil {
|
|
closeHandler()
|
|
}
|
|
})
|
|
}
|