Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package galene for openSUSE:Factory checked 
in at 2022-04-21 15:42:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/galene (Old)
 and      /work/SRC/openSUSE:Factory/.galene.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "galene"

Thu Apr 21 15:42:30 2022 rev:18 rq:971264 version:0.5.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/galene/galene.changes    2022-03-25 
21:55:15.590311695 +0100
+++ /work/SRC/openSUSE:Factory/.galene.new.1538/galene.changes  2022-04-21 
15:48:47.464324721 +0200
@@ -1,0 +2,11 @@
+Wed Apr 20 18:13:56 UTC 2022 - mich...@stroeder.com
+
+- Update to version 0.5.2:
+  * Implement audio-video sync in the diskwriter.
+  * Fix setting of the keyframe flag in audio samples in diskwriter.
+  * Don't use high-quality audio for screenshare by default, obey the
+    hqaudio preference in all cases.
+  * Maintain user information for oneself, not just other users.
+  * Call the onuser callback when a user deletes a stream.
+
+-------------------------------------------------------------------

Old:
----
  galene-0.5.1.tar.gz

New:
----
  galene-0.5.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ galene.spec ++++++
--- /var/tmp/diff_new_pack.wYgQta/_old  2022-04-21 15:48:48.036325332 +0200
+++ /var/tmp/diff_new_pack.wYgQta/_new  2022-04-21 15:48:48.040325337 +0200
@@ -25,7 +25,7 @@
 %bcond_without  apparmor
 
 Name:           galene
-Version:        0.5.1
+Version:        0.5.2
 Release:        0
 Summary:        Gal??ne videoconferencing server
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.wYgQta/_old  2022-04-21 15:48:48.092325392 +0200
+++ /var/tmp/diff_new_pack.wYgQta/_new  2022-04-21 15:48:48.096325397 +0200
@@ -3,8 +3,8 @@
     <param name="url">https://github.com/jech/galene.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">galene-0.5.1</param>
-    <param name="version">0.5.1</param>
+    <param name="revision">galene-0.5.2</param>
+    <param name="version">0.5.2</param>
     <param name="changesgenerate">enable</param>
     <!--param name="versionrewrite-pattern">galene-(\d+)</param>
     <param name="versionrewrite-replacement">\1</param-->

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.wYgQta/_old  2022-04-21 15:48:48.128325431 +0200
+++ /var/tmp/diff_new_pack.wYgQta/_new  2022-04-21 15:48:48.132325435 +0200
@@ -3,6 +3,6 @@
                 <param name="url">git://github.com/jech/galene.git</param>
               <param 
name="changesrevision">ba75bfeb3acd33f92084fa0eb88be9aee824badf</param></service><service
 name="tar_scm">
                 <param name="url">https://github.com/jech/galene.git</param>
-              <param 
name="changesrevision">a7ccfba407dc6b5fa76c9110fff49858cdd476b1</param></service></servicedata>
+              <param 
name="changesrevision">474c58cc7dcf39b39af52e679d4ca1dcc8466673</param></service></servicedata>
 (No newline at EOF)
 

++++++ galene-0.5.1.tar.gz -> galene-0.5.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/CHANGES new/galene-0.5.2/CHANGES
--- old/galene-0.5.1/CHANGES    2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/CHANGES    2022-04-20 19:55:33.000000000 +0200
@@ -1,3 +1,12 @@
+20 April 2022: Galene 0.5.2
+
+  * Implement audio-video sync in the diskwriter.
+  * Fix setting of the keyframe flag in audio samples in diskwriter.
+  * Don't use high-quality audio for screenshare by default, obey the
+    hqaudio preference in all cases.
+  * Maintain user information for oneself, not just other users.
+  * Call the onuser callback when a user deletes a stream.
+
 25 March 2022: Galene 0.5.1
 
   * Enable simulcast on Firefox.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/diskwriter/diskwriter.go 
new/galene-0.5.2/diskwriter/diskwriter.go
--- old/galene-0.5.1/diskwriter/diskwriter.go   2022-03-25 10:44:45.000000000 
+0100
+++ new/galene-0.5.2/diskwriter/diskwriter.go   2022-04-20 19:55:33.000000000 
+0200
@@ -24,6 +24,12 @@
        gcodecs "github.com/jech/galene/codecs"
        "github.com/jech/galene/conn"
        "github.com/jech/galene/group"
+       "github.com/jech/galene/rtptime"
+)
+
+const (
+       audioMaxLate = 32
+       videoMaxLate = 256
 )
 
 var Directory string
@@ -170,6 +176,8 @@
        tracks        []*diskTrack
        width, height uint32
        lastWarning   time.Time
+       originLocal   time.Time
+       originRemote  uint64
 }
 
 // called locked
@@ -184,15 +192,10 @@
 }
 
 // called locked
-func (conn *diskConn) reopen(extension string) error {
-       for _, t := range conn.tracks {
-               t.writeBuffered(true)
-               if t.writer != nil {
-                       t.writer.Close()
-                       t.writer = nil
-               }
+func (conn *diskConn) open(extension string) error {
+       if conn.file != nil {
+               return errors.New("already open")
        }
-       conn.file = nil
 
        file, err := openDiskFile(conn.directory, conn.username, extension)
        if err != nil {
@@ -203,10 +206,11 @@
        return nil
 }
 
-func (conn *diskConn) Close() error {
-       conn.remote.DelLocal(conn)
+// called locked
+func (conn *diskConn) close() []*diskTrack {
+       conn.originLocal = time.Time{}
+       conn.originRemote = 0
 
-       conn.mu.Lock()
        tracks := make([]*diskTrack, 0, len(conn.tracks))
        for _, t := range conn.tracks {
                t.writeBuffered(true)
@@ -214,8 +218,18 @@
                        t.writer.Close()
                        t.writer = nil
                }
+               t.origin = none
                tracks = append(tracks, t)
        }
+       conn.file = nil
+       return tracks
+}
+
+func (conn *diskConn) Close() error {
+       conn.remote.DelLocal(conn)
+
+       conn.mu.Lock()
+       tracks := conn.close()
        conn.mu.Unlock()
 
        for _, t := range tracks {
@@ -280,7 +294,11 @@
        writer    mkvcore.BlockWriteCloser
        builder   *samplebuilder.SampleBuilder
        lastSeqno maybeUint32
-       origin    maybeUint32
+
+       origin maybeUint32
+
+       remoteNTP uint64
+       remoteRTP uint32
 
        kfRequested time.Time
        lastKf      time.Time
@@ -337,21 +355,25 @@
                codec := remote.Codec()
                if strings.EqualFold(codec.MimeType, "audio/opus") {
                        builder = samplebuilder.New(
-                               16, &codecs.OpusPacket{}, codec.ClockRate,
+                               audioMaxLate,
+                               &codecs.OpusPacket{}, codec.ClockRate,
                        )
                } else if strings.EqualFold(codec.MimeType, "video/vp8") {
                        builder = samplebuilder.New(
-                               256, &codecs.VP8Packet{}, codec.ClockRate,
+                               videoMaxLate,
+                               &codecs.VP8Packet{}, codec.ClockRate,
                        )
                        conn.hasVideo = true
                } else if strings.EqualFold(codec.MimeType, "video/vp9") {
                        builder = samplebuilder.New(
-                               256, &codecs.VP9Packet{}, codec.ClockRate,
+                               videoMaxLate, &codecs.VP9Packet{},
+                               codec.ClockRate,
                        )
                        conn.hasVideo = true
                } else if strings.EqualFold(codec.MimeType, "video/h264") {
                        builder = samplebuilder.New(
-                               256, &codecs.H264Packet{}, codec.ClockRate,
+                               videoMaxLate, &codecs.H264Packet{},
+                               codec.ClockRate,
                        )
                        conn.hasVideo = true
                } else {
@@ -385,9 +407,6 @@
        return &conn, nil
 }
 
-func (t *diskTrack) SetTimeOffset(ntp uint64, rtp uint32) {
-}
-
 func (t *diskTrack) SetCname(string) {
 }
 
@@ -473,18 +492,33 @@
                if kf {
                        t.savedKf = p
                        t.lastKf = time.Now()
+                       if !valid(t.origin) {
+                               t.setOrigin(
+                                       p.Timestamp, time.Now(),
+                                       t.remote.Codec().ClockRate,
+                               )
+                       }
                } else if time.Since(t.lastKf) > 4*time.Second {
                        requestKeyframe(t)
                }
        }
 
+       if !valid(t.origin) {
+               if !t.conn.hasVideo || !t.conn.originLocal.Equal(time.Time{}) {
+                       t.setOrigin(
+                               p.Timestamp, time.Now(),
+                               t.remote.Codec().ClockRate,
+                       )
+               }
+       }
+
        t.builder.Push(p)
 
        return t.writeBuffered(false)
 }
 
-// writeBuffered writes any buffered samples to disk.  If force is true,
-// then samples will be flushed even if they are preceded by incomplete
+// writeBuffered writes buffered samples to disk.  If force is true, then
+// samples will be flushed even if they are preceded by incomplete
 // samples.
 func (t *diskTrack) writeBuffered(force bool) error {
        codec := t.remote.Codec().MimeType
@@ -501,6 +535,16 @@
                        return nil
                }
 
+               if valid(t.origin) && int32(ts-value(t.origin)) < 0 {
+                       if value(t.origin)-ts < 0x10000 {
+                               // late packet before origin, drop
+                               continue
+                       }
+                       // we've gone around 2^31 timestamps, force
+                       // creating a new file to avoid wraparound
+                       t.conn.close()
+               }
+
                var keyframe bool
                if len(codec) > 6 && strings.EqualFold(codec[:6], "video/") {
                        if t.savedKf == nil {
@@ -510,11 +554,10 @@
                        }
 
                        if keyframe {
-                               err := t.conn.initWriter(
-                                       gcodecs.KeyframeDimensions(
-                                               codec, t.savedKf,
-                                       ),
+                               w, h := gcodecs.KeyframeDimensions(
+                                       codec, t.savedKf,
                                )
+                               err := t.conn.initWriter(w, h, t, ts)
                                if err != nil {
                                        t.conn.warn(
                                                "Write to disk " + err.Error(),
@@ -523,9 +566,10 @@
                                }
                        }
                } else {
+                       keyframe = true
                        if t.writer == nil {
                                if !t.conn.hasVideo {
-                                       err := t.conn.initWriter(0, 0)
+                                       err := t.conn.initWriter(0, 0, t, ts)
                                        if err != nil {
                                                t.conn.warn(
                                                        "Write to disk " +
@@ -542,11 +586,12 @@
                }
 
                if !valid(t.origin) {
-                       t.origin = some(ts)
+                       log.Println("Invalid origin")
+                       return nil
                }
-               ts -= value(t.origin)
 
-               tm := ts / (t.remote.Codec().ClockRate / 1000)
+               tm := (ts - value(t.origin)) /
+                       (t.remote.Codec().ClockRate / 1000)
                _, err := t.writer.Write(keyframe, int64(tm), sample.Data)
                if err != nil {
                        return err
@@ -554,11 +599,122 @@
        }
 }
 
+// setOrigin sets the origin of track t after receiving a packet with
+// timestamp ts at local time now.
 // called locked
-func (conn *diskConn) initWriter(width, height uint32) error {
-       if conn.file != nil && width == conn.width && height == conn.height {
-               return nil
+func (t *diskTrack) setOrigin(ts uint32, now time.Time, clockrate uint32) {
+       sub := func(a, b uint32, hz uint32) time.Duration {
+               return rtptime.ToDuration(int64(int32(a-b)), hz)
        }
+
+       if t.conn.originLocal.Equal(time.Time{}) {
+               t.origin = some(ts)
+               t.conn.originLocal = now
+               if t.remoteNTP != 0 {
+                       remote := rtptime.NTPToTime(t.remoteNTP).Add(
+                               sub(ts, t.remoteRTP, clockrate),
+                       )
+                       t.conn.originRemote = rtptime.TimeToNTP(remote)
+               } else {
+                       t.conn.originRemote = 0
+               }
+       } else if t.conn.originRemote != 0 && t.remoteNTP != 0 {
+               remote := rtptime.NTPToTime(t.remoteNTP).Add(
+                       sub(ts, t.remoteRTP, clockrate),
+               )
+               origin := rtptime.NTPToTime(t.conn.originRemote)
+               delta := rtptime.FromDuration(remote.Sub(origin), clockrate)
+               t.origin = some(ts - uint32(delta))
+       } else {
+               d := now.Sub(t.conn.originLocal)
+               delta := rtptime.FromDuration(d, clockrate)
+               t.origin = some(ts - uint32(delta))
+               if t.remoteNTP != 0 {
+                       remote := rtptime.NTPToTime(t.remoteNTP).Add(
+                               sub(ts, t.remoteRTP, clockrate),
+                       )
+                       t.conn.originRemote = rtptime.TimeToNTP(
+                               remote.Add(-d),
+                       )
+               }
+       }
+}
+
+// SetTimeOffset adjusts the origin of track t given remote sync information.
+func (t *diskTrack) SetTimeOffset(ntp uint64, rtp uint32) {
+       t.conn.mu.Lock()
+       defer t.conn.mu.Unlock()
+       t.setTimeOffset(ntp, rtp, t.remote.Codec().ClockRate)
+}
+
+// called locked
+func (t *diskTrack) setTimeOffset(ntp uint64, rtp uint32, clockrate uint32) {
+       if valid(t.origin) {
+               local := rtptime.ToDuration(
+                       int64(int32(rtp-value(t.origin))), clockrate,
+               )
+               if t.conn.originRemote == 0 {
+                       t.conn.originRemote =
+                               rtptime.TimeToNTP(
+                                       rtptime.NTPToTime(ntp).Add(-local))
+               } else {
+                       remote := rtptime.NTPToTime(ntp).Sub(
+                               rtptime.NTPToTime(t.conn.originRemote))
+                       delta := rtptime.FromDuration(remote-local, clockrate)
+                       t.origin = some(value(t.origin) - uint32(delta))
+               }
+       }
+
+       t.remoteNTP = ntp
+       t.remoteRTP = rtp
+}
+
+// adjustOrigin adjusts all origin-related fields of all tracks so that
+// the origin of track t is equal to ts.
+// Called locked.
+func (t *diskTrack) adjustOrigin(ts uint32) {
+       if !valid(t.origin) || value(t.origin) == ts {
+               return
+       }
+
+       offset := rtptime.ToDuration(
+               int64(int32(ts-value(t.origin))), t.remote.Codec().ClockRate,
+       )
+
+       if !t.conn.originLocal.Equal(time.Time{}) {
+               t.conn.originLocal = t.conn.originLocal.Add(offset)
+       }
+       if t.conn.originRemote != 0 {
+               t.conn.originRemote =
+                       rtptime.TimeToNTP(
+                               rtptime.NTPToTime(
+                                       t.conn.originRemote,
+                               ).Add(offset),
+                       )
+       }
+
+       for _, tt := range t.conn.tracks {
+               if valid(tt.origin) {
+                       tt.origin = some(value(tt.origin) +
+                               uint32(rtptime.FromDuration(
+                                       offset,
+                                       tt.remote.Codec().ClockRate,
+                               )),
+                       )
+               }
+       }
+}
+
+// called locked
+func (conn *diskConn) initWriter(width, height uint32, track *diskTrack, ts 
uint32) error {
+       if conn.file != nil {
+               if width == conn.width && height == conn.height {
+                       return nil
+               } else {
+                       conn.close()
+               }
+       }
+
        isWebm := true
        var desc []mkvcore.TrackDescription
        for i, t := range conn.tracks {
@@ -629,15 +785,19 @@
                header = &h
        }
 
-       err := conn.reopen(extension)
+       if track != nil {
+               track.adjustOrigin(ts)
+       }
+
+       err := conn.open(extension)
        if err != nil {
                return err
        }
 
        interceptor, err := mkvcore.NewMultiTrackBlockSorter(
                // must be larger than the samplebuilder's MaxLate.
-               mkvcore.WithMaxDelayedPackets(384),
-               mkvcore.WithSortRule(mkvcore.BlockSorterDropOutdated),
+               mkvcore.WithMaxDelayedPackets(videoMaxLate+16),
+               mkvcore.WithSortRule(mkvcore.BlockSorterWriteOutdated),
        )
        if err != nil {
                conn.file.Close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/diskwriter/diskwriter_test.go 
new/galene-0.5.2/diskwriter/diskwriter_test.go
--- old/galene-0.5.1/diskwriter/diskwriter_test.go      1970-01-01 
01:00:00.000000000 +0100
+++ new/galene-0.5.2/diskwriter/diskwriter_test.go      2022-04-20 
19:55:33.000000000 +0200
@@ -0,0 +1,157 @@
+package diskwriter
+
+import (
+       "testing"
+       "time"
+
+       "github.com/jech/galene/rtptime"
+)
+
+func TestAdjustOriginLocalNow(t *testing.T) {
+       now := time.Now()
+
+       c := &diskConn{
+               tracks: []*diskTrack{
+                       &diskTrack{},
+               },
+       }
+       for _, t := range c.tracks {
+               t.conn = c
+       }
+       c.tracks[0].setOrigin(132, now, 100)
+
+       if !c.originLocal.Equal(now) {
+               t.Errorf("Expected %v, got %v", now, c.originLocal)
+       }
+
+       if c.originRemote != 0 {
+               t.Errorf("Expected 0, got %v", c.originRemote)
+       }
+
+       if c.tracks[0].origin != some(132) {
+               t.Errorf("Expected 132, got %v", value(c.tracks[0].origin))
+       }
+}
+
+func TestAdjustOriginLocalEarlier(t *testing.T) {
+       now := time.Now()
+       earlier := now.Add(-time.Second)
+
+       c := &diskConn{
+               originLocal: earlier,
+               tracks: []*diskTrack{
+                       &diskTrack{},
+               },
+       }
+       for _, t := range c.tracks {
+               t.conn = c
+       }
+       c.tracks[0].setOrigin(132, now, 100)
+
+       if !c.originLocal.Equal(earlier) {
+               t.Errorf("Expected %v, got %v", earlier, c.originLocal)
+       }
+
+       if c.originRemote != 0 {
+               t.Errorf("Expected 0, got %v", c.originRemote)
+       }
+
+       if c.tracks[0].origin != some(32) {
+               t.Errorf("Expected 32, got %v", value(c.tracks[0].origin))
+       }
+}
+
+func TestAdjustOriginLocalLater(t *testing.T) {
+       now := time.Now()
+       later := now.Add(time.Second)
+
+       c := &diskConn{
+               originLocal: later,
+               tracks: []*diskTrack{
+                       &diskTrack{},
+               },
+       }
+       for _, t := range c.tracks {
+               t.conn = c
+       }
+       c.tracks[0].setOrigin(32, now, 100)
+
+       if !c.originLocal.Equal(later) {
+               t.Errorf("Expected %v, got %v", later, c.originLocal)
+       }
+
+       if c.originRemote != 0 {
+               t.Errorf("Expected 0, got %v", c.originRemote)
+       }
+
+       if c.tracks[0].origin != some(132) {
+               t.Errorf("Expected 132, got %v", value(c.tracks[0].origin))
+       }
+}
+
+func TestAdjustOriginRemote(t *testing.T) {
+       now := time.Now()
+       earlier := now.Add(-time.Second)
+
+       c := &diskConn{
+               tracks: []*diskTrack{
+                       &diskTrack{
+                               remoteNTP: rtptime.TimeToNTP(earlier),
+                               remoteRTP: 32,
+                       },
+               },
+       }
+       for _, t := range c.tracks {
+               t.conn = c
+       }
+       c.tracks[0].setOrigin(132, now, 100)
+
+       if !c.originLocal.Equal(now) {
+               t.Errorf("Expected %v, got %v", now, c.originLocal)
+       }
+
+       d := now.Sub(rtptime.NTPToTime(c.originRemote))
+       if d < -time.Millisecond || d > time.Millisecond {
+               t.Errorf("Expected %v, got %v (delta %v)",
+                       rtptime.TimeToNTP(now),
+                       c.originRemote, d)
+       }
+
+       if c.tracks[0].origin != some(132) {
+               t.Errorf("Expected 132, got %v", value(c.tracks[0].origin))
+       }
+}
+
+func TestAdjustOriginLocalRemote(t *testing.T) {
+       now := time.Now()
+       earlier := now.Add(-time.Second)
+
+       c := &diskConn{
+               tracks: []*diskTrack{
+                       &diskTrack{},
+               },
+       }
+       for _, t := range c.tracks {
+               t.conn = c
+       }
+       c.tracks[0].setOrigin(132, now, 100)
+
+       c.tracks[0].setTimeOffset(rtptime.TimeToNTP(earlier), 32, 100)
+
+       c.tracks[0].setOrigin(132, now, 100)
+
+       if !c.originLocal.Equal(now) {
+               t.Errorf("Expected %v, got %v", now, c.originLocal)
+       }
+
+       d := now.Sub(rtptime.NTPToTime(c.originRemote))
+       if d < -time.Millisecond || d > time.Millisecond {
+               t.Errorf("Expected %v, got %v (delta %v)",
+                       rtptime.TimeToNTP(now),
+                       c.originRemote, d)
+       }
+
+       if c.tracks[0].origin != some(132) {
+               t.Errorf("Expected 132, got %v", value(c.tracks[0].origin))
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/estimator/estimator.go 
new/galene-0.5.2/estimator/estimator.go
--- old/galene-0.5.1/estimator/estimator.go     2022-03-25 10:44:45.000000000 
+0100
+++ new/galene-0.5.2/estimator/estimator.go     2022-04-20 19:55:33.000000000 
+0200
@@ -23,8 +23,10 @@
 // New creates a new estimator that estimates rate over the last interval.
 func New(interval time.Duration) *Estimator {
        return &Estimator{
-               interval: rtptime.FromDuration(interval, rtptime.JiffiesPerSec),
-               time:     rtptime.Now(rtptime.JiffiesPerSec),
+               interval: uint64(
+                       rtptime.FromDuration(interval, rtptime.JiffiesPerSec),
+               ),
+               time: rtptime.Now(rtptime.JiffiesPerSec),
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/go.mod new/galene-0.5.2/go.mod
--- old/galene-0.5.1/go.mod     2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/go.mod     2022-04-20 19:55:33.000000000 +0200
@@ -4,16 +4,18 @@
 
 require (
        github.com/at-wat/ebml-go v0.16.0
-       github.com/golang-jwt/jwt/v4 v4.3.0
+       github.com/golang-jwt/jwt/v4 v4.4.1
        github.com/gorilla/websocket v1.5.0
        github.com/jech/cert v0.0.0-20210819231831-aca735647728
-       github.com/jech/samplebuilder v0.0.0-20220125212352-4553ed6f9a6c
-       github.com/pion/ice/v2 v2.2.2
+       github.com/jech/samplebuilder v0.0.0-20220417174833-7353a593563a
+       github.com/pion/ice/v2 v2.2.4
        github.com/pion/rtcp v1.2.9
-       github.com/pion/rtp v1.7.7
+       github.com/pion/rtp v1.7.13
        github.com/pion/sdp/v3 v3.0.4
        github.com/pion/turn/v2 v2.0.8
-       github.com/pion/webrtc/v3 v3.1.25
-       golang.org/x/crypto v0.0.0-20220214200702-86341886e292
-       golang.org/x/sys v0.0.0-20220209214540-3681064d5158
+       github.com/pion/webrtc/v3 v3.1.32
+       golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
+       golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 // indirect
+       golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
+       golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/go.sum new/galene-0.5.2/go.sum
--- old/galene-0.5.1/go.sum     2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/go.sum     2022-04-20 19:55:33.000000000 +0200
@@ -6,8 +6,8 @@
 github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod 
h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
-github.com/golang-jwt/jwt/v4 v4.3.0 
h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
-github.com/golang-jwt/jwt/v4 v4.3.0/go.mod 
h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.4.1 
h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
+github.com/golang-jwt/jwt/v4 v4.4.1/go.mod 
h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod 
h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod 
h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -29,8 +29,8 @@
 github.com/hpcloud/tail v1.0.0/go.mod 
h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/jech/cert v0.0.0-20210819231831-aca735647728 
h1:tN+W1ll2oKuJGMCaO1CRK4rr+xSRjVSfWmnKlACdx38=
 github.com/jech/cert v0.0.0-20210819231831-aca735647728/go.mod 
h1:FXUA/zpiQfV4uBVN2kAwkf3X7pU7l1l2ovS45CsSYZs=
-github.com/jech/samplebuilder v0.0.0-20220125212352-4553ed6f9a6c 
h1:szaz3cPxulEofkxi5SDehgVF32ceQAi6E2VsRrm348U=
-github.com/jech/samplebuilder v0.0.0-20220125212352-4553ed6f9a6c/go.mod 
h1:U83y/Kl/5BrI9ceNw17+lmguIrlUlMVntxKmZmei5EA=
+github.com/jech/samplebuilder v0.0.0-20220417174833-7353a593563a 
h1:yFkaguK4pmi0K33b8TA9T5Qoj0mZHpNPMCFdtru2yDg=
+github.com/jech/samplebuilder v0.0.0-20220417174833-7353a593563a/go.mod 
h1:U83y/Kl/5BrI9ceNw17+lmguIrlUlMVntxKmZmei5EA=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -54,8 +54,8 @@
 github.com/pion/dtls/v2 v2.1.3 h1:3UF7udADqous+M2R5Uo2q/YaP4EzUoWKdfX2oscCUio=
 github.com/pion/dtls/v2 v2.1.3/go.mod 
h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
 github.com/pion/ice/v2 v2.1.12/go.mod 
h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
-github.com/pion/ice/v2 v2.2.2 h1:UfmAslxZ0u0itVjA4x7aw7WeQIv22FdF8VjW9cM+74g=
-github.com/pion/ice/v2 v2.2.2/go.mod 
h1:vLI7dFqxw8zMSb9J+ca74XU7JjLhddgfQB9+BbTydCo=
+github.com/pion/ice/v2 v2.2.4 h1:sTHT39ywr5uqzyEMT7thEhOWsNOcdkHSZBbgQohFuZU=
+github.com/pion/ice/v2 v2.2.4/go.mod 
h1:SWuHiOGP17lGromHTFadUe1EuPgFh/oCU6FCMZHooVE=
 github.com/pion/interceptor v0.1.0/go.mod 
h1:j5NIl3tJJPB3u8+Z2Xz8MZs/VV6rc+If9mXEKNuFmEM=
 github.com/pion/interceptor v0.1.10 
h1:DJ2GjMGm4XGIQgMJxuEpdaExdY/6RdngT7Uh4oVmquU=
 github.com/pion/interceptor v0.1.10/go.mod 
h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
@@ -72,8 +72,8 @@
 github.com/pion/rtp v1.7.0/go.mod 
h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
 github.com/pion/rtp v1.7.2/go.mod 
h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
 github.com/pion/rtp v1.7.4/go.mod 
h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
-github.com/pion/rtp v1.7.7 h1:MzaAfCVicTVxiZpM2o99+YFrKxyRsQ38nnIi4vJPuUY=
-github.com/pion/rtp v1.7.7/go.mod 
h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
+github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
+github.com/pion/rtp v1.7.13/go.mod 
h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
 github.com/pion/sctp v1.7.10/go.mod 
h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
 github.com/pion/sctp v1.7.12/go.mod 
h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
 github.com/pion/sctp v1.8.0/go.mod 
h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
@@ -96,8 +96,8 @@
 github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
 github.com/pion/udp v0.1.1/go.mod 
h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
 github.com/pion/webrtc/v3 v3.1.0/go.mod 
h1:t51XSam1k56eYLuO1Ubxjs3pDBfGYxkGBFhYf55Mn/s=
-github.com/pion/webrtc/v3 v3.1.25 
h1:8bTa2lLI5rszkKCKVO6L9VlKhhmmwMXZ/beSWLwQK14=
-github.com/pion/webrtc/v3 v3.1.25/go.mod 
h1:BA9hvF1mCu64w/to7nHrSNMxx+zMqVst990zA7xgfCM=
+github.com/pion/webrtc/v3 v3.1.32 
h1:FtHxI4F8mMbpdn2L5GXUqgzRkP5e9CIlcSQFgOFRebw=
+github.com/pion/webrtc/v3 v3.1.32/go.mod 
h1:NduZ5Q+rc1y8Zf81WOuNyV8WTBKOfBLhJQ045Z3qP+E=
 github.com/pkg/errors v0.9.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -105,16 +105,17 @@
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.5.1/go.mod 
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 
h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1 
h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/testify v1.7.1/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/yuin/goldmark v1.2.1/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod 
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod 
h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod 
h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220214200702-86341886e292 
h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
-golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod 
h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 
h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
+golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod 
h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -133,8 +134,9 @@
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod 
h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod 
h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod 
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f 
h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
-golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod 
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod 
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 
h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA=
+golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod 
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -152,8 +154,8 @@
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158 
h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
-golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad 
h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod 
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -166,8 +168,9 @@
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 
h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f 
h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod 
h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod 
h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod 
h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/rtpconn/rtpconn.go 
new/galene-0.5.2/rtpconn/rtpconn.go
--- old/galene-0.5.1/rtpconn/rtpconn.go 2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/rtpconn/rtpconn.go 2022-04-20 19:55:33.000000000 +0200
@@ -449,6 +449,13 @@
                        return nil
                }
        }
+       if up.srNTPTime != 0 {
+               local.SetTimeOffset(up.srNTPTime, up.srRTPTime)
+       }
+       cname, ok := up.cname.Load().(string)
+       if ok && cname != "" {
+               local.SetCname(cname)
+       }
        up.local = append(up.local, local)
        up.mu.Unlock()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/rtpconn/rtpstats.go 
new/galene-0.5.2/rtpconn/rtpstats.go
--- old/galene-0.5.1/rtpconn/rtpstats.go        2022-03-25 10:44:45.000000000 
+0100
+++ new/galene-0.5.2/rtpconn/rtpstats.go        2022-04-20 19:55:33.000000000 
+0200
@@ -57,7 +57,7 @@
                        maxTid := layer.maxTid
                        rate, _ := t.rate.Estimate()
                        maxRate, _, _ := t.GetMaxBitrate()
-                       rtt := rtptime.ToDuration(t.getRTT(),
+                       rtt := rtptime.ToDuration(int64(t.getRTT()),
                                rtptime.JiffiesPerSec)
                        loss, jitter := t.stats.Get(jiffies)
                        j := time.Duration(jitter) * time.Second /
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/rtpconn/rtpwriter.go 
new/galene-0.5.2/rtpconn/rtpwriter.go
--- old/galene-0.5.1/rtpconn/rtpwriter.go       2022-03-25 10:44:45.000000000 
+0100
+++ new/galene-0.5.2/rtpconn/rtpwriter.go       2022-04-20 19:55:33.000000000 
+0200
@@ -138,7 +138,7 @@
                        // audio, try again with a delay
                        d := delay / uint32(2*len(wp.writers))
                        timer := time.NewTimer(rtptime.ToDuration(
-                               uint64(d), rtptime.JiffiesPerSec,
+                               int64(d), rtptime.JiffiesPerSec,
                        ))
 
                        select {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/rtptime/rtptime.go 
new/galene-0.5.2/rtptime/rtptime.go
--- old/galene-0.5.1/rtptime/rtptime.go 2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/rtptime/rtptime.go 2022-04-20 19:55:33.000000000 +0200
@@ -9,18 +9,25 @@
 var epoch = time.Now()
 
 // FromDuration converts a time.Duration into units of 1/hz.
-func FromDuration(d time.Duration, hz uint32) uint64 {
-       return uint64(d) * uint64(hz) / uint64(time.Second)
+func FromDuration(d time.Duration, hz uint32) int64 {
+       return int64(d) * int64(hz) / int64(time.Second)
 }
 
 // ToDuration converts units of 1/hz into a time.Duration.
-func ToDuration(tm uint64, hz uint32) time.Duration {
-       return time.Duration(tm * uint64(time.Second) / uint64(hz))
+func ToDuration(tm int64, hz uint32) time.Duration {
+       return time.Duration(tm * int64(time.Second) / int64(hz))
+}
+
+func sat(a int64) uint64 {
+       if a < 0 {
+               return 0
+       }
+       return uint64(a)
 }
 
 // Now returns the current time in units of 1/hz from an arbitrary origin.
 func Now(hz uint32) uint64 {
-       return FromDuration(time.Since(epoch), hz)
+       return sat(FromDuration(time.Since(epoch), hz))
 }
 
 // Microseconds is like Now, but uses microseconds.
@@ -39,7 +46,7 @@
 
 // TimeToJiffies converts a time.Time into jiffies.
 func TimeToJiffies(tm time.Time) uint64 {
-       return FromDuration(tm.Sub(epoch), JiffiesPerSec)
+       return sat(FromDuration(tm.Sub(epoch), JiffiesPerSec))
 }
 
 // The origin of NTP time.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/rtptime/rtptime_test.go 
new/galene-0.5.2/rtptime/rtptime_test.go
--- old/galene-0.5.1/rtptime/rtptime_test.go    2022-03-25 10:44:45.000000000 
+0100
+++ new/galene-0.5.2/rtptime/rtptime_test.go    2022-04-20 19:55:33.000000000 
+0200
@@ -11,9 +11,19 @@
                t.Errorf("Expected 48000, got %v", a)
        }
 
-       b := ToDuration(48000, 48000)
-       if b != time.Second {
-               t.Errorf("Expected %v, got %v", time.Second, b)
+       b := FromDuration(-time.Second, 48000)
+       if b != -48000 {
+               t.Errorf("Expected -48000, got %v", b)
+       }
+
+       c := ToDuration(48000, 48000)
+       if c != time.Second {
+               t.Errorf("Expected %v, got %v", time.Second, c)
+       }
+
+       d := ToDuration(-48000, 48000)
+       if d != -time.Second {
+               t.Errorf("Expected %v, got %v", -time.Second, d)
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/static/galene.js 
new/galene-0.5.2/static/galene.js
--- old/galene-0.5.1/static/galene.js   2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/static/galene.js   2022-04-20 19:55:33.000000000 +0200
@@ -1049,7 +1049,7 @@
     if(!(old instanceof Filter))
         throw new Error('userdata.filter is not a filter');
 
-    c.stream = old.inputStream;
+    c.setStream(old.inputStream);
     old.stop();
     c.userdata.filter = null;
 }
@@ -1066,7 +1066,7 @@
         return;
 
     let filter = new Filter(c.stream, c.userdata.filterDefinition);
-    c.stream = filter.outputStream;
+    c.setStream(filter.outputStream);
     c.userdata.filter = filter;
 }
 
@@ -1162,7 +1162,7 @@
     if(c.stream != null)
         throw new Error("Setting nonempty stream");
 
-    c.stream = stream;
+    c.setStream(stream);
 
     try {
         setFilter(c);
@@ -1223,7 +1223,7 @@
                 });
             }
         } else {
-            if(c.label !== 'camera' || settings.hqaudio) {
+            if(settings.hqaudio) {
                 encodings.push({
                     maxBitrate: hqAudioRate,
                 });
@@ -2056,7 +2056,7 @@
     if(id === serverConnection.id) {
         let mydata = serverConnection.users[serverConnection.id].data;
         if(mydata['raisehand'])
-            items.push({label: 'Lower hand', onClick: () => {
+            items.push({label: 'Unraise hand', onClick: () => {
                 serverConnection.userAction(
                     'setdata', serverConnection.id, {'raisehand': null},
                 );
@@ -2107,12 +2107,7 @@
     let user = document.createElement('div');
     user.id = 'user-' + id;
     user.classList.add("user-p");
-    user.textContent = userinfo.username ? userinfo.username : '(anon)';
-    if (userinfo.data.raisehand)
-        user.classList.add('user-status-raisehand');
-    else
-        user.classList.remove('user-status-raisehand');
-
+    setUserStatus(id, user, userinfo);
     user.addEventListener('click', function(e) {
         let elt = e.target;
         if(!elt || !(elt instanceof HTMLElement))
@@ -2148,21 +2143,30 @@
     div.appendChild(user);
 }
 
-/**
- * @param {string} id
- * @param {user} userinfo
- */
+ /**
+  * @param {string} id
+  * @param {user} userinfo
+  */
 function changeUser(id, userinfo) {
-    let user = document.getElementById('user-' + id);
-    if(!user) {
+    let elt = document.getElementById('user-' + id);
+    if(!elt) {
         console.warn('Unknown user ' + id);
         return;
     }
-    user.textContent = userinfo.username ? userinfo.username : '(anon)';
-    if (userinfo.data.raisehand)
-        user.classList.add('user-status-raisehand');
+    setUserStatus(id, elt, userinfo);
+}
+
+/**
+ * @param {string} id
+ * @param {HTMLElement} elt
+ * @param {user} userinfo
+ */
+function setUserStatus(id, elt, userinfo) {
+    elt.textContent = userinfo.username ? userinfo.username : '(anon)';
+    if(userinfo.data.raisehand)
+        elt.classList.add('user-status-raisehand');
     else
-        user.classList.remove('user-status-raisehand');
+        elt.classList.remove('user-status-raisehand');
 }
 
 /**
@@ -3016,7 +3020,7 @@
     footer.classList.add('message-footer');
     if(!peerId)
         container.classList.add('message-system');
-    if(peerId === serverConnection.id)
+    if(serverConnection && peerId === serverConnection.id)
         container.classList.add('message-sender');
     if(dest)
         container.classList.add('message-private');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/galene-0.5.1/static/protocol.js 
new/galene-0.5.2/static/protocol.js
--- old/galene-0.5.1/static/protocol.js 2022-03-25 10:44:45.000000000 +0100
+++ new/galene-0.5.2/static/protocol.js 2022-04-20 19:55:33.000000000 +0200
@@ -66,7 +66,7 @@
  * @property {string} username
  * @property {Array<string>} permissions
  * @property {Object<string,any>} data
- * @property {Object<string,Object<string,boolean>>} down
+ * @property {Object<string,Object<string,boolean>>} streams
  */
 
 /**
@@ -359,7 +359,7 @@
                         username: m.username,
                         permissions: m.permissions || [],
                         data: m.data || {},
-                        down: {},
+                        streams: {},
                     };
                     break;
                 case 'change':
@@ -369,7 +369,7 @@
                             username: m.username,
                             permissions: m.permissions || [],
                             data: m.data || {},
-                            down: {},
+                            streams: {},
                         };
                     } else {
                         sc.users[m.id].username = m.username;
@@ -593,7 +593,6 @@
     };
 
     pc.ontrack = console.error;
-
     return c;
 };
 
@@ -750,7 +749,7 @@
                 return;
             }
             c.stream = e.streams[0];
-            let changed = recomputeUserStreams(sc, source, c);
+            let changed = recomputeUserStreams(sc, source);
             if(c.ondowntrack) {
                 c.ondowntrack.call(
                     c, e.track, e.transceiver, e.streams[0],
@@ -1062,6 +1061,19 @@
 }
 
 /**
+ * setStream sets the stream of an upwards connection.
+ *
+ * @param {MediaStream} stream
+ */
+Stream.prototype.setStream = function(stream) {
+    let c = this;
+    c.stream = stream;
+    let changed = recomputeUserStreams(c.sc, c.sc.id);
+    if(changed && c.sc.onuser)
+        c.sc.onuser.call(c.sc, c.sc.id, "change");
+}
+
+/**
  * close closes a stream.
  *
  * For streams in the up direction, this may be called at any time.  For
@@ -1096,18 +1108,23 @@
         }
     }
 
+    let userid;
     if(c.up) {
+        userid = c.sc.id;
         if(c.sc.up[c.id] === c)
             delete(c.sc.up[c.id]);
         else
             console.warn('Closing unknown stream');
     } else {
+        userid = c.source;
         if(c.sc.down[c.id] === c)
             delete(c.sc.down[c.id]);
         else
             console.warn('Closing unknown stream');
-        recomputeUserStreams(c.sc, c.source);
     }
+    let changed = recomputeUserStreams(c.sc, userid);
+    if(changed && c.sc.onuser)
+        c.sc.onuser.call(c.sc, userid, "change");
     c.sc = null;
 
     if(c.onclose)
@@ -1115,53 +1132,35 @@
 };
 
 /**
- * recomputeUserStreams recomputes the user.down array for a given user.
+ * recomputeUserStreams recomputes the user.streams array for a given user.
  * It returns true if anything changed.
  *
  * @param {ServerConnection} sc
  * @param {string} id
- * @param {Stream} [c]
  * @returns {boolean}
  */
-function recomputeUserStreams(sc, id, c) {
+function recomputeUserStreams(sc, id) {
     let user = sc.users[id];
     if(!user) {
         console.warn("recomputing streams for unknown user");
         return false;
     }
 
-    if(c) {
-        let changed = false;
-        if(!user.down[c.label])
-            user.down[c.label] = {};
-        c.stream.getTracks().forEach(t => {
-            if(!user.down[c.label][t.kind]) {
-                user.down[c.label][t.kind] = true;
-                changed = true;
-            }
-        });
-        return changed;
-    }
-
-    if(!user.down || Object.keys(user.down).length === 0)
-        return false;
-
-    let old = user.down;
-    user.down = {};
-
-    for(id in sc.down) {
-        let c = sc.down[id];
+    let streams = id === sc.id ? sc.up : sc.down;
+    let old = user.streams;
+    user.streams = {};
+    for(id in streams) {
+        let c = streams[id];
         if(!c.stream)
             continue;
-        if(!user.down[c.label])
-            user.down[c.label] = {};
+        if(!user.streams[c.label])
+            user.streams[c.label] = {};
         c.stream.getTracks().forEach(t => {
-            user.down[c.label][t.kind] = true;
+            user.streams[c.label][t.kind] = true;
         });
     }
 
-    // might lead to false positives.  Oh, well.
-    return JSON.stringify(old) != JSON.stringify(user.down);
+    return JSON.stringify(old) != JSON.stringify(user.streams);
 }
 
 /**

++++++ vendor.tar.gz ++++++
++++ 6277 lines of diff (skipped)

Reply via email to