1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * Play one song and be able to stop playback
5 * This file is part of monster
7 * Copyright (C) 2006,2007 Nedko Arnaudov <nedko@arnaudov.name>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 *****************************************************************************/
26 #include <libxml/parser.h>
30 #define DISABLE_DEBUG_OUTPUT
32 #include "media_source.h"
34 #include "media_source_dv.h"
35 #include "media_source_wav.h"
36 #include "media_source_midi.h"
37 #include "player_video1394.h"
38 #include "player_alsa_pcm.h"
39 #include "player_alsa_midi.h"
42 #include "song_player.h"
46 #define XPATH_SONG_NAME_EXPRESSION "/song/name"
48 #define EOD_CONTEXT_VIDEO 1
49 #define EOD_CONTEXT_AUDIO 2
50 #define EOD_CONTEXT_MIDI 4
52 pthread_mutex_t g_real_mask_mutex
;
53 unsigned int g_real_mask
;
55 struct media_source
* g_media_source_dv_ptr
;
56 struct media_source
* g_media_source_wav_ptr
;
57 struct media_source
* g_media_source_midi_ptr
;
58 struct player
* g_player_video1394_ptr
;
59 struct player
* g_player_alsa_pcm_ptr
;
60 struct player
* g_player_alsa_midi_ptr
;
61 struct song_descriptor
* g_song_descriptor_ptr
;
64 eod(unsigned int context
)
68 case EOD_CONTEXT_VIDEO
:
69 DEBUG_OUT("eod: video");
71 case EOD_CONTEXT_AUDIO
:
72 DEBUG_OUT("eod: audio");
74 case EOD_CONTEXT_MIDI
:
75 DEBUG_OUT("eod: MIDI");
78 DEBUG_OUT("eod: %u", context
);
81 pthread_mutex_lock(&g_real_mask_mutex
);
82 g_real_mask
&= ~context
;
85 OUTPUT_MESSAGE("====== End of song");
88 pthread_mutex_unlock(&g_real_mask_mutex
);
91 struct song_descriptor
94 char * media_video_filename_ptr
;
95 char * media_audio_filename_ptr
;
96 char * media_midi_filename_ptr
;
97 int start_offset_video
;
98 int start_offset_audio
;
99 int start_offset_midi
;
103 free_song_descriptor(
104 struct song_descriptor
* song_descriptor_ptr
)
106 free(song_descriptor_ptr
->name_ptr
);
108 if (song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
110 free(song_descriptor_ptr
->media_video_filename_ptr
);
113 if (song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
115 free(song_descriptor_ptr
->media_audio_filename_ptr
);
118 if (song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
120 free(song_descriptor_ptr
->media_midi_filename_ptr
);
123 free(song_descriptor_ptr
);
127 dump_song_descriptor(
128 struct song_descriptor
* song_descriptor_ptr
)
130 NOTICE_OUT("Song name: \"%s\"", song_descriptor_ptr
->name_ptr
);
132 if (song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
134 NOTICE_OUT("Video media: \"%s\"", song_descriptor_ptr
->media_video_filename_ptr
);
137 if (song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
139 NOTICE_OUT("Audio media: \"%s\"", song_descriptor_ptr
->media_audio_filename_ptr
);
142 if (song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
144 NOTICE_OUT("MIDI media: \"%s\"", song_descriptor_ptr
->media_midi_filename_ptr
);
150 const char * song_filename_ptr
,
151 char ** song_name_ptr_ptr
)
156 doc_ptr
= xmlParseFile(song_filename_ptr
);
159 ERROR_OUT("Failed to parse song \"%s\"", song_filename_ptr
);
164 ret
= xml_get_string_dup(doc_ptr
, XPATH_SONG_NAME_EXPRESSION
, song_name_ptr_ptr
);
167 ERROR_OUT("Cannot find song name within \"%s\"", song_filename_ptr
);
183 const char * song_filename_ptr
,
184 struct song_descriptor
** song_descriptor_ptr_ptr
)
186 int ret
, midi
, audio
, video
;
188 struct song_descriptor
* song_descriptor_ptr
;
189 char * media_filename_ptr
;
190 char * song_filename_copy_ptr
;
191 const char * song_dirname_ptr
;
192 size_t song_dirname_size
;
195 DEBUG_OUT("Parsing %s", song_filename_ptr
);
197 song_filename_copy_ptr
= strdup(song_filename_ptr
);
198 if (song_filename_copy_ptr
== NULL
)
200 ERROR_OUT("strdup() failed");
205 song_dirname_ptr
= dirname(song_filename_copy_ptr
);
207 DEBUG_OUT("song dirname is \"%s\"", song_dirname_ptr
);
209 song_dirname_size
= strlen(song_dirname_ptr
);
211 doc_ptr
= xmlParseFile(song_filename_ptr
);
214 ERROR_OUT("Failed to parse song \"%s\"", song_filename_ptr
);
219 song_descriptor_ptr
= (struct song_descriptor
*)malloc(sizeof(struct song_descriptor
));
220 if (song_descriptor_ptr
== NULL
)
222 ERROR_OUT("Cannot allocate song descriptor");
227 midi
= xml_check_path(doc_ptr
, "/song/midi");
230 ERROR_OUT("xml_check_path() failed.");
235 audio
= xml_check_path(doc_ptr
, "/song/audio");
238 ERROR_OUT("xml_check_path() failed.");
243 video
= xml_check_path(doc_ptr
, "/song/video");
246 ERROR_OUT("xml_check_path() failed.");
253 ERROR_OUT("Only one MIDI media allowed.");
260 ERROR_OUT("Only one audio media allowed.");
267 ERROR_OUT("Only one video media allowed.");
274 ret
= xml_get_string_dup(doc_ptr
, "/song/midi/media", &media_filename_ptr
);
277 ERROR_OUT("Cannot find MIDI media filename within \"%s\"", song_filename_ptr
);
279 goto exit_free_song_descriptor
;
282 NOTICE_OUT("MIDI present");
284 if (media_filename_ptr
[0] == '/')
286 song_descriptor_ptr
->media_midi_filename_ptr
= media_filename_ptr
;
290 temp_size
= strlen(media_filename_ptr
);
292 song_descriptor_ptr
->media_midi_filename_ptr
= (char *)malloc(song_dirname_size
+ 1 + temp_size
+ 1);
293 if (song_descriptor_ptr
->media_midi_filename_ptr
== NULL
)
295 ERROR_OUT("malloc() failed.");
297 goto exit_free_song_descriptor
;
300 memcpy(song_descriptor_ptr
->media_midi_filename_ptr
, song_dirname_ptr
, song_dirname_size
);
301 song_descriptor_ptr
->media_midi_filename_ptr
[song_dirname_size
] = '/';
302 memcpy(song_descriptor_ptr
->media_midi_filename_ptr
+ song_dirname_size
+ 1, media_filename_ptr
, temp_size
);
303 song_descriptor_ptr
->media_midi_filename_ptr
[song_dirname_size
+ 1 + temp_size
] = 0;
305 path_normalize(song_descriptor_ptr
->media_midi_filename_ptr
);
310 song_descriptor_ptr
->media_midi_filename_ptr
= NULL
;
311 NOTICE_OUT("MIDI absent");
316 ret
= xml_get_string_dup(doc_ptr
, "/song/audio/media", &media_filename_ptr
);
319 ERROR_OUT("Cannot find audio media filename within \"%s\"", song_filename_ptr
);
321 goto free_midi_filename
;
324 NOTICE_OUT("Audio present");
326 if (media_filename_ptr
[0] == '/')
328 song_descriptor_ptr
->media_audio_filename_ptr
= media_filename_ptr
;
332 temp_size
= strlen(media_filename_ptr
);
334 song_descriptor_ptr
->media_audio_filename_ptr
= (char *)malloc(song_dirname_size
+ 1 + temp_size
+ 1);
335 if (song_descriptor_ptr
->media_audio_filename_ptr
== NULL
)
337 ERROR_OUT("malloc() failed.");
339 goto exit_free_song_descriptor
;
342 memcpy(song_descriptor_ptr
->media_audio_filename_ptr
, song_dirname_ptr
, song_dirname_size
);
343 song_descriptor_ptr
->media_audio_filename_ptr
[song_dirname_size
] = '/';
344 memcpy(song_descriptor_ptr
->media_audio_filename_ptr
+ song_dirname_size
+ 1, media_filename_ptr
, temp_size
);
345 song_descriptor_ptr
->media_audio_filename_ptr
[song_dirname_size
+ 1 + temp_size
] = 0;
347 path_normalize(song_descriptor_ptr
->media_audio_filename_ptr
);
352 song_descriptor_ptr
->media_audio_filename_ptr
= NULL
;
353 NOTICE_OUT("Audio absent");
358 ret
= xml_get_string_dup(doc_ptr
, "/song/video/media", &media_filename_ptr
);
361 ERROR_OUT("Cannot find video media filename within \"%s\"", song_filename_ptr
);
363 goto free_audio_filename
;
366 NOTICE_OUT("Video present");
368 if (media_filename_ptr
[0] == '/')
370 song_descriptor_ptr
->media_video_filename_ptr
= media_filename_ptr
;
374 temp_size
= strlen(media_filename_ptr
);
376 song_descriptor_ptr
->media_video_filename_ptr
= (char *)malloc(song_dirname_size
+ 1 + temp_size
+ 1);
377 if (song_descriptor_ptr
->media_video_filename_ptr
== NULL
)
379 ERROR_OUT("malloc() failed.");
381 goto exit_free_song_descriptor
;
384 memcpy(song_descriptor_ptr
->media_video_filename_ptr
, song_dirname_ptr
, song_dirname_size
);
385 song_descriptor_ptr
->media_video_filename_ptr
[song_dirname_size
] = '/';
386 memcpy(song_descriptor_ptr
->media_video_filename_ptr
+ song_dirname_size
+ 1, media_filename_ptr
, temp_size
);
387 song_descriptor_ptr
->media_video_filename_ptr
[song_dirname_size
+ 1 + temp_size
] = 0;
389 path_normalize(song_descriptor_ptr
->media_video_filename_ptr
);
394 song_descriptor_ptr
->media_video_filename_ptr
= NULL
;
395 NOTICE_OUT("Video absent");
398 ret
= xml_get_string_dup(doc_ptr
, XPATH_SONG_NAME_EXPRESSION
, &song_descriptor_ptr
->name_ptr
);
401 ERROR_OUT("Cannot find song name within \"%s\"", song_filename_ptr
);
403 goto free_video_filename
;
406 ret
= xml_get_int(doc_ptr
, "/song/start_offsets/video", &song_descriptor_ptr
->start_offset_video
);
409 DEBUG_OUT("song video start offset is not supplied, defaulting to 0");
410 song_descriptor_ptr
->start_offset_video
= 0;
414 DEBUG_OUT("song video start offset is %d microseconds", song_descriptor_ptr
->start_offset_video
);
417 ret
= xml_get_int(doc_ptr
, "/song/start_offsets/audio", &song_descriptor_ptr
->start_offset_audio
);
420 DEBUG_OUT("song audio start offset is not supplied, defaulting to 0");
421 song_descriptor_ptr
->start_offset_audio
= 0;
425 DEBUG_OUT("song audio start offset is %d microseconds", song_descriptor_ptr
->start_offset_audio
);
428 ret
= xml_get_int(doc_ptr
, "/song/start_offsets/midi", &song_descriptor_ptr
->start_offset_midi
);
431 DEBUG_OUT("song midi start offset is not supplied, defaulting to 0");
432 song_descriptor_ptr
->start_offset_midi
= 0;
436 DEBUG_OUT("song midi start offset is %d microseconds", song_descriptor_ptr
->start_offset_midi
);
439 *song_descriptor_ptr_ptr
= song_descriptor_ptr
;
444 free(song_descriptor_ptr
->media_video_filename_ptr
);
447 free(song_descriptor_ptr
->media_audio_filename_ptr
);
450 free(song_descriptor_ptr
->media_midi_filename_ptr
);
452 exit_free_song_descriptor
:
453 free(song_descriptor_ptr
);
459 free(song_filename_copy_ptr
);
467 const char * song_filename_ptr
,
471 int start_offsets
[3];
472 struct player
* players
[3];
475 struct player
* player_temp_ptr
;
476 int start_offset_temp
;
477 int global_start_offset_video
;
478 int global_start_offset_audio
;
479 int global_start_offset_midi
;
481 DEBUG_OUT("play_song(%s) called.", song_filename_ptr
);
483 ret
= conf_file_get_int("/conf/start_offsets/video", &global_start_offset_video
);
486 ERROR_OUT("failed to read from configuration what global video start offset to use");
491 ret
= conf_file_get_int("/conf/start_offsets/audio", &global_start_offset_audio
);
494 ERROR_OUT("failed to read from configuration what global audio start offset to use");
499 ret
= conf_file_get_int("/conf/start_offsets/midi", &global_start_offset_midi
);
502 ERROR_OUT("failed to read from configuration what global midi start offset to use");
507 DEBUG_OUT("Using global video start offset of %d microseconds", global_start_offset_video
);
508 DEBUG_OUT("Using global audio start offset of %d microseconds", global_start_offset_audio
);
509 DEBUG_OUT("Using global midi start offset of %d microseconds", global_start_offset_midi
);
511 ret
= get_song_descriptor(song_filename_ptr
, &g_song_descriptor_ptr
);
514 ERROR_OUT("Failed to get song descriptor (%d)", ret
);
519 OUTPUT_MESSAGE("====== Play \"%s\"", g_song_descriptor_ptr
->name_ptr
);
521 dump_song_descriptor(g_song_descriptor_ptr
);
523 DEBUG_OUT("Initializing...");
527 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
529 g_real_mask
|= EOD_CONTEXT_VIDEO
;
532 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
534 g_real_mask
|= EOD_CONTEXT_AUDIO
;
537 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
539 g_real_mask
|= EOD_CONTEXT_MIDI
;
542 ret
= pthread_mutex_init(&g_real_mask_mutex
, NULL
);
545 ERROR_OUT("Failed to init real mask mutex (%d)", ret
);
547 goto exit_free_song_descriptor
;
550 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
552 ret
= media_source_dv(g_song_descriptor_ptr
->media_video_filename_ptr
, &g_media_source_dv_ptr
);
555 ERROR_OUT("failed to create the DV source");
557 goto exit_destroy_mutex
;
561 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
563 ret
= media_source_wav(g_song_descriptor_ptr
->media_audio_filename_ptr
, &g_media_source_wav_ptr
);
566 ERROR_OUT("failed to create the WAV source");
568 goto exit_destroy_media_source_dv
;
572 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
574 ret
= media_source_midi(g_song_descriptor_ptr
->media_midi_filename_ptr
, &g_media_source_midi_ptr
);
577 ERROR_OUT("failed to create the MIDI source");
579 goto exit_destroy_media_source_wav
;
583 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
585 ret
= player_video1394(g_media_source_dv_ptr
, eod
, EOD_CONTEXT_VIDEO
, &g_player_video1394_ptr
);
588 ERROR_OUT("failed to create the firewire player");
590 goto exit_destroy_media_source_midi
;
595 g_player_video1394_ptr
= NULL
;
598 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
600 ret
= player_alsa_pcm(g_media_source_wav_ptr
, eod
, EOD_CONTEXT_AUDIO
, &g_player_alsa_pcm_ptr
);
603 ERROR_OUT("failed to create the ALSA PCM player");
605 goto exit_destroy_video_1394_player
;
610 g_player_alsa_pcm_ptr
= NULL
;
613 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
615 ret
= player_alsa_midi(g_media_source_midi_ptr
, eod
, EOD_CONTEXT_MIDI
, &g_player_alsa_midi_ptr
);
618 ERROR_OUT("failed to create the ALSA MIDI player");
620 goto exit_destroy_alsa_pcm_player
;
625 g_player_alsa_midi_ptr
= NULL
;
628 players
[0] = g_player_video1394_ptr
;
629 start_offsets
[0] = global_start_offset_video
+ g_song_descriptor_ptr
->start_offset_video
;
631 players
[1] = g_player_alsa_pcm_ptr
;
632 start_offsets
[1] = global_start_offset_audio
+ g_song_descriptor_ptr
->start_offset_audio
;
634 players
[2] = g_player_alsa_midi_ptr
;
635 start_offsets
[2] = global_start_offset_midi
+ g_song_descriptor_ptr
->start_offset_midi
;
637 DEBUG_OUT("Preparing...");
639 for (i
= 0 ; i
< 3 ; i
++)
641 //ERROR_OUT("Preparing %s player", players[i]->name);
642 if (players
[i
] != NULL
)
644 ret
= player_start_prepare(players
[i
]);
647 ERROR_OUT("failed to prepare %s player for start", players
[i
]->name
);
649 goto exit_destroy_players
;
654 /* sort players by start offset */
655 for (i
= 0 ; i
< 3 ; i
++)
657 for (j
= i
+ 1 ; j
< 3 ; j
++)
659 //DEBUG_OUT("Comparing %i (%i) and %i (%i)", j, start_offsets[j], i, start_offsets[i]);
660 if (start_offsets
[j
] < start_offsets
[i
])
662 //DEBUG_OUT("Exchanging %i and %i", i, j);
663 start_offset_temp
= start_offsets
[i
];
664 player_temp_ptr
= players
[i
];
666 start_offsets
[i
] = start_offsets
[j
];
667 players
[i
] = players
[j
];
669 start_offsets
[j
] = start_offset_temp
;
670 players
[j
] = player_temp_ptr
;
675 /* DEBUG_OUT("------ sorted players"); */
676 /* for (i = 0 ; i < 3 ; i++) */
678 /* DEBUG_OUT("%s player, start offset %d", players[i]->name, start_offsets[i]); */
681 /* normalize offsets and make start offsets relative */
682 start_offset_temp
= start_offsets
[0];
683 for (i
= 0 ; i
< 3 ; i
++)
685 start_offsets
[i
] -= start_offset_temp
;
688 for (i
= 1 ; i
< 3 ; i
++)
690 start_offsets
[i
] -= start_offsets
[i
-1];
693 /* DEBUG_OUT("------ normalized players"); */
694 /* for (i = 0 ; i < 3 ; i++) */
696 /* DEBUG_OUT("%s player, start offset %d", players[i]->name, start_offsets[i]); */
699 /* show startup plan */
700 DEBUG_OUT("------ players startup plan");
701 for (i
= 0 ; i
< 3 ; i
++)
703 if (start_offsets
[i
] != 0)
705 DEBUG_OUT("Wait %d microseconds", start_offsets
[i
]);
706 if (start_offsets
[i
] < 0)
708 ERROR_OUT("Cannot reverse the time (sort and/or normalize failed)");
709 goto exit_destroy_players
;
713 if (players
[i
] != NULL
)
715 DEBUG_OUT("Start %s player", players
[i
]->name
);
721 OUTPUT_MESSAGE("...... GO!");
722 for (i
= 0 ; i
< 3 ; i
++)
724 if (start_offsets
[i
] != 0)
726 //DEBUG_OUT("Waiting %d microseconds", start_offsets[i]);
727 usleep(start_offsets
[i
]);
730 if (players
[i
] != NULL
)
732 //DEBUG_OUT("Starting %s player", players[i]->name);
733 ret
= player_start(players
[i
]);
736 ERROR_OUT("failed to start %s player", players
[i
]->name
);
738 goto exit_destroy_players
;
746 exit_destroy_players
:
747 //exit_destroy_alsa_midi_player:
748 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
750 player_destroy(g_player_alsa_midi_ptr
);
753 exit_destroy_alsa_pcm_player
:
754 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
756 player_destroy(g_player_alsa_pcm_ptr
);
759 exit_destroy_video_1394_player
:
760 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
762 player_destroy(g_player_video1394_ptr
);
765 exit_destroy_media_source_midi
:
766 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
768 media_source_destroy(g_media_source_midi_ptr
);
771 exit_destroy_media_source_wav
:
772 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
774 media_source_destroy(g_media_source_wav_ptr
);
777 exit_destroy_media_source_dv
:
778 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
780 media_source_destroy(g_media_source_dv_ptr
);
784 ret1
= pthread_mutex_destroy(&g_real_mask_mutex
);
787 ERROR_OUT("Failed to destroy real mask mutex (%d)", ret1
);
790 exit_free_song_descriptor
:
791 free_song_descriptor(g_song_descriptor_ptr
);
800 DEBUG_OUT("------ STOP!");
802 pthread_mutex_lock(&g_real_mask_mutex
);
803 if (g_real_mask
!= 0)
805 OUTPUT_MESSAGE("====== Stopping...");
807 pthread_mutex_unlock(&g_real_mask_mutex
);
809 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
810 player_destroy(g_player_alsa_midi_ptr
);
812 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
813 player_destroy(g_player_alsa_pcm_ptr
);
815 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
816 player_destroy(g_player_video1394_ptr
);
818 if (g_song_descriptor_ptr
->media_midi_filename_ptr
!= NULL
)
819 media_source_destroy(g_media_source_midi_ptr
);
821 if (g_song_descriptor_ptr
->media_audio_filename_ptr
!= NULL
)
822 media_source_destroy(g_media_source_wav_ptr
);
824 if (g_song_descriptor_ptr
->media_video_filename_ptr
!= NULL
)
825 media_source_destroy(g_media_source_dv_ptr
);
827 pthread_mutex_destroy(&g_real_mask_mutex
);
829 free_song_descriptor(g_song_descriptor_ptr
);
831 g_player_alsa_midi_ptr
= NULL
;
832 g_player_alsa_pcm_ptr
= NULL
;
833 g_player_video1394_ptr
= NULL
;
834 g_media_source_midi_ptr
= NULL
;
835 g_media_source_wav_ptr
= NULL
;
836 g_media_source_dv_ptr
= NULL
;
837 g_song_descriptor_ptr
= NULL
;
839 if (g_real_mask
!= 0)
841 OUTPUT_MESSAGE("====== Stopped");