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)