La playlist dans totem

Voici une étude du chargement d'une playlist dans totem-xine. J'essayerais d'indiquer ce que j'ai fait et de résumer ce que j'aurais pu faire. Il s'agit d'une étude remplit d'essais et d'erreurs. Le but est de trouver comment totem charge une playlist asf et pourquoi il charge la playlist en UTF-8 même si le charset du serveur envoit du charset=iso-8859-1.

Avoir le source

sous debian
$ apt-get source totem-xine
$ su -c "apt-get build-dep totem-xine"
$ cd totem-2.16.5  # la version peut variée

L'entrée des paramètres

On peut entrer les paramètres suivants à la ligne de commande: $ totem --debug "http://www.site.com/playlist.php?type=asf"

.

La première rechercher est de savoir à quel endroit il:

  • 1. initialise le programme
  • 2. charge les options
  • 3. gère l'URL

Tout programme en C, et surtout en linux (pour le type de retour int) commence par un int main(int argc, char **argv) ou int main(int argc, char *argv[]). Il y a plusieurs syntaxe pour les paramètres et l'indentation peut variée. On suppose que le type de retour est int. On peut donc faire dans le répertoire de "src" de totem: grep -ERn "main\s*\(int argc" *.c (c'est seulement une expression régulière qui indique qu'il peut y avoir 0 ou plusieurs espace (le \s*) entre le main et la parenthèse de paramètres. On obtient le résultat suivant:

list_v4l.c:30:int main (int argc, char **argv)
metadata-test.c:160:int main (int argc, char **argv)
test-properties-page.c:63:int main (int argc, char **argv)
totem.c:3647:main (int argc, char **argv)
totem-mozilla-viewer.c:835:int main (int argc, char **argv)
totem-video-thumbnailer.c:330:int main (int argc, char *argv[])
vanity.c:631:main (int argc, char **argv)

On a plusieurs possibilités, on peut les essayer une par une ou encore se douter que le main principal va être dans le fichier "totem.c", ligne 3647. Habituellement, les programmes exécutables ont le même nom que le fichier .c, mais ce n'est pas tout le temps vrai. Donc on fait un vim totem.c +347 et regarder si on a vu juste.

L'important est de regarder le paramètre argc et argv et de le suivre dans la fonction main. On peut voir ces lignes:

3656         if (XInitThreads () == 0)
3657         {
3658                 gtk_init (&argc, &argv);
3659                 g_set_application_name (_("Totem Movie Player"));
3660                 totem_action_error_and_exit (_("Could not initialize the thread-safe libraries."), _("Verify your system installation.
     Totem will now exit."), NULL);
3661         }
...
3665 #ifdef HAVE_GTK_ONLY
3666         gtk_init (&argc, &argv);
3667 #else
3668         gnome_program_init ("totem", VERSION,
3669                         LIBGNOMEUI_MODULE,
3670                         argc, argv,
3671                         GNOME_PARAM_APP_DATADIR, DATADIR,
3672                         GNOME_PARAM_POPT_TABLE, totem_options_get_options (),
3673                         GNOME_PARAM_NONE);
3674 #endif /* HAVE_GTK_ONLY */

Ce qui me semble le plus intéressant, sur linux avec gnome est la fonction gnome_program_init. On peut aussi voir GNOME_PARAM_POPT_TABLE et totem_options_get_options(). Puisque j'ai déjà programmé en C, je sais que "popt" est un programme très utilisé pour analyser les paramètres (Parser OPTion). GNOME_PARAM_POPT_TABLE doit être son penchant gnome. (Voir aussi: man popt). Je rejette les deux premiers gtk_init parce que le premier semble mener vers une erreur et le second est utilisé seulement avec un paramètre HAVE_GTK_ONLY (sûrement en environnement sans GNOME). J'utilise donc la fonction find dans vim pour chercher la fonction totem_options_get_options. Puisque je ne trouve rien d'autre, je fais un :!grep -n "totem_options_get_options" *

totem.c:                        GNOME_PARAM_POPT_TABLE, totem_options_get_options (),
totem-options.c:totem_options_get_options (void)
totem-options.h:poptOption totem_options_get_options (void);

Le premier résultat est la ligne que nous examinons: rejet, le totem-options.h est la définition: rejet. Nous regardons donc :sp totem-options.c. 55j. La fonction est presque vide, on peut voir un peu plus haut la liste des options, comme debug, mais pas d'appels. Puisque debug est une option, on pourrait rechercher "debug", mais je crois instinctivement qu'il va y avoir trop de résultat. Recherchons une ligne qui peut avoir moins de lignes comme toggle-controls. :!grep -n "toggle-controls" *. On voit que dans le même fichier, l'option est gérée. Regardons le nom de la fonction: totem_options_process_late, regardons la suite des fonctions... totem_options_process_early. On peut voir le code pour la gestion de --debug:

134                 if (strcmp (argv[i], "--debug") == 0)
135                 {
136                         gconf_client_set_bool (gc, GCONF_PREFIX"/debug",
137                                         TRUE, NULL);

Mais toujours rien pour notre dernier paramètre. Dans totem_options_process_for_server, on peut voir encore plus de traitement des options. Bon, ça se complique un peu, niveau code, mais suffit de lire ligne par ligne.

173         if (strlen (argv[1]) > 3 && g_str_has_prefix (argv[1], "--") == FALSE)
174         {
175                 command = TOTEM_REMOTE_COMMAND_REPLACE;
176                 i = 1;

Le code signifie: si le 2e argument (le premier, c'est le nom du programme) possède plus de 3 lettres et ne commence pas par "--", la valeur de la variable command est TOTEM_REMOTE_COMMAND_REPLACE. (Note: à lire ce code, on dirait que totem ne gère pas les playlist de 2 caractères). Je suppose que la gestion de --debug dans les fonctions plus haut a enlevé les paramètres précédents. argv[1] doit être l'URL. Puisqu'on a entré dans la condition if(), on lit ce qui suit (après tous les else):

230         for (; argv[i] != NULL; i++)
231         {
232                 full_path = totem_create_full_path (argv[i]);
233                 line = g_strdup_printf ("%03d %s", command, full_path);
234                 bacon_message_connection_send (conn, line);
235                 g_free (line);
236                 g_free (full_path);
237                 command = TOTEM_REMOTE_COMMAND_ENQUEUE;
238         }

Le code indique: pour tous les arguments restants, on exécute totem_create_full_path(argv[i]) et la commande bacon_message_connection_send(conn, TOTEM_REMOTE_COMMAND_ENQUEUE + " " + argv[i]. Remarquer que chaque argument après le premier argument sera traité comme un TOTEM_REMOTE_COMMAND_ENQUEUE.

À ce stade, il ne reste qu'à regarder la fonction totem_create_full_path. :!grep -n totem_create_full_path *". On peut trouver la ligne de déclaration:

totem-uri.c:91:totem_create_full_path (const char *path)

On ouvre le fichier: :sp totem-uri.c 90 j et on voit:

 97         if (strstr (path, "://") != NULL)
 98                 return g_strdup (path);

Rah, il ne s'agissait qu'une ruse!, lorsqu'il y a "://" dans l'url, il ne fait que dupliquer la chaîne et allouer de la mémoire. C'est donc bacon_message_connection_send qui fait tout le travail avec l'option TOTEM_REMOTE_COMMAND_ENQUEUE.

Comprendre le bacon

Qu'est-ce qu'on fait? On recherche TOTEM_REMOTE_COMMAND_ENQUEUE bien attendu! !grep -n TOTEM_REMOTE_COMMAND_ENQUEUE *.c et qui nous retourne la ligne: totem.c:2252: case TOTEM_REMOTE_COMMAND_ENQUEUE:

On revient dans notre fichier totem.c, à la ligne 2252. Voici le code intéressant (les paramètres de la fonction, et le traitement de l'option)

2212 static void
2213 totem_action_remote (Totem *totem, TotemRemoteCommand cmd, const char *url)
2214 {
2215         gboolean handled = TRUE;
2216
2217         switch (cmd) {
...
2252         case TOTEM_REMOTE_COMMAND_ENQUEUE:
2253                 g_assert (url != NULL);
2254                 if (totem_playlist_add_mrl (totem->playlist, url, NULL) != FALSE) {
2255                         totem_action_add_recent (totem, url);
2256                 }
2257                 break;

C'est donc la fonction totem_playlist_add_mrl qui traite l'URL de notre playlist. On fait une recherche dans les *.c, on trouve: totem-playlist.c:1600:totem_playlist_add_mrl (TotemPlaylist *playlist, const char *mrl,. Et on observe le traitement de notre URL. Cette fonction appelle: totem_pl_parser_parse (playlist->_priv->parser, mrl, TRUE) qui est dans le fichier plparse/totem-pl-parser.c, ligne 2452 (un autre grep -Rn) qui appelle totem_pl_parser_parse_internal (parser, url);

2366 static TotemPlParserResult
2367 totem_pl_parser_parse_internal (TotemPlParser *parser, const char *url)