@@ -4,9 +4,11 @@ import (
44 "bufio"
55 "crypto/sha1"
66 "encoding/hex"
7+ "fmt"
78 "io"
89 "os"
910 "os/exec"
11+ "slices"
1012 "testing"
1113
1214 "github.com/livekit/amrwb-cgo"
@@ -15,14 +17,148 @@ import (
1517 "github.com/livekit/media-sdk/res/testdata"
1618)
1719
20+ const rate = 16000
21+
1822func TestAMRWB (t * testing.T ) {
19- const rate = 16000
20- frames := res .ReadOggAudioFile (testdata .TestAudioOgg16K , rate , 1 )
23+ frames := readOGG ()
24+
25+ modes := [9 ]amrwb.Mode {
26+ amrwb .Mode6Kb ,
27+ amrwb .Mode8Kb ,
28+ amrwb .Mode12Kb ,
29+ amrwb .Mode14Kb ,
30+ amrwb .Mode16Kb ,
31+ amrwb .Mode18Kb ,
32+ amrwb .Mode20Kb ,
33+ amrwb .Mode23Kb ,
34+ amrwb .Mode24Kb ,
35+ }
36+
37+ const selFrame = 41
38+
39+ t .Run ("storage" , func (t * testing.T ) {
40+ const format = Storage
41+ hashes := [9 ][]string {
42+ 0 : {
43+ "0236b84c931bcf121da1a0587420d30d1aac0301" ,
44+ },
45+ 1 : {
46+ "dabd16afd6fcacefc26d221e3fa06a2bc6644076" ,
47+ },
48+ 2 : {
49+ "61d20f4e120dd13e2fbaaf74dd3c08863ed5a557" ,
50+ },
51+ 3 : {
52+ "bece54885e71b89dfcd86c8cbe7ce9fd2fefb4f7" ,
53+ },
54+ 4 : {
55+ "67fa8975e5757d3b83aba349a7cc1f4e5d06ff66" ,
56+ },
57+ 5 : {
58+ "6f9c014385c8e7dbde780ae2e4a89b03b5e03dcb" ,
59+ },
60+ 6 : {
61+ "039be8ddd5d2de4bb148d166552e6d59eebb3e40" ,
62+ },
63+ 7 : {
64+ "2d0346353617d23bb59a6519167707115be2245e" ,
65+ },
66+ 8 : {
67+ "266c17405ad9cb6057bfe1a3e0cf764c448a10a0" ,
68+ "b3d9349b01e93c523311e587d639142d0c79546b" ,
69+ },
70+ }
71+ for mi , mode := range modes {
72+ t .Run (fmt .Sprintf ("mode %d" , mi ), func (t * testing.T ) {
73+ hashes := hashes [mi ]
74+
75+ blocks := encodeAMR (t , format , mode , frames )
76+ t .Logf ("block: %x" , blocks [selFrame ])
77+
78+ name := fmt .Sprintf ("testdata_mode_%d" , mode )
79+
80+ hashAMR := dumpAMR (t , name + ".amrwb" , blocks )
81+ ffmpegAMRFileToOGG (t , name + ".amrwb" )
82+ if ! slices .Contains (hashes , hashAMR ) {
83+ t .Errorf ("unexpected amrwb hash %s" , hashAMR )
84+ }
85+
86+ out := decodeAMR (t , format , blocks )
87+
88+ hashOut := dumpPCM (t , name + ".s16le" , out )
89+ ffmpegPCMFileToOGG (t , name + ".s16le" )
90+ if hashOut != "da39a3ee5e6b4b0d3255bfef95601890afd80709" {
91+ t .Errorf ("unexpected output hash %s" , hashOut )
92+ }
93+ })
94+ }
95+ })
96+ t .Run ("rtp" , func (t * testing.T ) {
97+ const format = RTPBandwidthEfficient
98+ hashes := [9 ][]string {
99+ 0 : {
100+ "a8e453a08c894e2c3d0f7bf62142d6eb63bfe5c8" ,
101+ },
102+ 1 : {
103+ "270a13237d862e9e20e725a0a9484edddc3b4f00" ,
104+ },
105+ 2 : {
106+ "607966a93720aaa1c8425e08b6471f58282c0884" ,
107+ },
108+ 3 : {
109+ "8a620e9c3ce1656ea07804be210befe5c878f3f3" ,
110+ },
111+ 4 : {
112+ "9121d8781a397f4784174f15309f6f48d86db338" ,
113+ },
114+ 5 : {
115+ "a6e005daf0e8040530157be090934376610beeb7" ,
116+ },
117+ 6 : {
118+ "4497873be7c5574468e68c0718a5e57d3c8ac099" ,
119+ },
120+ 7 : {
121+ "b73f2049b96be4793f611339e4d3435ec19a8760" ,
122+ },
123+ 8 : {
124+ "7aa1a489f7f951ab421f0e462abb18c7d4c00c68" ,
125+ },
126+ }
127+ for mi , mode := range modes {
128+ t .Run (fmt .Sprintf ("mode %d" , mi ), func (t * testing.T ) {
129+ hashes := hashes [mi ]
130+
131+ blocks := encodeAMR (t , format , mode , frames )
132+ t .Logf ("block: %x" , blocks [selFrame ])
133+
134+ name := fmt .Sprintf ("testdata_rtp_mode_%d" , mode )
135+
136+ hashAMR := dumpAMR (t , name + ".amrwb" , blocks )
137+ if ! slices .Contains (hashes , hashAMR ) {
138+ t .Errorf ("unexpected amrwb hash %s" , hashAMR )
139+ }
140+
141+ out := decodeAMR (t , format , blocks )
142+
143+ hashOut := dumpPCM (t , name + ".s16le" , out )
144+ ffmpegPCMFileToOGG (t , name + ".s16le" )
145+ if hashOut != "da39a3ee5e6b4b0d3255bfef95601890afd80709" {
146+ t .Errorf ("unexpected output hash %s" , hashOut )
147+ }
148+ })
149+ }
150+ })
151+ }
21152
153+ func readOGG () []media.PCM16Sample {
154+ return res .ReadOggAudioFile (testdata .TestAudioOgg16K , rate , 1 )
155+ }
156+
157+ func encodeAMR (t testing.TB , format amrwb.Format , mode amrwb.Mode , frames []media.PCM16Sample ) []Sample {
22158 blocks := make ([]Sample , 0 , len (frames ))
23159 fw := media .NewFrameWriter (& blocks , rate )
24160
25- enc := Encode (fw )
161+ enc := EncodeWith (fw , format , mode )
26162 t .Cleanup (func () {
27163 enc .Close ()
28164 })
@@ -32,33 +168,32 @@ func TestAMRWB(t *testing.T) {
32168 t .Errorf ("encoding frame %d/%d: %v" , i + 1 , len (frames ), err )
33169 }
34170 }
35- famr , err := os .Create ("testdata.amrwb" )
171+ return blocks
172+ }
173+
174+ func dumpAMR (t testing.TB , name string , blocks []Sample ) string {
175+ f , err := os .Create (name )
36176 if err != nil {
37177 t .Fatal (err )
38178 }
39- defer famr .Close ()
40-
41- hamr := sha1 .New ()
179+ defer f .Close ()
42180
43- wbamr := bufio .NewWriter (io .MultiWriter (famr , hamr ))
44- wbamr .WriteString (amrwb .Magic )
181+ h := sha1 .New ()
182+ bw := bufio .NewWriter (io .MultiWriter (f , h ))
183+ bw .WriteString (amrwb .Magic )
45184 for _ , block := range blocks {
46- wbamr .Write (block )
47- }
48- wbamr .Flush ()
49-
50- hashAMR := hex .EncodeToString (hamr .Sum (nil ))
51- switch hashAMR {
52- default :
53- t .Errorf ("unexpected amrwb hash %s" , hashAMR )
54- case "266c17405ad9cb6057bfe1a3e0cf764c448a10a0" ,
55- "b3d9349b01e93c523311e587d639142d0c79546b" :
185+ bw .Write (block )
56186 }
187+ bw .Flush ()
188+
189+ return hex .EncodeToString (h .Sum (nil ))
190+ }
57191
192+ func decodeAMR (t testing.TB , format amrwb.Format , blocks []Sample ) []media.PCM16Sample {
58193 var out []media.PCM16Sample
59194 pw := media .NewPCM16FrameWriter (& out , rate )
60195
61- dec := Decode (pw )
196+ dec := Decode (pw , format )
62197 t .Cleanup (func () {
63198 dec .Close ()
64199 })
@@ -68,44 +203,54 @@ func TestAMRWB(t *testing.T) {
68203 t .Error (err )
69204 }
70205 }
206+ return out
207+ }
71208
72- f , err := os .Create ("testdata.s16le" )
209+ func dumpPCM (t testing.TB , name string , data []media.PCM16Sample ) string {
210+ f , err := os .Create (name )
73211 if err != nil {
74212 t .Fatal (err )
75213 }
76214 defer f .Close ()
77215
78216 h := sha1 .New ()
79217 bw := bufio .NewWriter (io .MultiWriter (f , h ))
80- err = media .DumpFramesPCM16 (f , rate , out )
218+ err = media .DumpFramesPCM16 (f , rate , data )
81219 if err != nil {
82220 t .Fatal (err )
83221 }
84222 bw .Flush ()
85223
86- hashOut := hex .EncodeToString (h .Sum (nil ))
87- if hashOut != "da39a3ee5e6b4b0d3255bfef95601890afd80709" {
88- t .Errorf ("unexpected output hash %s" , hashOut )
89- }
224+ return hex .EncodeToString (h .Sum (nil ))
225+ }
90226
227+ func ffmpegAMRFileToOGG (t testing.TB , name string ) {
91228 if _ , err := exec .LookPath ("ffmpeg" ); err != nil {
92229 t .Log ("ffmpeg not found in $PATH" )
93230 return
94231 }
95-
96- err = exec .Command ("ffmpeg" ,
97- "-i" , "testdata.amrwb" ,
98- "testdata.amrwb.ogg" ,
232+ err := exec .Command ("ffmpeg" ,
233+ "-i" , name , name + ".ogg" ,
99234 ).Run ()
100235 if err != nil {
101236 t .Error (err )
237+ } else {
238+ os .Remove (name )
239+ }
240+ }
241+
242+ func ffmpegPCMFileToOGG (t testing.TB , name string ) {
243+ if _ , err := exec .LookPath ("ffmpeg" ); err != nil {
244+ t .Log ("ffmpeg not found in $PATH" )
245+ return
102246 }
103- err = exec .Command ("ffmpeg" ,
247+ err : = exec .Command ("ffmpeg" ,
104248 "-f" , "s16le" , "-ar" , "16000" , "-ac" , "1" ,
105- "-i" , "testdata.s16le" ,
106- "testdata.s16le.ogg" ,
249+ "-i" , name , name + ".ogg" ,
107250 ).Run ()
108251 if err != nil {
109252 t .Error (err )
253+ } else {
254+ os .Remove (name )
110255 }
111256}
0 commit comments