commit 896f60249033051fe531557d83031f3d0e2fa1c1
parent 035ab79449be5db836ae24e00d8bfe3317f14ea5
Author: Oliver Lowe <o@olowe.co>
Date: Fri, 4 Jul 2025 21:28:03 +1000
sdp: use encoding.TextMarshaler for Session encoding
fmt.Stringer is not really meant for larger multi-line text.
It sucks a bit that we may return an error, but this lets us
put some validation logic in; we don't have any validation yet.
Diffstat:
4 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/sdp/encode.go b/sdp/encode.go
@@ -1,21 +1,21 @@
package sdp
import (
+ "bytes"
"fmt"
"strings"
)
-func (s Session) String() string {
+func (s Session) MarshalText() ([]byte, error) {
buf := &strings.Builder{}
fmt.Fprintln(buf, "v=0")
+
if s.Origin.Username == "" {
s.Origin.Username = NoUsername
}
- ipv := "IP6"
- if s.Origin.Address.Is4() {
- ipv = "IP4"
- }
- fmt.Fprintf(buf, "o=%s %d %d IN %s %s\n", s.Origin.Username, s.Origin.ID, s.Origin.Version, ipv, s.Origin.Address)
+
+ fmt.Fprintln(buf, s.Origin)
+
fmt.Fprintf(buf, "s=%s\n", s.Name)
if s.Info != "" {
@@ -65,5 +65,5 @@ func (s Session) String() string {
fmt.Fprintln(buf, m)
}
- return strings.TrimSpace(buf.String())
+ return bytes.TrimSpace([]byte(buf.String())), nil
}
diff --git a/sdp/encode_test.go b/sdp/encode_test.go
@@ -12,18 +12,21 @@ func TestWriteSession(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- b, err := io.ReadAll(f)
+ want, err := io.ReadAll(f)
if err != nil {
t.Fatal(err)
}
- want := string(b)
- session, err := ReadSession(bytes.NewReader(b))
+ session, err := ReadSession(bytes.NewReader(want))
if err != nil {
t.Fatal(err)
}
- if want != session.String() {
+ got, err := session.MarshalText()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(want, got) {
t.Errorf("mismatched sdp text")
- t.Log("want", want)
- t.Log("got", session.String())
+ t.Log("want", string(want))
+ t.Log("got", string(got))
}
}
diff --git a/sdp/example_test.go b/sdp/example_test.go
@@ -12,8 +12,8 @@ import (
// audio in RTP starts by setting the mandatory fields Origin and Name.
// The Media field contains information about the audio such as the sample rate
// and the number of audio channels.
-// The Session type implements fmt.Stringer;
-// to encode a Session in the SDP text format, use Session.String().
+// Session implements encoding.TextMarshaler;
+// to encode a Session in the SDP text format, use Session.MarshalText().
func Example() {
session := sdp.Session{
Origin: sdp.Origin{
@@ -35,7 +35,8 @@ func Example() {
},
},
}
- fmt.Printf("%s", session)
+ text, _ := session.MarshalText()
+ fmt.Printf("%s", text)
// Output:
// v=0
// o=- 3930287268 3930287268 IN IP6 2001:db8::1
diff --git a/sdp/sdp.go b/sdp/sdp.go
@@ -60,6 +60,14 @@ type Origin struct {
Address netip.Addr
}
+func (o Origin) String() string {
+ ipv := "IP6"
+ if o.Address.Is4() {
+ ipv = "IP4"
+ }
+ return fmt.Sprintf("o=%s %d %d IN %s %s", o.Username, o.ID, o.Version, ipv, o.Address)
+}
+
func ReadSession(rd io.Reader) (*Session, error) {
parser := &parser{Scanner: bufio.NewScanner(rd)}
if err := parser.parse(); err != nil {