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;
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);
@ -48,6 +60,9 @@ GST_DEBUG_CATEGORY_STATIC (photo_booth_debug);
/* GObject / GApplication */
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_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);
PhotoBooth *photo_booth_new (void);
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_window_destroyed_signal (PhotoBoothWindow *win, 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 gboolean photo_booth_snapshot_prepare (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 ("photo_booth_class_init");
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->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)
{
PhotoBoothPrivate *priv;
priv = photo_booth_get_instance_private (pb);
GST_DEBUG_OBJECT (pb, "photo_booth_init init object!");
int control_sock[2];
@ -100,8 +124,7 @@ static void photo_booth_init (PhotoBooth *pb)
fcntl (READ_SOCKET (pb), F_SETFL, O_NONBLOCK);
fcntl (WRITE_SOCKET (pb), F_SETFL, O_NONBLOCK);
if (!photo_booth_cam_init (&pb->cam_info))
GST_ERROR_OBJECT (pb, "can't init cam!");
pb->cam_info = NULL;
pb->pipeline = NULL;
pb->state = PB_STATE_NONE;
@ -110,6 +133,8 @@ static void photo_booth_init (PhotoBooth *pb)
pb->capture_thread = 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)
@ -147,6 +172,14 @@ static void photo_booth_finalize (GObject *object)
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)
{
GdkRectangle ret;
@ -235,14 +268,44 @@ static void photo_booth_window_destroyed_signal (PhotoBoothWindow *win, PhotoBoo
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)
{
PhotoboothCaptureThreadState state = CAPTURE_NONE;
PhotoboothCaptureThreadState state = CAPTURE_INIT;
mkfifo("moviepipe", 0666);
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;
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].events = POLLIN | POLLERR | POLLHUP | POLLPRI;
if (!pb->cam_info)
if (state == CAPTURE_INIT && !pb->cam_info)
{
if (!photo_booth_cam_init (&pb->cam_info))
GST_DEBUG_OBJECT (pb, "no camera info - can't capture!");
timeout = 10000;
if (photo_booth_cam_init (&pb->cam_info))
{
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)
timeout = 1000;
else
timeout = 1000 / PREVIEW_FPS;
int ret = poll(rfd, 1, timeout);
if (G_UNLIKELY (ret == -1))
{
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);
if (gpret < 0) {
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;
}
else {
@ -300,7 +373,6 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
g_mutex_unlock (&pb->cam_info->mutex);
if (strcmp (mime, GP_MIME_JPEG)) {
GST_ERROR_OBJECT ("Movie capture error... Unhandled MIME type '%s'.", mime);
state = CAPTURE_STOP;
continue;
}
captured_frames++;
@ -318,7 +390,7 @@ static void photo_booth_capture_thread_func (PhotoBooth *pb)
else
{
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:
GST_DEBUG_OBJECT (pb, "CONTROL_PHOTO");
state = CAPTURE_PHOTO;
// photo_booth_flush_pipe (pb->video_fd);
break;
default:
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));
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;
}
@ -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;
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_DEBUG_OBJECT (pb, "photo_booth_preview done");
pb->state = PB_STATE_PREVIEW;
return FALSE;
}
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;
}
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);
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)
{
PhotoBoothPrivate *priv = photo_booth_get_instance_private (pb);
photo_booth_window_start_countdown (priv->win, 5);
g_timeout_add (4000, (GSourceFunc) photo_booth_snapshot_prepare, pb);
photo_booth_window_start_countdown (priv->win, priv->countdown);
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)
{
PhotoBoothPrivate *priv;
GstPad *pad;
gboolean ret;
@ -724,10 +808,12 @@ static gboolean photo_booth_snapshot_prepare (PhotoBooth *pb)
if (!pb->cam_info)
return FALSE;
pb->state = PB_STATE_TAKING_PHOTO;
PhotoBoothPrivate *priv;
priv = photo_booth_get_instance_private (pb);
photo_booth_window_set_spinner (priv->win, TRUE);
gst_element_set_state (priv->audio_playbin, GST_STATE_READY);
SEND_COMMAND (pb, CONTROL_PHOTO);
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_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)
@ -771,7 +857,7 @@ static gboolean photo_booth_snapshot_taken (PhotoBooth *pb)
SEND_COMMAND (pb, CONTROL_PAUSE);
pb->state = PB_STATE_ASKING;
return FALSE; // prevent continously re-running
return FALSE;
}
PhotoBooth *photo_booth_new (void)

View file

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