comparison src/neon/neon.c @ 1730:50d151b259bb

- Add lots of code to support the completely braindead concept that is StreamCast
author Ralf Ertzinger <ralf@skytale.net>
date Tue, 18 Sep 2007 18:01:00 +0200
parents eaa8a5747628
children f0b53c4db5ba 8feacd004f50
comparison
equal deleted inserted replaced
1729:eaa8a5747628 1730:50d151b259bb
60 h->request = NULL; 60 h->request = NULL;
61 h->redircount = 0; 61 h->redircount = 0;
62 h->pos = 0; 62 h->pos = 0;
63 h->content_length = -1; 63 h->content_length = -1;
64 h->can_ranges = FALSE; 64 h->can_ranges = FALSE;
65 h->icy_metaint = 0;
66 h->icy_metaleft = 0;
67 h->icy_metadata.stream_name = NULL;
68 h->icy_metadata.stream_title = NULL;
69 h->icy_metadata.stream_url = NULL;
65 h->reader = NULL; 70 h->reader = NULL;
66 h->reader_status.mutex = g_mutex_new(); 71 h->reader_status.mutex = g_mutex_new();
67 h->reader_status.cond = g_cond_new(); 72 h->reader_status.cond = g_cond_new();
68 h->reader_status.reading = FALSE; 73 h->reader_status.reading = FALSE;
69 h->reader_status.status = NEON_READER_INIT; 74 h->reader_status.status = NEON_READER_INIT;
118 static void fini(void) { 123 static void fini(void) {
119 124
120 _ENTER; 125 _ENTER;
121 126
122 ne_sock_exit(); 127 ne_sock_exit();
128
129 _LEAVE;
130 }
131
132 /*
133 * -----
134 */
135
136 static void add_icy(struct icy_metadata* m, gchar* name, gchar* value) {
137
138 _ENTER;
139
140 if (0 == g_ascii_strncasecmp(name, "StreamTitle", 11)) {
141 _DEBUG("Found StreamTitle: %s", value);
142 if (NULL != m->stream_title) {
143 free(m->stream_title);
144 }
145 m->stream_title = g_strdup(value);
146 }
147
148 if (0 == g_ascii_strncasecmp(name, "StreamUrl", 9)) {
149 _DEBUG("Found StreamUrl: %s", value);
150 if (NULL != m->stream_url) {
151 free(m->stream_url);
152 }
153 m->stream_url = g_strdup(value);
154 }
155
156 _LEAVE;
157 }
158
159 /*
160 * -----
161 */
162
163 static void parse_icy(struct icy_metadata* m, gchar* metadata, int len) {
164
165 gchar* p;
166 gchar* tstart;
167 gchar* tend;
168 gchar name[4096];
169 gchar value[4096];
170 int state;
171 int pos;
172
173 _ENTER;
174
175 p = metadata;
176 state = 1;
177 pos = 0;
178 name[0] = '\0';
179 value[0] = '\0';
180 tstart = metadata;
181 tend = metadata;
182 while ((pos < len) && (*p != '\0')) {
183 switch (state) {
184 case 1:
185 /*
186 * Reading tag name
187 */
188 if ('=' == *p) {
189 /*
190 * End of tag name.
191 */
192 *p = '\0';
193 strcpy(name, tstart);
194 _DEBUG("Found tag name: %s", name);
195 state = 2;
196 } else {
197 tend = p;
198 };
199 break;
200 case 2:
201 /*
202 * Waiting for start of value
203 */
204 if ('\'' == *p) {
205 /*
206 * Leading ' of value
207 */
208 tend = tstart = p + 1;
209 state = 3;
210 value[0] = '\0';
211 }
212 break;
213 case 3:
214 /*
215 * Reading value
216 */
217 if ('\'' == *p) {
218 /*
219 * End of value
220 */
221 *p = '\0';
222 strcpy(value, tstart);
223 _DEBUG("Found tag value: %s", value);
224 add_icy(m, name, value);
225 state = 4;
226 } else {
227 tend = p;
228 }
229 break;
230 case 4:
231 /*
232 * Waiting for next tag start
233 */
234 if (';' == *p) {
235 /*
236 * Next tag name starts after this char
237 */
238 tend = tstart = p + 1;
239 state = 1;
240 name[0] = '\0';
241 value[0] = '\0';
242 }
243 break;
244 }
245 p++;
246 pos++;
247 }
123 248
124 _LEAVE; 249 _LEAVE;
125 } 250 }
126 251
127 /* 252 /*
174 if (0 == g_ascii_strncasecmp("content-length", name, 14)) { 299 if (0 == g_ascii_strncasecmp("content-length", name, 14)) {
175 /* 300 /*
176 * The server sent us the content length. Parse and store. 301 * The server sent us the content length. Parse and store.
177 */ 302 */
178 len = strtol(value, &endptr, 10); 303 len = strtol(value, &endptr, 10);
179 if ((*value != '\0') && (*endptr == '\0')) { 304 if ((*value != '\0') && (*endptr == '\0') && (len >= 0)) {
180 /* 305 /*
181 * Valid data. 306 * Valid data.
182 */ 307 */
183 _DEBUG("Content length as advertised by server: %d", len); 308 _DEBUG("Content length as advertised by server: %ld", len);
184 h->content_length = len; 309 h->content_length = len;
310 } else {
311 _ERROR("Invalid content length header: %s", value);
185 } 312 }
313 }
314
315 if (0 == g_ascii_strncasecmp("icy-metaint", name, 11)) {
316 /*
317 * The server sent us a ICY metaint header. Parse and store.
318 */
319 len = strtol(value, &endptr, 10);
320 if ((*value != '\0') && (*endptr == '\0') && (len > 0)) {
321 /*
322 * Valid data
323 */
324 _DEBUG("ICY MetaInt as advertised by server: %ld", len);
325 h->icy_metaint = len;
326 h->icy_metaleft = len;
327 } else {
328 _ERROR("Invalid ICY MetaInt header: %s", value);
329 }
330 }
331
332 if (0 == g_ascii_strncasecmp("icy-name", name, 8)) {
333 /*
334 * The server sent us a ICY name. Save it for later
335 */
336 _DEBUG("ICY stream name: %s", value);
337 if (NULL != h->icy_metadata.stream_name) {
338 free(h->icy_metadata.stream_name);
339 }
340 h->icy_metadata.stream_name = g_strdup(value);
186 } 341 }
187 } 342 }
188 343
189 _LEAVE; 344 _LEAVE;
190 } 345 }
199 354
200 _ENTER; 355 _ENTER;
201 356
202 handle->request = ne_request_create(handle->session, "GET", handle->purl->path); 357 handle->request = ne_request_create(handle->session, "GET", handle->purl->path);
203 ne_print_request_header(handle->request, "Range", "bytes=%ld-", startbyte); 358 ne_print_request_header(handle->request, "Range", "bytes=%ld-", startbyte);
359 ne_print_request_header(handle->request, "Icy-MetaData", "1");
204 360
205 /* 361 /*
206 * Try to connect to the server. 362 * Try to connect to the server.
207 */ 363 */
208 _DEBUG("Connecting..."); 364 _DEBUG("Connecting...");
519 675
520 size_t neon_vfs_fread_impl(gpointer ptr_, size_t size, size_t nmemb, VFSFile* file) { 676 size_t neon_vfs_fread_impl(gpointer ptr_, size_t size, size_t nmemb, VFSFile* file) {
521 677
522 struct neon_handle* h = (struct neon_handle*)file->handle; 678 struct neon_handle* h = (struct neon_handle*)file->handle;
523 int belem; 679 int belem;
680 int relem;
524 int ret; 681 int ret;
682 char icy_metadata[4096];
683 unsigned char icy_metalen;
525 684
526 _ENTER; 685 _ENTER;
527 686
528 if (NULL == h->request) { 687 if (NULL == h->request) {
529 _ERROR("No request to read from, seek gone wrong?"); 688 _ERROR("No request to read from, seek gone wrong?");
547 g_mutex_lock(h->reader_status.mutex); 706 g_mutex_lock(h->reader_status.mutex);
548 if (NEON_READER_RUN == h->reader_status.status) { 707 if (NEON_READER_RUN == h->reader_status.status) {
549 g_mutex_unlock(h->reader_status.mutex); 708 g_mutex_unlock(h->reader_status.mutex);
550 _ERROR("Buffer underrun, trying rebuffering"); 709 _ERROR("Buffer underrun, trying rebuffering");
551 kill_reader(h); 710 kill_reader(h);
711
712 /*
713 * We have to check if the reader terminated gracefully
714 * again
715 */
716 if (NEON_READER_TERM != h->reader_status.status) {
717 /*
718 * Reader thread did not terminate gracefully.
719 */
720 _LEAVE 0;
721 }
552 } else { 722 } else {
553 g_mutex_unlock(h->reader_status.mutex); 723 g_mutex_unlock(h->reader_status.mutex);
554 } 724 }
555 } 725 }
556 726
632 } 802 }
633 803
634 /* 804 /*
635 * Deliver data from the buffer 805 * Deliver data from the buffer
636 */ 806 */
637 belem = used_rb(&h->rb) / size; 807 if (0 == used_rb(&h->rb)) {
638
639 if (0 == belem) {
640 /* 808 /*
641 * The buffer is empty, we can deliver no data! 809 * The buffer is still empty, we can deliver no data!
642 */ 810 */
643 _ERROR("Buffer still underrun, fatal."); 811 _ERROR("Buffer still underrun, fatal.");
644 _LEAVE 0; 812 _LEAVE 0;
645 } 813 }
646 814
647 _DEBUG("%d elements of data in the buffer", belem); 815 if (0 != h->icy_metaint) {
648 read_rb(&h->rb, ptr_, MIN(belem, nmemb)*size); 816 _DEBUG("%ld bytes left before next ICY metadata announcement", h->icy_metaleft);
817 if (0 == h->icy_metaleft) {
818 /*
819 * The next data in the buffer is a ICY metadata announcement.
820 * Get the length byte
821 */
822 read_rb(&h->rb, &icy_metalen, 1);
823
824 /*
825 * We need enough data in the buffer to
826 * a) Read the complete ICY metadata block
827 * b) deliver at least one byte to the reader
828 */
829 _DEBUG("Expecting %d bytes of ICY metadata", (icy_metalen*16));
830
831 if ((free_rb(&h->rb)-(icy_metalen*16)) < size) {
832 /* There is not enough data. We do not have much choice at this point,
833 * so we'll deliver the metadata as normal data to the reader and
834 * hope for the best.
835 */
836 _ERROR("Buffer underrun when reading metadata. Expect audio degradation");
837 h->icy_metaleft = h->icy_metaint + (icy_metalen*16);
838 } else {
839 /*
840 * Grab the metadata from the buffer and send it to the parser
841 */
842 read_rb(&h->rb, icy_metadata, (icy_metalen*16));
843 parse_icy(&h->icy_metadata, icy_metadata, (icy_metalen*16));
844 h->icy_metaleft = h->icy_metaint;
845 }
846 }
847
848 /*
849 * The maximum number of bytes we can deliver is determined
850 * by the number of bytes left until the next metadata announcement
851 */
852 belem = h->icy_metaleft / size;
853 } else {
854 belem = used_rb(&h->rb) / size;
855 }
856
857 relem = MIN(belem, nmemb);
858 _DEBUG("%d elements of returnable data in the buffer", belem);
859 read_rb(&h->rb, ptr_, relem*size);
649 860
650 /* 861 /*
651 * Signal the network thread to continue reading 862 * Signal the network thread to continue reading
652 */ 863 */
653 _DEBUG("Waking up reader thread"); 864 _DEBUG("Waking up reader thread");
654 g_mutex_lock(h->reader_status.mutex); 865 g_mutex_lock(h->reader_status.mutex);
655 g_cond_signal(h->reader_status.cond); 866 g_cond_signal(h->reader_status.cond);
656 g_mutex_unlock(h->reader_status.mutex); 867 g_mutex_unlock(h->reader_status.mutex);
657 868
658 h->pos += (MIN(belem, nmemb)*size); 869 h->pos += (relem*size);
659 870 h->icy_metaleft -= (relem*size);
660 _DEBUG("Returning %d elements", MIN(belem, nmemb)); 871
661 872 _DEBUG("Returning %d elements", relem);
662 _LEAVE MIN(belem, nmemb); 873
874 _LEAVE relem;
663 } 875 }
664 876
665 877
666 /* 878 /*
667 * ----- 879 * -----
728 940
729 struct neon_handle* h = (struct neon_handle *)file->handle; 941 struct neon_handle* h = (struct neon_handle *)file->handle;
730 942
731 _ENTER; 943 _ENTER;
732 944
733 _DEBUG("Current file position: %d", h->pos); 945 _DEBUG("Current file position: %ld", h->pos);
734 946
735 _LEAVE h->pos; 947 _LEAVE h->pos;
736 } 948 }
737 949
738 /* 950 /*
856 1068
857 /* 1069 /*
858 * ----- 1070 * -----
859 */ 1071 */
860 1072
861 gchar *neon_vfs_metadata_impl(VFSFile* file, const gchar * field) { 1073 gchar *neon_vfs_metadata_impl(VFSFile* file, const gchar* field) {
862 1074
863 _ENTER; 1075 struct neon_handle* h = (struct neon_handle*)file->handle;
864 1076
865 _ERROR("NOT IMPLEMENTED"); 1077 _ENTER;
1078
1079 _DEBUG("Field name: %s", field);
1080
1081 if (0 == g_ascii_strncasecmp(field, "track-name", 10)) {
1082 _LEAVE g_strdup(h->icy_metadata.stream_title);
1083 }
1084
1085 if (0 == g_ascii_strncasecmp(field, "stream-name", 11)) {
1086 _LEAVE g_strdup(h->icy_metadata.stream_name);
1087 }
866 1088
867 _LEAVE NULL; 1089 _LEAVE NULL;
868 } 1090 }
869 1091
870 /* 1092 /*