xref: /aosp_15_r20/external/libopus/tests/test_opus_extensions.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1 /* Copyright (c) 2023 Amazon
2    Written by Michael Klingbeil */
3 /*
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7 
8    - Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 
11    - Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14 
15    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #ifndef _WIN32
37 #include <unistd.h>
38 #else
39 #include <process.h>
40 #define getpid _getpid
41 #endif
42 
43 #include "../src/opus_private.h"
44 #include "test_opus_common.h"
45 
test_extensions_generate_success(void)46 void test_extensions_generate_success(void)
47 {
48    static const opus_extension_data ext[] = {
49       {2, 0, (const unsigned char *)"a", 1},
50       {32, 10, (const unsigned char *)"DRED", 4},
51       {33, 1, (const unsigned char *)"NOT DRED", 8},
52       {3, 4, (const unsigned char *)NULL, 0}
53    };
54 
55    int result;
56    unsigned char packet[32];
57    const unsigned char *p = packet;
58    result = opus_packet_extensions_generate(packet, 23+4, ext, 4, 1);
59    expect_true(result == 23+4, "expected length 23+4");
60 
61    /* expect padding */
62    expect_true(p[0] == 1 && p[1] == 1 && p[2] == 1 && p[3] == 1, "expected padding");
63    p += 4;
64 
65    /* extension ID=2 */
66    expect_true((p[0] >> 1) == 2, "expected extension id 2");
67    /* For extension IDs 1 through 31, L=0 means that no data follows the
68       extension, whereas L=1 means that exactly one byte of extension data follows. */
69    expect_true((p[0] & 0x01) == 1, "expected L-bit set");
70    /* content */
71    expect_true(p[1] == 'a', "expected extension content");
72    p += 2;
73 
74    /* next byte should increment the frame count, ID=1, L=0 */
75    expect_true(p[0] == 0x02, "bad frame separator");
76    p += 1;
77    /* extension ID=33 */
78    expect_true((p[0] >> 1) == 33, "expected extension id 33");
79    /* For IDs 32 to 127, L=0 signals that the extension data takes up the
80       rest of the padding, and L=1 signals that a length indicator follows. */
81    expect_true((p[0] & 0x01) == 1, "expected L-bit set");
82    /* content */
83    expect_true(p[1] == ext[2].len, "expected length");
84    p += 2;
85    expect_true(0 == memcmp(p, ext[2].data, ext[2].len), "expected extension content");
86    p += ext[2].len;
87 
88    /* advance to frame 4, increment by 3 */
89    /* next byte should increment the frame count, ID=1, L=1 */
90    expect_true(p[0] == 0x03, "bad frame separator");
91    expect_true(p[1] == 0x03, "bad frame increment");
92    p += 2;
93    /* extension ID=3 */
94    expect_true((p[0] >> 1) == 3, "expected extension id 3");
95    /* For extension IDs 1 through 31, L=0 means that no data follows the
96       extension, whereas L=1 means that exactly one byte of extension data follows. */
97    expect_true((p[0] & 0x01) == 0, "expected L-bit unset");
98    p += 1;
99 
100    /* advance to frame 10, increment by 6 */
101    /* next byte should increment the frame count, ID=1, L=1 */
102    expect_true(p[0] == 0x03, "bad frame separator");
103    expect_true(p[1] == 0x06, "bad frame increment");
104    p += 2;
105    /* extension ID=32 */
106    expect_true((p[0] >> 1) == 32, "expected extension id 32");
107    /* For IDs 32 to 127, L=0 signals that the extension data takes up the
108       rest of the padding */
109    expect_true((p[0] & 0x01) == 0, "expected L-bit unset");
110    p += 1;
111    expect_true(0 == memcmp(p, ext[1].data, ext[1].len), "expected extension content");
112 }
113 
test_extensions_generate_zero(void)114 void test_extensions_generate_zero(void)
115 {
116    int result;
117    unsigned char packet[32];
118 
119    /* zero length packet, zero extensions */
120    result = opus_packet_extensions_generate(packet, 0, NULL, 0, 1);
121    expect_true(result == 0, "expected length 0");
122 }
123 
test_extensions_generate_no_padding(void)124 void test_extensions_generate_no_padding(void)
125 {
126    static const opus_extension_data ext[] = {
127       {2, 0, (const unsigned char *)"a", 1},
128       {32, 10, (const unsigned char *)"DRED", 4},
129       {33, 1, (const unsigned char *)"NOT DRED", 8},
130       {3, 4, (const unsigned char *)NULL, 0}
131    };
132 
133    int result;
134    unsigned char packet[32];
135    result = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
136    expect_true(result == 23, "expected length 23");
137 }
138 
test_extensions_generate_fail(void)139 void test_extensions_generate_fail(void)
140 {
141    static const opus_extension_data ext[] = {
142       {2, 0, (const unsigned char *)"a", 1},
143       {32, 10, (const unsigned char *)"DRED", 4},
144       {33, 1, (const unsigned char *)"NOT DRED", 8},
145       {3, 4, (const unsigned char *)NULL, 0}
146    };
147 
148    int result;
149    unsigned char packet[100];
150 
151    /* buffer too small */
152    result = opus_packet_extensions_generate(packet, 4, ext, 4, 1);
153    expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
154 
155    /* invalid id */
156    {
157       static const opus_extension_data id_too_big[] = {
158          {256, 0, (const unsigned char *)"a", 1},
159       };
160       result = opus_packet_extensions_generate(packet, sizeof(packet), id_too_big, 1, 1);
161       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
162    }
163 
164    /* invalid id */
165    {
166       static const opus_extension_data id_too_small[] = {
167          {1, 0, (const unsigned char *)"a", 1},
168       };
169       result = opus_packet_extensions_generate(packet, sizeof(packet), id_too_small, 1, 1);
170       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
171    }
172 
173    /* frame index too big */
174    {
175       static const opus_extension_data frame_too_big[] = {
176          {33, 48, (const unsigned char *)"a", 1},
177       };
178       result = opus_packet_extensions_generate(packet, sizeof(packet), frame_too_big, 1, 1);
179       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
180    }
181 
182    /* size too big for extension IDs 1 through 31 */
183    {
184       static const opus_extension_data size_too_big[] = {
185          {2, 0, (const unsigned char *)"abcd", 4},
186       };
187       result = opus_packet_extensions_generate(packet, sizeof(packet), size_too_big, 1, 1);
188       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
189    }
190 
191    /* negative size for extension IDs 1 through 31 */
192    {
193       static const opus_extension_data neg_size[] = {
194          {2, 0, NULL, -4},
195       };
196       result = opus_packet_extensions_generate(packet, sizeof(packet), neg_size, 1, 1);
197       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
198    }
199 
200    /* negative size for extension IDs 32 through 127 */
201    {
202       static const opus_extension_data neg_size_33[] = {
203          {33, 0, NULL, -4},
204       };
205       result = opus_packet_extensions_generate(packet, sizeof(packet), neg_size_33, 1, 1);
206       expect_true(result == OPUS_BAD_ARG, "expected OPUS_BAD_ARG");
207    }
208 }
209 
test_extensions_parse_success(void)210 void test_extensions_parse_success(void)
211 {
212    static const opus_extension_data ext[] = {
213       {2, 0, (const unsigned char *)"a", 1},
214       {32, 10, (const unsigned char *)"DRED", 4},
215       {33, 1, (const unsigned char *)"NOT DRED", 8},
216       {3, 4, (const unsigned char *)NULL, 0}
217    };
218    opus_extension_data ext_out[10];
219    int nb_ext;
220    int len, result;
221    unsigned char packet[32];
222 
223    nb_ext = 10;
224    len = opus_packet_extensions_generate(packet, 32, ext, 4, 1);
225    expect_true(len == 32, "expected length 32");
226    result = opus_packet_extensions_count(packet, len);
227    expect_true(result == 4, "expected opus_packet_extensions_count 4");
228    result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
229    expect_true(nb_ext == 4, "expected 4 extensions");
230 
231    expect_true(ext_out[0].id == 2, "expected id 2");
232    expect_true(ext_out[0].frame == 0, "expected frame 0");
233    expect_true(ext_out[0].len == 1, "expected len 1");
234    expect_true(0 == memcmp(ext_out[0].data, ext[0].data, 1), "expected data");
235 
236    expect_true(ext_out[1].id == 33, "expected id 33");
237    expect_true(ext_out[1].frame == 1, "expected frame 1");
238    expect_true(ext_out[1].len == 8, "expected len 8");
239    expect_true(0 == memcmp(ext_out[1].data, ext[2].data, 8), "expected data");
240 
241    expect_true(ext_out[2].id == 3, "expected id 3");
242    expect_true(ext_out[2].frame == 4, "expected frame 4");
243    expect_true(ext_out[2].len == 0, "expected len 0");
244 
245    expect_true(ext_out[3].id == 32, "expected id 32");
246    expect_true(ext_out[3].frame == 10, "expected frame 10");
247    expect_true(ext_out[3].len == 4, "expected len 4");
248    expect_true(0 == memcmp(ext_out[3].data, ext[1].data, 4), "expected data");
249 }
250 
test_extensions_parse_zero(void)251 void test_extensions_parse_zero(void)
252 {
253    static const opus_extension_data ext[] = {
254       {32, 1, (const unsigned char *)"DRED", 4},
255    };
256    int nb_ext;
257    int len, result;
258    unsigned char packet[32];
259 
260    len = opus_packet_extensions_generate(packet, 32, ext, 1, 1);
261    expect_true(len == 32, "expected length 32");
262 
263    nb_ext = 0;
264    result = opus_packet_extensions_parse(packet, len, NULL, &nb_ext);
265    expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
266 }
267 
test_extensions_parse_fail(void)268 void test_extensions_parse_fail(void)
269 {
270    static const opus_extension_data ext[] = {
271       {2, 0, (const unsigned char *)"a", 1},
272       {33, 1, (const unsigned char *)"NOT DRED", 8},
273       {3, 4, (const unsigned char *)NULL, 0},
274       {32, 10, (const unsigned char *)"DRED", 4}
275    };
276    opus_extension_data ext_out[10];
277    int nb_ext;
278    int len, result;
279    unsigned char packet[32];
280 
281    /* create invalid length */
282    len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
283    packet[4] = 255;
284    nb_ext = 10;
285    result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
286    expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
287    result = opus_packet_extensions_count(packet, len);
288    expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
289 
290    /* create invalid frame increment */
291    nb_ext = 10;
292    len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
293    packet[14] = 255;
294    result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
295    expect_true(result == OPUS_INVALID_PACKET, "expected OPUS_INVALID_PACKET");
296    /* note, opus_packet_extensions_count does not read the invalid frame increment
297       and tells us that we have 4 extensions */
298    result = opus_packet_extensions_count(packet, len);
299    expect_true(result == 4, "expected opus_packet_extensions_count to return 4");
300 
301    /* not enough space */
302    nb_ext = 1;
303    len = opus_packet_extensions_generate(packet, sizeof(packet), ext, 4, 0);
304    result = opus_packet_extensions_parse(packet, len, ext_out, &nb_ext);
305    expect_true(result == OPUS_BUFFER_TOO_SMALL, "expected OPUS_BUFFER_TOO_SMALL");
306 }
307 
308 #define NB_RANDOM_EXTENSIONS 100000000
309 #define MAX_EXTENSION_SIZE 200
310 #define MAX_NB_EXTENSIONS 100
311 
test_random_extensions_parse(void)312 void test_random_extensions_parse(void)
313 {
314    int i;
315    for (i=0;i<NB_RANDOM_EXTENSIONS;i++)
316    {
317       opus_extension_data ext_out[MAX_NB_EXTENSIONS];
318       int nb_ext;
319       unsigned char payload[MAX_EXTENSION_SIZE];
320       int len;
321       int j;
322       int result;
323       len = fast_rand()%(MAX_EXTENSION_SIZE+1);
324       for (j=0;j<len;j++)
325          payload[j] = fast_rand()&0xFF;
326       nb_ext = fast_rand()%(MAX_NB_EXTENSIONS+1);
327       result = opus_packet_extensions_parse(payload, len, ext_out, &nb_ext);
328       expect_true(result == OPUS_OK || result == OPUS_BUFFER_TOO_SMALL || result == OPUS_INVALID_PACKET, "expected OPUS_OK, OPUS_BUFFER_TOO_SMALL or OPUS_INVALID_PACKET");
329       /* Even if parsing fails, check that the extensions that got extracted make sense. */
330       for (j=0;j<nb_ext;j++)
331       {
332          expect_true(ext_out[j].frame >= 0 && ext_out[j].frame < 48, "expected frame between 0 and 47");
333          expect_true(ext_out[j].id >= 2 && ext_out[j].id <= 127, "expected id between 2 and 127");
334          expect_true(ext_out[j].data >= payload && ext_out[j].data+ext_out[j].len <= payload+len, "expected data to be within packet");
335       }
336    }
337 }
338 
test_opus_repacketizer_out_range_impl(void)339 void test_opus_repacketizer_out_range_impl(void)
340 {
341    OpusRepacketizer rp;
342    unsigned char packet[1024];
343    unsigned char packet_out[1024];
344    opus_int16 size[48];
345    const unsigned char *padding;
346    opus_int32 padding_len;
347    opus_extension_data ext_out[10];
348    int i;
349    int nb_ext;
350    int res, len;
351    int first_count = 0, second_count = 0;
352    static const opus_extension_data ext[] = {
353       {33, 0, (const unsigned char *)"abcdefg", 7},
354       {100, 0, (const unsigned char *)"uvwxyz", 6},
355    };
356 
357    opus_repacketizer_init(&rp);
358 
359    memset(packet, 0, sizeof(packet));
360    /* Hybrid Packet with 20 msec frames, Code 3 */
361    packet[0] = (15 << 3) | 3;
362    /* Code 3, padding bit set, 1 frame */
363    packet[1] = 1 << 6 | 1;
364    packet[2] = 0;
365    packet[3] = 0;
366 
367    /* generate 2 extensions, id 33 and 100 */
368    len = opus_packet_extensions_generate(&packet[4], sizeof(packet)-4, ext, 2, 0);
369    /* update the padding length */
370    packet[2] = len;
371 
372    /* concatenate 3 frames */
373    res = opus_repacketizer_cat(&rp, packet, 4+len);
374    /* for the middle frame, no padding, no extensions */
375    packet[1] = 1;
376    res = opus_repacketizer_cat(&rp, packet, 4);
377    /* switch back to extensions for the last frame extensions */
378    packet[1] = 1 << 6 | 1;
379    res = opus_repacketizer_cat(&rp, packet, 4+len);
380 
381    expect_true(rp.nb_frames == 3, "Expected 3 frames");
382    res = opus_repacketizer_out_range_impl(&rp,
383       0, 3, /* begin, end */
384       packet_out, /* unsigned char *data */
385       sizeof(packet_out), /* opus_int32 maxlen */
386       0, /*int self_delimited */
387       0, /* int pad */
388       NULL, /* const opus_extension_data *extensions */
389       0 /* int nb_extensions */);
390    expect_true(res > 0, "expected valid packet length");
391 
392    /* now verify that we have the expected extensions */
393    res = opus_packet_parse_impl(packet_out, res, 0, NULL, NULL, size,
394       NULL, NULL, &padding, &padding_len);
395    nb_ext = 10;
396    res = opus_packet_extensions_parse(padding, padding_len, ext_out, &nb_ext);
397    expect_true(nb_ext == 4, "Expected 4 extensions");
398    for (i = 0 ; i < nb_ext; i++)
399    {
400       if (ext_out[i].id == 33)
401       {
402          opus_test_assert(ext_out[i].len == ext[0].len);
403          opus_test_assert(0 == memcmp(ext_out[i].data, ext[0].data, ext[0].len));
404          first_count++;
405       }
406       else if (ext_out[i].id == 100)
407       {
408          opus_test_assert(ext_out[i].len == ext[1].len);
409          opus_test_assert(0 == memcmp(ext_out[i].data, ext[1].data, ext[1].len));
410          second_count++;
411       }
412       if (i < 2)
413          opus_test_assert(ext_out[i].frame == 0)
414       else
415          opus_test_assert(ext_out[i].frame == 2)
416    }
417    opus_test_assert(first_count == 2);
418    opus_test_assert(second_count == 2);
419 }
420 
main(int argc,char ** argv)421 int main(int argc, char **argv)
422 {
423    int env_used;
424    char *env_seed;
425    env_used=0;
426    env_seed=getenv("SEED");
427    if(argc>1)iseed=atoi(argv[1]);
428    else if(env_seed)
429    {
430       iseed=atoi(env_seed);
431       env_used=1;
432    }
433    else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16);
434    Rw=Rz=iseed;
435 
436    fprintf(stderr,"Testing extensions. Random seed: %u (%.4X)\n", iseed, fast_rand() % 65535);
437    if(env_used)fprintf(stderr,"  Random seed set from the environment (SEED=%s).\n", env_seed);
438 
439    test_extensions_generate_success();
440    test_extensions_generate_zero();
441    test_extensions_generate_no_padding();
442    test_extensions_generate_fail();
443    test_extensions_parse_success();
444    test_extensions_parse_zero();
445    test_extensions_parse_fail();
446    test_random_extensions_parse();
447    test_opus_repacketizer_out_range_impl();
448    fprintf(stderr,"Tests completed successfully.\n");
449    return 0;
450 }
451