Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session Progress early media for outbound calls #41

Open
serfreeman1337 opened this issue Jan 29, 2025 · 4 comments
Open

Session Progress early media for outbound calls #41

serfreeman1337 opened this issue Jan 29, 2025 · 4 comments

Comments

@serfreeman1337
Copy link

There should be a way to access an RTP session of outbound calls without waiting for 200 Answer.
During call setup other side can start sending audio with 183 Session Progress.

Currently, RTP session is only created after 200 Answer:

diago/diago.go

Lines 668 to 684 in 8a9f709

if err := dialog.WaitAnswer(ctx, answO); err != nil {
return err
}
remoteSDP := dialog.InviteResponse.Body()
if remoteSDP == nil {
return fmt.Errorf("no SDP in response")
}
if err := sess.RemoteSDP(remoteSDP); err != nil {
return err
}
// Create RTP session. After this no media session configuration should be changed
rtpSess := media.NewRTPSession(sess)
if opts.OnRTPSession != nil {
opts.OnRTPSession(rtpSess)
}

@emiago
Copy link
Owner

emiago commented Jan 30, 2025

Hi @serfreeman1337 . Yes I am aware of this. Creating media session is not completely closed, but I agree we need better control over this, and maybe even providing explicit func.
So there are many things experimental, and way it goes that you should be able to grab dialog control even before making call.

I guess this is where you are targeting, but feel free to provide example how you would expect this.

@serfreeman1337
Copy link
Author

I think media.RTPSession can be created on remote SDP receive,
and this session can then be accessed in the OnRTPSession callback to read RTP packets.

options := diago.InviteOptions{
	Username: "test",
	Password: "test",
	OnResponse: func(res *sip.Response) error {
		fmt.Println("--- SIP response", res.StartLine())
		return nil
	},
	OnRTPSession: func(rtpSess *media.RTPSession) {
		// Start receiving RTP packets as soon as SDP is received.
		go func() {
			var err error

			pkt := &rtp.Packet{}
			buf := make([]byte, media.RTPBufSize)

			for {
				_, err = rtpSess.ReadRTP(buf, pkt)
				if err != nil {
					break
				}

				...
			}
		}()
	},
}

Or it could be done with OnDialogMedia callback so that we can setup AudioReader for early media.

options := diago.InviteOptions{
	Username: "test",
	Password: "test",
	OnResponse: func(res *sip.Response) error {
		fmt.Println("--- SIP response", res.StartLine())
		return nil
	},
	OnDialogMedia: func(dm *diago.DialogMedia) {
		// Setup audio reader as soon as SDP is received.
		go func() {
			m := diago.MediaProps{}
			r, err := dm.AudioReader(diago.WithAudioReaderMediaProps(&m))
			if err != nil {
				return
			}
			decoder, err := audio.NewPCMDecoderReader(m.Codec.PayloadType, r)
			if err != nil {
				return
			}
			
			...
		}()
		
		// Or use RTPSession to receive RTP packets.
		rtpSess := dm.RTPSession()
		rtpSess.ReadRTP(...)
		...
	},
}

serfreeman1337@658ed6e

@emiago
Copy link
Owner

emiago commented Jan 31, 2025

hi @serfreeman1337 there is very similar experimenting already.
I think it goes just more complex, as adding hooks goes more and more. Ex bridging.
For outbound I think we just need to give early control of dialog like sipgo.
This will be my focus in next releases. Please stay tuned.

Where this gets problematic is probably that it could make API harder to grasp, but therefore I consider higher level API to stay as well.

@aaron2198
Copy link

I don't need early media for outbound calls but I have been running into trouble trying to preemptively cancel an outbound call if an answer does not occur within a certain amount of time. I have tried to achieve this a few ways

  • using a context.WithTimeout() which seems to hit the internal Timer_B of sipgo before my context.Done() is handled
  • throwing the diago.Invite() in a goroutine with my own timeout but this doesn't allow me to actually terminate the call with the DialogueClientSession.Hangup() method

I could attempt to set timers for the first approach but it seems to leave the remote sip server ringing which is undesirable.
Any chance this could be considered in the implementation for early control of the dialogue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants