streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

commit 2611483e348541c03d648c6455415a50298bda3e
parent ff1c5bccc7b8e868d34831a859fa962c408f104a
Author: Oliver Lowe <o@olowe.co>
Date:   Sun, 30 Jun 2024 12:58:43 +1000

sdp: implement parsing some (not all) optional fields

Diffstat:
Msdp/sdp.go | 48+++++++++++++++++++++++++++++++++++++++---------
Msdp/sdp_test.go | 26++++++++++++++++++++++++--
2 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/sdp/sdp.go b/sdp/sdp.go @@ -18,10 +18,12 @@ type Session struct { Origin Origin Name string - Info string - URI *url.URL - Email *mail.Address - Phone string + Info string + URI *url.URL + Email *mail.Address + // TODO(otl): can we do any sanitisation here? at least delete spaces or something...? + // The number "+1 617 555-6011" is semantically equal to "+16175556011" + Phone string // TODO(otl): add rest of fields } @@ -31,13 +33,17 @@ type Origin struct { Version int Network string // TODO(otl): only "IN" is valid... so int type? AddressType string // TODO(otl): only "IP4", "IP6" valid... new int type? - Address string + Address string // IPv4, IPv6 literal or a hostname } +var fchars = [...]string{"i", "u", "e", "p"} + func ReadSession(rd io.Reader) (*Session, error) { sc := bufio.NewScanner(rd) next := "v" var session Session +First: + // read the mandatory fields first for sc.Scan() { if sc.Text() == "" { continue // TODO(otl): empty lines allowed? @@ -72,25 +78,49 @@ func ReadSession(rd io.Reader) (*Session, error) { return nil, fmt.Errorf("empty name") } session.Name = v + break First + default: + return nil, fmt.Errorf("expected key %q, found %q", next, v) + } + } + + // Time for the optional fields. We keep a slice... + // TODO(otl): document in plain language what's going on here. + onext := fchars[:] + for sc.Scan() { + if onext == nil { + break + } + if sc.Text() == "" { + continue // TODO(otl): empty lines allowed? + } + k, v, found := strings.Cut(sc.Text(), "=") + if !found { + return nil, fmt.Errorf("parse field %q: missing %q", next, "=") + } + switch k { case "i": session.Info = v - // TODO(otl): what do we expect next? + onext = fchars[1:] case "u": u, err := url.Parse(v) if err != nil { return nil, fmt.Errorf("parse uri: %w", err) } session.URI = u - // TODO(otl): what do we expect next? + onext = fchars[2:] case "e": addr, err := parseEmail(v) if err != nil { return nil, fmt.Errorf("parse email: %w", err) } session.Email = addr - // TODO(otl): what do we expect next? + onext = fchars[3:] + case "p": + session.Phone = v + onext = nil default: - return &session, fmt.Errorf("unsupported field %q", k) + return nil, fmt.Errorf("expected one of %v, found %q", onext, k) } } return &session, sc.Err() diff --git a/sdp/sdp_test.go b/sdp/sdp_test.go @@ -1,6 +1,9 @@ package sdp import ( + "net/mail" + "net/url" + "reflect" "strings" "testing" ) @@ -21,11 +24,30 @@ m=audio 49180 RTP/AVP 0 m=video 51372 RTP/AVP 99 c=IN IP6 2001:db8::2 a=rtpmap:99 h263-1998/90000` + want := Session{ + Name: "Call to John Smith", + Origin: Origin{ + Username: "jdoe", + ID: 3724394400, + Version: 3724394405, + Network: "IN", + AddressType: "IP4", + Address: "198.51.100.1", + }, + Info: "SDP Offer #1", + URI: &url.URL{Scheme: "http", + Host: "www.jdoe.example.com", + Path: "/home.html", + }, + Email: &mail.Address{"Jane Doe", "jane@jdoe.example.com"}, + Phone: "+1 617 555-6011", + } session, err := ReadSession(strings.NewReader(s)) if err != nil { t.Fatalf("read session: %v", err) } - if session.Name != "Call to John Smith" { - t.Errorf("bad name bla bla TODO") + if !reflect.DeepEqual(*session, want) { + t.Errorf("got %+v\nwant %+v\n", *session, want) } + t.Errorf("TODO still not parsing all fields") }