add second beep sound

This commit is contained in:
Andreas Frisch 2016-04-26 23:59:01 +02:00
parent b8f8f9f24a
commit 327a0d84e5
2 changed files with 110 additions and 24 deletions

View file

@ -38,6 +38,18 @@ struct _PhotoBoothPrivate
{ {
PhotoBoothWindow *win; PhotoBoothWindow *win;
GdkRectangle monitor_geo; GdkRectangle monitor_geo;
GSettings *settings;
guint countdown;
GstElement *audio_playbin;
};
#define DEFAULT_AUDIOFILE_COUNTDOWN "/net/home/fraxinas/microcontroller/photobooth/beep.m4a"
#define DEFAULT_COUNTDOWN 5
enum
{
ARG_0,
ARG_COUNTDOWN,
}; };
G_DEFINE_TYPE_WITH_PRIVATE (PhotoBooth, photo_booth, GTK_TYPE_APPLICATION); G_DEFINE_TYPE_WITH_PRIVATE (PhotoBooth, photo_booth, GTK_TYPE_APPLICATION);
@ -48,6 +60,9 @@ GST_DEBUG_CATEGORY_STATIC (photo_booth_debug);
/* GObject / GApplication */ /* GObject / GApplication */
static void photo_booth_activate (GApplication *app); static void photo_booth_activate (GApplication *app);
static void photo_booth_open (GApplication *app, GFile **files, gint n_files, const gchar *hint); static void photo_booth_open (GApplication *app, GFile **files, gint n_files, const gchar *hint);
static void photo_booth_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void photo_booth_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void photo_booth_dispose (GObject *object);
static void photo_booth_finalize (GObject *object); static void photo_booth_finalize (GObject *object);
PhotoBooth *photo_booth_new (void); PhotoBooth *photo_booth_new (void);
static void photo_booth_clicked (GtkWidget *button, GdkEventButton *event, PhotoBooth *pb); static void photo_booth_clicked (GtkWidget *button, GdkEventButton *event, PhotoBooth *pb);
@ -57,7 +72,7 @@ static GdkRectangle photo_boot_monitor_geo (PhotoBooth *pb);
static void photo_booth_quit_signal (PhotoBooth *pb); static void photo_booth_quit_signal (PhotoBooth *pb);
static void photo_booth_window_destroyed_signal (PhotoBoothWindow *win, PhotoBooth *pb); static void photo_booth_window_destroyed_signal (PhotoBoothWindow *win, PhotoBooth *pb);
static void photo_booth_setup_window (PhotoBooth *pb); static void photo_booth_setup_window (PhotoBooth *pb);
static void photo_booth_preview (PhotoBooth *pb); static gboolean photo_booth_preview (PhotoBooth *pb);
static void photo_booth_snapshot_start (PhotoBooth *pb); static void photo_booth_snapshot_start (PhotoBooth *pb);
static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb); static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb);
static gboolean photo_booth_snapshot_taken (PhotoBooth *pb); static gboolean photo_booth_snapshot_taken (PhotoBooth *pb);
@ -81,12 +96,21 @@ static void photo_booth_class_init (PhotoBoothClass *klass)
GST_DEBUG_CATEGORY_INIT (photo_booth_debug, "photobooth", GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW | GST_DEBUG_BG_BLUE, "PhotoBooth"); GST_DEBUG_CATEGORY_INIT (photo_booth_debug, "photobooth", GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW | GST_DEBUG_BG_BLUE, "PhotoBooth");
GST_DEBUG ("photo_booth_class_init"); GST_DEBUG ("photo_booth_class_init");
gobject_class->finalize = photo_booth_finalize; gobject_class->finalize = photo_booth_finalize;
gobject_class->set_property = photo_booth_set_property;
gobject_class->get_property = photo_booth_get_property;
gapplication_class->activate = photo_booth_activate; gapplication_class->activate = photo_booth_activate;
gapplication_class->open = photo_booth_open; gapplication_class->open = photo_booth_open;
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COUNTDOWN,
g_param_spec_uint ("countdown", "Shutter delay (s)",
"Shutter actuation delay countdown in seconds", 0, 60, DEFAULT_COUNTDOWN,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} }
static void photo_booth_init (PhotoBooth *pb) static void photo_booth_init (PhotoBooth *pb)
{ {
PhotoBoothPrivate *priv;
priv = photo_booth_get_instance_private (pb);
GST_DEBUG_OBJECT (pb, "photo_booth_init init object!"); GST_DEBUG_OBJECT (pb, "photo_booth_init init object!");
int control_sock[2]; int control_sock[2];
@ -100,8 +124,7 @@ static void photo_booth_init (PhotoBooth *pb)
fcntl (READ_SOCKET (pb), F_SETFL, O_NONBLOCK); fcntl (READ_SOCKET (pb), F_SETFL, O_NONBLOCK);
fcntl (WRITE_SOCKET (pb), F_SETFL, O_NONBLOCK); fcntl (WRITE_SOCKET (pb), F_SETFL, O_NONBLOCK);
if (!photo_booth_cam_init (&pb->cam_info)) pb->cam_info = NULL;
GST_ERROR_OBJECT (pb, "can't init cam!");
pb->pipeline = NULL; pb->pipeline = NULL;
pb->state = PB_STATE_NONE; pb->state = PB_STATE_NONE;
@ -110,6 +133,8 @@ static void photo_booth_init (PhotoBooth *pb)
pb->capture_thread = NULL; pb->capture_thread = NULL;
pb->capture_thread = g_thread_try_new ("gphoto-capture", (GThreadFunc) photo_booth_capture_thread_func, pb, NULL); pb->capture_thread = g_thread_try_new ("gphoto-capture", (GThreadFunc) photo_booth_capture_thread_func, pb, NULL);
priv->settings = NULL;
} }
static void photo_booth_setup_window (PhotoBooth *pb) static void photo_booth_setup_window (PhotoBooth *pb)
@ -147,6 +172,14 @@ static void photo_booth_finalize (GObject *object)
photo_booth_cam_close (&pb->cam_info); photo_booth_cam_close (&pb->cam_info);
} }
static void photo_booth_dispose (GObject *object)
{
PhotoBoothPrivate *priv;
priv = photo_booth_get_instance_private (PHOTO_BOOTH (object));
g_clear_object (&priv->settings);
G_OBJECT_CLASS (photo_booth_parent_class)->dispose (object);
}
static GdkRectangle photo_boot_monitor_geo (PhotoBooth *pb) static GdkRectangle photo_boot_monitor_geo (PhotoBooth *pb)
{ {
GdkRectangle ret; GdkRectangle ret;
@ -235,14 +268,44 @@ static void photo_booth_window_destroyed_signal (PhotoBoothWindow *win, PhotoBoo
g_application_quit (G_APPLICATION (pb)); g_application_quit (G_APPLICATION (pb));
} }
static void photo_booth_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
{
PhotoBooth *pb = PHOTO_BOOTH (object);
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
switch (prop_id) {
case ARG_COUNTDOWN:
priv->countdown = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void photo_booth_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
{
PhotoBooth *pb = PHOTO_BOOTH (object);
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
switch (prop_id) {
case ARG_COUNTDOWN:
g_value_set_int (value, priv->countdown);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void photo_booth_capture_thread_func (PhotoBooth *pb) static void photo_booth_capture_thread_func (PhotoBooth *pb)
{ {
PhotoboothCaptureThreadState state = CAPTURE_NONE; PhotoboothCaptureThreadState state = CAPTURE_INIT;
mkfifo("moviepipe", 0666); mkfifo("moviepipe", 0666);
pb->video_fd = open("moviepipe", O_RDWR); pb->video_fd = open("moviepipe", O_RDWR);
GST_DEBUG_OBJECT (pb, "enter capture thread fd = %d cam_info@%p", pb->video_fd, pb->cam_info); GST_DEBUG_OBJECT (pb, "enter capture thread fd = %d", pb->video_fd);
CameraFile *gp_file = NULL; CameraFile *gp_file = NULL;
int gpret, captured_frames = 0; int gpret, captured_frames = 0;
@ -262,20 +325,25 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
rfd[0].fd = READ_SOCKET (pb); rfd[0].fd = READ_SOCKET (pb);
rfd[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI; rfd[0].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
if (!pb->cam_info) if (state == CAPTURE_INIT && !pb->cam_info)
{ {
if (!photo_booth_cam_init (&pb->cam_info)) if (photo_booth_cam_init (&pb->cam_info))
GST_DEBUG_OBJECT (pb, "no camera info - can't capture!"); {
timeout = 10000; GST_INFO_OBJECT (pb, "photo_booth_cam_inited @ %p", pb->cam_info);
state = CAPTURE_VIDEO;
g_main_context_invoke (NULL, (GSourceFunc) photo_booth_preview, pb);
}
else
GST_INFO_OBJECT (pb, "no camera info.");
timeout = 5000;
} }
else if (pb->state == PB_STATE_NONE)
pb->state = PB_STATE_PREVIEW;
else if (state == CAPTURE_PAUSED) else if (state == CAPTURE_PAUSED)
timeout = 1000; timeout = 1000;
else else
timeout = 1000 / PREVIEW_FPS; timeout = 1000 / PREVIEW_FPS;
int ret = poll(rfd, 1, timeout); int ret = poll(rfd, 1, timeout);
if (G_UNLIKELY (ret == -1)) if (G_UNLIKELY (ret == -1))
{ {
GST_ERROR_OBJECT (pb, "SELECT ERROR!"); GST_ERROR_OBJECT (pb, "SELECT ERROR!");
@ -291,7 +359,12 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
g_mutex_unlock (&pb->cam_info->mutex); g_mutex_unlock (&pb->cam_info->mutex);
if (gpret < 0) { if (gpret < 0) {
GST_ERROR_OBJECT (pb, "Movie capture error %d", gpret); GST_ERROR_OBJECT (pb, "Movie capture error %d", gpret);
state = CAPTURE_STOP; if (gpret == -7)
{
state = CAPTURE_INIT;
pb->state = PB_STATE_NONE;
photo_booth_cam_close (&pb->cam_info);
}
continue; continue;
} }
else { else {
@ -300,7 +373,6 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
g_mutex_unlock (&pb->cam_info->mutex); g_mutex_unlock (&pb->cam_info->mutex);
if (strcmp (mime, GP_MIME_JPEG)) { if (strcmp (mime, GP_MIME_JPEG)) {
GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime); GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime);
state = CAPTURE_STOP;
continue; continue;
} }
captured_frames++; captured_frames++;
@ -318,7 +390,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
else else
{ {
GST_ERROR_OBJECT (pb, "taking photo failed!"); GST_ERROR_OBJECT (pb, "taking photo failed!");
state = CAPTURE_STOP; state = CAPTURE_INIT;
} }
} }
} }
@ -342,7 +414,6 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
case CONTROL_PHOTO: case CONTROL_PHOTO:
GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO"); GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO");
state = CAPTURE_PHOTO; state = CAPTURE_PHOTO;
// photo_booth_flush_pipe (pb->video_fd);
break; break;
default: default:
GST_ERROR_OBJECT (pb, "illegal control socket command %c received!", command); GST_ERROR_OBJECT (pb, "illegal control socket command %c received!", command);
@ -509,7 +580,11 @@ static gboolean photo_booth_setup_gstreamer (PhotoBooth *pb)
bus = gst_pipeline_get_bus (GST_PIPELINE (pb->pipeline)); bus = gst_pipeline_get_bus (GST_PIPELINE (pb->pipeline));
gst_bus_add_watch (bus, (GstBusFunc) photo_booth_bus_callback, pb); gst_bus_add_watch (bus, (GstBusFunc) photo_booth_bus_callback, pb);
photo_booth_preview (pb); GstElement* audio_pipeline;
audio_pipeline = gst_pipeline_new ("audio-pipeline");
priv->audio_playbin = gst_element_factory_make ("playbin", "audio-playbin");
gst_bin_add (GST_BIN (audio_pipeline), priv->audio_playbin);
GST_LOG ("added %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT "", priv->audio_playbin, audio_pipeline);
return TRUE; return TRUE;
} }
@ -588,7 +663,7 @@ static gboolean photo_booth_bus_callback (GstBus *bus, GstMessage *message, Phot
} }
static void photo_booth_preview (PhotoBooth *pb) static gboolean photo_booth_preview (PhotoBooth *pb)
{ {
GstPad *pad; GstPad *pad;
if (pb->video_block_id) if (pb->video_block_id)
@ -610,6 +685,7 @@ static void photo_booth_preview (PhotoBooth *pb)
gst_element_set_state (pb->video_bin, GST_STATE_PLAYING); gst_element_set_state (pb->video_bin, GST_STATE_PLAYING);
GST_DEBUG_OBJECT (pb, "photo_booth_preview done"); GST_DEBUG_OBJECT (pb, "photo_booth_preview done");
pb->state = PB_STATE_PREVIEW; pb->state = PB_STATE_PREVIEW;
return FALSE;
} }
extern int camera_auto_focus (Camera *list, GPContext *context, int onoff); extern int camera_auto_focus (Camera *list, GPContext *context, int onoff);
@ -686,7 +762,7 @@ static gboolean photo_booth_take_photo (CameraInfo *cam_info)
return TRUE; return TRUE;
} }
static void photo_booth_clicked (GtkWidget *button, GdkEventButton *event, PhotoBooth *pb) static void photo_booth_clicked (GtkWidget *widget, GdkEventButton *event, PhotoBooth *pb)
{ {
GST_DEBUG_OBJECT (pb, "photo_booth_clicked state=%d", pb->state); GST_DEBUG_OBJECT (pb, "photo_booth_clicked state=%d", pb->state);
switch (pb->state) { switch (pb->state) {
@ -709,12 +785,20 @@ static void photo_booth_clicked (GtkWidget *button, GdkEventButton *event, Photo
static void photo_booth_snapshot_start (PhotoBooth *pb) static void photo_booth_snapshot_start (PhotoBooth *pb)
{ {
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb); PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
photo_booth_window_start_countdown (priv->win, 5); photo_booth_window_start_countdown (priv->win, priv->countdown);
g_timeout_add (4000, (GSourceFunc) photo_booth_snapshot_prepare, pb); guint delay = priv->countdown > 1 ? (priv->countdown*1000)-100 : 1;
GST_INFO_OBJECT (pb, "started countdown of %d seconds, start taking photo in %d ms", priv->countdown, delay);
g_timeout_add (delay, (GSourceFunc) photo_booth_snapshot_prepare, pb);
gchar* uri = g_filename_to_uri (DEFAULT_AUDIOFILE_COUNTDOWN, NULL, NULL);
GST_INFO_OBJECT (pb, "audio uri: %s", uri);
g_object_set (priv->audio_playbin, "uri", uri, NULL);
g_free (uri);
gst_element_set_state (GST_ELEMENT_PARENT (priv->audio_playbin), GST_STATE_PLAYING);
} }
static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb) static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
{ {
PhotoBoothPrivate *priv;
GstPad *pad; GstPad *pad;
gboolean ret; gboolean ret;
@ -724,10 +808,12 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
if (!pb->cam_info) if (!pb->cam_info)
return FALSE; return FALSE;
pb->state = PB_STATE_TAKING_PHOTO; pb->state = PB_STATE_TAKING_PHOTO;
PhotoBoothPrivate *priv;
priv = photo_booth_get_instance_private (pb); priv = photo_booth_get_instance_private (pb);
photo_booth_window_set_spinner (priv->win, TRUE); photo_booth_window_set_spinner (priv->win, TRUE);
gst_element_set_state (priv->audio_playbin, GST_STATE_READY);
SEND_COMMAND (pb, CONTROL_PHOTO); SEND_COMMAND (pb, CONTROL_PHOTO);
gst_element_set_state (pb->video_bin, GST_STATE_READY); gst_element_set_state (pb->video_bin, GST_STATE_READY);
@ -749,7 +835,7 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
GST_DEBUG_OBJECT (pb, "linking %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ret=%i", pb->photo_bin, pb->pixoverlay, ret); GST_DEBUG_OBJECT (pb, "linking %" GST_PTR_FORMAT " ! %" GST_PTR_FORMAT " ret=%i", pb->photo_bin, pb->pixoverlay, ret);
gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING); gst_element_set_state (pb->photo_bin, GST_STATE_PLAYING);
return FALSE; // prevent continously re-running return FALSE;
} }
static gboolean photo_booth_snapshot_taken (PhotoBooth *pb) static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
@ -771,7 +857,7 @@ static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
SEND_COMMAND (pb, CONTROL_PAUSE); SEND_COMMAND (pb, CONTROL_PAUSE);
pb->state = PB_STATE_ASKING; pb->state = PB_STATE_ASKING;
return FALSE; // prevent continously re-running return FALSE;
} }
PhotoBooth *photo_booth_new (void) PhotoBooth *photo_booth_new (void)

View file

@ -63,7 +63,7 @@ struct _CameraInfo {
typedef enum typedef enum
{ {
CAPTURE_NONE = 0, CAPTURE_INIT = 0,
CAPTURE_VIDEO, CAPTURE_VIDEO,
CAPTURE_PHOTO, CAPTURE_PHOTO,
CAPTURE_PAUSED, CAPTURE_PAUSED,