arduino-audio-tools
Loading...
Searching...
No Matches
HLSStream.h
Go to the documentation of this file.
1#pragma once
6#include "AudioToolsConfig.h"
7
8#define MAX_HLS_LINE 512
9#define START_URLS_LIMIT 4
10#define HLS_BUFFER_COUNT 2
11#define HLS_MAX_NO_READ 2
12#define HLS_MAX_URL_LEN 256
13#define HLS_TIMEOUT 4000
14#define HLS_UNDER_OVERFLOW_WAIT_TIME 10
15#define HLS_RELOAD_RETRY_DELAY 2000
16
18
19namespace audio_tools_hls {
20
35template <typename URLStream>
37 public:
38 URLLoaderHLS() = default;
39
41
42 bool begin() {
43 TRACED();
45 url_stream.httpRequest().setAgent(agent);
46
47 active = true;
48 return true;
49 }
50
51 void end() {
52 TRACED();
53 url_stream.end();
54 buffer.clear();
55 active = false;
56 }
57
59 void addUrl(const char *url) {
60 LOGI("Adding %s", url);
61 StrView url_str(url);
62 char *str = new char[url_str.length() + 1];
63 memcpy(str, url_str.c_str(), url_str.length() + 1);
64 urls.push_back((const char *)str);
65 }
66
69 int urlCount() { return urls.size(); }
70
72 int available() {
73 if (!active) return 0;
74 TRACED();
76
77 return buffer.available();
78 }
79
81 size_t readBytes(uint8_t *data, size_t len) {
82 if (!active) return 0;
83 TRACED();
85
86 if (buffer.available() < len) LOGW("Buffer underflow");
87 return buffer.readArray(data, len);
88 }
89
90 const char *contentType() {
91 return url_stream.httpRequest().reply().get(CONTENT_TYPE);
92 }
93
94 int contentLength() { return url_stream.contentLength(); }
95
96 void setBufferSize(int size, int count) {
97 buffer_size = size;
98 buffer_count = count;
99 // support call after begin()!
100 if (buffer.size() != 0) {
102 }
103 }
104
105 void setCACert(const char *cert) { url_stream.setCACert(cert); }
106
109 void setAgent(const char *agent) {
110 this->agent = agent;
111 url_stream.httpRequest().setAgent(agent);
112 }
113
114 protected:
115 Vector<const char *> urls{10};
116 RingBuffer<uint8_t> buffer{0};
117 bool active = false;
120 URLStream url_stream;
121 const char *url_to_play = nullptr;
122 const char *agent = DEFAULT_AGENT;
123
126 TRACED();
127 // we have nothing to do
128 if (urls.empty()) {
129 LOGD("urls empty");
131 return;
132 }
133 if (buffer.availableForWrite() == 0) {
134 LOGD("buffer full");
136 return;
137 }
138
139 // switch current stream if we have no more data
140 if (!url_stream && !urls.empty()) {
141 LOGD("Refilling");
142 if (url_to_play != nullptr) {
143 delete url_to_play;
144 }
145 url_to_play = urls[0];
146 LOGI("playing %s", url_to_play);
147 url_stream.end();
148 url_stream.setConnectionClose(true);
149 url_stream.setTimeout(HLS_TIMEOUT);
150 url_stream.begin(url_to_play);
151 url_stream.waitForData(HLS_TIMEOUT);
152 urls.pop_front();
153 // assert(urls[0]!=url);
154
155 LOGI("Playing %s of %d", url_stream.urlStr(), (int)urls.size());
156 }
157
158 int total = 0;
159 int failed = 0;
160 int to_write = min(buffer.availableForWrite(), DEFAULT_BUFFER_SIZE);
161 // try to keep the buffer filled
162 while (to_write > 0) {
163 uint8_t tmp[to_write];
164 memset(tmp, 0, to_write);
165 int read = url_stream.readBytes(tmp, to_write);
166 total += read;
167 if (read > 0) {
168 failed = 0;
169 buffer.writeArray(tmp, read);
170 LOGD("buffer add %d -> %d:", read, buffer.available());
171
173 } else {
174 delay(10);
175 }
176 // After we processed all data we close the stream to get a new url
177 if (url_stream.totalRead() == url_stream.contentLength()) {
178 LOGI("Closing stream because all bytes were processed: available: %d",
179 url_stream.available());
180 url_stream.end();
181 break;
182 }
183 LOGD("Refilled with %d now %d available to write", total,
185 }
186 }
187};
188
194 public:
195 bool add(const char *url) {
196 if (url == nullptr) return true;
197 bool found = false;
198 StrView url_str(url);
199 for (int j = 0; j < history.size(); j++) {
200 if (url_str.equals(history[j])) {
201 found = true;
202 break;
203 }
204 }
205 if (!found) {
206 char *str = new char[url_str.length() + 1];
207 memcpy(str, url, url_str.length() + 1);
208 history.push_back((const char *)str);
209 if (history.size() > 20) {
210 delete (history[0]);
212 }
213 }
214 return !found;
215 }
216
217 void clear() { history.clear(); }
218
219 int size() { return history.size(); }
220
221 protected:
222 Vector<const char *> history;
223};
224
230template <typename URLStream>
232 public:
233 // loads the index url
234 bool begin(const char *urlStr) {
236 return begin();
237 }
238
239 bool begin() {
240 TRACEI();
241 segments_url_str = "";
242 bandwidth = 0;
243 total_read = 0;
244 url_stream.httpRequest().setAgent(agent);
245
246 if (!parseIndex()) {
247 TRACEE();
248 return false;
249 }
250
251 // in some exceptional cases the index provided segement info
252 if (url_loader.urlCount() == 0) {
253 if (!parseSegments()) {
254 TRACEE();
255 return false;
256 }
257 } else {
260 }
261
262 if (!url_loader.begin()) {
263 TRACEE();
264 return false;
265 }
266
267 return true;
268 }
269
270 int available() {
271 TRACED();
272 int result = 0;
274
275 if (active) result = url_loader.available();
276 return result;
277 }
278
279 size_t readBytes(uint8_t *data, size_t len) {
280 TRACED();
281 size_t result = 0;
283
284 if (active) result = url_loader.readBytes(data, len);
285 total_read += result;
286 return result;
287 }
288
290 const char *indexUrl() { return index_url_str; }
291
293 const char *segmentsUrl() { return segments_url_str.c_str(); }
294
296 const char *getCodec() { return codec.c_str(); }
297
299 const char *contentType() { return url_loader.contentType(); }
300
302 int contentLength() { return url_loader.contentLength(); }
303
305 void end() {
306 TRACEI();
307 codec.clear();
308 segments_url_str.clear();
309 url_stream.end();
310 url_loader.end();
312 active = false;
313 }
314
316 void setUrlCount(int count) { url_count = count; }
317
319 void setBufferSize(int size, int count) {
320 url_loader.setBufferSize(size, count);
321 }
322
324 void setCACert(const char *cert) {
325 url_stream.setCACert(cert);
326 url_loader.setCACert(cert);
327 }
328
330 void setPowerSave(bool flag) { url_stream.setPowerSave(flag); }
331
334 void setAgent(const char *agent) {
335 this->agent = agent;
336 url_stream.httpRequest().setAgent(agent);
337 url_loader.setAgent(agent);
338 }
339
342 void setURLResolver(const char *(*cb)(const char *segment,
343 const char *reqURL)) {
344 resolve_url = cb;
345 }
346
348 const char *urlStr() { return url_str.c_str(); }
349
351 size_t totalRead() { return total_read; };
352
353 protected:
354 enum class URLType { Undefined, Index, Segment };
356 int bandwidth = 0;
357 int url_count = 5;
358 size_t total_read = 0;
359 bool url_active = false;
360 bool is_extm3u = false;
361 Str codec;
364 const char *index_url_str = nullptr;
365 const char *agent = DEFAULT_AGENT;
366 URLStream url_stream;
369 bool active = false;
374 float play_time = 0;
376 uint64_t next_retry_time = 0;
377 const char *(*resolve_url)(const char *segment,
378 const char *reqURL) = resolveURL;
379
382 static const char *resolveURL(const char *segment, const char *reqURL) {
383 // avoid dynamic memory allocation
384 static char result[HLS_MAX_URL_LEN] = {0};
385 StrView result_str(result, HLS_MAX_URL_LEN);
386 StrView index_url(reqURL);
387 // Use prefix up to ? or laast /
388 int end = index_url.lastIndexOf("?");
389 if (end >= 0) {
390 result_str.substring(reqURL, 0, end);
391 } else {
392 end = index_url.lastIndexOf("/");
393 if (end >= 0) {
394 result_str.substring(reqURL, 0, end);
395 }
396 }
397 // Use the full url
398 if (result_str.isEmpty()) {
399 result_str = reqURL;
400 }
401 // add trailing /
402 if (!result_str.endsWith("/")) {
403 result_str.add("/");
404 }
405 // add relative segment
406 result_str.add(segment);
407 LOGI(">> relative addr: %s for %s", segment, reqURL);
408 LOGD(">> -> %s", result);
409 return result;
410 }
411
414 TRACED();
415 // get new urls
416 if (!segments_url_str.isEmpty()) {
418 }
419 }
420
422 bool parseIndex() {
423 TRACED();
424 url_stream.end();
425 url_stream.setTimeout(HLS_TIMEOUT);
426 url_stream.setConnectionClose(true);
427 if (!url_stream.begin(index_url_str)) return false;
428 url_active = true;
429 return parseIndexLines();
430 }
431
434 TRACEI();
435 char tmp[MAX_HLS_LINE];
436 bool result = true;
437 is_extm3u = false;
438
439 // parse lines
440 memset(tmp, 0, MAX_HLS_LINE);
441 while (true) {
442 memset(tmp, 0, MAX_HLS_LINE);
443 size_t len =
444 url_stream.httpRequest().readBytesUntil('\n', tmp, MAX_HLS_LINE);
445 // stop when there is no more data
446 if (len == 0 && url_stream.available() == 0) break;
447 StrView str(tmp);
448
449 // check header
450 if (str.startsWith("#EXTM3U")) {
451 is_extm3u = true;
452 // reset timings
453 resetTimings();
454 }
455
456 if (is_extm3u) {
457 if (!parseIndexLine(str)) {
458 return false;
459 }
460 }
461 }
462 return result;
463 }
464
466 bool parseIndexLine(StrView &str) {
467 TRACED();
468 LOGI("> %s", str.c_str());
470 // in some exceptional cases the index provided segement info
472 parseLineURL(str);
473 return true;
474 }
475
476 bool parseIndexLineMetaData(StrView &str) {
477 int tmp_bandwidth;
478 if (str.startsWith("#")) {
479 if (str.indexOf("EXT-X-STREAM-INF") >= 0) {
481 // determine min bandwidth
482 int pos = str.indexOf("BANDWIDTH=");
483 if (pos > 0) {
484 StrView num(str.c_str() + pos + 10);
485 tmp_bandwidth = num.toInt();
486 url_active = (tmp_bandwidth < bandwidth || bandwidth == 0);
487 if (url_active) {
488 bandwidth = tmp_bandwidth;
489 LOGD("-> bandwith: %d", bandwidth);
490 }
491 }
492
493 pos = str.indexOf("CODECS=");
494 if (pos > 0) {
495 int start = pos + 8;
496 int end = str.indexOf('"', pos + 10);
497 codec.substring(str, start, end);
498 LOGI("-> codec: %s", codec.c_str());
499 }
500 }
501 }
502 return true;
503 }
504
507 play_time = 0;
508 next_sement_load_time = 0xFFFFFFFFFFFFFFFF;
509 }
510
513 TRACED();
515 return false;
516 }
517
518 // back off after a failed reload attempt (e.g. server did not publish a
519 // new playlist yet) to avoid hammering the server and starving the
520 // watchdog with a tight retry loop
521 if (millis() < next_retry_time) {
522 delay(1);
523 return false;
524 }
525
526 // make sure that we load at relevant schedule: this pacing only applies
527 // once we are actually playing - while we are still buffering the
528 // initial segments (!active) we need to fetch as fast as possible so
529 // that we cross START_URLS_LIMIT and can start playback
530 if (active && millis() < next_sement_load_time &&
531 url_loader.urlCount() > 1) {
532 delay(1);
533 return false;
534 }
536
537 LOGI("Available urls: %d", url_loader.urlCount());
538
539 if (url_stream) url_stream.clear();
540 LOGI("parsing %s", segments_url_str.c_str());
541
542 if (segments_url_str.isEmpty()) {
543 TRACEE();
544 parse_segments_active = false;
545 return false;
546 }
547
548 if (!url_stream.begin(segments_url_str.c_str())) {
549 TRACEE();
550 parse_segments_active = false;
551 return false;
552 }
553
554 segment_count = 0;
555 if (!parseSegmentLines()) {
556 // e.g. the playlist has not been updated yet: not an error
557 parse_segments_active = false;
558 return true;
559 }
560
562 return true;
563 }
564
566 LOGI("Reloading in %f sec", play_time / 1000.0);
567 if (play_time > 0) {
569 }
570
571 // we request a minimum of collected urls to play before we start
572 if (url_history.size() > START_URLS_LIMIT) active = true;
573 parse_segments_active = false;
574 }
575
578 TRACEI();
579 char tmp[MAX_HLS_LINE];
580 bool result = true;
581 is_extm3u = false;
582
583 // parse lines
584 memset(tmp, 0, MAX_HLS_LINE);
585 while (true) {
586 memset(tmp, 0, MAX_HLS_LINE);
587 size_t len =
588 url_stream.httpRequest().readBytesUntil('\n', tmp, MAX_HLS_LINE);
589 if (len == 0 && url_stream.available() == 0) break;
590 StrView str(tmp);
591
592 // check header
593 if (str.startsWith("#EXTM3U")) {
594 is_extm3u = true;
595 resetTimings();
596 }
597
598 if (is_extm3u) {
599 if (!parseSegmentLine(str)) {
600 return false;
601 }
602 }
603 }
604 return result;
605 }
606
608 bool parseSegmentLine(StrView &str) {
609 TRACED();
610 LOGI("> %s", str.c_str());
611 if (!parseSegmentLineMetaData(str)) return false;
612 parseLineURL(str);
613 return true;
614 }
615
616 bool parseSegmentLineMetaData(StrView &str) {
617 if (str.startsWith("#")) {
618 if (str.startsWith("#EXT-X-MEDIA-SEQUENCE:")) {
619 int new_media_sequence = atoi(str.c_str() + 22);
620 LOGI("media_sequence: %d", new_media_sequence);
621 if (new_media_sequence == media_sequence) {
622 LOGW("MEDIA-SEQUENCE already loaded: %d", media_sequence);
623 // the server has not published a new playlist yet: back off
624 // before retrying instead of reloading in a tight loop
626 return false;
627 }
628 media_sequence = new_media_sequence;
629 }
630
631 // add play time to next_sement_load_time_planned
632 if (str.startsWith("#EXTINF")) {
634 StrView sec_str(str.c_str() + 8);
635 float sec = sec_str.toFloat();
636 LOGI("adding play time: %f sec", sec);
637 play_time += (sec * 1000.0);
638 }
639 }
640 return true;
641 }
642
643 bool parseLineURL(StrView &str) {
644 if (!str.startsWith("#")) {
645 switch (next_url_type) {
647 // we should not get here
648 assert(false);
649 break;
650 case URLType::Index:
651 if (str.startsWith("http")) {
652 segments_url_str.set(str);
653 } else {
654 segments_url_str.set(resolve_url(str.c_str(), index_url_str));
655 }
656 LOGD("segments_url_str = %s", segments_url_str.c_str());
657 break;
658 case URLType::Segment:
660 if (url_history.add(str.c_str())) {
661 // provide audio urls to the url_loader
662 if (str.startsWith("http")) {
663 url_str = str;
664 } else {
665 // we create the complete url
666 url_str = resolve_url(str.c_str(), index_url_str);
667 }
668 url_loader.addUrl(url_str.c_str());
669 } else {
670 LOGD("Duplicate ignored: %s", str.c_str());
671 }
672 }
673 // clear url type
675 }
676 return true;
677 }
678};
679
680} // namespace audio_tools_hls
681
682namespace audio_tools {
694template <typename URLStream>
696 public:
698 HLSStreamT() = default;
699
701 HLSStreamT(const char *ssid, const char *password) {
702 setSSID(ssid);
704 }
705
707 bool begin(const char *urlStr) {
708 TRACEI();
709 login();
710 // parse the url to the HLS
711 bool rc = parser.begin(urlStr);
712 return rc;
713 }
714
716 bool begin() override {
717 TRACEI();
718 login();
719 bool rc = parser.begin();
720 return rc;
721 }
722
724 void end() override { parser.end(); }
725
727 void setSSID(const char *ssid) override { this->ssid = ssid; }
728
730 void setPassword(const char *password) override { this->password = password; }
731
733 const char *codec() { return parser.getCodec(); }
734
736 const char *contentType() { return parser.contentType(); }
737
739 int contentLength() override { return parser.contentLength(); }
740
742 int available() override {
743 TRACED();
744 return parser.available();
745 }
746
748 size_t readBytes(uint8_t *data, size_t len) override {
749 TRACED();
750 return parser.readBytes(data, len);
751 }
752
754 void setBufferSize(int size, int count) { parser.setBufferSize(size, count); }
755
757 void setCACert(const char *cert) override { parser.setCACert(cert); }
758
760 void setPowerSave(bool flag) override { parser.setPowerSave(flag); }
761
765 void setAgent(const char *agent) { parser.setAgent(agent); }
766
769 const char *getReplyHeader(const char *header) override {
770 const char *codec = parser.getCodec();
771 const char *result = nullptr;
772 if (StrView(header).equalsIgnoreCase(CONTENT_TYPE)) {
773 result = parser.contentType();
774 }
775 if (result) LOGI("-> Format: %s", result);
776 return result;
777 }
778
781 void setURLResolver(const char *(*cb)(const char *segment,
782 const char *reqURL)) {
783 parser.setURLResolver(cb);
784 }
785
786 const char *urlStr() override { return parser.urlStr(); }
787
788 size_t totalRead() override { return parser.totalRead(); };
790 void setConnectionClose(bool flag) override {};
792 bool waitForData(int timeout) override { return false; }
793
794 protected:
796 const char *ssid = nullptr;
797 const char *password = nullptr;
798
799 void login() {
800#ifdef USE_WIFI
801 if (ssid != nullptr && password != nullptr &&
802 WiFi.status() != WL_CONNECTED) {
803 TRACED();
804 delay(1000);
806 while (WiFi.status() != WL_CONNECTED) {
807 Serial.print(".");
808 delay(500);
809 }
810 }
811#else
812 LOGW("login not supported");
813#endif
814 }
815
817 bool begin(const char *urlStr, const char *acceptMime, MethodID action = GET,
818 const char *reqMime = "", const char *reqData = "") override {
819 return begin(urlStr);
820 }
821
823 static HttpRequest dummy;
824 return dummy;
825 }
826
828 void setClient(Client &clientPar) override {}
829
831 void addRequestHeader(const char *header, const char *value) override {}
832};
833
835
836} // namespace audio_tools
static HardwareSerial Serial
Definition Arduino.h:179
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACEI()
Definition AudioLoggerIDF.h:32
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define TRACEE()
Definition AudioLoggerIDF.h:34
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define START_URLS_LIMIT
Definition HLSStream.h:9
#define HLS_RELOAD_RETRY_DELAY
Definition HLSStream.h:15
#define MAX_HLS_LINE
Definition HLSStream.h:8
#define HLS_MAX_URL_LEN
Definition HLSStream.h:12
#define HLS_UNDER_OVERFLOW_WAIT_TIME
Definition HLSStream.h:14
#define HLS_TIMEOUT
Definition HLSStream.h:13
#define HLS_BUFFER_COUNT
Definition HLSStream.h:10
MethodID
supported http methods
Definition HttpTypes.h:3
@ GET
Definition HttpTypes.h:5
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
#define assert(T)
Definition avr.h:10
Definition Arduino.h:162
Abstract Base class for all URLStream implementations.
Definition AbstractURLStream.h:17
void clear()
same as reset
Definition Buffers.h:96
HTTP Live Streaming using HLS: The resulting .ts data is provided via readBytes() that dynamically re...
Definition HLSStream.h:695
audio_tools_hls::HLSParser< URLStream > parser
Definition HLSStream.h:795
void setBufferSize(int size, int count)
Redefines the read buffer size.
Definition HLSStream.h:754
size_t totalRead() override
Total amout of data that was consumed so far.
Definition HLSStream.h:788
const char * getReplyHeader(const char *header) override
Definition HLSStream.h:769
void setAgent(const char *agent)
Definition HLSStream.h:765
const char * codec()
Returns the string representation of the codec of the audio stream.
Definition HLSStream.h:733
void addRequestHeader(const char *header, const char *value) override
Not implemented.
Definition HLSStream.h:831
bool waitForData(int timeout) override
not implemented
Definition HLSStream.h:792
size_t readBytes(uint8_t *data, size_t len) override
Provides the data fro the next .ts Segment.
Definition HLSStream.h:748
const char * ssid
Definition HLSStream.h:796
HLSStreamT(const char *ssid, const char *password)
Convenience constructor which logs in to the WiFi.
Definition HLSStream.h:701
void end() override
ends the request
Definition HLSStream.h:724
int available() override
Provides number of available bytes in the read buffer.
Definition HLSStream.h:742
bool begin(const char *urlStr)
Open an HLS url.
Definition HLSStream.h:707
void setURLResolver(const char *(*cb)(const char *segment, const char *reqURL))
Definition HLSStream.h:781
const char * contentType()
Provides the content type from the http reply.
Definition HLSStream.h:736
HttpRequest & httpRequest() override
provides access to the HttpRequest
Definition HLSStream.h:822
const char * password
Definition HLSStream.h:797
void setSSID(const char *ssid) override
Sets the ssid that will be used for logging in (when calling begin)
Definition HLSStream.h:727
const char * urlStr() override
Provides the url as string.
Definition HLSStream.h:786
void setConnectionClose(bool flag) override
not implemented
Definition HLSStream.h:790
void setClient(Client &clientPar) override
Not implemented: potential future improvement.
Definition HLSStream.h:828
void setCACert(const char *cert) override
Defines the certificate.
Definition HLSStream.h:757
HLSStreamT()=default
Empty constructor.
bool begin() override
Reopens the last url.
Definition HLSStream.h:716
int contentLength() override
Provides the content length of the actual .ts Segment.
Definition HLSStream.h:739
bool begin(const char *urlStr, const char *acceptMime, MethodID action=GET, const char *reqMime="", const char *reqData="") override
Added to comply with AbstractURLStream.
Definition HLSStream.h:817
void setPassword(const char *password) override
Sets the password that will be used for logging in (when calling begin)
Definition HLSStream.h:730
void login()
Definition HLSStream.h:799
void setPowerSave(bool flag) override
Changes the Wifi to power saving mode.
Definition HLSStream.h:760
Simple API to process get, put, post, del http requests I tried to use Arduino HttpClient,...
Definition HttpRequest.h:25
virtual int readArray(T data[], int len) override
reads multiple values
Definition Buffers.h:412
virtual int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:432
virtual int availableForWrite() override
provides the number of entries that are available to write
Definition Buffers.h:478
virtual size_t size() override
Returns the maximum capacity of the buffer.
Definition Buffers.h:493
virtual bool resize(size_t len)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:483
virtual int available() override
provides the number of entries that are available to read
Definition Buffers.h:475
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:29
bool empty()
Definition Vector.h:180
void pop_front()
Definition Vector.h:220
void push_back(T &&value)
Definition Vector.h:182
void clear()
Definition Vector.h:176
int size()
Definition Vector.h:178
bool begin(const char *ssid, const char *password)
Definition WiFiZephyr.h:51
wifi_status_t status()
Definition WiFiZephyr.h:85
Simple Parser for HLS data.
Definition HLSStream.h:231
int contentLength()
Provides the http content lengh.
Definition HLSStream.h:302
bool active
Definition HLSStream.h:369
void setBufferSize(int size, int count)
Redefines the buffer size.
Definition HLSStream.h:319
bool parseIndexLineMetaData(StrView &str)
Definition HLSStream.h:476
bool parseIndexLines()
parse the index file
Definition HLSStream.h:433
const char * index_url_str
Definition HLSStream.h:364
bool parse_segments_active
Definition HLSStream.h:370
URLStream url_stream
Definition HLSStream.h:366
const char *(* resolve_url)(const char *segment, const char *reqURL)
Definition HLSStream.h:377
size_t total_read
Definition HLSStream.h:358
int url_count
Definition HLSStream.h:357
void setUrlCount(int count)
Defines the number of urls that are preloaded in the URLLoaderHLS.
Definition HLSStream.h:316
void setAgent(const char *agent)
Definition HLSStream.h:334
bool is_extm3u
Definition HLSStream.h:360
URLType next_url_type
Definition HLSStream.h:355
int segment_count
Definition HLSStream.h:372
bool url_active
Definition HLSStream.h:359
bool parseSegmentLine(StrView &str)
Add all segments to queue.
Definition HLSStream.h:608
int available()
Definition HLSStream.h:270
const char * indexUrl()
Provides the actual url of the index.
Definition HLSStream.h:290
bool parseIndexLine(StrView &str)
Determine codec for min bandwidth.
Definition HLSStream.h:466
int media_sequence
Definition HLSStream.h:371
const char * agent
Definition HLSStream.h:365
uint64_t next_sement_load_time_planned
Definition HLSStream.h:373
bool begin()
Definition HLSStream.h:239
size_t totalRead()
Povides the number of bytes read.
Definition HLSStream.h:351
bool begin(const char *urlStr)
Definition HLSStream.h:234
void setURLResolver(const char *(*cb)(const char *segment, const char *reqURL))
Definition HLSStream.h:342
URLHistory url_history
Definition HLSStream.h:368
const char * contentType()
Provides the content type of the audio data.
Definition HLSStream.h:299
int bandwidth
Definition HLSStream.h:356
bool parseSegments()
parse the segment url provided by the index
Definition HLSStream.h:512
void segmentsActivate()
Definition HLSStream.h:565
size_t readBytes(uint8_t *data, size_t len)
Definition HLSStream.h:279
Str url_str
Definition HLSStream.h:363
void reloadSegments()
trigger the reloading of segments if the limit is underflowing
Definition HLSStream.h:413
bool parseSegmentLineMetaData(StrView &str)
Definition HLSStream.h:616
uint64_t next_retry_time
Definition HLSStream.h:376
bool parseSegmentLines()
parse the segments
Definition HLSStream.h:577
void setCACert(const char *cert)
Defines the certificate.
Definition HLSStream.h:324
void end()
Closes the processing.
Definition HLSStream.h:305
const char * urlStr()
Provides the hls url as string.
Definition HLSStream.h:348
Str codec
Definition HLSStream.h:361
void resetTimings()
Definition HLSStream.h:505
bool parseLineURL(StrView &str)
Definition HLSStream.h:643
const char * getCodec()
Provides the codec.
Definition HLSStream.h:296
bool parseIndex()
parse the index file and the segments
Definition HLSStream.h:422
const char * segmentsUrl()
Provides the actual url of the segments.
Definition HLSStream.h:293
float play_time
Definition HLSStream.h:374
static const char * resolveURL(const char *segment, const char *reqURL)
Definition HLSStream.h:382
URLLoaderHLS< URLStream > url_loader
Definition HLSStream.h:367
Str segments_url_str
Definition HLSStream.h:362
void setPowerSave(bool flag)
Changes the Wifi to power saving mode.
Definition HLSStream.h:330
URLType
Definition HLSStream.h:354
uint64_t next_sement_load_time
Definition HLSStream.h:375
Definition HLSStream.h:193
bool add(const char *url)
Definition HLSStream.h:195
Vector< const char * > history
Definition HLSStream.h:222
void clear()
Definition HLSStream.h:217
int size()
Definition HLSStream.h:219
We feed the URLLoaderHLS with some url strings. The data of the related segments are provided via the...
Definition HLSStream.h:36
int contentLength()
Definition HLSStream.h:94
void bufferRefill()
try to keep the buffer filled
Definition HLSStream.h:125
bool active
Definition HLSStream.h:117
void setBufferSize(int size, int count)
Definition HLSStream.h:96
URLStream url_stream
Definition HLSStream.h:120
int buffer_count
Definition HLSStream.h:119
void setAgent(const char *agent)
Definition HLSStream.h:109
int urlCount()
Definition HLSStream.h:69
~URLLoaderHLS()
Definition HLSStream.h:40
int available()
Available bytes of the audio stream.
Definition HLSStream.h:72
const char * agent
Definition HLSStream.h:122
bool begin()
Definition HLSStream.h:42
const char * contentType()
Definition HLSStream.h:90
size_t readBytes(uint8_t *data, size_t len)
Provides data from the audio stream.
Definition HLSStream.h:81
void addUrl(const char *url)
Adds the next url to be played in sequence.
Definition HLSStream.h:59
void setCACert(const char *cert)
Definition HLSStream.h:105
void end()
Definition HLSStream.h:51
const char * url_to_play
Definition HLSStream.h:121
Vector< const char * > urls
Definition HLSStream.h:115
RingBuffer< uint8_t > buffer
Definition HLSStream.h:116
int buffer_size
Definition HLSStream.h:118
hide hls implementation in it's own namespace
Definition HLSStream.h:19
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:259
@ WL_CONNECTED
Definition WiFiZephyr.h:30
static WiFiZephyr WiFi
Definition WiFiZephyr.h:230
static const char * CONTENT_TYPE
Definition HttpHeader.h:16