diff --git a/pkg/service/sip.go b/pkg/service/sip.go index d98d92d33..0de748795 100644 --- a/pkg/service/sip.go +++ b/pkg/service/sip.go @@ -584,7 +584,7 @@ func (s *SIPService) CreateSIPParticipant(ctx context.Context, req *livekit.Crea ireq, err := s.CreateSIPParticipantRequest(ctx, req, "", "", "", "") if err != nil { unlikelyLogger.Errorw("cannot create sip participant request", err) - return nil, err + return nil, wrapSIPContextError(err) } unlikelyLogger = unlikelyLogger.WithValues( "callID", ireq.SipCallId, @@ -613,7 +613,7 @@ func (s *SIPService) CreateSIPParticipant(ctx context.Context, req *livekit.Crea resp, err := s.psrpcClient.CreateSIPParticipant(ctx, "", ireq, psrpc.WithRequestTimeout(timeout)) if err != nil { unlikelyLogger.Errorw("cannot create sip participant", err) - return nil, err + return nil, wrapSIPContextError(err) } return &livekit.SIPParticipantInfo{ ParticipantId: resp.ParticipantId, @@ -682,7 +682,7 @@ func (s *SIPService) TransferSIPParticipant(ctx context.Context, req *livekit.Tr ireq, err := s.transferSIPParticipantRequest(ctx, req) if err != nil { log.Errorw("cannot create transfer sip participant request", err) - return nil, err + return nil, wrapSIPContextError(err) } // by default we set the timeout to be 30 seconds. @@ -709,7 +709,7 @@ func (s *SIPService) TransferSIPParticipant(ctx context.Context, req *livekit.Tr _, err = s.psrpcClient.TransferSIPParticipant(ctx, ireq.SipCallId, ireq, psrpc.WithRequestTimeout(timeout)) if err != nil { log.Errorw("cannot transfer sip participant", err) - return nil, err + return nil, wrapSIPContextError(err) } return &emptypb.Empty{}, nil @@ -756,3 +756,24 @@ func (s *SIPService) transferSIPParticipantRequest(ctx context.Context, req *liv RingingTimeout: req.RingingTimeout, }, nil } + +// wrapSIPContextError converts raw context.DeadlineExceeded / context.Canceled +// into psrpc-coded errors so they aren't surfaced as @code:unknown / HTTP 500 +// at the Twirp boundary. psrpc errors and any error that already carries a +// gRPC status are passed through unchanged. +func wrapSIPContextError(err error) error { + if err == nil { + return nil + } + var psErr psrpc.Error + if errors.As(err, &psErr) { + return err + } + switch { + case errors.Is(err, context.DeadlineExceeded): + return psrpc.NewError(psrpc.DeadlineExceeded, err) + case errors.Is(err, context.Canceled): + return psrpc.NewError(psrpc.Canceled, err) + } + return err +}