Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
sfu
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Alain Takoudjou
sfu
Commits
208f023d
Commit
208f023d
authored
Jun 08, 2020
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make upConnections generic.
parent
0f96f944
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1297 additions
and
1184 deletions
+1297
-1184
conn.go
conn.go
+17
-317
disk.go
disk.go
+13
-15
group.go
group.go
+15
-15
rtpconn.go
rtpconn.go
+1127
-0
webclient.go
webclient.go
+125
-837
No files found.
conn.go
View file @
208f023d
...
...
@@ -7,338 +7,38 @@ package main
import
(
"errors"
"sync"
"sync/atomic"
"sfu/estimator"
"sfu/jitter"
"sfu/packetcache"
"sfu/rtptime"
"github.com/pion/rtp"
"github.com/pion/webrtc/v2"
)
type
localTrackAction
struct
{
add
bool
track
downTrack
}
type
upTrack
struct
{
track
*
webrtc
.
Track
label
string
rate
*
estimator
.
Estimator
cache
*
packetcache
.
Cache
jitter
*
jitter
.
Estimator
maxBitrate
uint64
lastPLI
uint64
lastFIR
uint64
firSeqno
uint32
localCh
chan
localTrackAction
// signals that local has changed
writerDone
chan
struct
{}
// closed when the loop dies
mu
sync
.
Mutex
local
[]
downTrack
srTime
uint64
srNTPTime
uint64
srRTPTime
uint32
}
func
(
up
*
upTrack
)
notifyLocal
(
add
bool
,
track
downTrack
)
{
select
{
case
up
.
localCh
<-
localTrackAction
{
add
,
track
}
:
case
<-
up
.
writerDone
:
}
}
func
(
up
*
upTrack
)
addLocal
(
local
downTrack
)
error
{
up
.
mu
.
Lock
()
for
_
,
t
:=
range
up
.
local
{
if
t
==
local
{
up
.
mu
.
Unlock
()
return
nil
}
}
up
.
local
=
append
(
up
.
local
,
local
)
up
.
mu
.
Unlock
()
up
.
notifyLocal
(
true
,
local
)
return
nil
}
func
(
up
*
upTrack
)
delLocal
(
local
downTrack
)
bool
{
up
.
mu
.
Lock
()
for
i
,
l
:=
range
up
.
local
{
if
l
==
local
{
up
.
local
=
append
(
up
.
local
[
:
i
],
up
.
local
[
i
+
1
:
]
...
)
up
.
mu
.
Unlock
()
up
.
notifyLocal
(
false
,
l
)
return
true
}
}
up
.
mu
.
Unlock
()
return
false
}
func
(
up
*
upTrack
)
getLocal
()
[]
downTrack
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
local
:=
make
([]
downTrack
,
len
(
up
.
local
))
copy
(
local
,
up
.
local
)
return
local
}
func
(
up
*
upTrack
)
hasRtcpFb
(
tpe
,
parameter
string
)
bool
{
for
_
,
fb
:=
range
up
.
track
.
Codec
()
.
RTCPFeedback
{
if
fb
.
Type
==
tpe
&&
fb
.
Parameter
==
parameter
{
return
true
}
}
return
false
}
type
iceConnection
interface
{
addICECandidate
(
candidate
*
webrtc
.
ICECandidateInit
)
error
flushICECandidates
()
error
}
type
upConnection
struct
{
id
string
label
string
pc
*
webrtc
.
PeerConnection
labels
map
[
string
]
string
iceCandidates
[]
*
webrtc
.
ICECandidateInit
mu
sync
.
Mutex
closed
bool
tracks
[]
*
upTrack
local
[]
downConnection
}
var
ErrConnectionClosed
=
errors
.
New
(
"connection is closed"
)
var
ErrKeyframeNeeded
=
errors
.
New
(
"keyframe needed"
)
func
(
up
*
upConnection
)
getTracks
()
[]
*
upTrack
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
tracks
:=
make
([]
*
upTrack
,
len
(
up
.
tracks
))
copy
(
tracks
,
up
.
tracks
)
return
tracks
}
func
(
up
*
upConnection
)
addLocal
(
local
downConnection
)
error
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
if
up
.
closed
{
return
ErrConnectionClosed
}
for
_
,
t
:=
range
up
.
local
{
if
t
==
local
{
return
nil
}
}
up
.
local
=
append
(
up
.
local
,
local
)
return
nil
}
func
(
up
*
upConnection
)
delLocal
(
local
downConnection
)
bool
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
for
i
,
l
:=
range
up
.
local
{
if
l
==
local
{
up
.
local
=
append
(
up
.
local
[
:
i
],
up
.
local
[
i
+
1
:
]
...
)
return
true
}
}
return
false
}
func
(
up
*
upConnection
)
getLocal
()
[]
downConnection
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
local
:=
make
([]
downConnection
,
len
(
up
.
local
))
copy
(
local
,
up
.
local
)
return
local
}
func
(
up
*
upConnection
)
Close
()
error
{
up
.
mu
.
Lock
()
defer
up
.
mu
.
Unlock
()
go
func
(
local
[]
downConnection
)
{
for
_
,
l
:=
range
local
{
l
.
Close
()
}
}(
up
.
local
)
up
.
local
=
nil
up
.
closed
=
true
return
up
.
pc
.
Close
()
}
func
(
up
*
upConnection
)
addICECandidate
(
candidate
*
webrtc
.
ICECandidateInit
)
error
{
if
up
.
pc
.
RemoteDescription
()
!=
nil
{
return
up
.
pc
.
AddICECandidate
(
*
candidate
)
}
up
.
iceCandidates
=
append
(
up
.
iceCandidates
,
candidate
)
return
nil
}
func
flushICECandidates
(
pc
*
webrtc
.
PeerConnection
,
candidates
[]
*
webrtc
.
ICECandidateInit
)
error
{
if
pc
.
RemoteDescription
()
==
nil
{
return
errors
.
New
(
"flushICECandidates called in bad state"
)
}
var
err
error
for
_
,
candidate
:=
range
candidates
{
err2
:=
pc
.
AddICECandidate
(
*
candidate
)
if
err
==
nil
{
err
=
err2
}
}
return
err
}
func
(
up
*
upConnection
)
flushICECandidates
()
error
{
err
:=
flushICECandidates
(
up
.
pc
,
up
.
iceCandidates
)
up
.
iceCandidates
=
nil
return
err
}
func
getUpMid
(
pc
*
webrtc
.
PeerConnection
,
track
*
webrtc
.
Track
)
string
{
for
_
,
t
:=
range
pc
.
GetTransceivers
()
{
if
t
.
Receiver
()
!=
nil
&&
t
.
Receiver
()
.
Track
()
==
track
{
return
t
.
Mid
()
}
}
return
""
}
// called locked
func
(
up
*
upConnection
)
complete
()
bool
{
for
mid
,
_
:=
range
up
.
labels
{
found
:=
false
for
_
,
t
:=
range
up
.
tracks
{
m
:=
getUpMid
(
up
.
pc
,
t
.
track
)
if
m
==
mid
{
found
=
true
break
}
}
if
!
found
{
return
false
}
}
return
true
}
type
bitrate
struct
{
bitrate
uint64
jiffies
uint64
}
const
receiverReportTimeout
=
8
*
rtptime
.
JiffiesPerSec
func
(
br
*
bitrate
)
Set
(
bitrate
uint64
,
now
uint64
)
{
// this is racy -- a reader might read the
// data between the two writes. This shouldn't
// matter, we'll recover at the next sample.
atomic
.
StoreUint64
(
&
br
.
bitrate
,
bitrate
)
atomic
.
StoreUint64
(
&
br
.
jiffies
,
now
)
}
func
(
br
*
bitrate
)
Get
(
now
uint64
)
uint64
{
ts
:=
atomic
.
LoadUint64
(
&
br
.
jiffies
)
if
now
<
ts
||
now
-
ts
>
receiverReportTimeout
{
return
^
uint64
(
0
)
}
return
atomic
.
LoadUint64
(
&
br
.
bitrate
)
}
type
receiverStats
struct
{
loss
uint32
jitter
uint32
jiffies
uint64
type
upConnection
interface
{
addLocal
(
downConnection
)
error
delLocal
(
downConnection
)
bool
Id
()
string
Label
()
string
}
func
(
s
*
receiverStats
)
Set
(
loss
uint8
,
jitter
uint32
,
now
uint64
)
{
atomic
.
StoreUint32
(
&
s
.
loss
,
uint32
(
loss
))
atomic
.
StoreUint32
(
&
s
.
jitter
,
jitter
)
atomic
.
StoreUint64
(
&
s
.
jiffies
,
now
)
type
upTrack
interface
{
addLocal
(
downTrack
)
error
delLocal
(
downTrack
)
bool
Label
()
string
Codec
()
*
webrtc
.
RTPCodec
// get a recent packet. Returns 0 if the packet is not in cache.
getRTP
(
seqno
uint16
,
result
[]
byte
)
uint16
// returns the last timestamp, if possible
getTimestamp
()
(
uint32
,
bool
)
}
func
(
s
*
receiverStats
)
Get
(
now
uint64
)
(
uint8
,
uint32
)
{
ts
:=
atomic
.
LoadUint64
(
&
s
.
jiffies
)
if
now
<
ts
||
now
>
ts
+
receiverReportTimeout
{
return
0
,
0
}
return
uint8
(
atomic
.
LoadUint32
(
&
s
.
loss
)),
atomic
.
LoadUint32
(
&
s
.
jitter
)
type
downConnection
interface
{
Close
()
error
}
var
ErrKeyframeNeeded
=
errors
.
New
(
"keyframe needed"
)
type
downTrack
interface
{
WriteRTP
(
packat
*
rtp
.
Packet
)
error
Accumulate
(
bytes
uint32
)
GetMaxBitrate
(
now
uint64
)
uint64
}
type
rtpDownTrack
struct
{
track
*
webrtc
.
Track
remote
*
upTrack
maxLossBitrate
*
bitrate
maxREMBBitrate
*
bitrate
rate
*
estimator
.
Estimator
stats
*
receiverStats
srTime
uint64
srNTPTime
uint64
rtt
uint64
}
func
(
down
*
rtpDownTrack
)
WriteRTP
(
packet
*
rtp
.
Packet
)
error
{
return
down
.
track
.
WriteRTP
(
packet
)
}
func
(
down
*
rtpDownTrack
)
Accumulate
(
bytes
uint32
)
{
down
.
rate
.
Accumulate
(
bytes
)
}
func
(
down
*
rtpDownTrack
)
GetMaxBitrate
(
now
uint64
)
uint64
{
br1
:=
down
.
maxLossBitrate
.
Get
(
now
)
br2
:=
down
.
maxREMBBitrate
.
Get
(
now
)
if
br1
<
br2
{
return
br1
}
return
br2
}
type
downConnection
interface
{
Close
()
error
}
type
rtpDownConnection
struct
{
id
string
client
*
webClient
pc
*
webrtc
.
PeerConnection
remote
*
upConnection
tracks
[]
*
rtpDownTrack
iceCandidates
[]
*
webrtc
.
ICECandidateInit
}
func
(
down
*
rtpDownConnection
)
Close
()
error
{
return
down
.
client
.
action
(
delConnAction
{
down
.
id
})
}
func
(
down
*
rtpDownConnection
)
addICECandidate
(
candidate
*
webrtc
.
ICECandidateInit
)
error
{
if
down
.
pc
.
RemoteDescription
()
!=
nil
{
return
down
.
pc
.
AddICECandidate
(
*
candidate
)
}
down
.
iceCandidates
=
append
(
down
.
iceCandidates
,
candidate
)
return
nil
}
func
(
down
*
rtpDownConnection
)
flushICECandidates
()
error
{
err
:=
flushICECandidates
(
down
.
pc
,
down
.
iceCandidates
)
down
.
iceCandidates
=
nil
return
err
}
disk.go
View file @
208f023d
...
...
@@ -24,15 +24,15 @@ type diskClient struct {
closed
bool
}
func
(
client
*
diskClient
)
get
Group
()
*
group
{
func
(
client
*
diskClient
)
Group
()
*
group
{
return
client
.
group
}
func
(
client
*
diskClient
)
get
Id
()
string
{
func
(
client
*
diskClient
)
Id
()
string
{
return
client
.
id
}
func
(
client
*
diskClient
)
get
Username
()
string
{
func
(
client
*
diskClient
)
Username
()
string
{
return
"RECORDING"
}
...
...
@@ -52,7 +52,7 @@ func (client *diskClient) Close() error {
return
nil
}
func
(
client
*
diskClient
)
pushConn
(
conn
*
upConnection
,
tracks
[]
*
upTrack
,
label
string
)
error
{
func
(
client
*
diskClient
)
pushConn
(
conn
upConnection
,
tracks
[]
upTrack
,
label
string
)
error
{
client
.
mu
.
Lock
()
defer
client
.
mu
.
Unlock
()
...
...
@@ -75,15 +75,13 @@ func (client *diskClient) pushConn(conn *upConnection, tracks []*upTrack, label
return
nil
}
var
_
client
=
&
diskClient
{}
type
diskConn
struct
{
directory
string
label
string
mu
sync
.
Mutex
file
*
os
.
File
remote
*
upConnection
remote
upConnection
tracks
[]
*
diskTrack
width
,
height
uint32
}
...
...
@@ -154,7 +152,7 @@ func openDiskFile(directory, label string) (*os.File, error) {
}
type
diskTrack
struct
{
remote
*
upTrack
remote
upTrack
conn
*
diskConn
writer
webm
.
BlockWriteCloser
...
...
@@ -162,7 +160,7 @@ type diskTrack struct {
timestamp
uint32
}
func
newDiskConn
(
directory
,
label
string
,
up
*
upConnection
,
remoteTracks
[]
*
upTrack
)
(
*
diskConn
,
error
)
{
func
newDiskConn
(
directory
,
label
string
,
up
upConnection
,
remoteTracks
[]
upTrack
)
(
*
diskConn
,
error
)
{
conn
:=
diskConn
{
directory
:
directory
,
label
:
label
,
...
...
@@ -172,7 +170,7 @@ func newDiskConn(directory, label string, up *upConnection, remoteTracks []*upTr
video
:=
false
for
_
,
remote
:=
range
remoteTracks
{
var
builder
*
samplebuilder
.
SampleBuilder
switch
remote
.
track
.
Codec
()
.
Name
{
switch
remote
.
Codec
()
.
Name
{
case
webrtc
.
Opus
:
builder
=
samplebuilder
.
New
(
16
,
&
codecs
.
OpusPacket
{})
case
webrtc
.
VP8
:
...
...
@@ -245,7 +243,7 @@ func (t *diskTrack) WriteRTP(packet *rtp.Packet) error {
keyframe
:=
true
switch
t
.
remote
.
track
.
Codec
()
.
Name
{
switch
t
.
remote
.
Codec
()
.
Name
{
case
webrtc
.
VP8
:
if
len
(
sample
.
Data
)
<
1
{
return
nil
...
...
@@ -265,7 +263,7 @@ func (t *diskTrack) WriteRTP(packet *rtp.Packet) error {
return
nil
}
tm
:=
t
.
timestamp
/
(
t
.
remote
.
track
.
Codec
()
.
ClockRate
/
1000
)
tm
:=
t
.
timestamp
/
(
t
.
remote
.
Codec
()
.
ClockRate
/
1000
)
_
,
err
:=
t
.
writer
.
Write
(
keyframe
,
int64
(
tm
),
sample
.
Data
)
if
err
!=
nil
{
return
err
...
...
@@ -275,7 +273,7 @@ func (t *diskTrack) WriteRTP(packet *rtp.Packet) error {
// called locked
func
(
t
*
diskTrack
)
initWriter
(
data
[]
byte
)
error
{
switch
t
.
remote
.
track
.
Codec
()
.
Name
{
switch
t
.
remote
.
Codec
()
.
Name
{
case
webrtc
.
VP8
:
if
len
(
data
)
<
10
{
return
nil
...
...
@@ -300,9 +298,9 @@ func (conn *diskConn) initWriter(width, height uint32) error {
}
var
entries
[]
webm
.
TrackEntry
for
i
,
t
:=
range
conn
.
tracks
{
codec
:=
t
.
remote
.
track
.
Codec
()
codec
:=
t
.
remote
.
Codec
()
var
entry
webm
.
TrackEntry
switch
t
.
remote
.
track
.
Codec
()
.
Name
{
switch
t
.
remote
.
Codec
()
.
Name
{
case
webrtc
.
Opus
:
entry
=
webm
.
TrackEntry
{
Name
:
"Audio"
,
...
...
group.go
View file @
208f023d
...
...
@@ -22,10 +22,10 @@ import (
)
type
client
interface
{
get
Group
()
*
group
get
Id
()
string
get
Username
()
string
pushConn
(
conn
*
upConnection
,
tracks
[]
*
upTrack
,
label
string
)
error
Group
()
*
group
Id
()
string
Username
()
string
pushConn
(
conn
upConnection
,
tracks
[]
upTrack
,
label
string
)
error
pushClient
(
id
,
username
string
,
add
bool
)
error
}
...
...
@@ -58,8 +58,8 @@ type delConnAction struct {
}
type
addConnAction
struct
{
conn
*
upConnection
tracks
[]
*
upTrack
conn
upConnection
tracks
[]
upTrack
}
type
addLabelAction
struct
{
...
...
@@ -230,20 +230,20 @@ func addClient(name string, c client, user, pass string) (*group, error) {
return
nil
,
userError
(
"too many users"
)
}
}
if
g
.
clients
[
c
.
get
Id
()]
!=
nil
{
if
g
.
clients
[
c
.
Id
()]
!=
nil
{
return
nil
,
protocolError
(
"duplicate client id"
)
}
g
.
clients
[
c
.
get
Id
()]
=
c
g
.
clients
[
c
.
Id
()]
=
c
go
func
(
clients
[]
client
)
{
c
.
pushClient
(
c
.
getId
(),
c
.
get
Username
(),
true
)
c
.
pushClient
(
c
.
Id
(),
c
.
Username
(),
true
)
for
_
,
cc
:=
range
clients
{
err
:=
c
.
pushClient
(
cc
.
getId
(),
cc
.
get
Username
(),
true
)
err
:=
c
.
pushClient
(
cc
.
Id
(),
cc
.
Username
(),
true
)
if
err
==
ErrClientDead
{
return
}
cc
.
pushClient
(
c
.
getId
(),
c
.
get
Username
(),
true
)
cc
.
pushClient
(
c
.
Id
(),
c
.
Username
(),
true
)
}
}(
g
.
getClientsUnlocked
(
c
))
...
...
@@ -251,19 +251,19 @@ func addClient(name string, c client, user, pass string) (*group, error) {
}
func
delClient
(
c
client
)
{
g
:=
c
.
get
Group
()
g
:=
c
.
Group
()
g
.
mu
.
Lock
()
defer
g
.
mu
.
Unlock
()
if
g
.
clients
[
c
.
get
Id
()]
!=
c
{
if
g
.
clients
[
c
.
Id
()]
!=
c
{
log
.
Printf
(
"Deleting unknown client"
)
return
}
delete
(
g
.
clients
,
c
.
get
Id
())
delete
(
g
.
clients
,
c
.
Id
())
go
func
(
clients
[]
client
)
{
for
_
,
cc
:=
range
clients
{
cc
.
pushClient
(
c
.
getId
(),
c
.
get
Username
(),
false
)
cc
.
pushClient
(
c
.
Id
(),
c
.
Username
(),
false
)
}
}(
g
.
getClientsUnlocked
(
nil
))
}
...
...
rtpconn.go
0 → 100644
View file @
208f023d
This diff is collapsed.
Click to expand it.
webclient.go
View file @
208f023d
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment