Skip to content

Commit

Permalink
feat: add late offer answer
Browse files Browse the repository at this point in the history
  • Loading branch information
emiago committed Dec 19, 2024
1 parent e0592fa commit 6b6effe
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
74 changes: 74 additions & 0 deletions dialog_server_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package diago

import (
"context"
"errors"
"fmt"
"sync/atomic"
"time"
Expand Down Expand Up @@ -160,10 +161,83 @@ func (d *DialogServerSession) answerSession(rtpSess *media.RTPSession) error {
if state == sip.DialogStateConfirmed {
return nil
}
if state == sip.DialogStateEnded {
return fmt.Errorf("dialog ended on ack")
}
}
}
}

// AnswerLate does answer with Late offer.
func (d *DialogServerSession) AnswerLate() error {
sess, err := d.createMediaSessionConf(d.mediaConf)
if err != nil {
return err
}
rtpSess := media.NewRTPSession(sess)
localSDP := sess.LocalSDP()

d.mu.Lock()
d.initRTPSessionUnsafe(sess, rtpSess)
// Close RTP session
d.onCloseUnsafe(func() {
if err := rtpSess.Close(); err != nil {
log.Error().Err(err).Msg("Closing session")
}
})
d.mu.Unlock()

if err := d.RespondSDP(localSDP); err != nil {
return err
}
// Wait ACK
// It is expected that on ReadACK SDP will be updated
for {
select {
case <-time.After(10 * time.Second):
return fmt.Errorf("no ACK received")
case state := <-d.StateRead():
if state == sip.DialogStateConfirmed {
// Must be called after media and reader writer is setup
return rtpSess.MonitorBackground()
}
if state == sip.DialogStateEnded {
return fmt.Errorf("dialog ended on ack")
}
}
}
}

func (d *DialogServerSession) ReadAck(req *sip.Request, tx sip.ServerTransaction) error {
// Check do we have some session
err := func() error {
d.mu.Lock()
defer d.mu.Unlock()
sess := d.mediaSession
if sess == nil {
return nil
}
contentType := req.ContentType()
if contentType == nil {
return nil
}
body := req.Body()
if body != nil && contentType.Value() == "application/sdp" {
// This is Late offer response
if err := sess.RemoteSDP(body); err != nil {
return err
}
}
return nil
}()
if err != nil {
e := d.Hangup(d.Context())
return errors.Join(err, e)
}

return d.DialogServerSession.ReadAck(req, tx)
}

func (d *DialogServerSession) Hangup(ctx context.Context) error {
state := d.LoadState()
if state == sip.DialogStateConfirmed {
Expand Down
3 changes: 2 additions & 1 deletion digest_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ func (s *DigestAuthServer) AuthorizeDialog(d *DialogServerSession, auth DigestAu
res, err := s.AuthorizeRequest(req, auth)
if err == nil && res.StatusCode != 200 {
err = fmt.Errorf("not authorized")
return errors.Join(err, d.WriteResponse(res))
}
return errors.Join(err, d.WriteResponse(res))
return errors.Join(err, nil)
}

func generateNonce() (string, error) {
Expand Down
5 changes: 3 additions & 2 deletions media/rtp_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ func (s *RTPSession) Monitor() error {

// MonitorBackground is helper to keep monitoring in background
// MUST Be called after session REMOTE SDP is parsed
func (s *RTPSession) MonitorBackground() {
func (s *RTPSession) MonitorBackground() error {
if s.Sess.Raddr == nil || s.Sess.rtcpRaddr == nil {
panic("raddr of RTP is not present. You must call this after RemoteSDP is parsed")
return fmt.Errorf("raddr of RTP is not present. Is RemoteSDP called. Monitor RTP Session failed")
}

go func() {
Expand Down Expand Up @@ -342,6 +342,7 @@ func (s *RTPSession) MonitorBackground() {
}
}
}()
return nil
}

func (s *RTPSession) readRTCP() error {
Expand Down

0 comments on commit 6b6effe

Please sign in to comment.