Merge branch 'chunk_queue' of /home/maan/scm/paraslash_meins/paraslash into tmp
[paraslash.git] / vss.c
1 /*
2  * Copyright (C) 1997-2007 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file vss.c the virtual streaming system
8  *
9  * This contains the audio streaming code of para_server which is independent
10  * of the current audio format, audio file selector and of the activated
11  * senders.
12  */
13
14 #include "server.h"
15 #include <sys/mman.h> /* mmap */
16 #include <sys/time.h> /* gettimeofday */
17 #include "server.cmdline.h"
18 #include "afs.h"
19 #include "vss.h"
20 #include "send.h"
21 #include "error.h"
22 #include "string.h"
23 #include "fd.h"
24
25 extern const char *status_item_list[];
26
27 static struct timeval announce_tv;
28 static struct timeval data_send_barrier;
29 static struct timeval eof_barrier;
30 static struct timeval autoplay_barrier;
31
32 extern struct misc_meta_data *mmd;
33 extern struct audio_file_selector selectors[];
34 extern struct sender senders[];
35
36 static int audio_file;
37 static char *map;
38
39 #if 1
40         void mp3_init(struct audio_format_handler *);
41 #endif
42
43 #ifdef HAVE_OGGVORBIS
44         void ogg_init(struct audio_format_handler *);
45 #endif
46 #ifdef HAVE_FAAD
47         void aac_afh_init(struct audio_format_handler *);
48 #endif
49
50 /**
51  * the list of supported  audio formats
52  */
53 static struct audio_format_handler afl[] = {
54 #if 1
55         {
56                 .name = "mp3",
57                 .init = mp3_init,
58         },
59 #endif
60 #ifdef HAVE_OGGVORBIS
61         {
62                 .name = "ogg",
63                 .init = ogg_init,
64         },
65 #endif
66 #ifdef HAVE_FAAD
67         {
68                 .name = "aac",
69                 .init = aac_afh_init,
70         },
71 #endif
72         {
73                 .name = NULL,
74         }
75 };
76
77 /** iterate over each supported audio format */
78 #define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++)
79
80
81
82 /**
83  * check if vss status flag \a P (playing) is set
84  *
85  * \return greater than zero if playing, zero otherwise.
86  *
87  */
88 unsigned int vss_playing(void)
89 {
90         return mmd->new_vss_status_flags & VSS_PLAYING;
91 }
92
93 /**
94  * check if \a N (next) status flag is set
95  *
96  * \return greater than zero if set, zero if not.
97  *
98  */
99 unsigned int vss_next(void)
100 {
101         return mmd->new_vss_status_flags & VSS_NEXT;
102 }
103
104 /**
105  * check if a reposition request is pending
106  *
107  * \return greater than zero if true, zero otherwise.
108  *
109  */
110 unsigned int vss_repos(void)
111 {
112         return mmd->new_vss_status_flags & VSS_REPOS;
113 }
114
115 /**
116  * check if the vss is currently paused
117  *
118  * \return greater than zero if paused, zero otherwise.
119  *
120  */
121 unsigned int vss_paused(void)
122 {
123         return !(mmd->new_vss_status_flags & VSS_NEXT)
124                 && !(mmd->new_vss_status_flags & VSS_PLAYING);
125 }
126
127 /**
128  * get the name of the given audio format
129  * \param i the audio format number
130  *
131  * This returns a pointer to statically allocated memory so it
132  * must not be freed by the caller.
133  */
134 const char *audio_format_name(int i)
135 {
136         return i >= 0?  afl[i].name : "(none)";
137 }
138
139 /**
140  * initialize the virtual streaming system
141  *
142  * Call the init functions of all supported audio format handlers and
143  * initialize all supported senders.
144  */
145 void vss_init(void)
146 {
147         int i;
148         char *hn = para_hostname(), *home = para_homedir();
149         long unsigned announce_time = conf.announce_time_arg > 0?
150                         conf.announce_time_arg : 300,
151                 autoplay_delay = conf.autoplay_delay_arg > 0?
152                         conf.autoplay_delay_arg : 0;
153
154         PARA_DEBUG_LOG("supported audio formats: %s\n",
155                 SUPPORTED_AUDIO_FORMATS);
156         for (i = 0; afl[i].name; i++) {
157                 PARA_NOTICE_LOG("initializing %s handler\n",
158                         afl[i].name);
159                 afl[i].init(&afl[i]);
160         }
161         ms2tv(announce_time, &announce_tv);
162         PARA_INFO_LOG("announce timeval: %lums\n", tv2ms(&announce_tv));
163         for (i = 0; senders[i].name; i++) {
164                 PARA_NOTICE_LOG("initializing %s sender\n", senders[i].name);
165                 senders[i].init(&senders[i]);
166         }
167         free(hn);
168         free(home);
169         if (conf.autoplay_given) {
170                 struct timeval now, tmp;
171                 mmd->vss_status_flags |= VSS_PLAYING;
172                 mmd->new_vss_status_flags |= VSS_PLAYING;
173                 gettimeofday(&now, NULL);
174                 ms2tv(autoplay_delay, &tmp);
175                 tv_add(&now, &tmp, &autoplay_barrier);
176         }
177 }
178
179 static int get_file_info(int i)
180 {
181         return  afl[i].get_file_info(map, mmd->size, &mmd->afi);
182 }
183
184 /**
185  * guess the audio format judging from filename
186  *
187  * \param name the filename
188  *
189  * \return This function returns -1 if it has no idea what kind of audio
190  * file this might be. Otherwise the (non-negative) number of the audio format
191  * is returned.
192  */
193 int guess_audio_format(const char *name)
194 {
195         int i,j, len = strlen(name);
196
197         FOR_EACH_AUDIO_FORMAT(i) {
198                 for (j = 0; afl[i].suffixes[j]; j++) {
199                         const char *p = afl[i].suffixes[j];
200                         int plen = strlen(p);
201                         if (len < plen + 1)
202                                 continue;
203                         if (name[len - plen - 1] != '.')
204                                 continue;
205                         if (strcasecmp(name + len - plen, p))
206                                 continue;
207 //                      PARA_DEBUG_LOG("might be %s\n", audio_format_name(i));
208                         return i;
209                 }
210         }
211         return -1;
212 }
213
214 static int get_audio_format(int omit)
215 {
216         int i;
217
218         FOR_EACH_AUDIO_FORMAT(i) {
219                 if (i == omit)
220                         continue;
221                 if (get_file_info(i) > 0)
222                         return i;
223         }
224         return -E_AUDIO_FORMAT;
225 }
226
227 /*
228  * upddate shared mem
229  */
230 static int update_mmd(void)
231 {
232         int i;
233
234         i = guess_audio_format(mmd->filename);
235         if (i < 0 || get_file_info(i) < 0)
236                 i = get_audio_format(i);
237         if (i < 0)
238                 return i;
239         mmd->audio_format = i;
240         mmd->chunks_sent = 0;
241         mmd->current_chunk = 0;
242         mmd->offset = 0;
243         mmd->events++;
244         return 1;
245 }
246
247 static void vss_get_audio_file(void)
248 {
249         char **sl = selectors[mmd->selector_num].get_audio_file_list(10);
250         int i;
251         struct stat file_status;
252
253         if (!sl)
254                 goto err_out;
255         for (i = 0; sl[i]; i++) {
256                 struct timeval now;
257                 PARA_INFO_LOG("trying %s\n", sl[i]);
258                 if (strlen(sl[i]) >= _POSIX_PATH_MAX)
259                         continue;
260                 audio_file = open(sl[i], O_RDONLY);
261                 if (audio_file < 0)
262                         continue;
263                 if (fstat(audio_file, &file_status) == -1 ||
264                                 !file_status.st_size) {
265                         close(audio_file);
266                         continue;
267                 }
268                 mmd->size = file_status.st_size;
269                 mmd->mtime = file_status.st_mtime;
270                 map = para_mmap(mmd->size, PROT_READ, MAP_PRIVATE,
271                         audio_file, 0);
272                 strcpy(mmd->filename, sl[i]);
273                 mmd->afi.header_len = 0; /* default: no header */
274                 if (update_mmd() < 0) { /* invalid file */
275                         close(audio_file);
276                         munmap(map, mmd->size);
277                         map = NULL;
278                         continue;
279                 }
280                 mmd->num_played++;
281                 if (selectors[mmd->selector_num].update_audio_file)
282                         selectors[mmd->selector_num].update_audio_file(sl[i]);
283                 PARA_NOTICE_LOG("next audio file: %s\n", mmd->filename);
284                 mmd->new_vss_status_flags &= (~VSS_NEXT);
285                 gettimeofday(&now, NULL);
286                 tv_add(&now, &announce_tv, &data_send_barrier);
287                 goto free;
288         }
289 err_out:
290         PARA_ERROR_LOG("%s", "no valid files found\n");
291         mmd->new_vss_status_flags = VSS_NEXT;
292 free:
293         if (sl) {
294                 for (i = 0; sl[i]; i++)
295                         free(sl[i]);
296                 free(sl);
297         }
298 }
299
300 static int chk_barrier(const char *bname, const struct timeval *now,
301                 const struct timeval *barrier, struct timeval *diff,
302                 int print_log)
303 {
304         long ms;
305
306         if (tv_diff(now, barrier, diff) > 0)
307                 return 1;
308         ms = tv2ms(diff);
309         if (print_log && ms)
310                 PARA_DEBUG_LOG("%s barrier: %lims left\n", bname, ms);
311         return -1;
312 }
313
314 static void vss_next_chunk_time(struct timeval *due)
315 {
316         struct timeval tmp;
317
318         tv_scale(mmd->chunks_sent, &mmd->afi.chunk_tv, &tmp);
319         tv_add(&tmp, &mmd->stream_start, due);
320 }
321
322 /*
323  * != NULL: timeout for next chunk
324  * NULL: nothing to do
325  */
326 static struct timeval *vss_compute_timeout(void)
327 {
328         static struct timeval the_timeout;
329         struct timeval now, next_chunk;
330
331         if (vss_next() && mmd->audio_format >= 0) {
332                 /* only sleep a bit, nec*/
333                 the_timeout.tv_sec = 0;
334                 the_timeout.tv_usec = 100;
335                 return &the_timeout;
336         }
337         gettimeofday(&now, NULL);
338         if (chk_barrier("autoplay_delay", &now, &autoplay_barrier,
339                         &the_timeout, 1) < 0)
340                 return &the_timeout;
341         if (chk_barrier("eof", &now, &eof_barrier, &the_timeout, 1) < 0)
342                 return &the_timeout;
343         if (chk_barrier("data send", &now, &data_send_barrier,
344                         &the_timeout, 1) < 0)
345                 return &the_timeout;
346         if (mmd->audio_format < 0 || !vss_playing() || !map)
347                 return NULL;
348         vss_next_chunk_time(&next_chunk);
349         if (chk_barrier(afl[mmd->audio_format].name, &now, &next_chunk,
350                         &the_timeout, 0) < 0)
351                 return &the_timeout;
352         /* chunk is due or bof */
353         the_timeout.tv_sec = 0;
354         the_timeout.tv_usec = 0;
355         return &the_timeout;
356 }
357
358 static void vss_eof(void)
359 {
360         struct timeval now;
361         int i;
362         char *tmp;
363
364         if (!map) {
365                 for (i = 0; senders[i].name; i++)
366                         senders[i].shutdown_clients();
367                 return;
368         }
369         gettimeofday(&now, NULL);
370         tv_add(&mmd->afi.eof_tv, &now, &eof_barrier);
371         munmap(map, mmd->size);
372         map = NULL;
373         close(audio_file);
374         mmd->audio_format = -1;
375         mmd->chunks_sent = 0;
376         mmd->offset = 0;
377         mmd->afi.seconds_total = 0;
378         free(mmd->afi.chunk_table);
379         mmd->afi.chunk_table = NULL;
380         tmp  = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_AUDIO_INFO1],
381                 status_item_list[SI_AUDIO_INFO2], status_item_list[SI_AUDIO_INFO3]);
382         strcpy(mmd->afi.info_string, tmp);
383         free(tmp);
384         tmp  = make_message("%s:\n%s:\n%s:\n", status_item_list[SI_DBINFO1],
385                 status_item_list[SI_DBINFO2], status_item_list[SI_DBINFO3]);
386         strcpy(mmd->selector_info, tmp);
387         free(tmp);
388         mmd->filename[0] = '\0';
389         mmd->size = 0;
390         mmd->events++;
391 }
392
393 /**
394  * get the header and of the current audio file
395  *
396  * \param header_len the length of the header is stored here
397  *
398  * \return a pointer to a buffer containing the header, or NULL, if no audio
399  * file is selected or if the current audio format does not need special header
400  * treamtment.
401  *
402  */
403 char *vss_get_header(unsigned *header_len)
404 {
405         if (mmd->audio_format < 0 || !map || !mmd->afi.header_len)
406                 return NULL;
407         *header_len = mmd->afi.header_len;
408         return map + mmd->afi.header_offset;
409 }
410
411 /**
412  * get the list of all supported audio formats
413  *
414  * \return a space separated list of all supported audio formats
415  * It is not allocated at runtime, i.e. there is no need to free
416  * the returned string in the caller.
417  */
418 const char *supported_audio_formats(void)
419 {
420         return SUPPORTED_AUDIO_FORMATS;
421 }
422
423 /**
424  * get the chunk time of the current audio file
425  *
426  * \return a pointer to a struct containing the chunk time, or NULL,
427  * if currently no audio file is selected.
428  */
429 struct timeval *vss_chunk_time(void)
430 {
431         if (mmd->audio_format < 0)
432                 return NULL;
433         return &mmd->afi.chunk_tv;
434 }
435
436 /**
437  * compute the timeout for para_server's main select-loop
438  *
439  * This function gets called from para_server to determine the timeout value
440  * for its main select loop.
441  *
442  * Before the timeout is computed, the current vss status flags are evaluated
443  * and acted upon by calling appropriate functions from the lower layers.
444  * Possible actions include
445  *
446  *      - request a new file list from the current audio file selector
447  *      - shutdown of all senders (stop/pause command)
448  *      - reposition the stream (ff/jmp command)
449  *
450  * \return A pointer to a struct timeval containing the timeout for the next
451  * chunk of data to be sent, or NULL if we're not sending right now.
452  */
453 struct timeval *vss_preselect(void)
454 {
455         struct audio_format_handler *af = NULL;
456         int i, format;
457         struct timeval *ret;
458 again:
459         format = mmd->audio_format;
460         if (format >= 0)
461                 af = afl + format;
462         else
463                 for (i = 0; senders[i].name; i++)
464                         senders[i].shutdown_clients();
465         if (vss_next() && af) {
466                 vss_eof();
467                 return vss_compute_timeout();
468         }
469         if (vss_paused() || vss_repos()) {
470                 for (i = 0; senders[i].name; i++)
471                         senders[i].shutdown_clients();
472                 if (af) {
473                         struct timeval now;
474                         gettimeofday(&now, NULL);
475                         if (!vss_paused() || mmd->chunks_sent)
476                                 tv_add(&mmd->afi.eof_tv, &now, &eof_barrier);
477                         if (vss_repos())
478                                 tv_add(&now, &announce_tv, &data_send_barrier);
479                         if (mmd->new_vss_status_flags & VSS_NOMORE)
480                                 mmd->new_vss_status_flags = VSS_NEXT;
481                 }
482                 mmd->chunks_sent = 0;
483         }
484         if (vss_repos()) {
485                 mmd->new_vss_status_flags &= ~(VSS_REPOS);
486                 mmd->current_chunk = mmd->repos_request;
487         }
488         ret = vss_compute_timeout();
489         if (!ret && !map && vss_playing() &&
490                         !(mmd->new_vss_status_flags & VSS_NOMORE)) {
491                 PARA_DEBUG_LOG("%s", "ready and playing, but no audio file\n");
492                 vss_get_audio_file();
493                 goto again;
494         }
495         return ret;
496 }
497
498 static void get_chunk(long unsigned chunk_num, char **buf, size_t *len)
499 {
500         size_t pos = mmd->afi.chunk_table[chunk_num];
501         *buf = map + pos;
502         *len = mmd->afi.chunk_table[chunk_num + 1] - pos;
503 }
504
505 /**
506  * Get the data of the given chunk.
507  *
508  * \param chunk_num The number of the desired chunk.
509  * \param buf Chunk data.
510  * \param len Chunk length in bytes.
511  *
512  * \return Positive on success, negative on errors.
513  */
514 int vss_get_chunk(long unsigned chunk_num, char **buf, size_t *len)
515 {
516         if (mmd->audio_format < 0 || !map || !vss_playing())
517                 return -E_CHUNK;
518         if (chunk_num >= mmd->afi.chunks_total)
519                 return -E_CHUNK;
520         get_chunk(chunk_num, buf, len);
521         return 1;
522 }
523
524 /**
525  * main sending function
526  *
527  * This function gets called from para_server as soon as the next chunk of
528  * data should be pushed out. It first calls the read_chunk() function of
529  * the current audio format handler to obtain a pointer to the data to be
530  * sent out as well as its length. This information is then passed to each
531  * supported sender's send() function which does the actual sending.
532  */
533 void vss_send_chunk(void)
534 {
535         int i;
536         struct audio_format_handler *af;
537         struct timeval now, due;
538
539         if (mmd->audio_format < 0 || !map || !vss_playing())
540                 return;
541         af = &afl[mmd->audio_format];
542         gettimeofday(&now, NULL);
543         vss_next_chunk_time(&due);
544         if (tv_diff(&due, &now, NULL) > 0)
545                 return;
546         if (chk_barrier("eof", &now, &eof_barrier, &due, 1) < 0)
547                 return;
548         if (chk_barrier("data send", &now, &data_send_barrier,
549                         &due, 1) < 0)
550                 return;
551         mmd->new_vss_status_flags &= ~VSS_REPOS;
552         if (mmd->current_chunk >= mmd->afi.chunks_total) { /* eof */
553                 mmd->new_vss_status_flags |= VSS_NEXT;
554                 return vss_eof();
555         }
556         /*
557          * We call the send function also in case of empty chunks as they
558          * might have still some data queued which can be sent in this case.
559          */
560         if (!mmd->chunks_sent) {
561                 struct timeval tmp;
562                 gettimeofday(&mmd->stream_start, NULL);
563                 tv_scale(mmd->current_chunk, &mmd->afi.chunk_tv, &tmp);
564                 mmd->offset = tv2ms(&tmp);
565                 mmd->events++;
566         }
567         for (i = 0; senders[i].name; i++) {
568                 char *buf;
569                 size_t len;
570                 get_chunk(mmd->current_chunk, &buf, &len);
571                 senders[i].send(mmd->current_chunk, mmd->chunks_sent, buf, len);
572         }
573         mmd->new_vss_status_flags |= VSS_PLAYING;
574         mmd->chunks_sent++;
575         mmd->current_chunk++;
576 }