Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
galene
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
nexedi
galene
Commits
795a40ce
Commit
795a40ce
authored
Apr 29, 2021
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Simulcast.
parent
f1a15f07
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
217 additions
and
111 deletions
+217
-111
README.PROTOCOL
README.PROTOCOL
+20
-5
conn/conn.go
conn/conn.go
+2
-1
diskwriter/diskwriter.go
diskwriter/diskwriter.go
+1
-1
group/group.go
group/group.go
+9
-1
rtpconn/rtpconn.go
rtpconn/rtpconn.go
+55
-51
rtpconn/rtpreader.go
rtpconn/rtpreader.go
+10
-0
rtpconn/rtpstats.go
rtpconn/rtpstats.go
+0
-1
rtpconn/webclient.go
rtpconn/webclient.go
+47
-19
static/galene.html
static/galene.html
+2
-0
static/galene.js
static/galene.js
+59
-23
static/protocol.js
static/protocol.js
+12
-9
No files found.
README.PROTOCOL
View file @
795a40ce
...
@@ -135,8 +135,17 @@ A peer must explicitly request the streams that it wants to receive.
...
@@ -135,8 +135,17 @@ A peer must explicitly request the streams that it wants to receive.
```
```
The field `request` is a dictionary that maps the labels of requested
The field `request` is a dictionary that maps the labels of requested
streams to a list containing either 'audio', 'video' or both. An entry
streams to a list containing either 'audio', or one of 'video' or
with an empty key `''` serves as default.
'video-low'. The empty key `''` serves as default. For example:
```javascript
{
type: 'request',
request: {
camera: ['audio', 'video-low'],
'': ['audio', 'video']
}
}
## Pushing streams
## Pushing streams
...
@@ -157,16 +166,22 @@ A stream is created by the sender with the `offer` message:
...
@@ -157,16 +166,22 @@ A stream is created by the sender with the `offer` message:
If a stream with the same id exists, then this is a renegotation;
If a stream with the same id exists, then this is a renegotation;
otherwise this message creates a new stream. If the field `replace` is
otherwise this message creates a new stream. If the field `replace` is
not empty, then this request additionally requests that an existing stream
not empty, then this request additionally requests that an existing stream
with the given id should be closed, and the new stream should replace it.
with the given id should be closed, and the new stream should replace it;
this is used most notably when changing the simulcast envelope.
The field `label` is one of `camera`, `screenshare` or `video`, a
s in the
The field `label` is one of `camera`, `screenshare` or `video`, a
nd will
`request` message.
be matched against the keys sent by the receiver in their
`request` message.
The field `sdp` contains the raw SDP string (i.e. the `sdp` field of
The field `sdp` contains the raw SDP string (i.e. the `sdp` field of
a JSEP session description). Galène will interpret the `nack`,
a JSEP session description). Galène will interpret the `nack`,
`nack pli`, `ccm fir` and `goog-remb` RTCP feedback types, and act
`nack pli`, `ccm fir` and `goog-remb` RTCP feedback types, and act
accordingly.
accordingly.
The sender may either send a single stream per media section in the SDP,
or use rid-based simulcasting. In the latter case, it should send two
video streams, one with rid 'h' and high throughput, and one with rid 'l'
and throughput limited to roughly 100kbit/s.
The receiver may either abort the stream immediately (see below), or send
The receiver may either abort the stream immediately (see below), or send
an answer.
an answer.
...
...
conn/conn.go
View file @
795a40ce
...
@@ -25,6 +25,7 @@ type UpTrack interface {
...
@@ -25,6 +25,7 @@ type UpTrack interface {
AddLocal
(
DownTrack
)
error
AddLocal
(
DownTrack
)
error
DelLocal
(
DownTrack
)
bool
DelLocal
(
DownTrack
)
bool
Kind
()
webrtc
.
RTPCodecType
Kind
()
webrtc
.
RTPCodecType
Label
()
string
Codec
()
webrtc
.
RTPCodecCapability
Codec
()
webrtc
.
RTPCodecCapability
// get a recent packet. Returns 0 if the packet is not in cache.
// get a recent packet. Returns 0 if the packet is not in cache.
GetRTP
(
seqno
uint16
,
result
[]
byte
)
uint16
GetRTP
(
seqno
uint16
,
result
[]
byte
)
uint16
...
@@ -33,7 +34,6 @@ type UpTrack interface {
...
@@ -33,7 +34,6 @@ type UpTrack interface {
// Type Down represents a connection in the server to client direction.
// Type Down represents a connection in the server to client direction.
type
Down
interface
{
type
Down
interface
{
GetMaxBitrate
(
now
uint64
)
uint64
}
}
// Type DownTrack represents a track in the server to client direction.
// Type DownTrack represents a track in the server to client direction.
...
@@ -42,4 +42,5 @@ type DownTrack interface {
...
@@ -42,4 +42,5 @@ type DownTrack interface {
Accumulate
(
bytes
uint32
)
Accumulate
(
bytes
uint32
)
SetTimeOffset
(
ntp
uint64
,
rtp
uint32
)
SetTimeOffset
(
ntp
uint64
,
rtp
uint32
)
SetCname
(
string
)
SetCname
(
string
)
GetMaxBitrate
()
uint64
}
}
diskwriter/diskwriter.go
View file @
795a40ce
...
@@ -600,7 +600,7 @@ func (conn *diskConn) initWriter(width, height uint32) error {
...
@@ -600,7 +600,7 @@ func (conn *diskConn) initWriter(width, height uint32) error {
return
nil
return
nil
}
}
func
(
down
*
diskConn
)
GetMaxBitrate
(
now
uint64
)
uint64
{
func
(
t
*
diskTrack
)
GetMaxBitrate
(
)
uint64
{
return
^
uint64
(
0
)
return
^
uint64
(
0
)
}
}
...
...
group/group.go
View file @
795a40ce
...
@@ -13,6 +13,7 @@ import (
...
@@ -13,6 +13,7 @@ import (
"time"
"time"
"github.com/pion/ice/v2"
"github.com/pion/ice/v2"
"github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3"
)
)
...
@@ -60,7 +61,8 @@ type ChatHistoryEntry struct {
...
@@ -60,7 +61,8 @@ type ChatHistoryEntry struct {
}
}
const
(
const
(
MinBitrate
=
200000
LowBitrate
=
100000
MinBitrate
=
2
*
LowBitrate
)
)
type
Group
struct
{
type
Group
struct
{
...
@@ -252,6 +254,12 @@ func APIFromCodecs(codecs []webrtc.RTPCodecCapability) (*webrtc.API, error) {
...
@@ -252,6 +254,12 @@ func APIFromCodecs(codecs []webrtc.RTPCodecCapability) (*webrtc.API, error) {
if
UDPMin
>
0
&&
UDPMax
>
0
{
if
UDPMin
>
0
&&
UDPMax
>
0
{
s
.
SetEphemeralUDPPortRange
(
UDPMin
,
UDPMax
)
s
.
SetEphemeralUDPPortRange
(
UDPMin
,
UDPMax
)
}
}
m
.
RegisterHeaderExtension
(
webrtc
.
RTPHeaderExtensionCapability
{
sdp
.
SDESMidURI
},
webrtc
.
RTPCodecTypeVideo
)
m
.
RegisterHeaderExtension
(
webrtc
.
RTPHeaderExtensionCapability
{
sdp
.
SDESRTPStreamIDURI
},
webrtc
.
RTPCodecTypeVideo
)
return
webrtc
.
NewAPI
(
return
webrtc
.
NewAPI
(
webrtc
.
WithSettingEngine
(
s
),
webrtc
.
WithSettingEngine
(
s
),
...
...
rtpconn/rtpconn.go
View file @
795a40ce
...
@@ -77,15 +77,16 @@ type downTrackAtomics struct {
...
@@ -77,15 +77,16 @@ type downTrackAtomics struct {
}
}
type
rtpDownTrack
struct
{
type
rtpDownTrack
struct
{
track
*
webrtc
.
TrackLocalStaticRTP
track
*
webrtc
.
TrackLocalStaticRTP
sender
*
webrtc
.
RTPSender
sender
*
webrtc
.
RTPSender
remote
conn
.
UpTrack
remote
conn
.
UpTrack
ssrc
webrtc
.
SSRC
ssrc
webrtc
.
SSRC
maxBitrate
*
bitrate
maxBitrate
*
bitrate
rate
*
estimator
.
Estimator
maxREMBBitrate
*
bitrate
stats
*
receiverStats
rate
*
estimator
.
Estimator
atomics
*
downTrackAtomics
stats
*
receiverStats
cname
atomic
.
Value
atomics
*
downTrackAtomics
cname
atomic
.
Value
}
}
func
(
down
*
rtpDownTrack
)
WriteRTP
(
packet
*
rtp
.
Packet
)
error
{
func
(
down
*
rtpDownTrack
)
WriteRTP
(
packet
*
rtp
.
Packet
)
error
{
...
@@ -140,7 +141,6 @@ type rtpDownConnection struct {
...
@@ -140,7 +141,6 @@ type rtpDownConnection struct {
id
string
id
string
pc
*
webrtc
.
PeerConnection
pc
*
webrtc
.
PeerConnection
remote
conn
.
Up
remote
conn
.
Up
maxREMBBitrate
*
bitrate
iceCandidates
[]
*
webrtc
.
ICECandidateInit
iceCandidates
[]
*
webrtc
.
ICECandidateInit
negotiationNeeded
int
negotiationNeeded
int
...
@@ -174,31 +174,22 @@ func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection,
...
@@ -174,31 +174,22 @@ func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection,
id
:
id
,
id
:
id
,
pc
:
pc
,
pc
:
pc
,
remote
:
remote
,
remote
:
remote
,
maxREMBBitrate
:
new
(
bitrate
),
}
}
return
conn
,
nil
return
conn
,
nil
}
}
func
(
down
*
rtpDownConnection
)
GetMaxBitrate
(
now
uint64
)
uint64
{
func
(
t
*
rtpDownTrack
)
GetMaxBitrate
()
uint64
{
rate
:=
down
.
maxREMBBitrate
.
Get
(
now
)
now
:=
rtptime
.
Jiffies
()
var
trackRate
uint64
r
:=
t
.
maxBitrate
.
Get
(
now
)
tracks
:=
down
.
getTracks
()
if
r
==
^
uint64
(
0
)
{
for
_
,
t
:=
range
tracks
{
r
=
512
*
1024
r
:=
t
.
maxBitrate
.
Get
(
now
)
if
r
==
^
uint64
(
0
)
{
if
t
.
track
.
Kind
()
==
webrtc
.
RTPCodecTypeAudio
{
r
=
128
*
1024
}
else
{
r
=
512
*
1024
}
}
trackRate
+=
r
}
}
if
trackRate
<
rate
{
rr
:=
t
.
maxREMBBitrate
.
Get
(
now
)
return
trackRate
if
rr
==
0
||
r
<
rr
{
return
r
}
}
return
r
ate
return
r
r
}
}
func
(
down
*
rtpDownConnection
)
addICECandidate
(
candidate
*
webrtc
.
ICECandidateInit
)
error
{
func
(
down
*
rtpDownConnection
)
addICECandidate
(
candidate
*
webrtc
.
ICECandidateInit
)
error
{
...
@@ -311,6 +302,10 @@ func (up *rtpUpTrack) GetRTP(seqno uint16, result []byte) uint16 {
...
@@ -311,6 +302,10 @@ func (up *rtpUpTrack) GetRTP(seqno uint16, result []byte) uint16 {
return
up
.
cache
.
Get
(
seqno
,
result
)
return
up
.
cache
.
Get
(
seqno
,
result
)
}
}
func
(
up
*
rtpUpTrack
)
Label
()
string
{
return
up
.
track
.
RID
()
}
func
(
up
*
rtpUpTrack
)
Kind
()
webrtc
.
RTPCodecType
{
func
(
up
*
rtpUpTrack
)
Kind
()
webrtc
.
RTPCodecType
{
return
up
.
track
.
Kind
()
return
up
.
track
.
Kind
()
}
}
...
@@ -687,7 +682,7 @@ func rtcpUpListener(conn *rtpUpConnection, track *rtpUpTrack, r *webrtc.RTPRecei
...
@@ -687,7 +682,7 @@ func rtcpUpListener(conn *rtpUpConnection, track *rtpUpTrack, r *webrtc.RTPRecei
for
{
for
{
firstSR
:=
false
firstSR
:=
false
n
,
_
,
err
:=
r
.
Read
(
buf
)
n
,
_
,
err
:=
r
.
Read
Simulcast
(
buf
,
track
.
track
.
RID
()
)
if
err
!=
nil
{
if
err
!=
nil
{
if
err
!=
io
.
EOF
&&
err
!=
io
.
ErrClosedPipe
{
if
err
!=
io
.
EOF
&&
err
!=
io
.
ErrClosedPipe
{
log
.
Printf
(
"Read RTCP: %v"
,
err
)
log
.
Printf
(
"Read RTCP: %v"
,
err
)
...
@@ -752,11 +747,11 @@ func rtcpUpListener(conn *rtpUpConnection, track *rtpUpTrack, r *webrtc.RTPRecei
...
@@ -752,11 +747,11 @@ func rtcpUpListener(conn *rtpUpConnection, track *rtpUpTrack, r *webrtc.RTPRecei
}
}
}
}
func
sendUpRTCP
(
conn
*
rtpUpConnection
)
error
{
func
sendUpRTCP
(
up
*
rtpUpConnection
)
error
{
tracks
:=
conn
.
getTracks
()
tracks
:=
up
.
getTracks
()
if
len
(
conn
.
tracks
)
==
0
{
if
len
(
up
.
tracks
)
==
0
{
state
:=
conn
.
pc
.
ConnectionState
()
state
:=
up
.
pc
.
ConnectionState
()
if
state
==
webrtc
.
PeerConnectionStateClosed
{
if
state
==
webrtc
.
PeerConnectionStateClosed
{
return
io
.
ErrClosedPipe
return
io
.
ErrClosedPipe
}
}
...
@@ -765,7 +760,7 @@ func sendUpRTCP(conn *rtpUpConnection) error {
...
@@ -765,7 +760,7 @@ func sendUpRTCP(conn *rtpUpConnection) error {
now
:=
rtptime
.
Jiffies
()
now
:=
rtptime
.
Jiffies
()
reports
:=
make
([]
rtcp
.
ReceptionReport
,
0
,
len
(
conn
.
tracks
))
reports
:=
make
([]
rtcp
.
ReceptionReport
,
0
,
len
(
up
.
tracks
))
for
_
,
t
:=
range
tracks
{
for
_
,
t
:=
range
tracks
{
updateUpTrack
(
t
)
updateUpTrack
(
t
)
stats
:=
t
.
cache
.
GetStats
(
true
)
stats
:=
t
.
cache
.
GetStats
(
true
)
...
@@ -810,29 +805,38 @@ func sendUpRTCP(conn *rtpUpConnection) error {
...
@@ -810,29 +805,38 @@ func sendUpRTCP(conn *rtpUpConnection) error {
},
},
}
}
rate
:=
^
uint64
(
0
)
local
:=
conn
.
getLocal
()
for
_
,
l
:=
range
local
{
r
:=
l
.
GetMaxBitrate
(
now
)
if
r
<
rate
{
rate
=
r
}
}
if
rate
<
group
.
MinBitrate
{
rate
=
group
.
MinBitrate
}
var
ssrcs
[]
uint32
var
ssrcs
[]
uint32
var
rate
uint64
for
_
,
t
:=
range
tracks
{
for
_
,
t
:=
range
tracks
{
if
!
t
.
hasRtcpFb
(
"goog-remb"
,
""
)
{
if
!
t
.
hasRtcpFb
(
"goog-remb"
,
""
)
{
continue
continue
}
}
ssrcs
=
append
(
ssrcs
,
uint32
(
t
.
track
.
SSRC
()))
ssrcs
=
append
(
ssrcs
,
uint32
(
t
.
track
.
SSRC
()))
var
r
uint64
if
t
.
Kind
()
==
webrtc
.
RTPCodecTypeAudio
{
r
=
100
*
1024
}
else
if
t
.
Label
()
==
"l"
{
r
=
group
.
LowBitrate
}
else
{
local
:=
t
.
getLocal
()
r
=
^
uint64
(
0
)
for
_
,
down
:=
range
local
{
rr
:=
down
.
GetMaxBitrate
()
if
rr
<
group
.
MinBitrate
{
rr
=
group
.
MinBitrate
}
if
r
>
rr
{
r
=
rr
}
}
if
r
==
^
uint64
(
0
)
{
r
=
512
*
1024
}
}
rate
+=
r
}
}
if
len
(
ssrcs
)
>
0
{
if
rate
<
^
uint64
(
0
)
&&
len
(
ssrcs
)
>
0
{
packets
=
append
(
packets
,
packets
=
append
(
packets
,
&
rtcp
.
ReceiverEstimatedMaximumBitrate
{
&
rtcp
.
ReceiverEstimatedMaximumBitrate
{
Bitrate
:
rate
,
Bitrate
:
rate
,
...
@@ -840,7 +844,7 @@ func sendUpRTCP(conn *rtpUpConnection) error {
...
@@ -840,7 +844,7 @@ func sendUpRTCP(conn *rtpUpConnection) error {
},
},
)
)
}
}
return
conn
.
pc
.
WriteRTCP
(
packets
)
return
up
.
pc
.
WriteRTCP
(
packets
)
}
}
func
rtcpUpSender
(
conn
*
rtpUpConnection
)
{
func
rtcpUpSender
(
conn
*
rtpUpConnection
)
{
...
@@ -1049,7 +1053,7 @@ func rtcpDownListener(conn *rtpDownConnection, track *rtpDownTrack, s *webrtc.RT
...
@@ -1049,7 +1053,7 @@ func rtcpDownListener(conn *rtpDownConnection, track *rtpDownTrack, s *webrtc.RT
log
.
Printf
(
"sendFIR: %v"
,
err
)
log
.
Printf
(
"sendFIR: %v"
,
err
)
}
}
case
*
rtcp
.
ReceiverEstimatedMaximumBitrate
:
case
*
rtcp
.
ReceiverEstimatedMaximumBitrate
:
conn
.
maxREMBBitrate
.
Set
(
p
.
Bitrate
,
jiffies
)
track
.
maxREMBBitrate
.
Set
(
p
.
Bitrate
,
jiffies
)
case
*
rtcp
.
ReceiverReport
:
case
*
rtcp
.
ReceiverReport
:
for
_
,
r
:=
range
p
.
Reports
{
for
_
,
r
:=
range
p
.
Reports
{
if
r
.
SSRC
==
uint32
(
track
.
ssrc
)
{
if
r
.
SSRC
==
uint32
(
track
.
ssrc
)
{
...
...
rtpconn/rtpreader.go
View file @
795a40ce
...
@@ -149,6 +149,16 @@ func readLoop(conn *rtpUpConnection, track *rtpUpTrack) {
...
@@ -149,6 +149,16 @@ func readLoop(conn *rtpUpConnection, track *rtpUpTrack) {
kf
,
_
:=
isKeyframe
(
codec
.
MimeType
,
&
packet
)
kf
,
_
:=
isKeyframe
(
codec
.
MimeType
,
&
packet
)
if
packet
.
Extension
{
packet
.
Extension
=
false
packet
.
Extensions
=
nil
bytes
,
err
=
packet
.
MarshalTo
(
buf
)
if
err
!=
nil
{
log
.
Printf
(
"%v"
,
err
)
continue
}
}
first
,
index
:=
track
.
cache
.
Store
(
first
,
index
:=
track
.
cache
.
Store
(
packet
.
SequenceNumber
,
packet
.
Timestamp
,
packet
.
SequenceNumber
,
packet
.
Timestamp
,
kf
,
packet
.
Marker
,
buf
[
:
bytes
],
kf
,
packet
.
Marker
,
buf
[
:
bytes
],
...
...
rtpconn/rtpstats.go
View file @
795a40ce
...
@@ -47,7 +47,6 @@ func (c *webClient) GetStats() *stats.Client {
...
@@ -47,7 +47,6 @@ func (c *webClient) GetStats() *stats.Client {
for
_
,
down
:=
range
c
.
down
{
for
_
,
down
:=
range
c
.
down
{
conns
:=
stats
.
Conn
{
conns
:=
stats
.
Conn
{
Id
:
down
.
id
,
Id
:
down
.
id
,
MaxBitrate
:
down
.
GetMaxBitrate
(
jiffies
),
}
}
for
_
,
t
:=
range
down
.
tracks
{
for
_
,
t
:=
range
down
.
tracks
{
rate
,
_
:=
t
.
rate
.
Estimate
()
rate
,
_
:=
t
.
rate
.
Estimate
()
...
...
rtpconn/webclient.go
View file @
795a40ce
...
@@ -380,14 +380,15 @@ func addDownTrackUnlocked(conn *rtpDownConnection, remoteTrack *rtpUpTrack, remo
...
@@ -380,14 +380,15 @@ func addDownTrackUnlocked(conn *rtpDownConnection, remoteTrack *rtpUpTrack, remo
}
}
track
:=
&
rtpDownTrack
{
track
:=
&
rtpDownTrack
{
track
:
local
,
track
:
local
,
sender
:
sender
,
sender
:
sender
,
ssrc
:
parms
.
Encodings
[
0
]
.
SSRC
,
ssrc
:
parms
.
Encodings
[
0
]
.
SSRC
,
remote
:
remoteTrack
,
remote
:
remoteTrack
,
maxBitrate
:
new
(
bitrate
),
maxBitrate
:
new
(
bitrate
),
stats
:
new
(
receiverStats
),
maxREMBBitrate
:
new
(
bitrate
),
rate
:
estimator
.
New
(
time
.
Second
),
stats
:
new
(
receiverStats
),
atomics
:
&
downTrackAtomics
{},
rate
:
estimator
.
New
(
time
.
Second
),
atomics
:
&
downTrackAtomics
{},
}
}
conn
.
tracks
=
append
(
conn
.
tracks
,
track
)
conn
.
tracks
=
append
(
conn
.
tracks
,
track
)
...
@@ -646,33 +647,60 @@ func requestedTracks(c *webClient, up conn.Up, tracks []conn.UpTrack) []conn.UpT
...
@@ -646,33 +647,60 @@ func requestedTracks(c *webClient, up conn.Up, tracks []conn.UpTrack) []conn.UpT
return
nil
return
nil
}
}
var
audio
,
video
bool
var
audio
,
video
,
videoLow
bool
for
_
,
s
:=
range
r
{
for
_
,
s
:=
range
r
{
switch
s
{
switch
s
{
case
"audio"
:
case
"audio"
:
audio
=
true
audio
=
true
case
"video"
:
case
"video"
:
video
=
true
video
=
true
case
"video-low"
:
videoLow
=
true
default
:
default
:
log
.
Printf
(
"client requested unknown value %v"
,
s
)
log
.
Printf
(
"client requested unknown value %v"
,
s
)
}
}
}
}
var
ts
[]
conn
.
UpTrack
find
:=
func
(
kind
webrtc
.
RTPCodecType
,
labels
...
string
)
conn
.
UpTrack
{
if
audio
{
for
_
,
l
:=
range
labels
{
for
_
,
t
:=
range
tracks
{
if
t
.
Kind
()
!=
kind
{
continue
}
if
t
.
Label
()
==
l
{
return
t
}
}
}
for
_
,
t
:=
range
tracks
{
for
_
,
t
:=
range
tracks
{
if
t
.
Kind
()
==
webrtc
.
RTPCodecTypeAudio
{
if
t
.
Kind
()
!=
kind
{
ts
=
append
(
ts
,
t
)
continue
break
}
}
return
t
}
return
nil
}
var
ts
[]
conn
.
UpTrack
if
audio
{
t
:=
find
(
webrtc
.
RTPCodecTypeAudio
)
if
t
!=
nil
{
ts
=
append
(
ts
,
t
)
}
}
}
}
if
video
{
if
video
{
for
_
,
t
:=
range
tracks
{
t
:=
find
(
if
t
.
Kind
()
==
webrtc
.
RTPCodecTypeVideo
{
webrtc
.
RTPCodecTypeVideo
,
"h"
,
"m"
,
"video"
,
ts
=
append
(
ts
,
t
)
)
break
if
t
!=
nil
{
}
ts
=
append
(
ts
,
t
)
}
}
else
if
videoLow
{
t
:=
find
(
webrtc
.
RTPCodecTypeVideo
,
"l"
,
"m"
,
"video"
,
)
if
t
!=
nil
{
ts
=
append
(
ts
,
t
)
}
}
}
}
...
...
static/galene.html
View file @
795a40ce
...
@@ -213,7 +213,9 @@
...
@@ -213,7 +213,9 @@
<select
id=
"requestselect"
class=
"select select-inline"
>
<select
id=
"requestselect"
class=
"select select-inline"
>
<option
value=
""
>
nothing
</option>
<option
value=
""
>
nothing
</option>
<option
value=
"audio"
>
audio only
</option>
<option
value=
"audio"
>
audio only
</option>
<option
value=
"screenshare-low"
>
screen share (low)
</option>
<option
value=
"screenshare"
>
screen share
</option>
<option
value=
"screenshare"
>
screen share
</option>
<option
value=
"everything-low"
>
everything (low)
</option>
<option
value=
"everything"
selected
>
everything
</option>
<option
value=
"everything"
selected
>
everything
</option>
</select>
</select>
</form>
</form>
...
...
static/galene.js
View file @
795a40ce
...
@@ -78,6 +78,7 @@ function getUserPass() {
...
@@ -78,6 +78,7 @@ function getUserPass() {
* @property {boolean} [localMute]
* @property {boolean} [localMute]
* @property {string} [video]
* @property {string} [video]
* @property {string} [audio]
* @property {string} [audio]
* @property {boolean} [simulcast]
* @property {string} [send]
* @property {string} [send]
* @property {string} [request]
* @property {string} [request]
* @property {boolean} [activityDetection]
* @property {boolean} [activityDetection]
...
@@ -550,9 +551,15 @@ function mapRequest(what) {
...
@@ -550,9 +551,15 @@ function mapRequest(what) {
case
'
audio
'
:
case
'
audio
'
:
return
{
''
:
[
'
audio
'
]};
return
{
''
:
[
'
audio
'
]};
break
;
break
;
case
'
screenshare-low
'
:
return
{
screenshare
:
[
'
audio
'
,
'
video-low
'
],
''
:
[
'
audio
'
]};
break
;
case
'
screenshare
'
:
case
'
screenshare
'
:
return
{
screenshare
:
[
'
audio
'
,
'
video
'
],
''
:
[
'
audio
'
]};
return
{
screenshare
:
[
'
audio
'
,
'
video
'
],
''
:
[
'
audio
'
]};
break
;
break
;
case
'
everything-low
'
:
return
{
''
:
[
'
audio
'
,
'
video-low
'
]};
break
;
case
'
everything
'
:
case
'
everything
'
:
return
{
''
:
[
'
audio
'
,
'
video
'
]}
return
{
''
:
[
'
audio
'
,
'
video
'
]}
break
;
break
;
...
@@ -611,20 +618,25 @@ getInputElement('fileinput').onchange = function(e) {
...
@@ -611,20 +618,25 @@ getInputElement('fileinput').onchange = function(e) {
function
gotUpStats
(
stats
)
{
function
gotUpStats
(
stats
)
{
let
c
=
this
;
let
c
=
this
;
let
text
=
''
;
let
values
=
[]
;
c
.
pc
.
getSenders
().
forEach
(
s
=>
{
for
(
let
id
in
stats
)
{
let
tid
=
s
.
track
&&
s
.
track
.
id
;
if
(
stats
[
id
]
&&
stats
[
id
][
'
outbound-rtp
'
])
{
let
stats
=
tid
&&
c
.
stats
[
tid
];
let
rate
=
stats
[
id
][
'
outbound-rtp
'
].
rate
;
let
rate
=
stats
&&
stats
[
'
outbound-rtp
'
]
&&
stats
[
'
outbound-rtp
'
].
rate
;
if
(
typeof
rate
===
'
number
'
)
{
if
(
typeof
rate
===
'
number
'
)
{
values
.
push
(
rate
);
if
(
text
)
}
text
=
text
+
'
+
'
;
text
=
text
+
Math
.
round
(
rate
/
1000
)
+
'
kbps
'
;
}
}
}
);
}
setLabel
(
c
,
text
);
if
(
values
.
length
===
0
)
{
setLabel
(
c
,
''
);
}
else
{
values
.
sort
((
x
,
y
)
=>
x
-
y
);
setLabel
(
c
,
values
.
map
(
x
=>
Math
.
round
(
x
/
1000
).
toString
())
.
reduce
((
x
,
y
)
=>
x
+
'
+
'
+
y
));
}
}
}
/**
/**
...
@@ -800,6 +812,7 @@ function newUpStream(localId) {
...
@@ -800,6 +812,7 @@ function newUpStream(localId) {
* @param {number} [bps]
* @param {number} [bps]
*/
*/
async
function
setMaxVideoThroughput
(
c
,
bps
)
{
async
function
setMaxVideoThroughput
(
c
,
bps
)
{
let
simulcast
=
doSimulcast
();
let
senders
=
c
.
pc
.
getSenders
();
let
senders
=
c
.
pc
.
getSenders
();
for
(
let
i
=
0
;
i
<
senders
.
length
;
i
++
)
{
for
(
let
i
=
0
;
i
<
senders
.
length
;
i
++
)
{
let
s
=
senders
[
i
];
let
s
=
senders
[
i
];
...
@@ -808,17 +821,17 @@ async function setMaxVideoThroughput(c, bps) {
...
@@ -808,17 +821,17 @@ async function setMaxVideoThroughput(c, bps) {
let
p
=
s
.
getParameters
();
let
p
=
s
.
getParameters
();
if
(
!
p
.
encodings
)
if
(
!
p
.
encodings
)
p
.
encodings
=
[{}];
p
.
encodings
=
[{}];
if
((
!
simulcast
&&
p
.
encodings
.
length
!=
1
)
||
(
simulcast
&&
p
.
encodings
.
length
!=
2
))
{
// change the simulcast envelope
await
replaceUpStream
(
c
);
return
;
}
p
.
encodings
.
forEach
(
e
=>
{
p
.
encodings
.
forEach
(
e
=>
{
if
(
bps
>
0
)
if
(
!
e
.
rid
||
e
.
rid
===
'
h
'
)
e
.
maxBitrate
=
bps
;
e
.
maxBitrate
=
bps
||
unlimitedRate
;
else
delete
e
.
maxBitrate
;
});
});
try
{
await
s
.
setParameters
(
p
);
await
s
.
setParameters
(
p
);
}
catch
(
e
)
{
console
.
error
(
e
);
}
}
}
}
}
...
@@ -1022,6 +1035,19 @@ function isSafari() {
...
@@ -1022,6 +1035,19 @@ function isSafari() {
return
ua
.
indexOf
(
'
safari
'
)
>=
0
&&
ua
.
indexOf
(
'
chrome
'
)
<
0
;
return
ua
.
indexOf
(
'
safari
'
)
>=
0
&&
ua
.
indexOf
(
'
chrome
'
)
<
0
;
}
}
const
unlimitedRate
=
1000000000
;
const
simulcastRate
=
100000
;
/**
* @returns {boolean}
*/
function
doSimulcast
()
{
if
(
!
getSettings
().
simulcast
)
return
false
;
let
bps
=
getMaxVideoThroughput
();
return
bps
<=
0
||
bps
>=
2
*
simulcastRate
;
}
/**
/**
* Sets up c to send the given stream. Some extra parameters are stored
* Sets up c to send the given stream. Some extra parameters are stored
* in c.userdata.
* in c.userdata.
...
@@ -1029,6 +1055,7 @@ function isSafari() {
...
@@ -1029,6 +1055,7 @@ function isSafari() {
* @param {Stream} c
* @param {Stream} c
* @param {MediaStream} stream
* @param {MediaStream} stream
*/
*/
function
setUpStream
(
c
,
stream
)
{
function
setUpStream
(
c
,
stream
)
{
if
(
c
.
stream
!=
null
)
if
(
c
.
stream
!=
null
)
throw
new
Error
(
"
Setting nonempty stream
"
);
throw
new
Error
(
"
Setting nonempty stream
"
);
...
@@ -1073,11 +1100,20 @@ function setUpStream(c, stream) {
...
@@ -1073,11 +1100,20 @@ function setUpStream(c, stream) {
c
.
close
();
c
.
close
();
};
};
let
encodings
=
[
{}
];
let
encodings
=
[];
if
(
t
.
kind
===
'
video
'
)
{
if
(
t
.
kind
===
'
video
'
)
{
let
simulcast
=
doSimulcast
();
let
bps
=
getMaxVideoThroughput
();
let
bps
=
getMaxVideoThroughput
();
if
(
bps
>
0
)
encodings
.
push
({
encodings
[
0
].
maxBitrate
=
bps
;
rid
:
'
h
'
,
maxBitrate
:
bps
||
unlimitedRate
,
});
if
(
simulcast
)
encodings
.
push
({
rid
:
'
l
'
,
scaleResolutionDownBy
:
2
,
maxBitrate
:
simulcastRate
,
});
}
}
c
.
pc
.
addTransceiver
(
t
,
{
c
.
pc
.
addTransceiver
(
t
,
{
direction
:
'
sendonly
'
,
direction
:
'
sendonly
'
,
...
...
static/protocol.js
View file @
795a40ce
...
@@ -1246,17 +1246,20 @@ Stream.prototype.updateStats = async function() {
...
@@ -1246,17 +1246,20 @@ Stream.prototype.updateStats = async function() {
if
(
report
)
{
if
(
report
)
{
for
(
let
r
of
report
.
values
())
{
for
(
let
r
of
report
.
values
())
{
if
(
stid
&&
r
.
type
===
'
outbound-rtp
'
)
{
if
(
stid
&&
r
.
type
===
'
outbound-rtp
'
)
{
let
id
=
stid
;
if
(
r
.
rid
)
id
=
id
+
'
-
'
+
r
.
rid
if
(
!
(
'
bytesSent
'
in
r
))
if
(
!
(
'
bytesSent
'
in
r
))
continue
;
continue
;
if
(
!
stats
[
st
id
])
if
(
!
stats
[
id
])
stats
[
st
id
]
=
{};
stats
[
id
]
=
{};
stats
[
st
id
][
r
.
type
]
=
{};
stats
[
id
][
r
.
type
]
=
{};
stats
[
st
id
][
r
.
type
].
timestamp
=
r
.
timestamp
;
stats
[
id
][
r
.
type
].
timestamp
=
r
.
timestamp
;
stats
[
st
id
][
r
.
type
].
bytesSent
=
r
.
bytesSent
;
stats
[
id
][
r
.
type
].
bytesSent
=
r
.
bytesSent
;
if
(
old
[
stid
]
&&
old
[
st
id
][
r
.
type
])
if
(
old
[
id
]
&&
old
[
id
][
r
.
type
])
stats
[
st
id
][
r
.
type
].
rate
=
stats
[
id
][
r
.
type
].
rate
=
((
r
.
bytesSent
-
old
[
st
id
][
r
.
type
].
bytesSent
)
*
1000
/
((
r
.
bytesSent
-
old
[
id
][
r
.
type
].
bytesSent
)
*
1000
/
(
r
.
timestamp
-
old
[
st
id
][
r
.
type
].
timestamp
))
*
8
;
(
r
.
timestamp
-
old
[
id
][
r
.
type
].
timestamp
))
*
8
;
}
}
}
}
}
}
...
...
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