1 /* GStreamer
2  *
3  * unit test for hlsdemux
4  *
5  * Copyright (C) <2012> Fluendo S.A <support@fluendo.com>
6  *  Authors: Andoni Morales Alastruey <amorales@fluendo.com>
7  * Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24 
25 #include <unistd.h>
26 
27 #include <gst/check/gstcheck.h>
28 
29 #undef GST_CAT_DEFAULT
30 #include "m3u8.h"
31 #include "m3u8.c"
32 
33 GST_DEBUG_CATEGORY (hls_debug);
34 
35 static const gchar *INVALID_PLAYLIST = "#EXTM3 UINVALID";
36 
37 static const gchar *ON_DEMAND_PLAYLIST = "#EXTM3U \n\
38 #EXT-X-TARGETDURATION:10\n\
39 #EXTINF:10,Test\n\
40 http://media.example.com/001.ts\n\
41 #EXTINF:10,Test\n\
42 http://media.example.com/002.ts\n\
43 #EXTINF:10,Test\n\
44 http://media.example.com/003.ts\n\
45 #EXTINF:10,Test\n\
46 http://media.example.com/004.ts\n\
47 #EXT-X-ENDLIST";
48 
49 static const gchar *DOUBLES_PLAYLIST = "#EXTM3U \n\
50 #EXT-X-TARGETDURATION:10\n\
51 #EXTINF:10.321,Test\n\
52 http://media.example.com/001.ts\n\
53 #EXTINF:9.6789,Test\n\
54 http://media.example.com/002.ts\n\
55 #EXTINF:10.2344,Test\n\
56 http://media.example.com/003.ts\n\
57 #EXTINF:9.92,Test\n\
58 http://media.example.com/004.ts\n\
59 #EXT-X-ENDLIST";
60 
61 static const gchar *LIVE_PLAYLIST = "#EXTM3U\n\
62 #EXT-X-TARGETDURATION:8\n\
63 #EXT-X-MEDIA-SEQUENCE:2680\n\
64 \n\
65 #EXTINF:8,\n\
66 https://priv.example.com/fileSequence2680.ts\n\
67 #EXTINF:8,\n\
68 https://priv.example.com/fileSequence2681.ts\n\
69 #EXTINF:8,\n\
70 https://priv.example.com/fileSequence2682.ts\n\
71 #EXTINF:8,\n\
72 https://priv.example.com/fileSequence2683.ts";
73 
74 static const gchar *LIVE_ROTATED_PLAYLIST = "#EXTM3U\n\
75 #EXT-X-TARGETDURATION:8\n\
76 #EXT-X-MEDIA-SEQUENCE:3001\n\
77 \n\
78 #EXTINF:8,\n\
79 https://priv.example.com/fileSequence3001.ts\n\
80 #EXTINF:8,\n\
81 https://priv.example.com/fileSequence3002.ts\n\
82 #EXTINF:8,\n\
83 https://priv.example.com/fileSequence3003.ts\n\
84 #EXTINF:8,\n\
85 https://priv.example.com/fileSequence3004.ts";
86 
87 static const gchar *VARIANT_PLAYLIST = "#EXTM3U \n\
88 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\
89 http://example.com/low.m3u8\n\
90 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\
91 http://example.com/mid.m3u8\n\
92 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\
93 http://example.com/hi.m3u8\n\
94 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\
95 http://example.com/audio-only.m3u8";
96 
97 static const gchar *VARIANT_PLAYLIST_WITH_URI_MISSING = "#EXTM3U \n\
98 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\
99 http://example.com/low.m3u8\n\
100 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\
101 \n\
102 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\
103 http://example.com/hi.m3u8\n\
104 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\
105 http://example.com/audio-only.m3u8";
106 
107 static const gchar *EMPTY_LINES_VARIANT_PLAYLIST = "#EXTM3U \n\
108 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\n\n\
109 http://example.com/low.m3u8\n\n\
110 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\n\n\
111 http://example.com/mid.m3u8\n\n\
112 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\n\n\
113 http://example.com/hi.m3u8\n\n\
114 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n\n\
115 http://example.com/audio-only.m3u8";
116 
117 static const gchar *WINDOWS_EMPTY_LINES_VARIANT_PLAYLIST = "#EXTM3U \r\n\
118 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\r\n\r\n\
119 http://example.com/low.m3u8\r\n\r\n\
120 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\r\n\r\n\
121 http://example.com/mid.m3u8\r\n\r\n\
122 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\r\n\r\n\
123 http://example.com/hi.m3u8\r\n\r\n\
124 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\r\n\r\n\
125 http://example.com/audio-only.m3u8";
126 
127 static const gchar *EMPTY_LINES_PLAYLIST = "#EXTM3U \n\n\
128 #EXT-X-TARGETDURATION:10\n\
129 #EXTINF:10,Testr\n\n\
130 http://media.example.com/001.ts\n\n\
131 #EXTINF:10,Test\n\n\
132 http://media.example.com/002.ts\n\n\
133 #EXTINF:10,Test\n\n\
134 http://media.example.com/003.ts\n\n\
135 #EXTINF:10,Test\n\n\
136 http://media.example.com/004.ts\n\n\
137 #EXT-X-ENDLIST";
138 
139 static const gchar *WINDOWS_EMPTY_LINES_PLAYLIST = "#EXTM3U \r\n\
140 #EXT-X-TARGETDURATION:10\r\n\r\n\
141 #EXTINF:10,Test\r\n\r\n\
142 http://media.example.com/001.ts\r\n\r\n\
143 #EXTINF:10,Test\r\n\r\n\
144 http://media.example.com/002.ts\r\n\r\n\
145 #EXTINF:10,Test\r\n\r\n\
146 http://media.example.com/003.ts\r\n\r\n\
147 #EXTINF:10,Test\r\n\r\n\
148 http://media.example.com/004.ts\r\n\r\n\
149 #EXT-X-ENDLIST";
150 
151 static const gchar *BYTE_RANGES_PLAYLIST = "#EXTM3U \n\
152 #EXT-X-TARGETDURATION:40\n\
153 #EXTINF:10,Test\n\
154 #EXT-X-BYTERANGE:1000@100\n\
155 http://media.example.com/all.ts\n\
156 #EXTINF:10,Test\n\
157 #EXT-X-BYTERANGE:1000@1000\n\
158 http://media.example.com/all.ts\n\
159 #EXTINF:10,Test\n\
160 #EXT-X-BYTERANGE:1000@2000\n\
161 http://media.example.com/all.ts\n\
162 #EXTINF:10,Test\n\
163 #EXT-X-BYTERANGE:1000@3000\n\
164 http://media.example.com/all.ts\n\
165 #EXT-X-ENDLIST";
166 
167 static const gchar *BYTE_RANGES_ACC_OFFSET_PLAYLIST = "#EXTM3U \n\
168 #EXT-X-TARGETDURATION:40\n\
169 #EXTINF:10,Test\n\
170 #EXT-X-BYTERANGE:1000\n\
171 http://media.example.com/all.ts\n\
172 #EXTINF:10,Test\n\
173 #EXT-X-BYTERANGE:1000\n\
174 http://media.example.com/all.ts\n\
175 #EXTINF:10,Test\n\
176 #EXT-X-BYTERANGE:1000\n\
177 http://media.example.com/all.ts\n\
178 #EXTINF:10,Test\n\
179 #EXT-X-BYTERANGE:1000\n\
180 http://media.example.com/all.ts\n\
181 #EXT-X-ENDLIST";
182 
183 #if 0
184 static const gchar *ALTERNATE_AUDIO_PLAYLIST = "#EXTM3U\n\
185 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"English\",\
186   DEFAULT=YES,AUTOSELECT=YES,LANGUAGE=\"en\" \n\
187 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Deutsche\",\
188   DEFAULT=NO,AUTOSELECT=YES,LANGUAGE=\"de\",\
189   URI=\"http://localhost/main/german-audio.m3u8\"\n\
190 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Commentary\",\
191   DEFAULT=NO,AUTOSELECT=NO,\
192   URI=\"http://localhost/commentary/audio-only.m3u8\"\n\
193 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
194 low/video-only.m3u8\n\
195 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
196 mid/video-only.m3u8\n\
197 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f\",AUDIO=\"aac\"\n\
198 hi/video-only.m3u8\n\
199 #EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n\
200 main/english-audio.m3u8";
201 
202 static const gchar *ALT_AUDIO_PLAYLIST_WITH_VIDEO_AUDIO = "#EXTM3U\n\
203 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"English\",\
204   DEFAULT=YES,AUTOSELECT=YES,LANGUAGE=\"en\" \n\
205 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Deutsche\",\
206   DEFAULT=NO,AUTOSELECT=YES,LANGUAGE=\"de\",\
207   URI=\"http://localhost/main/german-audio.m3u8\"\n\
208 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Commentary\",\
209   DEFAULT=NO,AUTOSELECT=NO,\
210   URI=\"http://localhost/commentary/audio-only.m3u8\"\n\
211 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
212 low/video-audio.m3u8\n\
213 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
214 mid/video-audio.m3u8\n\
215 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f, mp4a.40.5\",AUDIO=\"aac\"\n\
216 hi/video-audio.m3u8\n\
217 #EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n\
218 main/english-audio.m3u8";
219 
220 static const gchar *ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST = "#EXTM3U \n\
221 #EXT-X-TARGETDURATION:10\n\
222 #EXTINF:10,Test\n\
223 http://media.example.com/low/video-only-001.ts\n\
224 #EXTINF:10,Test\n\
225 http://media.example.com/low/video-only-002.ts\n\
226 #EXTINF:10,Test\n\
227 http://media.example.com/low/video-only-003.ts\n\
228 #EXTINF:10,Test\n\
229 http://media.example.com/low/video-only-004.ts\n\
230 #EXT-X-ENDLIST";
231 
232 static const gchar *ON_DEMAND_MID_VIDEO_ONLY_PLAYLIST = "#EXTM3U \n\
233 #EXT-X-TARGETDURATION:10\n\
234 #EXTINF:10,Test\n\
235 http://media.example.com/mid/video-only-001.ts\n\
236 #EXTINF:10,Test\n\
237 http://media.example.com/mid/video-only-002.ts\n\
238 #EXTINF:10,Test\n\
239 http://media.example.com/mid/video-only-003.ts\n\
240 #EXTINF:10,Test\n\
241 http://media.example.com/mid/video-only-004.ts\n\
242 #EXT-X-ENDLIST";
243 
244 static const gchar *ON_DEMAND_ENGLISH_PLAYLIST = "#EXTM3U \n\
245 #EXT-X-TARGETDURATION:10\n\
246 #EXTINF:10,Test\n\
247 http://media.example.com/audio/english-001.ts\n\
248 #EXTINF:10,Test\n\
249 http://media.example.com/audio/english-002.ts\n\
250 #EXTINF:10,Test\n\
251 http://media.example.com/audio/english-003.ts\n\
252 #EXTINF:10,Test\n\
253 http://media.example.com/audio/english-004.ts\n\
254 #EXT-X-ENDLIST";
255 
256 static const gchar *ON_DEMAND_GERMAN_PLAYLIST = "#EXTM3U \n\
257 #EXT-X-TARGETDURATION:10\n\
258 #EXTINF:10,Test\n\
259 http://media.example.com/audio/german-001.ts\n\
260 #EXTINF:10,Test\n\
261 http://media.example.com/audio/german-002.ts\n\
262 #EXTINF:10,Test\n\
263 http://media.example.com/audio/german-003.ts\n\
264 #EXTINF:10,Test\n\
265 http://media.example.com/audio/german-004.ts\n\
266 #EXT-X-ENDLIST";
267 
268 static const gchar *SUBTITLES_PLAYLIST = "#EXTM3U\n\
269 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"English\",\
270   DEFAULT=YES,LANGUAGE=\"en\",\
271   URI=\"http://localhost/main/subs-en.m3u8\"\n\
272 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"Deutsche\",\
273   DEFAULT=NO,LANGUAGE=\"de\",\
274   URI=\"http://localhost/main/subs-de.m3u8\"\n\
275 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"Spanish\",\
276   DEFAULT=NO,LANGUAGE=\"es\",\
277   URI=\"http://localhost/main/subs-es.m3u8\"\n\
278 #EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
279 low/video-audio.m3u8\n\
280 #EXT-X-STREAM-INF:BANDWIDTH=256000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
281 mid/video-audio.m3u8\n\
282 #EXT-X-STREAM-INF:BANDWIDTH=768000,CODECS=\"avc1.42001f, mp4a.40.5\",SUBTITLES=\"subs\"\n\
283 hi/video-audio.m3u8";
284 #endif
285 
286 static const gchar *AES_128_ENCRYPTED_PLAYLIST = "#EXTM3U \n\
287 #EXT-X-TARGETDURATION:10\n\
288 #EXTINF:10,Test\n\
289 http://media.example.com/mid/video-only-001.ts\n\
290 #EXT-X-KEY:METHOD=NONE\n\
291 #EXTINF:10,Test\n\
292 http://media.example.com/mid/video-only-002.ts\n\
293 #EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.bin\"\n\
294 #EXTINF:10,Test\n\
295 http://media.example.com/mid/video-only-003.ts\n\
296 #EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key2.bin\",IV=0x00000000000000000000000000000001\n\
297 #EXTINF:10,Test\n\
298 http://media.example.com/mid/video-only-004.ts\n\
299 #EXTINF:10,Test\n\
300 http://media.example.com/mid/video-only-005.ts\n\
301 #EXT-X-ENDLIST";
302 
303 static const gchar *WINDOWS_LINE_ENDINGS_PLAYLIST = "#EXTM3U \r\n\
304 #EXT-X-TARGETDURATION:10\r\n\
305 #EXTINF:10,Test\r\n\
306 http://media.example.com/001.ts\r\n\
307 #EXTINF:10,Test\r\n\
308 http://media.example.com/002.ts\r\n\
309 #EXTINF:10,Test\r\n\
310 http://media.example.com/003.ts\r\n\
311 #EXTINF:10,Test\r\n\
312 http://media.example.com/004.ts\r\n\
313 #EXT-X-ENDLIST";
314 
315 static const gchar *WINDOWS_LINE_ENDINGS_VARIANT_PLAYLIST = "#EXTM3U \r\n\
316 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=128000\r\n\
317 http://example.com/low.m3u8\r\n\
318 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000\r\n\
319 http://example.com/mid.m3u8\r\n\
320 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=768000\r\n\
321 http://example.com/hi.m3u8\r\n\
322 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\r\n\
323 http://example.com/audio-only.m3u8";
324 
325 static GstHLSMasterPlaylist *
load_playlist(const gchar * data)326 load_playlist (const gchar * data)
327 {
328   GstHLSMasterPlaylist *master;
329 
330   master = gst_hls_master_playlist_new_from_data (g_strdup (data),
331       "http://localhost/test.m3u8");
332   fail_unless (master != NULL);
333 
334   return master;
335 }
336 
GST_START_TEST(test_load_main_playlist_invalid)337 GST_START_TEST (test_load_main_playlist_invalid)
338 {
339   GstHLSMasterPlaylist *master;
340 
341   master =
342       gst_hls_master_playlist_new_from_data (g_strdup (INVALID_PLAYLIST), NULL);
343   fail_unless (master == NULL);
344 }
345 
346 GST_END_TEST;
347 
GST_START_TEST(test_load_main_playlist_rendition)348 GST_START_TEST (test_load_main_playlist_rendition)
349 {
350   GstHLSMasterPlaylist *master;
351   GstHLSVariantStream *variant;
352 
353   master = load_playlist (ON_DEMAND_PLAYLIST);
354   variant = master->default_variant;
355 
356   assert_equals_int (g_list_length (variant->m3u8->files), 4);
357   assert_equals_int (master->version, 0);
358 
359   gst_hls_master_playlist_unref (master);
360 }
361 
362 GST_END_TEST;
363 
364 static void
do_test_load_main_playlist_variant(const gchar * playlist)365 do_test_load_main_playlist_variant (const gchar * playlist)
366 {
367   GstHLSMasterPlaylist *master;
368   GstHLSVariantStream *stream;
369   GList *tmp;
370 
371   master = gst_hls_master_playlist_new_from_data (g_strdup (playlist), NULL);
372   fail_unless (master != NULL);
373 
374   assert_equals_int (g_list_length (master->variants), 4);
375 
376   /* Audio-Only */
377   tmp = g_list_first (master->variants);
378   stream = tmp->data;
379   assert_equals_int (stream->bandwidth, 65000);
380   assert_equals_int (stream->program_id, 1);
381   assert_equals_string (stream->uri, "http://example.com/audio-only.m3u8");
382   assert_equals_string (stream->codecs, "mp4a.40.5");
383 
384   /* Low */
385   tmp = g_list_next (tmp);
386   stream = tmp->data;
387   assert_equals_int (stream->bandwidth, 128000);
388   assert_equals_int (stream->program_id, 1);
389   assert_equals_string (stream->uri, "http://example.com/low.m3u8");
390 
391   /* Mid */
392   tmp = g_list_next (tmp);
393   stream = tmp->data;
394   assert_equals_int (stream->bandwidth, 256000);
395   assert_equals_int (stream->program_id, 1);
396   assert_equals_string (stream->uri, "http://example.com/mid.m3u8");
397 
398   /* High */
399   tmp = g_list_next (tmp);
400   stream = tmp->data;
401   assert_equals_int (stream->bandwidth, 768000);
402   assert_equals_int (stream->program_id, 1);
403   assert_equals_string (stream->uri, "http://example.com/hi.m3u8");
404 
405   /* Check the first playlist is selected */
406   assert_equals_int (master->default_variant != NULL, TRUE);
407   assert_equals_int (master->default_variant->bandwidth, 128000);
408 
409   gst_hls_master_playlist_unref (master);
410 }
411 
GST_START_TEST(test_load_main_playlist_variant)412 GST_START_TEST (test_load_main_playlist_variant)
413 {
414   do_test_load_main_playlist_variant (VARIANT_PLAYLIST);
415 }
416 
417 GST_END_TEST;
418 
GST_START_TEST(test_load_main_playlist_variant_with_missing_uri)419 GST_START_TEST (test_load_main_playlist_variant_with_missing_uri)
420 {
421   GstHLSMasterPlaylist *master;
422 
423   master = load_playlist (VARIANT_PLAYLIST_WITH_URI_MISSING);
424   assert_equals_int (g_list_length (master->variants), 3);
425   gst_hls_master_playlist_unref (master);
426 }
427 
428 GST_END_TEST;
429 
GST_START_TEST(test_load_windows_line_endings_variant_playlist)430 GST_START_TEST (test_load_windows_line_endings_variant_playlist)
431 {
432   do_test_load_main_playlist_variant (WINDOWS_LINE_ENDINGS_VARIANT_PLAYLIST);
433 }
434 
435 GST_END_TEST;
436 
GST_START_TEST(test_load_main_playlist_with_empty_lines)437 GST_START_TEST (test_load_main_playlist_with_empty_lines)
438 {
439   do_test_load_main_playlist_variant (EMPTY_LINES_VARIANT_PLAYLIST);
440 }
441 
442 GST_END_TEST;
443 
GST_START_TEST(test_load_windows_main_playlist_with_empty_lines)444 GST_START_TEST (test_load_windows_main_playlist_with_empty_lines)
445 {
446   do_test_load_main_playlist_variant (WINDOWS_EMPTY_LINES_VARIANT_PLAYLIST);
447 }
448 
449 GST_END_TEST;
450 
451 static void
check_on_demand_playlist(const gchar * data)452 check_on_demand_playlist (const gchar * data)
453 {
454   GstHLSMasterPlaylist *master;
455   GstM3U8 *pl;
456   GstM3U8MediaFile *file;
457 
458   master = load_playlist (data);
459   pl = master->default_variant->m3u8;
460 
461   /* Sequence should be 0 as it's an ondemand playlist */
462   assert_equals_int (pl->sequence, 0);
463   /* Check that we are not live */
464   assert_equals_int (gst_m3u8_is_live (pl), FALSE);
465   /* Check number of entries */
466   assert_equals_int (g_list_length (pl->files), 4);
467   /* Check first media segments */
468   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
469   assert_equals_string (file->uri, "http://media.example.com/001.ts");
470   assert_equals_int (file->sequence, 0);
471   /* Check last media segments */
472   file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
473   assert_equals_string (file->uri, "http://media.example.com/004.ts");
474   assert_equals_int (file->sequence, 3);
475 
476   gst_hls_master_playlist_unref (master);
477 }
478 
GST_START_TEST(test_on_demand_playlist)479 GST_START_TEST (test_on_demand_playlist)
480 {
481   check_on_demand_playlist (ON_DEMAND_PLAYLIST);
482 }
483 
484 GST_END_TEST;
485 
GST_START_TEST(test_windows_line_endings_playlist)486 GST_START_TEST (test_windows_line_endings_playlist)
487 {
488   check_on_demand_playlist (WINDOWS_LINE_ENDINGS_PLAYLIST);
489 }
490 
491 GST_END_TEST;
492 
GST_START_TEST(test_empty_lines_playlist)493 GST_START_TEST (test_empty_lines_playlist)
494 {
495   check_on_demand_playlist (EMPTY_LINES_PLAYLIST);
496 }
497 
498 GST_END_TEST;
499 
GST_START_TEST(test_windows_empty_lines_playlist)500 GST_START_TEST (test_windows_empty_lines_playlist)
501 {
502   check_on_demand_playlist (WINDOWS_EMPTY_LINES_PLAYLIST);
503 }
504 
505 GST_END_TEST;
506 
GST_START_TEST(test_live_playlist)507 GST_START_TEST (test_live_playlist)
508 {
509   GstHLSMasterPlaylist *master;
510   GstM3U8 *pl;
511   GstM3U8MediaFile *file;
512   gint64 start = -1;
513   gint64 stop = -1;
514 
515   master = load_playlist (LIVE_PLAYLIST);
516 
517   pl = master->default_variant->m3u8;
518   /* Check that we are live */
519   assert_equals_int (gst_m3u8_is_live (pl), TRUE);
520   assert_equals_int (pl->sequence, 2680);
521   /* Check number of entries */
522   assert_equals_int (g_list_length (pl->files), 4);
523   /* Check first media segments */
524   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
525   assert_equals_string (file->uri,
526       "https://priv.example.com/fileSequence2680.ts");
527   assert_equals_int (file->sequence, 2680);
528   /* Check last media segments */
529   file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
530   assert_equals_string (file->uri,
531       "https://priv.example.com/fileSequence2683.ts");
532   assert_equals_int (file->sequence, 2683);
533   fail_unless (gst_m3u8_get_seek_range (pl, &start, &stop));
534   assert_equals_int64 (start, 0);
535   assert_equals_float (stop / (double) GST_SECOND, 8.0);
536 
537   gst_hls_master_playlist_unref (master);
538 }
539 
540 GST_END_TEST;
541 
542 /* This test is for live sreams in which we pause the stream for more than the
543  * DVR window and we resume playback. The playlist has rotated completely and
544  * there is a jump in the media sequence that must be handled correctly. */
GST_START_TEST(test_live_playlist_rotated)545 GST_START_TEST (test_live_playlist_rotated)
546 {
547   GstHLSMasterPlaylist *master;
548   GstM3U8 *pl;
549   GstM3U8MediaFile *file;
550   gboolean ret;
551 
552   master = load_playlist (LIVE_PLAYLIST);
553   pl = master->default_variant->m3u8;
554 
555   assert_equals_int (pl->sequence, 2680);
556   /* Check first media segments */
557   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
558   assert_equals_int (file->sequence, 2680);
559 
560   ret = gst_m3u8_update (pl, g_strdup (LIVE_ROTATED_PLAYLIST));
561   assert_equals_int (ret, TRUE);
562   file = gst_m3u8_get_next_fragment (pl, TRUE, NULL, NULL);
563   fail_unless (file != NULL);
564   gst_m3u8_media_file_unref (file);
565 
566   /* FIXME: Sequence should last - 3. Should it? */
567   assert_equals_int (pl->sequence, 3001);
568   /* Check first media segments */
569   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
570   assert_equals_int (file->sequence, 3001);
571 
572   gst_hls_master_playlist_unref (master);
573 }
574 
575 GST_END_TEST;
576 
GST_START_TEST(test_playlist_with_doubles_duration)577 GST_START_TEST (test_playlist_with_doubles_duration)
578 {
579   GstHLSMasterPlaylist *master;
580   GstM3U8 *pl;
581   GstM3U8MediaFile *file;
582   gint64 start = -1;
583   gint64 stop = -1;
584 
585   master = load_playlist (DOUBLES_PLAYLIST);
586   pl = master->default_variant->m3u8;
587 
588   /* Check first media segments */
589   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 0));
590   assert_equals_float (file->duration / (double) GST_SECOND, 10.321);
591   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 1));
592   assert_equals_float (file->duration / (double) GST_SECOND, 9.6789);
593   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 2));
594   assert_equals_float (file->duration / (double) GST_SECOND, 10.2344);
595   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 3));
596   assert_equals_float (file->duration / (double) GST_SECOND, 9.92);
597   fail_unless (gst_m3u8_get_seek_range (pl, &start, &stop));
598   assert_equals_int64 (start, 0);
599   assert_equals_float (stop / (double) GST_SECOND,
600       10.321 + 9.6789 + 10.2344 + 9.92);
601 
602   gst_hls_master_playlist_unref (master);
603 }
604 
605 GST_END_TEST;
606 
GST_START_TEST(test_playlist_with_encryption)607 GST_START_TEST (test_playlist_with_encryption)
608 {
609   GstHLSMasterPlaylist *master;
610   GstM3U8 *pl;
611   GstM3U8MediaFile *file;
612   guint8 iv1[16] = { 0, };
613   guint8 iv2[16] = { 0, };
614 
615   iv1[15] = 1;
616   iv2[15] = 2;
617 
618   master = load_playlist (AES_128_ENCRYPTED_PLAYLIST);
619   pl = master->default_variant->m3u8;
620 
621   assert_equals_int (g_list_length (pl->files), 5);
622 
623   /* Check all media segments */
624   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 0));
625   fail_unless (file->key == NULL);
626 
627   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 1));
628   fail_unless (file->key == NULL);
629 
630   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 2));
631   fail_unless (file->key != NULL);
632   assert_equals_string (file->key, "https://priv.example.com/key.bin");
633   fail_unless (memcmp (&file->iv, iv2, 16) == 0);
634 
635   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 3));
636   fail_unless (file->key != NULL);
637   assert_equals_string (file->key, "https://priv.example.com/key2.bin");
638   fail_unless (memcmp (&file->iv, iv1, 16) == 0);
639 
640   file = GST_M3U8_MEDIA_FILE (g_list_nth_data (pl->files, 4));
641   fail_unless (file->key != NULL);
642   assert_equals_string (file->key, "https://priv.example.com/key2.bin");
643   fail_unless (memcmp (&file->iv, iv1, 16) == 0);
644 
645   gst_hls_master_playlist_unref (master);
646 }
647 
648 GST_END_TEST;
649 
650 
GST_START_TEST(test_update_invalid_playlist)651 GST_START_TEST (test_update_invalid_playlist)
652 {
653   GstHLSMasterPlaylist *master;
654   GstM3U8 *pl;
655   gboolean ret;
656 
657   /* Test updates in on-demand playlists */
658   master = load_playlist (ON_DEMAND_PLAYLIST);
659   pl = master->default_variant->m3u8;
660   assert_equals_int (g_list_length (pl->files), 4);
661   ret = gst_m3u8_update (pl, g_strdup ("#INVALID"));
662   assert_equals_int (ret, FALSE);
663 
664   gst_hls_master_playlist_unref (master);
665 }
666 
667 GST_END_TEST;
668 
GST_START_TEST(test_update_playlist)669 GST_START_TEST (test_update_playlist)
670 {
671   GstHLSMasterPlaylist *master;
672   GstM3U8 *pl;
673   gchar *live_pl;
674   gboolean ret;
675 
676   /* Test updates in on-demand playlists */
677   master = load_playlist (ON_DEMAND_PLAYLIST);
678   pl = master->default_variant->m3u8;
679   assert_equals_int (g_list_length (pl->files), 4);
680   ret = gst_m3u8_update (pl, g_strdup (ON_DEMAND_PLAYLIST));
681   assert_equals_int (ret, TRUE);
682   assert_equals_int (g_list_length (pl->files), 4);
683   gst_hls_master_playlist_unref (master);
684 
685   /* Test updates in live playlists */
686   master = load_playlist (LIVE_PLAYLIST);
687   pl = master->default_variant->m3u8;
688   assert_equals_int (g_list_length (pl->files), 4);
689   /* Add a new entry to the playlist and check the update */
690   live_pl = g_strdup_printf ("%s\n%s\n%s", LIVE_PLAYLIST, "#EXTINF:8",
691       "https://priv.example.com/fileSequence2683.ts");
692   ret = gst_m3u8_update (pl, live_pl);
693   assert_equals_int (ret, TRUE);
694   assert_equals_int (g_list_length (pl->files), 5);
695   /* Test sliding window */
696   ret = gst_m3u8_update (pl, g_strdup (LIVE_PLAYLIST));
697   assert_equals_int (ret, TRUE);
698   assert_equals_int (g_list_length (pl->files), 4);
699   gst_hls_master_playlist_unref (master);
700 }
701 
702 GST_END_TEST;
703 
GST_START_TEST(test_playlist_media_files)704 GST_START_TEST (test_playlist_media_files)
705 {
706   GstHLSMasterPlaylist *master;
707   GstM3U8 *pl;
708   GstM3U8MediaFile *file;
709 
710   master = load_playlist (ON_DEMAND_PLAYLIST);
711   pl = master->default_variant->m3u8;
712 
713   /* Check number of entries */
714   assert_equals_int (g_list_length (pl->files), 4);
715   /* Check first media segments */
716   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
717   assert_equals_string (file->uri, "http://media.example.com/001.ts");
718   assert_equals_int (file->sequence, 0);
719   assert_equals_float (file->duration, 10 * (double) GST_SECOND);
720   assert_equals_int (file->offset, 0);
721   assert_equals_int (file->size, -1);
722   assert_equals_string (file->title, "Test");
723 
724   gst_hls_master_playlist_unref (master);
725 }
726 
727 GST_END_TEST;
728 
GST_START_TEST(test_playlist_byte_range_media_files)729 GST_START_TEST (test_playlist_byte_range_media_files)
730 {
731   GstHLSMasterPlaylist *master;
732   GstM3U8 *pl;
733   GstM3U8MediaFile *file;
734 
735   master = load_playlist (BYTE_RANGES_PLAYLIST);
736   pl = master->default_variant->m3u8;
737 
738   /* Check number of entries */
739   assert_equals_int (g_list_length (pl->files), 4);
740   /* Check first media segments */
741   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
742   assert_equals_string (file->uri, "http://media.example.com/all.ts");
743   assert_equals_int (file->sequence, 0);
744   assert_equals_float (file->duration, 10 * (double) GST_SECOND);
745   assert_equals_int (file->offset, 100);
746   assert_equals_int (file->size, 1000);
747   /* Check last media segments */
748   file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
749   assert_equals_string (file->uri, "http://media.example.com/all.ts");
750   assert_equals_int (file->sequence, 3);
751   assert_equals_float (file->duration, 10 * (double) GST_SECOND);
752   assert_equals_int (file->offset, 3000);
753   assert_equals_int (file->size, 1000);
754 
755   gst_hls_master_playlist_unref (master);
756 
757 
758   master = load_playlist (BYTE_RANGES_ACC_OFFSET_PLAYLIST);
759   pl = master->default_variant->m3u8;
760 
761   /* Check number of entries */
762   assert_equals_int (g_list_length (pl->files), 4);
763   /* Check first media segments */
764   file = GST_M3U8_MEDIA_FILE (g_list_first (pl->files)->data);
765   assert_equals_string (file->uri, "http://media.example.com/all.ts");
766   assert_equals_int (file->sequence, 0);
767   assert_equals_float (file->duration, 10 * (double) GST_SECOND);
768   assert_equals_int (file->offset, 0);
769   assert_equals_int (file->size, 1000);
770   /* Check last media segments */
771   file = GST_M3U8_MEDIA_FILE (g_list_last (pl->files)->data);
772   assert_equals_string (file->uri, "http://media.example.com/all.ts");
773   assert_equals_int (file->sequence, 3);
774   assert_equals_float (file->duration, 10 * (double) GST_SECOND);
775   assert_equals_int (file->offset, 3000);
776   assert_equals_int (file->size, 1000);
777 
778   gst_hls_master_playlist_unref (master);
779 }
780 
781 GST_END_TEST;
782 
GST_START_TEST(test_get_next_fragment)783 GST_START_TEST (test_get_next_fragment)
784 {
785   GstHLSMasterPlaylist *master;
786   GstM3U8 *pl;
787   GstM3U8MediaFile *mf;
788   gboolean discontinous;
789   GstClockTime timestamp;
790 
791   master = load_playlist (BYTE_RANGES_PLAYLIST);
792   pl = master->default_variant->m3u8;
793 
794   /* Check the next fragment */
795   mf = gst_m3u8_get_next_fragment (pl, TRUE, &timestamp, &discontinous);
796   fail_unless (mf != NULL);
797   assert_equals_int (discontinous, FALSE);
798   assert_equals_string (mf->uri, "http://media.example.com/all.ts");
799   assert_equals_uint64 (timestamp, 0);
800   assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
801   assert_equals_uint64 (mf->offset, 100);
802   assert_equals_uint64 (mf->offset + mf->size, 1100);
803   gst_m3u8_media_file_unref (mf);
804 
805   gst_m3u8_advance_fragment (pl, TRUE);
806 
807   /* Check next media segments */
808   mf = gst_m3u8_get_next_fragment (pl, TRUE, &timestamp, &discontinous);
809   fail_unless (mf != NULL);
810   assert_equals_int (discontinous, FALSE);
811   assert_equals_string (mf->uri, "http://media.example.com/all.ts");
812   assert_equals_uint64 (timestamp, 10 * GST_SECOND);
813   assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
814   assert_equals_uint64 (mf->offset, 1000);
815   assert_equals_uint64 (mf->offset + mf->size, 2000);
816   gst_m3u8_media_file_unref (mf);
817 
818   gst_m3u8_advance_fragment (pl, TRUE);
819 
820   /* Check next media segments */
821   mf = gst_m3u8_get_next_fragment (pl, TRUE, &timestamp, &discontinous);
822   assert_equals_int (discontinous, FALSE);
823   assert_equals_string (mf->uri, "http://media.example.com/all.ts");
824   assert_equals_uint64 (timestamp, 20 * GST_SECOND);
825   assert_equals_uint64 (mf->duration, 10 * GST_SECOND);
826   assert_equals_uint64 (mf->offset, 2000);
827   assert_equals_uint64 (mf->offset + mf->size, 3000);
828   gst_m3u8_media_file_unref (mf);
829 
830   gst_hls_master_playlist_unref (master);
831 }
832 
833 GST_END_TEST;
834 
GST_START_TEST(test_get_duration)835 GST_START_TEST (test_get_duration)
836 {
837   GstHLSMasterPlaylist *master;
838   GstM3U8 *pl;
839 
840   /* Test duration for on-demand playlists */
841   master = load_playlist (ON_DEMAND_PLAYLIST);
842   pl = master->default_variant->m3u8;
843 
844   assert_equals_uint64 (gst_m3u8_get_duration (pl), 40 * GST_SECOND);
845   gst_hls_master_playlist_unref (master);
846 
847   /* Test duration for live playlists */
848   master = load_playlist (LIVE_PLAYLIST);
849   pl = master->default_variant->m3u8;
850   assert_equals_uint64 (gst_m3u8_get_duration (pl), GST_CLOCK_TIME_NONE);
851 
852   gst_hls_master_playlist_unref (master);
853 }
854 
855 GST_END_TEST;
856 
GST_START_TEST(test_get_target_duration)857 GST_START_TEST (test_get_target_duration)
858 {
859   GstHLSMasterPlaylist *master;
860   GstM3U8 *pl;
861 
862   master = load_playlist (ON_DEMAND_PLAYLIST);
863   pl = master->default_variant->m3u8;
864 
865   assert_equals_uint64 (gst_m3u8_get_target_duration (pl), 10 * GST_SECOND);
866 
867   gst_hls_master_playlist_unref (master);
868 }
869 
870 GST_END_TEST;
871 
872 
GST_START_TEST(test_get_stream_for_bitrate)873 GST_START_TEST (test_get_stream_for_bitrate)
874 {
875   GstHLSMasterPlaylist *master;
876   GstHLSVariantStream *stream;
877 
878   master = load_playlist (VARIANT_PLAYLIST);
879   stream = gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 0);
880 
881   assert_equals_int (stream->bandwidth, 65000);
882 
883   stream =
884       gst_hls_master_playlist_get_variant_for_bitrate (master, NULL,
885       G_MAXINT32);
886   assert_equals_int (stream->bandwidth, 768000);
887   stream =
888       gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 300000);
889   assert_equals_int (stream->bandwidth, 256000);
890   stream =
891       gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 500000);
892   assert_equals_int (stream->bandwidth, 256000);
893   stream =
894       gst_hls_master_playlist_get_variant_for_bitrate (master, NULL, 255000);
895   assert_equals_int (stream->bandwidth, 128000);
896 
897   gst_hls_master_playlist_unref (master);
898 }
899 
900 GST_END_TEST;
901 
902 #if 0
903 static void
904 do_test_seek (GstM3U8Client * client, guint seek_pos, gint pos)
905 {
906   GstClockTime cur_pos;
907   gboolean ret;
908 
909   ret = gst_m3u8_client_seek (client, seek_pos * GST_SECOND);
910   if (pos == -1) {
911     assert_equals_int (ret, FALSE);
912     return;
913   }
914   assert_equals_int (ret, TRUE);
915   gst_m3u8_client_get_current_position (client, &cur_pos, NULL);
916   assert_equals_uint64 (cur_pos, pos * GST_SECOND);
917 }
918 
919 GST_START_TEST (test_seek)
920 {
921   GstM3U8Client *client;
922 
923   master = load_playlist (ON_DEMAND_PLAYLIST);
924 
925   /* Test seek in the middle of a fragment */
926   do_test_seek (client, 1, 0);
927   do_test_seek (client, 11, 10);
928   do_test_seek (client, 22, 20);
929   do_test_seek (client, 39, 30);
930 
931   /* Test exact seeks */
932   do_test_seek (client, 0, 0);
933   do_test_seek (client, 10, 10);
934   do_test_seek (client, 20, 20);
935   do_test_seek (client, 30, 30);
936 
937   /* Test invalid seeks (end if list should be 30 + 10) */
938   do_test_seek (client, 39, 30);
939   do_test_seek (client, 40, -1);
940   gst_hls_master_playlist_unref (master);
941 
942   /* Test seeks on a live playlist */
943   master = load_playlist (LIVE_PLAYLIST);
944   do_test_seek (client, 0, 0);
945 
946   do_test_seek (client, 8, 8);
947   do_test_seek (client, 20, 16);
948   do_test_seek (client, 30, 24);
949 
950   do_test_seek (client, 3000, -1);
951   gst_hls_master_playlist_unref (master);
952 }
953 
954 GST_END_TEST;
955 
956 GST_START_TEST (test_alternate_audio_playlist)
957 {
958   GstM3U8Client *client;
959   GstM3U8Media *media;
960   GList *alternates;
961 
962   master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
963 
964   assert_equals_int (g_list_length (client->main->streams), 4);
965   assert_equals_int (g_hash_table_size (client->main->video_rendition_groups),
966       0);
967   assert_equals_int (g_hash_table_size (client->main->audio_rendition_groups),
968       1);
969   assert_equals_int (g_hash_table_size (client->
970           selected_stream->audio_alternates), 3);
971   assert_equals_int (g_hash_table_size (client->
972           selected_stream->video_alternates), 0);
973 
974   alternates =
975       g_hash_table_lookup (client->main->audio_rendition_groups, "aac");
976   assert_equals_int (alternates != NULL, TRUE);
977   media = GST_M3U8_MEDIA (g_list_nth_data (alternates, 0));
978   assert_equals_int (media->media_type, GST_M3U8_MEDIA_TYPE_AUDIO);
979   assert_equals_string (media->group_id, "aac");
980   assert_equals_string (media->name, "English");
981   assert_equals_string (media->language, "en");
982   assert_equals_string (media->uri, "http://localhost/main/english-audio.m3u8");
983   assert_equals_string (media->uri, GST_M3U8 (media->playlist)->uri);
984   assert_equals_int (media->is_default, TRUE);
985   assert_equals_int (media->autoselect, TRUE);
986 
987   assert_equals_int (g_hash_table_size (client->
988           selected_stream->audio_alternates), 3);
989   /* Check the list of audio alternates */
990   alternates = gst_m3u8_client_get_alternates (client,
991       GST_M3U8_MEDIA_TYPE_AUDIO);
992   assert_equals_int (g_list_length (alternates), 3);
993   /* Default comes always first */
994   assert_equals_string (g_list_nth_data (alternates, 0), "English");
995   assert_equals_string (g_list_nth_data (alternates, 1), "Commentary");
996   assert_equals_string (g_list_nth_data (alternates, 2), "Deutsche");
997 
998   gst_hls_master_playlist_unref (master);
999 }
1000 
1001 GST_END_TEST;
1002 
1003 GST_START_TEST (test_subtitles_playlist)
1004 {
1005   GstM3U8Client *client;
1006   GstM3U8Media *media;
1007   GList *alternates;
1008 
1009   master = load_playlist (SUBTITLES_PLAYLIST);
1010 
1011   assert_equals_int (g_list_length (client->main->streams), 3);
1012   assert_equals_int (g_hash_table_size (client->main->video_rendition_groups),
1013       0);
1014   assert_equals_int (g_hash_table_size (client->main->audio_rendition_groups),
1015       0);
1016   assert_equals_int (g_hash_table_size (client->main->subtt_rendition_groups),
1017       1);
1018   assert_equals_int (g_hash_table_size (client->
1019           selected_stream->audio_alternates), 0);
1020   assert_equals_int (g_hash_table_size (client->
1021           selected_stream->video_alternates), 0);
1022   assert_equals_int (g_hash_table_size (client->
1023           selected_stream->subtt_alternates), 3);
1024 
1025   alternates =
1026       g_hash_table_lookup (client->main->subtt_rendition_groups, "subs");
1027   assert_equals_int (alternates != NULL, TRUE);
1028   media = GST_M3U8_MEDIA (g_list_nth_data (alternates, 0));
1029   assert_equals_int (media->media_type, GST_M3U8_MEDIA_TYPE_SUBTITLES);
1030   assert_equals_string (media->group_id, "subs");
1031   assert_equals_string (media->name, "English");
1032   assert_equals_string (media->language, "en");
1033   assert_equals_string (media->uri, "http://localhost/main/subs-en.m3u8");
1034   assert_equals_string (media->uri, GST_M3U8 (media->playlist)->uri);
1035   assert_equals_int (media->is_default, TRUE);
1036   assert_equals_int (media->autoselect, FALSE);
1037 
1038   /* Check the list of subtitles */
1039   alternates = gst_m3u8_client_get_alternates (client,
1040       GST_M3U8_MEDIA_TYPE_SUBTITLES);
1041   assert_equals_int (g_list_length (alternates), 3);
1042   assert_equals_string (g_list_nth_data (alternates, 0), "Deutsche");
1043   assert_equals_string (g_list_nth_data (alternates, 1), "Spanish");
1044   assert_equals_string (g_list_nth_data (alternates, 2), "English");
1045 
1046   gst_hls_master_playlist_unref (master);
1047 }
1048 
1049 GST_END_TEST;
1050 GST_START_TEST (test_select_subs_alternate)
1051 {
1052   GstM3U8Client *client;
1053   const gchar *a_uri, *v_uri, *s_uri;
1054   gboolean ret;
1055 
1056   /* Check with a playlist with alternative audio renditions where the video
1057    * stream is video-only and therefor we always have 2 playlists, one for
1058    * video and another one for audio */
1059   master = load_playlist (SUBTITLES_PLAYLIST);
1060   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1061   assert_equals_int (a_uri == NULL, TRUE);
1062   assert_equals_int (s_uri != NULL, TRUE);
1063   assert_equals_string (s_uri, "http://localhost/main/subs-de.m3u8");
1064   assert_equals_int (v_uri != NULL, TRUE);
1065   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1066 
1067   ret =
1068       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1069       "English");
1070   assert_equals_int (ret, TRUE);
1071   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1072   assert_equals_int (a_uri == NULL, TRUE);
1073   assert_equals_int (v_uri != NULL, TRUE);
1074   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1075   assert_equals_int (s_uri != NULL, TRUE);
1076   assert_equals_string (s_uri, "http://localhost/main/subs-en.m3u8");
1077 
1078   ret =
1079       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1080       "Spanish");
1081   assert_equals_int (ret, TRUE);
1082   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1083   assert_equals_int (a_uri == NULL, TRUE);
1084   assert_equals_int (v_uri != NULL, TRUE);
1085   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1086   assert_equals_int (s_uri != NULL, TRUE);
1087   assert_equals_string (s_uri, "http://localhost/main/subs-es.m3u8");
1088 
1089   ret =
1090       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_SUBTITLES,
1091       NULL);
1092   assert_equals_int (ret, TRUE);
1093   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1094   assert_equals_int (a_uri == NULL, TRUE);
1095   assert_equals_int (v_uri != NULL, TRUE);
1096   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1097   assert_equals_int (s_uri == NULL, TRUE);
1098 
1099   gst_hls_master_playlist_unref (master);
1100 }
1101 
1102 GST_END_TEST;
1103 GST_START_TEST (test_select_alternate)
1104 {
1105   GstM3U8Client *client;
1106   const gchar *a_uri, *v_uri, *s_uri;
1107   gboolean ret;
1108 
1109   /* Check with a playlist with alternative audio renditions where the video
1110    * stream is video-only and therefor we always have 2 playlists, one for
1111    * video and another one for audio */
1112   master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
1113   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1114   assert_equals_int (a_uri != NULL, TRUE);
1115   assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1116   assert_equals_int (v_uri != NULL, TRUE);
1117   assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1118   assert_equals_int (s_uri == NULL, TRUE);
1119 
1120   ret =
1121       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1122       "Deutsche");
1123   assert_equals_int (ret, TRUE);
1124   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1125   assert_equals_int (a_uri != NULL, TRUE);
1126   assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1127   assert_equals_int (v_uri != NULL, TRUE);
1128   assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1129   assert_equals_int (s_uri == NULL, TRUE);
1130 
1131   /* Check that selecting the audio-only fallback stream we only have the audio
1132    * uri */
1133   gst_m3u8_client_set_current (client,
1134       GST_M3U8_STREAM (client->main->streams->data));
1135   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1136   assert_equals_int (a_uri != NULL, TRUE);
1137   assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1138   assert_equals_int (v_uri == NULL, TRUE);
1139   assert_equals_int (s_uri == NULL, TRUE);
1140 
1141   gst_hls_master_playlist_unref (master);
1142 
1143   /* Now check with a playlist with alternative audio renditions where the
1144    * video * stream has the default audio rendition muxed and therefore we
1145    * only have 2 playlists when the audio alternative rendition is not the
1146    * default one */
1147   master = load_playlist (ALT_AUDIO_PLAYLIST_WITH_VIDEO_AUDIO);
1148   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1149   assert_equals_int (a_uri == NULL, TRUE);
1150   assert_equals_int (v_uri != NULL, TRUE);
1151   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1152   assert_equals_int (s_uri == NULL, TRUE);
1153 
1154   /* Check that selecting the audio-only fallback stream we only have the audio
1155    * uri */
1156   gst_m3u8_client_set_current (client,
1157       GST_M3U8_STREAM (client->main->streams->data));
1158   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1159   assert_equals_int (a_uri != NULL, TRUE);
1160   assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1161   assert_equals_int (v_uri == NULL, TRUE);
1162   assert_equals_int (s_uri == NULL, TRUE);
1163 
1164   /* Get back to the audio-video stream */
1165   gst_m3u8_client_set_current (client,
1166       GST_M3U8_STREAM (client->main->streams->next->data));
1167   /* Now set a different audio and check that we have 2 playlists */
1168   ret =
1169       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1170       "Deutsche");
1171   assert_equals_int (ret, TRUE);
1172   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1173   assert_equals_int (a_uri != NULL, TRUE);
1174   assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1175   assert_equals_int (v_uri != NULL, TRUE);
1176   assert_equals_string (v_uri, "http://localhost/low/video-audio.m3u8");
1177   assert_equals_int (s_uri == NULL, TRUE);
1178 
1179   gst_hls_master_playlist_unref (master);
1180 }
1181 
1182 GST_END_TEST;
1183 
1184 GST_START_TEST (test_simulation)
1185 {
1186   GstM3U8Client *client;
1187   const gchar *a_uri, *v_uri, *s_uri;
1188   GstFragment *a_frag, *v_frag, *s_frag;
1189   gboolean ret;
1190 
1191   master = load_playlist (ALTERNATE_AUDIO_PLAYLIST);
1192   /* The default selection should be audio-only, which only has audio and not
1193    * video */
1194   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1195   assert_equals_int (a_uri != NULL, TRUE);
1196   assert_equals_string (a_uri, "http://localhost/main/english-audio.m3u8");
1197   assert_equals_int (v_uri != NULL, TRUE);
1198   assert_equals_string (v_uri, "http://localhost/low/video-only.m3u8");
1199   assert_equals_int (s_uri == NULL, TRUE);
1200 
1201   /* Update the playlists */
1202   ret = gst_m3u8_update (client,
1203       g_strdup (ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST),
1204       g_strdup (ON_DEMAND_ENGLISH_PLAYLIST), NULL);
1205   assert_equals_int (ret, TRUE);
1206   assert_equals_int (g_list_length (client->selected_stream->selected_video->
1207           files), 4);
1208   assert_equals_int (g_list_length (client->selected_stream->selected_audio->
1209           files), 4);
1210 
1211   /* Get the first fragment */
1212   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1213   assert_equals_int (v_frag != NULL, TRUE);
1214   assert_equals_int (a_frag != NULL, TRUE);
1215   assert_equals_string (v_frag->name,
1216       "http://media.example.com/low/video-only-001.ts");
1217   assert_equals_string (a_frag->name,
1218       "http://media.example.com/audio/english-001.ts");
1219   g_object_unref (v_frag);
1220   g_object_unref (a_frag);
1221 
1222   /* Get the next fragment */
1223   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1224   assert_equals_int (v_frag != NULL, TRUE);
1225   assert_equals_int (a_frag != NULL, TRUE);
1226   assert_equals_string (v_frag->name,
1227       "http://media.example.com/low/video-only-002.ts");
1228   assert_equals_string (a_frag->name,
1229       "http://media.example.com/audio/english-002.ts");
1230   g_object_unref (v_frag);
1231   g_object_unref (a_frag);
1232 
1233   /* Switch to German audio */
1234   ret =
1235       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1236       "Deutsche");
1237   assert_equals_int (ret, TRUE);
1238   /* Get the new uri's */
1239   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1240   assert_equals_int (a_uri != NULL, TRUE);
1241   assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1242   /* On demand  so the uri does not need to be downloaded again */
1243   assert_equals_int (v_uri == NULL, TRUE);
1244   assert_equals_int (s_uri == NULL, TRUE);
1245   /* Update the new uri's */
1246   ret =
1247       gst_m3u8_update (client,
1248       g_strdup (ON_DEMAND_LOW_VIDEO_ONLY_PLAYLIST),
1249       g_strdup (ON_DEMAND_GERMAN_PLAYLIST), NULL);
1250   assert_equals_int (ret, TRUE);
1251   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1252   assert_equals_int (s_frag == NULL, TRUE);
1253   assert_equals_int (v_frag != NULL, TRUE);
1254   assert_equals_int (a_frag != NULL, TRUE);
1255   assert_equals_string (a_frag->name,
1256       "http://media.example.com/audio/german-003.ts");
1257   assert_equals_string (v_frag->name,
1258       "http://media.example.com/low/video-only-003.ts");
1259   g_object_unref (v_frag);
1260   g_object_unref (a_frag);
1261 
1262   /* Switch to a higher bitrate */
1263   gst_m3u8_client_set_current (client,
1264       gst_m3u8_client_get_stream_for_bitrate (client, 260000));
1265   gst_m3u8_client_get_current_uri (client, &v_uri, &a_uri, &s_uri);
1266   assert_equals_int (a_uri != NULL, TRUE);
1267   assert_equals_string (a_uri, "http://localhost/main/german-audio.m3u8");
1268   assert_equals_int (v_uri != NULL, TRUE);
1269   assert_equals_string (v_uri, "http://localhost/mid/video-only.m3u8");
1270   assert_equals_int (s_uri == NULL, TRUE);
1271   ret =
1272       gst_m3u8_update (client,
1273       g_strdup (ON_DEMAND_MID_VIDEO_ONLY_PLAYLIST),
1274       g_strdup (ON_DEMAND_GERMAN_PLAYLIST), NULL);
1275   assert_equals_int (ret, TRUE);
1276   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1277   assert_equals_int (s_frag == NULL, TRUE);
1278   assert_equals_int (a_frag != NULL, TRUE);
1279   assert_equals_int (v_frag != NULL, TRUE);
1280   assert_equals_string (a_frag->name,
1281       "http://media.example.com/audio/german-004.ts");
1282   assert_equals_string (v_frag->name,
1283       "http://media.example.com/mid/video-only-004.ts");
1284   g_object_unref (v_frag);
1285   g_object_unref (a_frag);
1286 
1287   /* Seek to the beginning */
1288   gst_m3u8_client_seek (client, 0);
1289   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1290   assert_equals_int (s_frag == NULL, TRUE);
1291   assert_equals_int (a_frag != NULL, TRUE);
1292   assert_equals_int (v_frag != NULL, TRUE);
1293   assert_equals_string (a_frag->name,
1294       "http://media.example.com/audio/german-001.ts");
1295   assert_equals_string (v_frag->name,
1296       "http://media.example.com/mid/video-only-001.ts");
1297   g_object_unref (v_frag);
1298   g_object_unref (a_frag);
1299 
1300   /* Select English audio again */
1301   ret =
1302       gst_m3u8_client_set_alternate (client, GST_M3U8_MEDIA_TYPE_AUDIO,
1303       "English");
1304   assert_equals_int (ret, TRUE);
1305   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1306   assert_equals_int (s_frag == NULL, TRUE);
1307   assert_equals_int (a_frag != NULL, TRUE);
1308   assert_equals_int (v_frag != NULL, TRUE);
1309   assert_equals_string (a_frag->name,
1310       "http://media.example.com/audio/english-002.ts");
1311   assert_equals_string (v_frag->name,
1312       "http://media.example.com/mid/video-only-002.ts");
1313   g_object_unref (v_frag);
1314   g_object_unref (a_frag);
1315 
1316   /* Go to the audio-only fallback */
1317   gst_m3u8_client_set_current (client,
1318       gst_m3u8_client_get_stream_for_bitrate (client, 20000));
1319   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1320   assert_equals_int (s_frag == NULL, TRUE);
1321   assert_equals_int (a_frag != NULL, TRUE);
1322   assert_equals_int (v_frag == NULL, TRUE);
1323   assert_equals_string (a_frag->name,
1324       "http://media.example.com/audio/english-003.ts");
1325   g_object_unref (a_frag);
1326 
1327   /* Go to mid again */
1328   gst_m3u8_client_set_current (client,
1329       gst_m3u8_client_get_stream_for_bitrate (client, 260000));
1330   gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1331   assert_equals_int (s_frag == NULL, TRUE);
1332   assert_equals_int (a_frag != NULL, TRUE);
1333   assert_equals_int (v_frag != NULL, TRUE);
1334   assert_equals_string (a_frag->name,
1335       "http://media.example.com/audio/english-004.ts");
1336   assert_equals_string (v_frag->name,
1337       "http://media.example.com/mid/video-only-004.ts");
1338   g_object_unref (a_frag);
1339   g_object_unref (v_frag);
1340 
1341   /* End of stream */
1342   ret = gst_m3u8_client_get_next_fragment (client, &v_frag, &a_frag, &s_frag);
1343   assert_equals_int (ret, FALSE);
1344 
1345   gst_hls_master_playlist_unref (master);
1346 }
1347 
1348 GST_END_TEST;
1349 #endif
1350 
GST_START_TEST(test_url_with_slash_query_param)1351 GST_START_TEST (test_url_with_slash_query_param)
1352 {
1353   static const gchar *MASTER_PLAYLIST = "#EXTM3U \n"
1354       "#EXT-X-VERSION:4\n"
1355       "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f, mp4a.40.2\", RESOLUTION=640x352\n"
1356       "1251/media.m3u8?acl=/*1054559_h264_1500k.mp4\n";
1357   GstHLSMasterPlaylist *master;
1358   GstHLSVariantStream *stream;
1359   GstM3U8 *media;
1360 
1361   master = load_playlist (MASTER_PLAYLIST);
1362 
1363   assert_equals_int (g_list_length (master->variants), 1);
1364   stream = g_list_nth_data (master->variants, 0);
1365   media = stream->m3u8;
1366 
1367   assert_equals_string (media->uri,
1368       "http://localhost/1251/media.m3u8?acl=/*1054559_h264_1500k.mp4");
1369   gst_hls_master_playlist_unref (master);
1370 }
1371 
1372 GST_END_TEST;
1373 
GST_START_TEST(test_stream_inf_tag)1374 GST_START_TEST (test_stream_inf_tag)
1375 {
1376   static const gchar *MASTER_PLAYLIST = "#EXTM3U \n"
1377       "#EXT-X-VERSION:4\n"
1378       "#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=1251135, CODECS=\"avc1.42001f, mp4a.40.2\", RESOLUTION=640x352\n"
1379       "media.m3u8\n";
1380   GstHLSMasterPlaylist *master;
1381   GstHLSVariantStream *stream;
1382 
1383   master = load_playlist (MASTER_PLAYLIST);
1384 
1385   assert_equals_int (g_list_length (master->variants), 1);
1386   stream = g_list_nth_data (master->variants, 0);
1387 
1388   assert_equals_int64 (stream->program_id, 1);
1389   assert_equals_int64 (stream->width, 640);
1390   assert_equals_int64 (stream->height, 352);
1391   assert_equals_int64 (stream->bandwidth, 1251135);
1392   assert_equals_string (stream->codecs, "avc1.42001f, mp4a.40.2");
1393   gst_hls_master_playlist_unref (master);
1394 }
1395 
1396 GST_END_TEST;
1397 
1398 static Suite *
hlsdemux_suite(void)1399 hlsdemux_suite (void)
1400 {
1401   Suite *s = suite_create ("hlsdemux_m3u8");
1402   TCase *tc_m3u8 = tcase_create ("m3u8client");
1403 
1404   GST_DEBUG_CATEGORY_INIT (hls_debug, "hlsdemux_m3u", 0, "hlsdemux m3u test");
1405 
1406   suite_add_tcase (s, tc_m3u8);
1407   tcase_add_test (tc_m3u8, test_load_main_playlist_invalid);
1408   tcase_add_test (tc_m3u8, test_load_main_playlist_rendition);
1409   tcase_add_test (tc_m3u8, test_load_main_playlist_variant);
1410   tcase_add_test (tc_m3u8, test_load_main_playlist_variant_with_missing_uri);
1411   tcase_add_test (tc_m3u8, test_load_windows_line_endings_variant_playlist);
1412   tcase_add_test (tc_m3u8, test_load_main_playlist_with_empty_lines);
1413   tcase_add_test (tc_m3u8, test_load_windows_main_playlist_with_empty_lines);
1414   tcase_add_test (tc_m3u8, test_on_demand_playlist);
1415   tcase_add_test (tc_m3u8, test_windows_line_endings_playlist);
1416   tcase_add_test (tc_m3u8, test_windows_empty_lines_playlist);
1417   tcase_add_test (tc_m3u8, test_empty_lines_playlist);
1418   tcase_add_test (tc_m3u8, test_live_playlist);
1419   tcase_add_test (tc_m3u8, test_live_playlist_rotated);
1420   tcase_add_test (tc_m3u8, test_playlist_with_doubles_duration);
1421   tcase_add_test (tc_m3u8, test_playlist_with_encryption);
1422   tcase_add_test (tc_m3u8, test_update_invalid_playlist);
1423   tcase_add_test (tc_m3u8, test_update_playlist);
1424   tcase_add_test (tc_m3u8, test_playlist_media_files);
1425   tcase_add_test (tc_m3u8, test_playlist_byte_range_media_files);
1426   tcase_add_test (tc_m3u8, test_get_next_fragment);
1427   tcase_add_test (tc_m3u8, test_get_duration);
1428   tcase_add_test (tc_m3u8, test_get_target_duration);
1429   tcase_add_test (tc_m3u8, test_get_stream_for_bitrate);
1430 #if 0
1431   tcase_add_test (tc_m3u8, test_seek);
1432   tcase_add_test (tc_m3u8, test_alternate_audio_playlist);
1433   tcase_add_test (tc_m3u8, test_subtitles_playlist);
1434   tcase_add_test (tc_m3u8, test_select_alternate);
1435   tcase_add_test (tc_m3u8, test_select_subs_alternate);
1436   tcase_add_test (tc_m3u8, test_simulation);
1437 #endif
1438   tcase_add_test (tc_m3u8, test_url_with_slash_query_param);
1439   tcase_add_test (tc_m3u8, test_stream_inf_tag);
1440   return s;
1441 }
1442 
1443 GST_CHECK_MAIN (hlsdemux);
1444