/* Copyright (C) 2004 Novell, Inc. Author: Radek Doulik */ /* This file is licensed under the GNU GPL v2 or later */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for unlink */ #include #include "e-util/e-icon-factory.h" #include "e-util/e-mktemp.h" #include "camel/camel-medium.h" #include "camel/camel-mime-part.h" #include "camel/camel-stream.h" #include "camel/camel-stream-fs.h" #include "mail/em-format-hook.h" #include "mail/em-format-html.h" #include "gtk/gtkbutton.h" #include "gtk/gtkbox.h" #include "gtk/gtkimage.h" #include "gtk/gtkhbbox.h" #include "gtkhtml/gtkhtml-embedded.h" #include "gst/gst.h" #define d(x) x void org_gnome_audio_inline_format (void *ep, EMFormatHookTarget *t); static volatile int org_gnome_audio_class_id_counter = 0; struct _org_gnome_audio_inline_pobject { EMFormatHTMLPObject object; CamelMimePart *part; char *filename; GstElement *thread; }; static void org_gnome_audio_inline_pobject_free (EMFormatHTMLPObject *o) { struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) o; d(printf ("audio inline formatter: pobject free\n")); if (po->part) { camel_object_unref (po->part); po->part = NULL; } if (po->filename) { unlink (po->filename); g_free (po->filename); po->filename = NULL; } if (po->thread) { gst_element_set_state (po->thread, GST_STATE_NULL); gst_object_unref (GST_OBJECT (po->thread)); po->thread = NULL; } } static void org_gnome_audio_inline_pause_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject) { struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject; if (po->thread) { /* start playing */ gst_element_set_state (po->thread, GST_STATE_PAUSED); } } static void org_gnome_audio_inline_stop_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject) { struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject; if (po->thread) { /* start playing */ gst_element_set_state (po->thread, GST_STATE_READY); } } static GstElement * org_gnome_audio_inline_gst_mpeg_thread (GstElement *filesrc) { GstElement *thread, *decoder, *audiosink; /* create a new thread to hold the elements */ thread = gst_thread_new ("org-gnome-audio-inline-mpeg-thread"); /* now it's time to get the decoder */ decoder = gst_element_factory_make ("mad", "decoder"); /* and an audio sink */ audiosink = gst_element_factory_make ("osssink", "play_audio"); /* add objects to the main pipeline */ gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL); /* link src to sink */ gst_element_link_many (filesrc, decoder, audiosink, NULL); return thread; } static GstElement * org_gnome_audio_inline_gst_ogg_thread (GstElement *filesrc) { GstElement *thread, *demuxer, *decoder, *converter, *audiosink; /* create a new thread to hold the elements */ thread = gst_thread_new ("org-gnome-audio-inline-mpeg-thread"); /* create an ogg demuxer */ demuxer = gst_element_factory_make ("oggdemux", "demuxer"); g_assert (demuxer != NULL); /* create a vorbis decoder */ decoder = gst_element_factory_make ("vorbisdec", "decoder"); g_assert (decoder != NULL); /* create an audio converter */ converter = gst_element_factory_make ("audioconvert", "converter"); g_assert (decoder != NULL); /* and an audio sink */ audiosink = gst_element_factory_make ("osssink", "play_audio"); g_assert (audiosink != NULL); /* add objects to the thread */ gst_bin_add_many (GST_BIN (thread), filesrc, demuxer, decoder, converter, audiosink, NULL); /* link them in the logical order */ gst_element_link_many (filesrc, demuxer, decoder, converter, audiosink, NULL); return thread; } static GstElement * org_gnome_audio_inline_gst_flac_thread (GstElement *filesrc) { GstElement *thread, *decoder, *audiosink; /* create a new thread to hold the elements */ thread = gst_thread_new ("org-gnome-audio-inline-flac-thread"); /* now it's time to get the decoder */ decoder = gst_element_factory_make ("flacdec", "decoder"); /* and an audio sink */ audiosink = gst_element_factory_make ("osssink", "play_audio"); /* add objects to the main pipeline */ gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL); /* link src to sink */ gst_element_link_many (filesrc, decoder, audiosink, NULL); return thread; } static GstElement * org_gnome_audio_inline_gst_mod_thread (GstElement *filesrc) { GstElement *thread, *decoder, *audiosink; /* create a new thread to hold the elements */ thread = gst_thread_new ("org-gnome-audio-inline-flac-thread"); /* now it's time to get the decoder */ decoder = gst_element_factory_make ("mikmod", "decoder"); /* and an audio sink */ audiosink = gst_element_factory_make ("osssink", "play_audio"); /* add objects to the main pipeline */ gst_bin_add_many (GST_BIN (thread), filesrc, decoder, audiosink, NULL); /* link src to sink */ gst_element_link_many (filesrc, decoder, audiosink, NULL); return thread; } static void org_gnome_audio_inline_play_clicked (GtkWidget *button, EMFormatHTMLPObject *pobject) { struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject; d(printf ("audio inline formatter: play\n")); if (!po->filename) { CamelStream *stream; CamelDataWrapper *data; int argc = 1; char *argv [] = { "org_gnome_audio_inline", NULL }; po->filename = e_mktemp ("org-gnome-audio-inline-file-XXXXXX"); d(printf ("audio inline formatter: write to temp file %s\n", po->filename)); stream = camel_stream_fs_new_with_name (po->filename, O_RDWR | O_CREAT | O_TRUNC, 0600); data = camel_medium_get_content_object (CAMEL_MEDIUM (po->part)); camel_data_wrapper_decode_to_stream (data, stream); camel_stream_flush (stream); camel_object_unref (stream); d(printf ("audio inline formatter: init gst thread\n")); if (gst_init_check (&argc, (char ***) &argv)) { CamelContentType *type; GstElement *filesrc; /* create a disk reader */ filesrc = gst_element_factory_make ("filesrc", "disk_source"); g_object_set (G_OBJECT (filesrc), "location", po->filename, NULL); type = camel_mime_part_get_content_type (po->part); if (type) { if (!g_ascii_strcasecmp (type->type, "audio")) { if (!g_ascii_strcasecmp (type->subtype, "mpeg") || !g_ascii_strcasecmp (type->subtype, "x-mpeg") || !g_ascii_strcasecmp (type->subtype, "mpeg3") || !g_ascii_strcasecmp (type->subtype, "x-mpeg3") || !g_ascii_strcasecmp (type->subtype, "mp3") || !g_ascii_strcasecmp (type->subtype, "x-mp3")) { po->thread = org_gnome_audio_inline_gst_mpeg_thread (filesrc); } else if (!g_ascii_strcasecmp (type->subtype, "flac") || !g_ascii_strcasecmp (type->subtype, "x-flac")) { po->thread = org_gnome_audio_inline_gst_flac_thread (filesrc); } else if (!g_ascii_strcasecmp (type->subtype, "mod") || !g_ascii_strcasecmp (type->subtype, "x-mod")) { po->thread = org_gnome_audio_inline_gst_mod_thread (filesrc); } } else if (!g_ascii_strcasecmp (type->type, "application")) { if (!g_ascii_strcasecmp (type->subtype, "ogg") || !g_ascii_strcasecmp (type->subtype, "x-ogg")) { po->thread = org_gnome_audio_inline_gst_ogg_thread (filesrc); } } } } } if (po->thread) { /* start playing */ gst_element_set_state (po->thread, GST_STATE_PLAYING); } } static void org_gnome_audio_inline_add_button (GtkWidget *box, char *icon_name, GCallback cb, gpointer data) { GtkWidget *icon, *button; icon = e_icon_factory_get_image (icon_name, E_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_show (icon); button = gtk_button_new (); g_signal_connect (button, "clicked", cb, data); gtk_container_add ((GtkContainer *) button, icon); gtk_widget_show (button); gtk_box_pack_end_defaults (GTK_BOX (box), button); } static gboolean org_gnome_audio_inline_button_panel (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) { GtkWidget *box; struct _org_gnome_audio_inline_pobject *po = (struct _org_gnome_audio_inline_pobject *) pobject; /* it is OK to call UI functions here, since we are called from UI thread */ box = gtk_hbutton_box_new (); org_gnome_audio_inline_add_button (box, "stock_media-play", G_CALLBACK (org_gnome_audio_inline_play_clicked), po); org_gnome_audio_inline_add_button (box, "stock_media-pause", G_CALLBACK (org_gnome_audio_inline_pause_clicked), po); org_gnome_audio_inline_add_button (box, "stock_media-stop", G_CALLBACK (org_gnome_audio_inline_stop_clicked), po); gtk_widget_show (box); gtk_container_add ((GtkContainer *) eb, box); return TRUE; } void org_gnome_audio_inline_format (void *ep, EMFormatHookTarget *t) { struct _org_gnome_audio_inline_pobject *pobj; char *classid = g_strdup_printf ("org-gnome-audio-inline-button-panel-%d", org_gnome_audio_class_id_counter); org_gnome_audio_class_id_counter ++; d(printf ("audio inline formatter: format classid %s\n", classid)); pobj = (struct _org_gnome_audio_inline_pobject *) em_format_html_add_pobject ((EMFormatHTML *) t->format, sizeof(*pobj), classid, t->part, org_gnome_audio_inline_button_panel); camel_object_ref (t->part); pobj->part = t->part; pobj->filename = NULL; pobj->thread = NULL; pobj->object.free = org_gnome_audio_inline_pobject_free; camel_stream_printf (t->stream, "\n", classid); }