diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2022-03-14 20:33:10 +0100 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2022-03-14 20:33:10 +0100 |
commit | 8e8f7bf802109d986f7c2c083b1622d25c7f5356 (patch) | |
tree | 831473f9a4b0f7380ca40f0fa457b15ef7c40b11 | |
parent | 8ac4536fbfe1bbcc6da753e3bea2944d0c937323 (diff) | |
download | messenger-gtk-8e8f7bf802109d986f7c2c083b1622d25c7f5356.tar.gz messenger-gtk-8e8f7bf802109d986f7c2c083b1622d25c7f5356.zip |
Implement sending voice messages with preview functionality
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | resources/ui/chat.ui | 2 | ||||
-rw-r--r-- | src/application.c | 6 | ||||
-rw-r--r-- | src/ui/chat.c | 461 | ||||
-rw-r--r-- | src/ui/chat.h | 20 |
6 files changed, 481 insertions, 18 deletions
@@ -39,7 +39,14 @@ RESOURCES = css.gresource.xml\ | |||
39 | ui.gresource.xml | 39 | ui.gresource.xml |
40 | 40 | ||
41 | LIBRARIES = gnunetchat | 41 | LIBRARIES = gnunetchat |
42 | PACKAGES = gnunetutil libhandy-1 gtk+-3.0 libnotify zbar libqrencode | 42 | PACKAGES = gnunetutil\ |
43 | gstreamer-1.0\ | ||
44 | gtk+-3.0\ | ||
45 | libhandy-1\ | ||
46 | libnotify\ | ||
47 | libqrencode\ | ||
48 | zbar | ||
49 | |||
43 | INCLUDES = submodules/gnome-characters/lib | 50 | INCLUDES = submodules/gnome-characters/lib |
44 | 51 | ||
45 | GNU_CC ?= gcc | 52 | GNU_CC ?= gcc |
@@ -13,6 +13,7 @@ The following dependencies are required and need to be installed to build the ap | |||
13 | - [libnotify](https://gitlab.gnome.org/GNOME/libnotify): For notifications | 13 | - [libnotify](https://gitlab.gnome.org/GNOME/libnotify): For notifications |
14 | - [qrencode](https://github.com/fukuchi/libqrencode): For generating QR codes to share credentials | 14 | - [qrencode](https://github.com/fukuchi/libqrencode): For generating QR codes to share credentials |
15 | - [zbar](https://github.com/mchehab/zbar): For scanning QR codes via camera | 15 | - [zbar](https://github.com/mchehab/zbar): For scanning QR codes via camera |
16 | - [gstreamer](https://gitlab.freedesktop.org/gstreamer): For recording and playing voice messages | ||
16 | 17 | ||
17 | As additional step you will need to load all required git submodules via `git submodule init` and `git submodule update`. It is also possible to just add the `--recursive` flag while cloning the repository to do that automatically. | 18 | As additional step you will need to load all required git submodules via `git submodule init` and `git submodule update`. It is also possible to just add the `--recursive` flag while cloning the repository to do that automatically. |
18 | 19 | ||
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui index 0c08970..334fc81 100644 --- a/resources/ui/chat.ui +++ b/resources/ui/chat.ui | |||
@@ -449,7 +449,7 @@ Author: Tobias Frisch | |||
449 | <object class="GtkLabel" id="recording_label"> | 449 | <object class="GtkLabel" id="recording_label"> |
450 | <property name="visible">True</property> | 450 | <property name="visible">True</property> |
451 | <property name="can-focus">False</property> | 451 | <property name="can-focus">False</property> |
452 | <property name="label" translatable="yes">00:00</property> | 452 | <property name="label" translatable="yes">00:00:00</property> |
453 | </object> | 453 | </object> |
454 | <packing> | 454 | <packing> |
455 | <property name="expand">False</property> | 455 | <property name="expand">False</property> |
diff --git a/src/application.c b/src/application.c index fd6b86f..638e6f5 100644 --- a/src/application.c +++ b/src/application.c | |||
@@ -25,6 +25,11 @@ | |||
25 | #include "application.h" | 25 | #include "application.h" |
26 | #include "resources.h" | 26 | #include "resources.h" |
27 | 27 | ||
28 | #include <gstreamer-1.0/gst/gst.h> | ||
29 | #include <gtk-3.0/gtk/gtk.h> | ||
30 | #include <libhandy-1/handy.h> | ||
31 | #include <libnotify/notify.h> | ||
32 | |||
28 | static void | 33 | static void |
29 | _load_ui_stylesheets(MESSENGER_Application *app) | 34 | _load_ui_stylesheets(MESSENGER_Application *app) |
30 | { | 35 | { |
@@ -79,6 +84,7 @@ application_init(MESSENGER_Application *app, | |||
79 | app->argc = argc; | 84 | app->argc = argc; |
80 | app->argv = argv; | 85 | app->argv = argv; |
81 | 86 | ||
87 | gst_init (&argc, &argv); | ||
82 | gtk_init(&argc, &argv); | 88 | gtk_init(&argc, &argv); |
83 | hdy_init(); | 89 | hdy_init(); |
84 | 90 | ||
diff --git a/src/ui/chat.c b/src/ui/chat.c index 71ea810..e445e32 100644 --- a/src/ui/chat.c +++ b/src/ui/chat.c | |||
@@ -25,16 +25,19 @@ | |||
25 | #include "chat.h" | 25 | #include "chat.h" |
26 | 26 | ||
27 | #include <gdk/gdkkeysyms.h> | 27 | #include <gdk/gdkkeysyms.h> |
28 | #include <stdlib.h> | ||
28 | 29 | ||
29 | #include "file_load_entry.h" | 30 | #include "file_load_entry.h" |
30 | #include "message.h" | 31 | #include "message.h" |
31 | #include "messenger.h" | 32 | #include "messenger.h" |
32 | #include "picker.h" | 33 | #include "picker.h" |
33 | #include "../application.h" | ||
34 | #include "../contact.h" | ||
35 | #include "account_entry.h" | 34 | #include "account_entry.h" |
36 | #include "delete_messages.h" | 35 | #include "delete_messages.h" |
37 | 36 | ||
37 | #include "../application.h" | ||
38 | #include "../contact.h" | ||
39 | #include "../file.h" | ||
40 | |||
38 | static gboolean | 41 | static gboolean |
39 | _flap_reveal_switch(gpointer user_data) | 42 | _flap_reveal_switch(gpointer user_data) |
40 | { | 43 | { |
@@ -389,6 +392,12 @@ _send_text_from_view(MESSENGER_Application *app, | |||
389 | static void | 392 | static void |
390 | _drop_any_recording(UI_CHAT_Handle *handle) | 393 | _drop_any_recording(UI_CHAT_Handle *handle) |
391 | { | 394 | { |
395 | if ((handle->play_pipeline) && (handle->playing)) | ||
396 | { | ||
397 | gst_element_set_state(handle->play_pipeline, GST_STATE_NULL); | ||
398 | handle->playing = FALSE; | ||
399 | } | ||
400 | |||
392 | _update_send_record_symbol( | 401 | _update_send_record_symbol( |
393 | gtk_text_view_get_buffer(handle->send_text_view), | 402 | gtk_text_view_get_buffer(handle->send_text_view), |
394 | handle->send_record_symbol, | 403 | handle->send_record_symbol, |
@@ -397,10 +406,33 @@ _drop_any_recording(UI_CHAT_Handle *handle) | |||
397 | 406 | ||
398 | gtk_stack_set_visible_child(handle->send_stack, handle->send_text_box); | 407 | gtk_stack_set_visible_child(handle->send_stack, handle->send_text_box); |
399 | 408 | ||
409 | if (handle->recording_filename[0]) | ||
410 | remove(handle->recording_filename); | ||
411 | |||
412 | handle->recording_filename[0] = 0; | ||
400 | handle->recorded = FALSE; | 413 | handle->recorded = FALSE; |
401 | } | 414 | } |
402 | 415 | ||
403 | static void | 416 | static void |
417 | handle_sending_recording_upload_file(UNUSED void *cls, | ||
418 | const struct GNUNET_CHAT_File *file, | ||
419 | uint64_t completed, | ||
420 | uint64_t size) | ||
421 | { | ||
422 | UI_FILE_LOAD_ENTRY_Handle *file_load = cls; | ||
423 | |||
424 | gtk_progress_bar_set_fraction( | ||
425 | file_load->load_progress_bar, | ||
426 | 1.0 * completed / size | ||
427 | ); | ||
428 | |||
429 | file_update_upload_info(file, completed, size); | ||
430 | |||
431 | if ((completed >= size) && (file_load->chat)) | ||
432 | ui_chat_remove_file_load(file_load->chat, file_load); | ||
433 | } | ||
434 | |||
435 | static void | ||
404 | handle_send_record_button_click(GtkButton *button, | 436 | handle_send_record_button_click(GtkButton *button, |
405 | gpointer user_data) | 437 | gpointer user_data) |
406 | { | 438 | { |
@@ -410,17 +442,42 @@ handle_send_record_button_click(GtkButton *button, | |||
410 | g_object_get_qdata(G_OBJECT(button), app->quarks.ui) | 442 | g_object_get_qdata(G_OBJECT(button), app->quarks.ui) |
411 | ); | 443 | ); |
412 | 444 | ||
413 | if ((handle->recorded) && | 445 | struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) ( |
414 | (!gtk_revealer_get_child_revealed(handle->picker_revealer)) && | 446 | g_object_get_qdata(G_OBJECT(handle->send_text_view), app->quarks.data) |
415 | (gtk_stack_get_visible_child(handle->send_stack) == | 447 | ); |
416 | handle->send_recording_box)) | 448 | |
449 | if ((handle->recorded) && (context) && | ||
450 | (handle->recording_filename[0]) && | ||
451 | (!gtk_revealer_get_child_revealed(handle->picker_revealer))) | ||
417 | { | 452 | { |
418 | // TODO: send audio as file! | 453 | UI_FILE_LOAD_ENTRY_Handle *file_load = ui_file_load_entry_new(app); |
454 | |||
455 | gtk_label_set_text(file_load->file_label, handle->recording_filename); | ||
456 | gtk_progress_bar_set_fraction(file_load->load_progress_bar, 0.0); | ||
457 | |||
458 | struct GNUNET_CHAT_File *file = GNUNET_CHAT_context_send_file( | ||
459 | context, | ||
460 | handle->recording_filename, | ||
461 | handle_sending_recording_upload_file, | ||
462 | file_load | ||
463 | ); | ||
464 | |||
465 | if (file) | ||
466 | { | ||
467 | file_create_info(file); | ||
468 | |||
469 | ui_chat_add_file_load(handle, file_load); | ||
470 | } | ||
471 | else if (file_load) | ||
472 | ui_file_load_entry_delete(file_load); | ||
419 | 473 | ||
420 | _drop_any_recording(handle); | 474 | _drop_any_recording(handle); |
421 | return; | 475 | return; |
422 | } | 476 | } |
423 | 477 | ||
478 | if (gtk_stack_get_visible_child(handle->send_stack) != handle->send_text_box) | ||
479 | return; | ||
480 | |||
424 | GtkTextView *text_view = GTK_TEXT_VIEW( | 481 | GtkTextView *text_view = GTK_TEXT_VIEW( |
425 | g_object_get_qdata(G_OBJECT(button), app->quarks.widget) | 482 | g_object_get_qdata(G_OBJECT(button), app->quarks.widget) |
426 | ); | 483 | ); |
@@ -439,11 +496,27 @@ handle_send_record_button_pressed(GtkWidget *widget, | |||
439 | g_object_get_qdata(G_OBJECT(widget), app->quarks.ui) | 496 | g_object_get_qdata(G_OBJECT(widget), app->quarks.ui) |
440 | ); | 497 | ); |
441 | 498 | ||
442 | if ((handle->recorded) || | 499 | if ((handle->recorded) || (!(handle->record_pipeline)) || |
500 | (handle->recording_filename[0]) || | ||
443 | (gtk_revealer_get_child_revealed(handle->picker_revealer)) || | 501 | (gtk_revealer_get_child_revealed(handle->picker_revealer)) || |
444 | (handle->send_text_box != gtk_stack_get_visible_child(handle->send_stack))) | 502 | (handle->send_text_box != gtk_stack_get_visible_child(handle->send_stack))) |
445 | return FALSE; | 503 | return FALSE; |
446 | 504 | ||
505 | strcpy(handle->recording_filename, "/tmp/rec_XXXXXX.ogg"); | ||
506 | |||
507 | int fd = mkstemps(handle->recording_filename, 4); | ||
508 | |||
509 | if (-1 == fd) | ||
510 | return FALSE; | ||
511 | else | ||
512 | close(fd); | ||
513 | |||
514 | if ((handle->play_pipeline) && (handle->playing)) | ||
515 | { | ||
516 | gst_element_set_state(handle->play_pipeline, GST_STATE_NULL); | ||
517 | handle->playing = FALSE; | ||
518 | } | ||
519 | |||
447 | gtk_image_set_from_icon_name( | 520 | gtk_image_set_from_icon_name( |
448 | handle->play_pause_symbol, | 521 | handle->play_pause_symbol, |
449 | "media-playback-start-symbolic", | 522 | "media-playback-start-symbolic", |
@@ -456,10 +529,21 @@ handle_send_record_button_pressed(GtkWidget *widget, | |||
456 | GTK_ICON_SIZE_BUTTON | 529 | GTK_ICON_SIZE_BUTTON |
457 | ); | 530 | ); |
458 | 531 | ||
459 | gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), FALSE); | 532 | gtk_label_set_text(handle->recording_label, "00:00:00"); |
533 | gtk_progress_bar_set_fraction(handle->recording_progress_bar, 0.0); | ||
460 | 534 | ||
535 | gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), FALSE); | ||
461 | gtk_stack_set_visible_child(handle->send_stack, handle->send_recording_box); | 536 | gtk_stack_set_visible_child(handle->send_stack, handle->send_recording_box); |
462 | 537 | ||
538 | g_object_set( | ||
539 | G_OBJECT(handle->record_sink), | ||
540 | "location", | ||
541 | handle->recording_filename, | ||
542 | NULL | ||
543 | ); | ||
544 | |||
545 | gst_element_set_state(handle->record_pipeline, GST_STATE_PLAYING); | ||
546 | |||
463 | return TRUE; | 547 | return TRUE; |
464 | } | 548 | } |
465 | 549 | ||
@@ -474,7 +558,8 @@ handle_send_record_button_released(GtkWidget *widget, | |||
474 | g_object_get_qdata(G_OBJECT(widget), app->quarks.ui) | 558 | g_object_get_qdata(G_OBJECT(widget), app->quarks.ui) |
475 | ); | 559 | ); |
476 | 560 | ||
477 | if ((handle->recorded) || | 561 | if ((handle->recorded) || (!(handle->record_pipeline)) || |
562 | (!(handle->recording_filename[0])) || | ||
478 | (gtk_revealer_get_child_revealed(handle->picker_revealer)) || | 563 | (gtk_revealer_get_child_revealed(handle->picker_revealer)) || |
479 | (handle->send_recording_box != gtk_stack_get_visible_child( | 564 | (handle->send_recording_box != gtk_stack_get_visible_child( |
480 | handle->send_stack))) | 565 | handle->send_stack))) |
@@ -482,8 +567,7 @@ handle_send_record_button_released(GtkWidget *widget, | |||
482 | 567 | ||
483 | gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), TRUE); | 568 | gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), TRUE); |
484 | 569 | ||
485 | gtk_revealer_set_reveal_child(handle->picker_revealer, FALSE); | 570 | gst_element_set_state(handle->record_pipeline, GST_STATE_NULL); |
486 | |||
487 | handle->recorded = TRUE; | 571 | handle->recorded = TRUE; |
488 | 572 | ||
489 | gtk_image_set_from_icon_name( | 573 | gtk_image_set_from_icon_name( |
@@ -521,6 +605,62 @@ handle_recording_close_button_click(UNUSED GtkButton *button, | |||
521 | } | 605 | } |
522 | 606 | ||
523 | static void | 607 | static void |
608 | _stop_playing_recording(UI_CHAT_Handle *handle, | ||
609 | gboolean reset_bar) | ||
610 | { | ||
611 | gst_element_set_state(handle->play_pipeline, GST_STATE_NULL); | ||
612 | handle->playing = FALSE; | ||
613 | |||
614 | gtk_image_set_from_icon_name( | ||
615 | handle->play_pause_symbol, | ||
616 | "media-playback-start-symbolic", | ||
617 | GTK_ICON_SIZE_BUTTON | ||
618 | ); | ||
619 | |||
620 | gtk_progress_bar_set_fraction( | ||
621 | handle->recording_progress_bar, | ||
622 | reset_bar? 0.0 : 1.0 | ||
623 | ); | ||
624 | |||
625 | if (handle->play_timer) | ||
626 | { | ||
627 | g_source_remove(handle->play_timer); | ||
628 | handle->play_timer = 0; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | static void | ||
633 | handle_recording_play_button_click(UNUSED GtkButton *button, | ||
634 | gpointer user_data) | ||
635 | { | ||
636 | UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data; | ||
637 | |||
638 | if ((!(handle->recorded)) || (!(handle->play_pipeline))) | ||
639 | return; | ||
640 | |||
641 | if (handle->playing) | ||
642 | _stop_playing_recording(handle, TRUE); | ||
643 | else if (handle->recording_filename[0]) | ||
644 | { | ||
645 | g_object_set( | ||
646 | G_OBJECT(handle->play_source), | ||
647 | "location", | ||
648 | handle->recording_filename, | ||
649 | NULL | ||
650 | ); | ||
651 | |||
652 | gst_element_set_state(handle->play_pipeline, GST_STATE_PLAYING); | ||
653 | handle->playing = TRUE; | ||
654 | |||
655 | gtk_image_set_from_icon_name( | ||
656 | handle->play_pause_symbol, | ||
657 | "media-playback-stop-symbolic", | ||
658 | GTK_ICON_SIZE_BUTTON | ||
659 | ); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static void | ||
524 | handle_picker_button_click(UNUSED GtkButton *button, | 664 | handle_picker_button_click(UNUSED GtkButton *button, |
525 | gpointer user_data) | 665 | gpointer user_data) |
526 | { | 666 | { |
@@ -537,6 +677,268 @@ handle_picker_button_click(UNUSED GtkButton *button, | |||
537 | ); | 677 | ); |
538 | } | 678 | } |
539 | 679 | ||
680 | static gboolean | ||
681 | _record_timer_func(gpointer user_data) | ||
682 | { | ||
683 | UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data; | ||
684 | |||
685 | GString *time_string = g_string_new(NULL); | ||
686 | |||
687 | g_string_printf( | ||
688 | time_string, | ||
689 | "%02u:%02u:%02u", | ||
690 | (handle->record_time / 3600), | ||
691 | (handle->record_time / 60) % 60, | ||
692 | (handle->record_time % 60) | ||
693 | ); | ||
694 | |||
695 | gtk_label_set_text(handle->recording_label, time_string->str); | ||
696 | g_string_free(time_string, TRUE); | ||
697 | |||
698 | if (!(handle->recorded)) | ||
699 | { | ||
700 | handle->record_time++; | ||
701 | handle->record_timer = g_timeout_add_seconds( | ||
702 | 1, | ||
703 | _record_timer_func, | ||
704 | handle | ||
705 | ); | ||
706 | } | ||
707 | else | ||
708 | handle->record_timer = 0; | ||
709 | |||
710 | return FALSE; | ||
711 | } | ||
712 | |||
713 | static gboolean | ||
714 | _play_timer_func(gpointer user_data) | ||
715 | { | ||
716 | UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data; | ||
717 | |||
718 | if (handle->play_time < handle->record_time * 100) | ||
719 | gtk_progress_bar_set_fraction( | ||
720 | handle->recording_progress_bar, | ||
721 | 0.01 * handle->play_time / handle->record_time | ||
722 | ); | ||
723 | else | ||
724 | gtk_progress_bar_set_fraction( | ||
725 | handle->recording_progress_bar, | ||
726 | 1.0 | ||
727 | ); | ||
728 | |||
729 | if (handle->playing) | ||
730 | { | ||
731 | handle->play_time++; | ||
732 | handle->play_timer = g_timeout_add( | ||
733 | 10, | ||
734 | _play_timer_func, | ||
735 | handle | ||
736 | ); | ||
737 | } | ||
738 | else | ||
739 | handle->play_timer = 0; | ||
740 | |||
741 | return FALSE; | ||
742 | } | ||
743 | |||
744 | static gboolean | ||
745 | handle_record_bus_watch(UNUSED GstBus *bus, | ||
746 | GstMessage *msg, | ||
747 | gpointer data) | ||
748 | { | ||
749 | UI_CHAT_Handle *handle = (UI_CHAT_Handle*) data; | ||
750 | GstMessageType type = GST_MESSAGE_TYPE(msg); | ||
751 | |||
752 | switch (type) | ||
753 | { | ||
754 | case GST_MESSAGE_STREAM_START: | ||
755 | handle->record_time = 0; | ||
756 | handle->record_timer = g_timeout_add_seconds( | ||
757 | 0, | ||
758 | _record_timer_func, | ||
759 | handle | ||
760 | ); | ||
761 | |||
762 | break; | ||
763 | default: | ||
764 | break; | ||
765 | } | ||
766 | |||
767 | return TRUE; | ||
768 | } | ||
769 | |||
770 | static gboolean | ||
771 | handle_play_bus_watch(UNUSED GstBus *bus, | ||
772 | GstMessage *msg, | ||
773 | gpointer data) | ||
774 | { | ||
775 | UI_CHAT_Handle *handle = (UI_CHAT_Handle*) data; | ||
776 | GstMessageType type = GST_MESSAGE_TYPE(msg); | ||
777 | |||
778 | switch (type) | ||
779 | { | ||
780 | case GST_MESSAGE_STREAM_START: | ||
781 | handle->play_time = 0; | ||
782 | handle->play_timer = g_timeout_add_seconds( | ||
783 | 0, | ||
784 | _play_timer_func, | ||
785 | handle | ||
786 | ); | ||
787 | |||
788 | break; | ||
789 | case GST_MESSAGE_EOS: | ||
790 | if (handle->playing) | ||
791 | _stop_playing_recording(handle, FALSE); | ||
792 | break; | ||
793 | default: | ||
794 | break; | ||
795 | } | ||
796 | |||
797 | return TRUE; | ||
798 | } | ||
799 | |||
800 | static void | ||
801 | _play_pad_added(UNUSED GstElement *element, | ||
802 | GstPad *pad, | ||
803 | gpointer data) | ||
804 | { | ||
805 | GstElement *decoder = (GstElement*) data; | ||
806 | |||
807 | GstPad *sinkpad = gst_element_get_static_pad(decoder, "sink"); | ||
808 | gst_pad_link(pad, sinkpad); | ||
809 | gst_object_unref (sinkpad); | ||
810 | } | ||
811 | |||
812 | static void | ||
813 | _setup_gst_pipelines(UI_CHAT_Handle *handle) | ||
814 | { | ||
815 | handle->record_pipeline = gst_pipeline_new("audio-recorder"); | ||
816 | |||
817 | GstElement *audio_source = gst_element_factory_make( | ||
818 | "autoaudiosrc", | ||
819 | "audio-input" | ||
820 | ); | ||
821 | |||
822 | GstElement *audio_converter = gst_element_factory_make( | ||
823 | "audioconvert", | ||
824 | "audio-converter" | ||
825 | ); | ||
826 | |||
827 | GstElement *vorbis_encoder = gst_element_factory_make( | ||
828 | "vorbisenc", | ||
829 | "vorbis-encoder" | ||
830 | ); | ||
831 | |||
832 | GstElement *ogg_muxer = gst_element_factory_make( | ||
833 | "oggmux", | ||
834 | "ogg-muxer" | ||
835 | ); | ||
836 | |||
837 | handle->record_sink = gst_element_factory_make( | ||
838 | "filesink", | ||
839 | "file-output" | ||
840 | ); | ||
841 | |||
842 | gst_bin_add_many( | ||
843 | GST_BIN(handle->record_pipeline), | ||
844 | audio_source, | ||
845 | audio_converter, | ||
846 | vorbis_encoder, | ||
847 | ogg_muxer, | ||
848 | handle->record_sink, | ||
849 | NULL | ||
850 | ); | ||
851 | |||
852 | gst_element_link_many( | ||
853 | audio_source, | ||
854 | audio_converter, | ||
855 | vorbis_encoder, | ||
856 | ogg_muxer, | ||
857 | handle->record_sink, | ||
858 | NULL | ||
859 | ); | ||
860 | |||
861 | { | ||
862 | GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(handle->record_pipeline)); | ||
863 | |||
864 | handle->record_watch = gst_bus_add_watch( | ||
865 | bus, | ||
866 | handle_record_bus_watch, | ||
867 | handle | ||
868 | ); | ||
869 | |||
870 | gst_object_unref(bus); | ||
871 | } | ||
872 | |||
873 | handle->play_pipeline = gst_pipeline_new("audio-previewer"); | ||
874 | |||
875 | handle->play_source = gst_element_factory_make( | ||
876 | "filesrc", | ||
877 | "file-input" | ||
878 | ); | ||
879 | |||
880 | GstElement *ogg_demuxer = gst_element_factory_make( | ||
881 | "oggdemux", | ||
882 | "ogg-demuxer" | ||
883 | ); | ||
884 | |||
885 | GstElement *vorbis_decoder = gst_element_factory_make( | ||
886 | "vorbisdec", | ||
887 | "vorbis-decoder" | ||
888 | ); | ||
889 | |||
890 | GstElement *audio_play_converter = gst_element_factory_make( | ||
891 | "audioconvert", | ||
892 | "audio-converter" | ||
893 | ); | ||
894 | |||
895 | GstElement *audio_sink = gst_element_factory_make( | ||
896 | "autoaudiosink", | ||
897 | "audio-output" | ||
898 | ); | ||
899 | |||
900 | gst_bin_add_many( | ||
901 | GST_BIN(handle->play_pipeline), | ||
902 | handle->play_source, | ||
903 | ogg_demuxer, | ||
904 | vorbis_decoder, | ||
905 | audio_play_converter, | ||
906 | audio_sink, | ||
907 | NULL | ||
908 | ); | ||
909 | |||
910 | gst_element_link( | ||
911 | handle->play_source, | ||
912 | ogg_demuxer | ||
913 | ); | ||
914 | |||
915 | gst_element_link_many( | ||
916 | vorbis_decoder, | ||
917 | audio_play_converter, | ||
918 | audio_sink, | ||
919 | NULL | ||
920 | ); | ||
921 | |||
922 | g_signal_connect( | ||
923 | ogg_demuxer, | ||
924 | "pad-added", | ||
925 | G_CALLBACK(_play_pad_added), | ||
926 | vorbis_decoder | ||
927 | ); | ||
928 | |||
929 | { | ||
930 | GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(handle->play_pipeline)); | ||
931 | |||
932 | handle->play_watch = gst_bus_add_watch( | ||
933 | bus, | ||
934 | handle_play_bus_watch, | ||
935 | handle | ||
936 | ); | ||
937 | |||
938 | gst_object_unref(bus); | ||
939 | } | ||
940 | } | ||
941 | |||
540 | UI_CHAT_Handle* | 942 | UI_CHAT_Handle* |
541 | ui_chat_new(MESSENGER_Application *app) | 943 | ui_chat_new(MESSENGER_Application *app) |
542 | { | 944 | { |
@@ -545,12 +947,11 @@ ui_chat_new(MESSENGER_Application *app) | |||
545 | UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); | 947 | UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); |
546 | UI_MESSENGER_Handle *messenger = &(app->ui.messenger); | 948 | UI_MESSENGER_Handle *messenger = &(app->ui.messenger); |
547 | 949 | ||
548 | handle->recorded = FALSE; | 950 | memset(handle, 0, sizeof(*handle)); |
549 | 951 | ||
550 | handle->app = app; | 952 | _setup_gst_pipelines(handle); |
551 | 953 | ||
552 | handle->messages = NULL; | 954 | handle->app = app; |
553 | handle->edge_value = 0; | ||
554 | 955 | ||
555 | handle->loads = NULL; | 956 | handle->loads = NULL; |
556 | 957 | ||
@@ -845,6 +1246,13 @@ ui_chat_new(MESSENGER_Application *app) | |||
845 | gtk_builder_get_object(handle->builder, "recording_play_button") | 1246 | gtk_builder_get_object(handle->builder, "recording_play_button") |
846 | ); | 1247 | ); |
847 | 1248 | ||
1249 | g_signal_connect( | ||
1250 | handle->recording_play_button, | ||
1251 | "clicked", | ||
1252 | G_CALLBACK(handle_recording_play_button_click), | ||
1253 | handle | ||
1254 | ); | ||
1255 | |||
848 | handle->play_pause_symbol = GTK_IMAGE( | 1256 | handle->play_pause_symbol = GTK_IMAGE( |
849 | gtk_builder_get_object(handle->builder, "play_pause_symbol") | 1257 | gtk_builder_get_object(handle->builder, "play_pause_symbol") |
850 | ); | 1258 | ); |
@@ -1033,6 +1441,27 @@ ui_chat_delete(UI_CHAT_Handle *handle) | |||
1033 | if (handle->loads) | 1441 | if (handle->loads) |
1034 | g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete); | 1442 | g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete); |
1035 | 1443 | ||
1444 | if (handle->record_pipeline) | ||
1445 | { | ||
1446 | gst_element_set_state (handle->record_pipeline, GST_STATE_NULL); | ||
1447 | gst_object_unref(GST_OBJECT(handle->record_pipeline)); | ||
1448 | } | ||
1449 | |||
1450 | if (handle->play_pipeline) | ||
1451 | { | ||
1452 | gst_element_set_state (handle->play_pipeline, GST_STATE_NULL); | ||
1453 | gst_object_unref(GST_OBJECT(handle->play_pipeline)); | ||
1454 | } | ||
1455 | |||
1456 | if (handle->recording_filename[0]) | ||
1457 | remove(handle->recording_filename); | ||
1458 | |||
1459 | if (handle->record_timer) | ||
1460 | g_source_remove(handle->record_timer); | ||
1461 | |||
1462 | if (handle->play_timer) | ||
1463 | g_source_remove(handle->play_timer); | ||
1464 | |||
1036 | g_free(handle); | 1465 | g_free(handle); |
1037 | } | 1466 | } |
1038 | 1467 | ||
diff --git a/src/ui/chat.h b/src/ui/chat.h index 0134a85..5173596 100644 --- a/src/ui/chat.h +++ b/src/ui/chat.h | |||
@@ -25,9 +25,11 @@ | |||
25 | #ifndef UI_CHAT_H_ | 25 | #ifndef UI_CHAT_H_ |
26 | #define UI_CHAT_H_ | 26 | #define UI_CHAT_H_ |
27 | 27 | ||
28 | #include <gstreamer-1.0/gst/gst.h> | ||
28 | #include <gtk-3.0/gtk/gtk.h> | 29 | #include <gtk-3.0/gtk/gtk.h> |
29 | #include <libhandy-1/handy.h> | 30 | #include <libhandy-1/handy.h> |
30 | #include <libnotify/notify.h> | 31 | #include <libnotify/notify.h> |
32 | #include <stdio.h> | ||
31 | 33 | ||
32 | #include <gnunet/gnunet_chat_lib.h> | 34 | #include <gnunet/gnunet_chat_lib.h> |
33 | 35 | ||
@@ -39,6 +41,24 @@ typedef struct UI_FILE_LOAD_ENTRY_Handle UI_FILE_LOAD_ENTRY_Handle; | |||
39 | typedef struct UI_CHAT_Handle | 41 | typedef struct UI_CHAT_Handle |
40 | { | 42 | { |
41 | gboolean recorded; | 43 | gboolean recorded; |
44 | gboolean playing; | ||
45 | |||
46 | char recording_filename [PATH_MAX]; | ||
47 | |||
48 | guint record_timer; | ||
49 | guint record_time; | ||
50 | |||
51 | guint play_timer; | ||
52 | guint play_time; | ||
53 | |||
54 | GstElement *record_pipeline; | ||
55 | GstElement *record_sink; | ||
56 | |||
57 | GstElement *play_pipeline; | ||
58 | GstElement *play_source; | ||
59 | |||
60 | guint record_watch; | ||
61 | guint play_watch; | ||
42 | 62 | ||
43 | MESSENGER_Application *app; | 63 | MESSENGER_Application *app; |
44 | 64 | ||