4 * @file gmyth/gmyth_livetv.c
6 * @brief <p> GMythLiveTV starts a remote TV session with the MythTV backend.
8 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
9 * @author Rosfran Lins Borges <rosfran.borges@indt.org.br>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "gmyth_livetv.h"
32 #include "gmyth_remote_util.h"
33 #include "gmyth_tvchain.h"
34 #include "gmyth_socket.h"
35 #include "gmyth_backendinfo.h"
36 #include "gmyth_debug.h"
38 #include "gmyth_file.h"
39 #include "gmyth_file_transfer.h"
40 #include "gmyth_file_local.h"
41 #include "gmyth_monitor_handler.h"
43 #include "gmyth_common.h"
44 #include "gmyth_util.h"
46 static void gmyth_livetv_class_init(GMythLiveTVClass * klass);
47 static void gmyth_livetv_init(GMythLiveTV * object);
49 static void gmyth_livetv_dispose(GObject * object);
50 static void gmyth_livetv_finalize(GObject * object);
52 static gint tvchain_curr_index = -1;
55 * static GStaticMutex lock = G_STATIC_MUTEX_INIT;
58 #define GMYTHTV_TRANSFER_MAX_WAITS 100
60 G_DEFINE_TYPE(GMythLiveTV, gmyth_livetv, G_TYPE_OBJECT)
61 static void gmyth_livetv_class_init(GMythLiveTVClass * klass)
63 GObjectClass *gobject_class;
65 gobject_class = (GObjectClass *) klass;
67 gobject_class->dispose = gmyth_livetv_dispose;
68 gobject_class->finalize = gmyth_livetv_finalize;
72 gmyth_livetv_init(GMythLiveTV * livetv)
74 livetv->monitor = NULL;
75 livetv->backend_info = NULL;
76 livetv->local_hostname = NULL;
78 livetv->setup_done = FALSE;
80 livetv->socket = NULL;
81 livetv->recorder = NULL;
82 livetv->tvchain = NULL;
83 livetv->proginfo = NULL;
86 livetv->mutex = g_mutex_new();
90 gmyth_livetv_dispose(GObject * object)
92 GMythLiveTV *livetv = GMYTH_LIVETV(object);
95 if (livetv->disposed) {
97 * If dispose did already run, return.
103 * Make sure dispose does not run twice.
105 livetv->disposed = TRUE;
107 if (livetv->monitor != NULL) {
108 g_object_unref(livetv->monitor);
109 livetv->monitor = NULL;
112 if (livetv->file != NULL) {
113 g_object_unref(livetv->file);
118 if (livetv->recorder != NULL) {
119 // gmyth_recorder_close(livetv->recorder);
120 g_object_unref(livetv->recorder);
121 livetv->recorder = NULL;
124 if (livetv->socket != NULL) {
125 g_object_unref(livetv->socket);
126 livetv->socket = NULL;
129 if (livetv->tvchain != NULL) {
130 g_object_unref(livetv->tvchain);
131 livetv->tvchain = NULL;
135 if (livetv->proginfo != NULL) {
136 g_object_unref(livetv->proginfo);
137 livetv->proginfo = NULL;
140 if (livetv->backend_info != NULL) {
141 g_object_unref(livetv->backend_info);
142 livetv->backend_info = NULL;
146 if (livetv->uri != NULL) {
147 g_object_unref(livetv->uri);
151 if (livetv->mutex != NULL) {
152 g_mutex_free(livetv->mutex);
153 livetv->mutex = NULL;
157 if (livetv->local_hostname != NULL) {
158 g_string_free(livetv->local_hostname, TRUE);
159 livetv->local_hostname = NULL;
162 G_OBJECT_CLASS(gmyth_livetv_parent_class)->dispose(object);
166 gmyth_livetv_finalize(GObject * object)
168 g_signal_handlers_destroy(object);
170 G_OBJECT_CLASS(gmyth_livetv_parent_class)->finalize(object);
174 * Creates a new GMythLiveTV instance
176 * @return a newly allocated GMythLiveTV instance
179 gmyth_livetv_new(GMythBackendInfo * backend_info)
181 GMythLiveTV *livetv =
182 GMYTH_LIVETV(g_object_new(GMYTH_LIVETV_TYPE, NULL));
184 livetv->backend_info = backend_info;
185 g_object_ref(livetv->backend_info);
191 * The GObject signal handler function, from which all status messages
192 * from the Monitor Handler will be advertized, all time it receives
193 * LiveTV status messages from the MythTV backend
195 * @param monitor a GMythMonitorHandler instance
196 * @param msg_code the MythTV's server numeric status code
197 * @param message the message's string description
198 * @param user_data pointer to the GMythLiveTV instance
201 gmyth_livetv_monitor_signal_handler(GMythMonitorHandler * monitor,
202 gint msg_code, gchar * message,
205 GMythLiveTV *live_tv = GMYTH_LIVETV(user_data);
208 ("LIVETV Signal handler ( msg = %s, code = %d, live_tv param = %s, user_data = %s )\n",
209 message, msg_code, live_tv != NULL ? "" : "NULL",
210 user_data != NULL ? "" : "NULL");
212 if (NULL == live_tv || !IS_GMYTH_FILE_TRANSFER(live_tv->file)) {
213 gmyth_debug("LiveTV_obj is equals to NULL!!!");
219 case GMYTH_BACKEND_PROGRAM_INFO_CHANGED:
222 ("LIVETV Program Changed request received [ msg = %s ]. Watching if the new "
223 "TV Chain ID is the same as the old one...\n", message);
224 if (g_ascii_strcasecmp
226 (gmyth_tvchain_get_id(live_tv->tvchain))->str) != 0) {
228 ("OK!!! MOVED to the next program chain [actual == %s]!",
229 (gmyth_tvchain_get_id(live_tv->tvchain))->str);
231 * advertises the FileTransfer about the program info
234 if (live_tv->file != NULL) {
236 ("Emitting signal to the FileTransfer... [ \"program-info-changed \" ]");
238 gmyth_file_transfer_emit_program_info_changed_signal
239 (GMYTH_FILE_TRANSFER(live_tv->file), msg_code,
240 (gpointer) (live_tv->recorder));
243 * gmyth_livetv_monitor_handler_stop( live_tv );
247 ("LIVETV file_transfer is NULL!!! Cannot move to the next program chain event received.\n");
251 case GMYTH_BACKEND_DONE_RECORDING:
254 ("LIVETV Program Changed request received [ msg = %s ]. Watching if the new "
255 "TV Chain ID is the same as the old one...\n", message);
256 if (g_ascii_strcasecmp
258 (gmyth_tvchain_get_id(live_tv->tvchain))->str) != 0) {
260 ("OK!!! MOVED to the next program chain [actual == %s]!",
261 (gmyth_tvchain_get_id(live_tv->tvchain))->str);
263 * advertises the FileTransfer about the program info
266 if (live_tv->file != NULL) {
268 ("Emitting signal to the FileTransfer... [ \"backend-done-recording\" ]");
270 gmyth_file_transfer_emit_program_info_changed_signal
271 (GMYTH_FILE_TRANSFER(live_tv->file), msg_code,
272 (gpointer) (live_tv->recorder));
276 ("LIVETV file_transfer is NULL!!! Cannot move to the next program chain event received.\n");
280 case GMYTH_BACKEND_STOP_LIVETV:
283 ("LIVETV Stop LiveTV request received [ msg = %s ]. Going out the "
284 "LiveTV...\n", message);
288 if (live_tv != NULL) {
289 gmyth_debug("Going out the LiveTV... [ \"quit-livetv\" ]");
291 g_object_unref(live_tv);
294 ("LIVETV file_transfer is NULL!!! Cannot move to the next program chain event received.\n");
300 } /* switch (Monitor Handler messages) */
305 * Starts the Monitor Handler to this GMythLiveTV session, in order
306 * to receive the status messages from the MythTV's backend server
308 * @param live_tv the GMythLiveTV instance
310 * @return <code>true</code> if the Monitor Handler start-up process
311 * had been concluded succcesfully
314 gmyth_livetv_monitor_handler_start(GMythLiveTV * livetv)
318 if (livetv->monitor != NULL) {
319 g_object_unref(livetv->monitor);
320 livetv->monitor = NULL;
323 livetv->monitor = gmyth_monitor_handler_new();
326 gmyth_monitor_handler_open(livetv->monitor,
327 livetv->backend_info->hostname,
328 livetv->backend_info->port);
332 ("Connect MythTV Monitor event socket! Trying to start the message handler...");
334 res = gmyth_monitor_handler_start(livetv->monitor);
338 ("MythTV Monitor event socket connected and listening!");
339 g_signal_connect(G_OBJECT(livetv->monitor),
340 "backend-events-handler", (GCallback)
341 gmyth_livetv_monitor_signal_handler, livetv);
344 ("Problems when trying to start MythTV Monitor event socket!");
355 * Stops the Monitor Handler to this GMythLiveTV session, in order
356 * to stop receiving the status messages from the MythTV's backend server
358 * @param live_tv the GMythLiveTV instance
360 * @return <code>true</code> if the Monitor Handler shutdown process
361 * had been concluded succcesfully
364 gmyth_livetv_monitor_handler_stop(GMythLiveTV * livetv)
367 if (livetv->monitor != NULL) {
368 g_object_unref(livetv->monitor);
369 livetv->monitor = NULL;
376 gmyth_livetv_create_remote_url(GMythLiveTV * livetv)
378 gchar *uri = g_strdup("");
380 gmyth_backend_info_get_remote_h
381 // gmyth_backend(livetv->backend_info)
387 * Configures the GMythLiveTV session, sends SPAWN_LIVETV message,
388 * sets the channel name, and gets the first program info about the
391 * @param live_tv the GMythLiveTV instance
392 * @param channel the channel name (the chan_name field, from the tvchain table)
393 * @param backend_info the GMythBackendInfo describing the remote server
395 * @return <code>true</code> if the LiveTV's recorder instance configuration
396 * had been concluded succcesfully
399 gmyth_livetv_setup_recorder_channel_name(GMythLiveTV * livetv,
404 g_return_val_if_fail(livetv != NULL, FALSE);
406 if (NULL == livetv->socket) {
407 livetv->socket = gmyth_socket_new();
410 * FIME: Implement this at gmyth_socket
413 gmyth_socket_connect_to_backend(livetv->socket,
414 livetv->backend_info->hostname,
415 livetv->backend_info->port,
418 gmyth_debug("[%s] LiveTV can not connect to backend",
425 g_mutex_lock(livetv->mutex);
427 livetv->is_livetv = TRUE;
429 livetv->local_hostname = gmyth_socket_get_local_hostname();
431 if (livetv->local_hostname == NULL) {
432 g_warning("livetv could not retrieve the local hostname");
436 gmyth_debug("Local hostname: %s", livetv->local_hostname->str);
439 if (livetv->recorder != NULL) {
440 g_object_unref(livetv->recorder);
441 livetv->recorder = NULL;
444 if (gmyth_remote_util_get_free_recorder_count(livetv->socket) <= 0) {
445 gmyth_debug("No free remote encoder available.");
451 * Gets the recorder num
454 remote_request_next_free_recorder(livetv->socket, -1);
455 gmyth_socket_close_connection(livetv->socket);
457 if (NULL == livetv->recorder) {
458 gmyth_debug("[%s] None remote encoder available", __FUNCTION__);
464 * Init remote encoder. Opens its control socket.
466 res = gmyth_recorder_setup(livetv->recorder);
468 gmyth_debug("[%s] Fail while setting remote encoder\n",
475 * Creates livetv chain handler
477 livetv->tvchain = gmyth_tvchain_new();
478 gmyth_tvchain_initialize(livetv->tvchain, livetv->backend_info);
480 if (livetv->tvchain == NULL || livetv->tvchain->tvchain_id == NULL) {
484 // Spawn live tv. Uses the socket to send mythprotocol data to start
485 // livetv in the backend (remotelly)
486 res = gmyth_recorder_spawntv(livetv->recorder,
487 gmyth_tvchain_get_id(livetv->tvchain));
489 gmyth_debug("[%s] Fail while spawn tv\n", __FUNCTION__);
496 * loop finished, set the max tries variable to zero again...
498 gint wait_to_transfer = 0;
500 while (wait_to_transfer++ < GMYTHTV_TRANSFER_MAX_WAITS &&
501 (gmyth_recorder_is_recording(livetv->recorder) == FALSE))
504 if (channel != NULL) {
506 * Pauses remote encoder.
508 res = gmyth_recorder_pause_recording(livetv->recorder);
510 gmyth_debug("[%s] Fail while pausing remote encoder\n",
516 if (gmyth_recorder_check_channel_name
517 (livetv->recorder, channel)) {
518 if (gmyth_recorder_set_channel_name
519 (livetv->recorder, channel)) {
520 gmyth_debug("Channel changed!!! [%s].\n", channel);
526 * if - changes the channel number
532 * FIXME: this is evil (tpm)
539 GMythProgramInfo *prog_info =
540 gmyth_recorder_get_current_program_info(livetv->recorder);
542 if (NULL == prog_info) {
543 gmyth_debug("ProgramInfo is equals to NULL!!!");
546 gchar *channame = NULL;
548 gmyth_debug("Problem getting current proginfo!\n");
551 * mythbackend must not be tuned in to a channel, so keep
552 * changing channels until we find a valid one, or until
553 * we decide to give up.
555 for (i = 1; i < 1000; i++) {
556 if (channame != NULL)
558 channame = g_strdup_printf("%d", i);
559 if (gmyth_recorder_set_channel_name(livetv->recorder, channame)
564 gmyth_recorder_get_next_program_info(livetv->recorder,
565 BROWSE_DIRECTION_UP);
566 gmyth_program_info_print(prog_info);
567 if (prog_info != NULL)
577 * prints program info data text
579 gmyth_debug("New ProgramInfo...\n");
580 gmyth_program_info_print(prog_info);
583 * check if the program chain could be obtained from the MythTV
586 if (prog_info != NULL) {
587 gmyth_backend_info_set_username(livetv->tvchain->backend_info,
589 gmyth_backend_info_set_password(livetv->tvchain->backend_info,
591 gmyth_backend_info_set_db_name(livetv->tvchain->backend_info,
594 gmyth_tvchain_get_program_info_from_channel(livetv->tvchain,
596 GMythProgramInfo *ch_prog = NULL;
598 if (prog_list != NULL && g_list_length(prog_list) > 0) {
599 ch_prog = (GMythProgramInfo *) g_list_nth_data(prog_list, 0);
601 ("Channel program info (from a list with size = %d)!",
602 g_list_length(prog_list));
603 gmyth_program_info_print(ch_prog);
606 gmyth_debug("Program Info: %s\n",
607 gmyth_program_info_to_string(prog_info));
608 livetv->proginfo = prog_info;
610 * testing change channel
612 // gmyth_recorder_spawntv_no_tvchain( livetv->recorder );
616 * check for the program info in the TV program chain could be
617 * obtained from the MythTV MySQL database
621 * Reload all TV chain from Mysql database.
623 gmyth_tvchain_reload_all(livetv->tvchain);
625 if (livetv->tvchain == NULL) {
631 * Get program info from database using chanid and starttime
634 gmyth_tvchain_get_program_at(livetv->tvchain,
635 tvchain_curr_index++);
636 if (livetv->proginfo == NULL) {
637 gmyth_debug("LiveTV not successfully started.\n");
643 ("GMythLiveTV: All requests to backend to start TV were OK. [%s]\n",
644 livetv->proginfo->pathname->str);
650 (GMythURI *) gmyth_backend_info_get_uri(livetv->backend_info);
652 g_mutex_unlock(livetv->mutex);
654 if (!gmyth_livetv_monitor_handler_start(livetv)) {
656 gmyth_debug("LiveTV MONITOR handler error on setup!");
660 livetv->setup_done = TRUE;
665 g_mutex_unlock(livetv->mutex);
667 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
671 if (livetv->local_hostname != NULL) {
672 g_string_free(livetv->local_hostname, TRUE);
673 livetv->local_hostname = NULL;
676 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
678 if (livetv->recorder != NULL) {
679 g_object_unref(livetv->recorder);
680 livetv->recorder = NULL;
683 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
685 if (livetv->tvchain != NULL) {
686 g_object_unref(livetv->tvchain);
687 livetv->tvchain = NULL;
690 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
692 if (livetv->proginfo != NULL) {
693 g_object_unref(livetv->proginfo);
694 livetv->proginfo = NULL;
697 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
699 if (livetv->monitor != NULL) {
700 g_object_unref(livetv->monitor);
701 livetv->monitor = NULL;
705 gmyth_debug("[%s] ERROR running LiveTV setup.\n", __FUNCTION__);
712 * Setup the GMythLiveTV session, sends SPAWN_LIVETV message,
713 * sets the channel name, and gets the first program info about the
716 * @param live_tv the GMythLiveTV instance
717 * @param channel the channel name, in numerical format
718 * @param backend_info the GMythBackendInfo describing the remote server
720 * @return <code>true</code> if the LiveTV's recorder instance configuration
721 * had been concluded succcesfully
724 gmyth_livetv_setup_recorder(GMythLiveTV * livetv, gint channel)
726 return gmyth_livetv_setup_recorder_channel_name(livetv,
729 g_strdup_printf("%d",
735 * Setup the GMythLiveTV session, sends SPAWN_LIVETV message,
736 * sets the channel name (numerical format), and gets the first program info about the
739 * @param live_tv the GMythLiveTV instance
740 * @param channel the channel name, in numerical format
741 * @param backend_info the GMythBackendInfo describing the remote server
743 * @return <code>true</code> if the LiveTV's recorder instance configuration
744 * had been concluded succcesfully
747 gmyth_livetv_channel_setup(GMythLiveTV * livetv, gint channel)
749 return gmyth_livetv_setup_recorder(livetv, channel);
753 * Setup the GMythLiveTV session, sends SPAWN_LIVETV message,
754 * sets the channel name (string format), and gets the first program info about the
757 * @param live_tv the GMythLiveTV instance
758 * @param channel the channel name, in numerical format
759 * @param backend_info the GMythBackendInfo describing the remote server
761 * @return <code>true</code> if the LiveTV's recorder instance configuration
762 * had been concluded succcesfully
765 gmyth_livetv_channel_name_setup(GMythLiveTV * livetv, gchar * channel)
767 return gmyth_livetv_setup_recorder_channel_name(livetv, channel);
771 * Setup the GMythLiveTV session, sends SPAWN_LIVETV message,
772 * and gets the first program info about the actual recording
773 * (doesn't changes the channel).
775 * @param live_tv the GMythLiveTV instance
776 * @param backend_info the GMythBackendInfo describing the remote server
778 * @return <code>true</code> if the LiveTV's recorder instance configuration
779 * had been concluded succcesfully
782 gmyth_livetv_setup(GMythLiveTV * livetv)
784 return gmyth_livetv_setup_recorder(livetv, -1);
788 * Gets the next program info from this GMythLiveTV session.
790 * @param live_tv the GMythLiveTV instance
792 * @return <code>true</code> if the next program info could be got
795 gmyth_livetv_next_program_chain(GMythLiveTV * livetv)
798 GMythProgramInfo *prog_info = NULL;
800 if (!livetv->setup_done) {
801 gmyth_debug("Call the setup function first!");
805 gmyth_debug("Current ProgramInfo...\n");
806 prog_info = gmyth_recorder_get_current_program_info(livetv->recorder);
808 if (prog_info != NULL) {
809 livetv->proginfo = prog_info;
812 ("ProgramInfo equals to NULL!!! Getting the next program info...");
814 gmyth_recorder_get_next_program_info(livetv->recorder,
815 BROWSE_DIRECTION_RIGHT);
816 livetv->proginfo = prog_info;
819 * prints program info data text
821 gmyth_program_info_print(prog_info);
823 if (prog_info != NULL) {
825 livetv->proginfo = prog_info;
827 ("GMythLiveTV: All requests to backend to start TV were OK, program info changed.");
830 ("[%s] LiveTV not successfully started on the next program chain.\n",
835 livetv->setup_done = TRUE;
840 gmyth_debug("ERROR running LiveTV setup.\n");
844 g_string_free(livetv->local_hostname, TRUE);
846 if (livetv->recorder != NULL) {
847 g_object_unref(livetv->recorder);
848 livetv->recorder = NULL;
851 if (livetv->tvchain != NULL) {
852 g_object_unref(livetv->tvchain);
853 livetv->tvchain = NULL;
856 if (livetv->proginfo != NULL) {
857 g_object_unref(livetv->proginfo);
858 livetv->proginfo = NULL;
865 * Creates a File Transfer session, using all configuration information
866 * got from the actual program info.
868 * @param live_tv the GMythLiveTV instance
870 * @return the actual GMythFileTransfer instance, generated using the
871 * data got from the actual program info.
874 gmyth_livetv_create_file_transfer(GMythLiveTV * livetv)
876 // GMythURI* uri = NULL;
881 if (!livetv->setup_done) {
883 ("Error: You must do the LiveTV setup, just before generating the FileTransfer from LiveTV source!");
887 if (livetv->proginfo != NULL)
888 gmyth_debug("URI path (from program info) = %s.\n",
889 livetv->proginfo->pathname->str);
891 gmyth_debug("URI path (from URI) = %s.\n", livetv->uri->uri->str);
893 g_mutex_lock(livetv->mutex);
895 if (livetv->file != NULL) {
897 * gmyth_file_transfer_close( livetv->file );
899 g_object_unref(livetv->file);
903 if (livetv->uri != NULL) {
905 ("URI is not NULL, creating from the ProgramInfo pathname... (%s)",
906 livetv->proginfo->pathname->str);
907 livetv->uri->path = g_string_erase(livetv->uri->path, 0, -1);
909 g_string_new(g_strrstr(livetv->proginfo->pathname->str, "/"));
912 ("URI is NULL, creating from the ProgramInfo pathname... (%s)",
913 livetv->proginfo->pathname->str);
915 gmyth_uri_new_with_value(livetv->proginfo->pathname->str);
918 if (NULL == livetv->uri) {
919 gmyth_debug("Couldn't parse the URI to start LiveTV! [ uri = %s ]",
920 livetv->proginfo->pathname->str);
924 if (gmyth_uri_is_local_file(livetv->uri))
926 GMYTH_FILE(gmyth_file_local_new(livetv->backend_info));
929 GMYTH_FILE(gmyth_file_transfer_new(livetv->backend_info));
931 * gmyth_file_transfer_settimeout(
932 * GMYTH_FILE_TRANSFER(livetv->file), TRUE );
936 if (NULL == livetv->file) {
938 ("Error: couldn't create the FileTransfer from LiveTV source!");
942 g_object_ref(livetv->file);
944 g_mutex_unlock(livetv->mutex);
947 * Do some locking procedure with the Monitor Handler messages...
952 * if ( uri != NULL ) { g_object_unref( uri ); uri = NULL; }
960 * Stops this LiveTV session.
962 * @param live_tv the GMythLiveTV instance
965 gmyth_livetv_stop_playing(GMythLiveTV * livetv)
967 gmyth_debug("Stopping the LiveTV...\n");
969 if (livetv->is_livetv) {
970 if (!gmyth_recorder_stop_livetv(livetv->recorder)) {
971 gmyth_debug("[%s] Error while stoping remote encoder",
975 if (!gmyth_recorder_finish_recording(livetv->recorder)) {
977 ("[%s] Error while finishing recording on remote encoder",
984 gmyth_livetv_is_playing(GMythLiveTV * livetv)
990 gmyth_livetv_start_playing(GMythLiveTV * livetv)