@@ -789,14 +789,14 @@ func (c *outboundCall) handleDTMF(ev dtmf.Event) {
789789 }, lksdk .WithDataPublishReliable (true ))
790790}
791791
792- func (c * outboundCall ) transferCall (ctx context.Context , transferTo string , headers map [string ]string , dialtone bool ) (retErr error ) {
792+ func (c * outboundCall ) transferCall (ctx context.Context , transferTo string , headers map [string ]string , dialtone bool ) (transferID string , retErr error ) {
793793 ctx , span := Tracer .Start (ctx , "sip.outbound.transferCall" )
794794 defer span .End ()
795795 var err error
796796
797- tID : = c .state .StartTransfer (transferTo )
797+ transferID = c .state .StartTransfer (transferTo )
798798 defer func () {
799- c .state .EndTransfer (tID , retErr )
799+ c .state .EndTransfer (transferID , retErr )
800800 }()
801801
802802 if dialtone && c .started .IsBroken () && ! c .stopped .IsBroken () {
@@ -828,7 +828,7 @@ func (c *outboundCall) transferCall(ctx context.Context, transferTo string, head
828828 err = c .cc .transferCall (ctx , transferTo , headers , c .closing .Watch ())
829829 if err != nil {
830830 c .log .Infow ("outbound call failed to transfer" , "error" , err , "transferTo" , transferTo )
831- return err
831+ return transferID , err
832832 }
833833
834834 c .log .Infow ("outbound call transferred" , "transferTo" , transferTo )
@@ -842,7 +842,7 @@ func (c *outboundCall) transferCall(ctx context.Context, transferTo string, head
842842 })
843843 })
844844
845- return nil
845+ return transferID , nil
846846}
847847
848848func (c * Client ) newOutbound (log logger.Logger , id LocalTag , uri * sip.Uri , to * sip.ToHeader , from * sip.FromHeader , contact URI , getHeaders setHeadersFunc ) * sipOutbound {
@@ -1318,40 +1318,33 @@ func (c *sipOutbound) transferCall(ctx context.Context, transferTo string, heade
13181318 return err
13191319 }
13201320
1321- select {
1322- case <- ctx .Done ():
1323- return psrpc .NewErrorf (psrpc .Canceled , "refer canceled" )
1324- case <- callDone :
1325- // REFER was accepted (2xx) but the call ended before it completed —
1326- // remote BYE, room deletion, or local hangup.
1327- c .log .Infow ("refer canceled: call ended before transfer completed" )
1328- return nil
1329- case err := <- c .referDone :
1330- if err != nil {
1331- return err
1332- }
1333- }
1334-
1335- return nil
1321+ return waitReferResult (ctx , c .log , callDone , c .referDone )
13361322}
13371323
13381324func (c * sipOutbound ) handleNotify (req * sip.Request , tx sip.ServerTransaction ) error {
1339- method , cseq , status , reason , err := handleNotify (req )
1325+ info , err := handleNotify (req )
13401326 if err != nil {
13411327 c .log .Infow ("error parsing NOTIFY request" , "error" , err )
13421328
13431329 return err
13441330 }
13451331
1346- c .log .Infow ("handling NOTIFY" , "method" , method , "status" , status , "reason" , reason , "cseq" , cseq )
1332+ c .log .Infow ("handling NOTIFY" , "method" , info .Method , "status" , info .Status ,
1333+ "reason" , info .Reason , "cseq" , info .CSeq , "subscription" , info .Sub .String ())
13471334
1348- switch method {
1335+ switch info . Method {
13491336 default :
13501337 return nil
13511338 case sip .REFER :
1339+ // Read referCseq under the lock, then release it before handing the
1340+ // result over. That handoff can park on the unbuffered channel for
1341+ // notifyAckTimeout, and while we hold the read lock every caller of
1342+ // c.mu.Lock() waits: AcceptBye and Close among them, so an arriving BYE
1343+ // would be what we blocked.
13521344 c .mu .RLock ()
1353- defer c .mu .RUnlock ()
1354- handleReferNotify (cseq , status , reason , c .referCseq , c .referDone )
1345+ referCseq := c .referCseq
1346+ c .mu .RUnlock ()
1347+ handleReferNotify (info , referCseq , c .referDone )
13551348 return nil
13561349 }
13571350}
0 commit comments