Repository navigation
CalloraVoipSdk 4.15.0 #397
BechsteinDigital
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
A line can now say which numbers reach it, a PBX can read a busy lamp, and DTMF is sent as a tone
instead of a burst. Four additions, three fixes, nothing removed or changed. SemVer: MINOR.
The question a registration account could not answer
"Which numbers reach me on this line?" Every telephone system has to answer it, and almost nothing
else can answer it for them. A trunk contract brings a list somebody can type in. A registration account
brings nothing: it sends no list, and its username is as often
admin123as a number. Until now theonly remaining source was an inbound call that had already happened.
RFC 3455 §5.1 answers it outright. The registrar lists the URIs associated with the address-of-record it
just accepted, in the 200 OK to REGISTER:
An empty list means nobody said, never there are none. Carrier and IMS registrars send the header; a
CPE box on the local network generally does not. Read the other way round, a silent registrar turns into
a line nobody can reach — so every doc comment on the path says which of the two it is.
Order is preserved and duplicates are not. RFC 3455 gives the first entry a meaning: it is the default
public identity, the one the network uses when a request does not say otherwise. Sorting into a set
would throw away which number is the main one. Both
sip:andtel:forms occur, often for the samenumber, and both are returned as announced — what counts as a telephone number is a question about a
dial plan, and this layer does not have one.
Three details that would have been expensive to find later:
"Meier, Dana" <sip:…>in half and produces two entries, neither of them an address.
brackets it belongs to the URI (
sip:a@b;transport=tcp), outside them it starts the header parameters.The first version of this trimmed at the semicolon a second time and would have handed back an address
that lost its transport.
send it on the initial registration and not always afterwards, and an application reading "no numbers"
halfway through a session would conclude the line had lost them.
Subscriptions were built, and unreachable
SUBSCRIBE, the handle, the NOTIFY event, the refresh — all of it existed and all of it was
internal.Public now is
ISipSubscriptionwith exactly three things: which package, an event per NOTIFY, andending it. The internal handle stays internal; it carries the machinery, and that is nobody's business.
The two documents a PBX lives on are now parsed, not passed through
dialog-info (RFC 4235) is the busy lamp. Subscribe to an extension's dialog package and every
notification says free, ringing or on a call. PIDF (RFC 3863) says who is available. Both are parsed
here for the same reason as Diversion and History-Info before them: the rules are in an RFC, and two
consumers reading the same XML are wrong in different ways.
Three traps are encoded in the types and in tests, because each of them produces a lamp that lies:
IsFullStatesays which one you haveUnknown, not free. A lamp that goes out on a word we do not know is worse than one that stays onearlyRead namespace-tolerantly, because the RFC fixes the namespace and deployments do not. The price is
accepting a document that was never PIDF; it then yields no tuples and reads as "nothing known", exactly
like an empty one.
G.729: negotiable, never decodable
A carrier that offers only G.729 answers a call today with 488 Not Acceptable Here, and the call
never happens. That is the same failure a µ-law-only offer produced in Europe, one codec further along.
So it can be offered — opt-in through
PreferredAudioCodecs, not on by default. This SDK carries noG.729 implementation, which makes offering it a promise to forward the payload, not to understand
it: correct for a leg bridged to another G.729 leg, wrong for one whose audio somebody wants to hear.
It has its own payload-codec kind for that reason. "Some codec we could not transcode" and "G.729,
which we do not implement" are the same event and two very different sentences; the bridge now says the
second one, along with what to do about it.
Two fixes found by reading module by module
DTMF was sent as a burst in microseconds. Both send paths — the SIP RTP session and the bundled
WebRTC one — emitted three packets back to back, one start and two ends, all within microseconds, while
the payload claimed a duration of 160 ms. Two failures follow, and both show up at one customer and not
the next:
to analogue or ISDN, and what several IVRs do — sees a tone that never lasted, and reports no digit.
RFC protects against exactly that: each intermediate packet repeats the event with a grown duration,
so any single one of them carries the whole tone.
Now: three start packets (marker on the very first only — repeated on the duplicates it announced three
tones), intermediate packets every 20 ms with growing duration, three end packets. All on the same RTP
timestamp, because that is the event's start time (RFC 4733 §2.5.1.2); only the duration field grows. A
rising timestamp would describe several tones in sequence rather than one. Cancelling mid-tone still
sends the end — an event without one is a stuck tone at the far end, still waiting for the digit to
finish.
One implementation for both paths. Two versions of RFC 4733 in one SDK would be two chances to get the
timing wrong, and only one of them would ever be tested.
Hold in the older style went unrecognised. Detection read the direction attribute only. RFC 2543
held a call by setting the connection address to
0.0.0.0, and RFC 3264 §8.4 records that this is whatit means; plenty of gateways and older systems still send it that way.
The failure had the dangerous shape — it was silent. The call reported itself connected while the far
end had it on hold, and the media path kept aiming at an address that leads nowhere. Two places, because
they are two different bugs with one cause:
as a parsed address —
0.0.0.0,::and::0are one address in three spellings, and a stringcomparison catches one of them. An address on the m-section beats the session's (RFC 8866 §5.7): held
that way, only the audio stream is held, and reading the session line reported the opposite.
end sends a packet for symmetric RTP to latch onto there is nothing there to hit; sending throws on
some stacks and vanishes on others, once per packet for as long as the hold lasts. A packet not sent
is not counted as sent either — the sender report otherwise claimed packets that never left, and the
far end's loss calculation hangs on that counter.
Checked and found correct in the same pass, and worth recording so nobody re-derives them: sequence
validation (RFC 3550 §A.1, correct
ushortdifference including cycle counting), the jitter formula inboth places, the RTCP interval including its e−1.5 compensation, the per-transaction nonce count, the
reversal of the Record-Route set, the ICE role conflict with 487 and tiebreaker, the SRTP/SRTCP replay
window, the G.722 quirk (RTP clock 8000 at a 16 kHz sample rate), and TURN permission refresh.
What the release path now proves
Three gates, each closing a way for a green run to prove nothing:
packages were outside it — they could change shape between versions with nothing to review.
cirun for the exact commit being tagged. The pack job runs the unitset only; interop, FreeSWITCH, browser and soak need Docker and a Playwright container. Packages were
therefore published without any of what the README advertises having run. The work is not duplicated,
it is required to have happened.
--skip-duplicateis right for the second attempt after three of six packages went through, andsilently wrong after a tag was deleted, corrected and set again — the run reports success while
nuget.org keeps serving the old content under the new promise.
And the
interopandbrowser-interopjobs can no longer pass having executed zero tests: their skipconditions are the right convenience locally and a false green in CI, so a test that never skips now
asserts the prerequisite on the runner.
Compatibility
Purely additive: 164 lines added to
PublicApi.approved.txt, none removed or changed. G.729 is opt-inand off by default. Existing applications need no change; the DTMF and hold fixes apply on their own.
See
CHANGELOG.mdfor the itemised list.This discussion was created from the release CalloraVoipSdk 4.15.0.
All reactions