winks: improve error-handling
authorOle André Vadla Ravnås <oravnas@cisco.com>
Mon, 12 Oct 2009 15:26:15 +0000 (17:26 +0200)
committerOle André Vadla Ravnås <oravnas@cisco.com>
Thu, 28 Oct 2010 15:08:41 +0000 (17:08 +0200)
Most important part here is special-casing "device busy" so the application
is able to provide better feedback when another application is using the
device.

sys/winks/gstksclock.c
sys/winks/gstksvideodevice.c
sys/winks/gstksvideodevice.h
sys/winks/gstksvideosrc.c
sys/winks/kshelpers.c
sys/winks/kshelpers.h
sys/winks/ksvideohelpers.c

index db1a8a1..33c3e4d 100644 (file)
@@ -151,7 +151,7 @@ gst_ks_clock_open (GstKsClock * self)
 
   state = KSSTATE_STOP;
   if (!ks_object_set_property (priv->clock_handle, KSPROPSETID_Clock,
-          KSPROPERTY_CLOCK_STATE, &state, sizeof (state)))
+          KSPROPERTY_CLOCK_STATE, &state, sizeof (state), NULL))
     goto error;
 
   ks_device_list_free (devices);
@@ -193,7 +193,7 @@ gst_ks_clock_set_state_unlocked (GstKsClock * self, KSSTATE state)
         ks_state_to_string (priv->state), ks_state_to_string (next_state));
 
     if (ks_object_set_property (priv->clock_handle, KSPROPSETID_Clock,
-            KSPROPERTY_CLOCK_STATE, &next_state, sizeof (next_state))) {
+            KSPROPERTY_CLOCK_STATE, &next_state, sizeof (next_state), NULL)) {
       priv->state = next_state;
 
       GST_DEBUG ("Changed clock state to %s", ks_state_to_string (priv->state));
@@ -298,7 +298,7 @@ gst_ks_clock_worker_thread_func (gpointer data)
       now /= 100;
 
       if (ks_object_set_property (priv->clock_handle, KSPROPSETID_Clock,
-              KSPROPERTY_CLOCK_TIME, &now, sizeof (now))) {
+              KSPROPERTY_CLOCK_TIME, &now, sizeof (now), NULL)) {
         GST_DEBUG ("clock synchronized");
         gst_object_unref (priv->master_clock);
         priv->master_clock = NULL;
index 0b95e3d..ec09418 100644 (file)
@@ -556,7 +556,7 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
   alignment = 0;
 
   if (ks_object_get_property (pin_handle, KSPROPSETID_Connection,
-          KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, &framing_ex, NULL)) {
+          KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, &framing_ex, NULL, NULL)) {
     if (framing_ex->CountItems >= 1) {
       *num_outstanding = framing_ex->FramingItem[0].Frames;
       alignment = framing_ex->FramingItem[0].FileAlignment;
@@ -568,7 +568,8 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
         "ALLOCATORFRAMING");
 
     if (ks_object_get_property (pin_handle, KSPROPSETID_Connection,
-            KSPROPERTY_CONNECTION_ALLOCATORFRAMING, &framing, &framing_size)) {
+            KSPROPERTY_CONNECTION_ALLOCATORFRAMING, &framing, &framing_size,
+            NULL)) {
       *num_outstanding = framing->Frames;
       alignment = framing->FileAlignment;
     } else {
@@ -597,7 +598,7 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
     mem_transport = 0;          /* REVISIT: use the constant here */
     if (!ks_object_set_property (pin_handle, KSPROPSETID_MemoryTransport,
             KSPROPERTY_MEMORY_TRANSPORT, &mem_transport,
-            sizeof (mem_transport))) {
+            sizeof (mem_transport), NULL)) {
       GST_DEBUG ("failed to set memory transport, sticking with the default");
     }
   }
@@ -611,7 +612,7 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
 
     if (ks_object_get_property (pin_handle, KSPROPSETID_Stream,
             KSPROPERTY_STREAM_MASTERCLOCK, (gpointer *) & cur_clock_handle,
-            &cur_clock_handle_size)) {
+            &cur_clock_handle_size, NULL)) {
       GST_DEBUG ("current master clock handle: 0x%08x", *cur_clock_handle);
       CloseHandle (*cur_clock_handle);
       g_free (cur_clock_handle);
@@ -620,7 +621,7 @@ gst_ks_video_device_create_pin (GstKsVideoDevice * self,
 
       if (ks_object_set_property (pin_handle, KSPROPSETID_Stream,
               KSPROPERTY_STREAM_MASTERCLOCK, &new_clock_handle,
-              sizeof (new_clock_handle))) {
+              sizeof (new_clock_handle), NULL)) {
         gst_ks_clock_prepare (priv->clock);
       } else {
         GST_WARNING ("failed to set pin's master clock");
@@ -660,7 +661,7 @@ gst_ks_video_device_close_current_pin (GstKsVideoDevice * self)
   if (!ks_is_valid_handle (priv->pin_handle))
     return;
 
-  gst_ks_video_device_set_state (self, KSSTATE_STOP);
+  gst_ks_video_device_set_state (self, KSSTATE_STOP, NULL);
 
   CloseHandle (priv->pin_handle);
   priv->pin_handle = INVALID_HANDLE_VALUE;
@@ -801,7 +802,8 @@ same_caps:
 }
 
 gboolean
-gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state)
+gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state,
+    gulong * error_code)
 {
   GstKsVideoDevicePrivate *priv = GST_KS_VIDEO_DEVICE_GET_PRIVATE (self);
   KSSTATE initial_state;
@@ -828,7 +830,8 @@ gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state)
     GST_DEBUG ("Changing pin state from %s to %s",
         ks_state_to_string (priv->state), ks_state_to_string (next_state));
 
-    if (ks_object_set_connection_state (priv->pin_handle, next_state)) {
+    if (ks_object_set_connection_state (priv->pin_handle, next_state,
+            error_code)) {
       priv->state = next_state;
 
       GST_DEBUG ("Changed pin state to %s", ks_state_to_string (priv->state));
@@ -840,6 +843,7 @@ gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state)
     } else {
       GST_WARNING ("Failed to change pin state to %s",
           ks_state_to_string (next_state));
+
       return FALSE;
     }
   }
index 1d110ad..d830492 100644 (file)
@@ -71,7 +71,7 @@ GstCaps * gst_ks_video_device_get_available_caps (GstKsVideoDevice * self);
 gboolean gst_ks_video_device_has_caps (GstKsVideoDevice * self);
 gboolean gst_ks_video_device_set_caps (GstKsVideoDevice * self, GstCaps * caps);
 
-gboolean gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state);
+gboolean gst_ks_video_device_set_state (GstKsVideoDevice * self, KSSTATE state, gulong * error_code);
 
 GstClockTime gst_ks_video_device_get_duration (GstKsVideoDevice * self);
 gboolean gst_ks_video_device_get_latency (GstKsVideoDevice * self, GstClockTime * min_latency, GstClockTime * max_latency);
index df920a1..577bef5 100644 (file)
@@ -114,6 +114,8 @@ struct _GstKsVideoSrcPrivate
   gboolean worker_pending_run;
   gboolean worker_run_result;
 
+  gulong worker_error_code;
+
   /* Statistics */
   GstClockTime last_sampling;
   guint count;
@@ -555,15 +557,15 @@ error_no_devices:
 error_no_match:
   {
     if (priv->device_path != NULL) {
-      GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
           ("Specified video capture device with path '%s' not found",
               priv->device_path), (NULL));
     } else if (priv->device_name != NULL) {
-      GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
           ("Specified video capture device with name '%s' not found",
               priv->device_name), (NULL));
     } else {
-      GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
+      GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
           ("Specified video capture device with index %d not found",
               priv->device_index), (NULL));
     }
@@ -633,8 +635,8 @@ gst_ks_video_src_worker_func (gpointer data)
     } else if (priv->worker_pending_run) {
       if (priv->ksclock != NULL)
         gst_ks_clock_start (priv->ksclock);
-      priv->worker_run_result =
-          gst_ks_video_device_set_state (priv->device, KSSTATE_RUN);
+      priv->worker_run_result = gst_ks_video_device_set_state (priv->device,
+          KSSTATE_RUN, &priv->worker_error_code);
 
       priv->worker_pending_run = FALSE;
       KS_WORKER_NOTIFY_RESULT (priv);
@@ -1014,6 +1016,7 @@ gst_ks_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
     while (priv->worker_pending_run)
       KS_WORKER_WAIT_FOR_RESULT (priv);
     priv->running = priv->worker_run_result;
+    error_code = priv->worker_error_code;
     KS_WORKER_UNLOCK (priv);
 
     if (!priv->running)
@@ -1051,9 +1054,22 @@ error_no_caps:
   }
 error_start_capture:
   {
-    GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
-        ("could not start capture"),
-        ("failed to change pin state to KSSTATE_RUN"));
+    const gchar *debug_str = "failed to change pin state to KSSTATE_RUN";
+
+    switch (error_code) {
+      case ERROR_FILE_NOT_FOUND:
+        GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+            ("failed to start capture (device unplugged)"), (debug_str));
+        break;
+      case ERROR_NO_SYSTEM_RESOURCES:
+        GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
+            ("failed to start capture (device already in use)"), (debug_str));
+        break;
+      default:
+        GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+            ("failed to start capture (0x%08x)", error_code), (debug_str));
+        break;
+    }
 
     return GST_FLOW_ERROR;
   }
index 0f96dc7..d170180 100644 (file)
@@ -127,7 +127,7 @@ ks_device_list_free (GList * devices)
 static gboolean
 ks_sync_device_io_control (HANDLE device, gulong io_control_code,
     gpointer in_buffer, gulong in_buffer_size, gpointer out_buffer,
-    gulong out_buffer_size, gulong * bytes_returned)
+    gulong out_buffer_size, gulong * bytes_returned, gulong * error)
 {
   OVERLAPPED overlapped = { 0, };
   BOOL success;
@@ -136,8 +136,18 @@ ks_sync_device_io_control (HANDLE device, gulong io_control_code,
 
   success = DeviceIoControl (device, io_control_code, in_buffer,
       in_buffer_size, out_buffer, out_buffer_size, bytes_returned, &overlapped);
-  if (!success && GetLastError () == ERROR_IO_PENDING)
-    success = GetOverlappedResult (device, &overlapped, bytes_returned, TRUE);
+  if (!success) {
+    DWORD err;
+
+    if ((err = GetLastError ()) == ERROR_IO_PENDING) {
+      success = GetOverlappedResult (device, &overlapped, bytes_returned, TRUE);
+      if (!success)
+        err = GetLastError ();
+    }
+
+    if (error != NULL)
+      *error = err;
+  }
 
   CloseHandle (overlapped.hEvent);
 
@@ -146,7 +156,8 @@ ks_sync_device_io_control (HANDLE device, gulong io_control_code,
 
 gboolean
 ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id,
-    GUID prop_set, gulong prop_id, gpointer value, gulong value_size)
+    GUID prop_set, gulong prop_id, gpointer value, gulong value_size,
+    gulong * error)
 {
   KSP_PIN prop = { 0, };
   DWORD bytes_returned = 0;
@@ -157,15 +168,16 @@ ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id,
   prop.Property.Flags = KSPROPERTY_TYPE_GET;
 
   return ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
-      sizeof (prop), value, value_size, &bytes_returned);
+      sizeof (prop), value, value_size, &bytes_returned, error);
 }
 
 gboolean
 ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id,
-    GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items)
+    GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items, gulong * error)
 {
   KSP_PIN prop = { 0, };
   DWORD items_size = 0, bytes_written = 0;
+  gulong err;
   gboolean ret;
 
   *items = NULL;
@@ -176,23 +188,23 @@ ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id,
   prop.Property.Flags = KSPROPERTY_TYPE_GET;
 
   ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY,
-      &prop.Property, sizeof (prop), NULL, 0, &items_size);
-  if (!ret) {
-    DWORD err = GetLastError ();
-    if (err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
-      goto error;
-  }
+      &prop.Property, sizeof (prop), NULL, 0, &items_size, &err);
+  if (!ret && err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
+    goto ioctl_failed;
 
   *items = g_malloc0 (items_size);
 
   ret = ks_sync_device_io_control (filter_handle, IOCTL_KS_PROPERTY, &prop,
-      sizeof (prop), *items, items_size, &bytes_written);
+      sizeof (prop), *items, items_size, &bytes_written, &err);
   if (!ret)
-    goto error;
+    goto ioctl_failed;
 
   return ret;
 
-error:
+ioctl_failed:
+  if (error != NULL)
+    *error = err;
+
   g_free (*items);
   *items = NULL;
 
@@ -201,10 +213,11 @@ error:
 
 gboolean
 ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id,
-    gulong prop_flags, gpointer * value, gulong * value_size)
+    gulong prop_flags, gpointer * value, gulong * value_size, gulong * error)
 {
   KSPROPERTY prop = { 0, };
   DWORD req_value_size = 0, bytes_written = 0;
+  gulong err;
   gboolean ret;
 
   *value = NULL;
@@ -215,12 +228,9 @@ ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id,
 
   if (value_size == NULL || *value_size == 0) {
     ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY,
-        &prop, sizeof (prop), NULL, 0, &req_value_size);
-    if (!ret) {
-      DWORD err = GetLastError ();
-      if (err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
-        goto error;
-    }
+        &prop, sizeof (prop), NULL, 0, &req_value_size, &err);
+    if (!ret && err != ERROR_INSUFFICIENT_BUFFER && err != ERROR_MORE_DATA)
+      goto ioctl_failed;
   } else {
     req_value_size = *value_size;
   }
@@ -228,16 +238,19 @@ ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id,
   *value = g_malloc0 (req_value_size);
 
   ret = ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
-      sizeof (prop), *value, req_value_size, &bytes_written);
+      sizeof (prop), *value, req_value_size, &bytes_written, &err);
   if (!ret)
-    goto error;
+    goto ioctl_failed;
 
   if (value_size != NULL)
     *value_size = bytes_written;
 
   return ret;
 
-error:
+ioctl_failed:
+  if (error != NULL)
+    *error = err;
+
   g_free (*value);
   *value = NULL;
 
@@ -249,15 +262,15 @@ error:
 
 gboolean
 ks_object_get_property (HANDLE handle, GUID prop_set, gulong prop_id,
-    gpointer * value, gulong * value_size)
+    gpointer * value, gulong * value_size, gulong * error)
 {
   return ks_object_query_property (handle, prop_set, prop_id,
-      KSPROPERTY_TYPE_GET, value, value_size);
+      KSPROPERTY_TYPE_GET, value, value_size, error);
 }
 
 gboolean
 ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id,
-    gpointer value, gulong value_size)
+    gpointer value, gulong value_size, gulong * error)
 {
   KSPROPERTY prop = { 0, };
   DWORD bytes_returned;
@@ -267,7 +280,7 @@ ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id,
   prop.Flags = KSPROPERTY_TYPE_SET;
 
   return ks_sync_device_io_control (handle, IOCTL_KS_PROPERTY, &prop,
-      sizeof (prop), value, value_size, &bytes_returned);
+      sizeof (prop), value, value_size, &bytes_returned, error);
 }
 
 gboolean
@@ -275,12 +288,13 @@ ks_object_get_supported_property_sets (HANDLE handle, GUID ** propsets,
     gulong * len)
 {
   gulong size = 0;
+  gulong error;
 
   *propsets = NULL;
   *len = 0;
 
   if (ks_object_query_property (handle, GUID_NULL, 0,
-          KSPROPERTY_TYPE_SETSUPPORT, propsets, &size)) {
+          KSPROPERTY_TYPE_SETSUPPORT, propsets, &size, &error)) {
     if (size % sizeof (GUID) == 0) {
       *len = size / sizeof (GUID);
       return TRUE;
@@ -294,10 +308,10 @@ ks_object_get_supported_property_sets (HANDLE handle, GUID ** propsets,
 }
 
 gboolean
-ks_object_set_connection_state (HANDLE handle, KSSTATE state)
+ks_object_set_connection_state (HANDLE handle, KSSTATE state, gulong * error)
 {
   return ks_object_set_property (handle, KSPROPSETID_Connection,
-      KSPROPERTY_CONNECTION_STATE, &state, sizeof (state));
+      KSPROPERTY_CONNECTION_STATE, &state, sizeof (state), error);
 }
 
 gchar *
index a233722..b84fcde 100644 (file)
@@ -41,16 +41,16 @@ GList * ks_enumerate_devices (const GUID * category);
 void ks_device_entry_free (KsDeviceEntry * entry);
 void ks_device_list_free (GList * devices);
 
-gboolean ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id, GUID prop_set, gulong prop_id, gpointer value, gulong value_size);
-gboolean ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id, GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items);
+gboolean ks_filter_get_pin_property (HANDLE filter_handle, gulong pin_id, GUID prop_set, gulong prop_id, gpointer value, gulong value_size, gulong * error);
+gboolean ks_filter_get_pin_property_multi (HANDLE filter_handle, gulong pin_id, GUID prop_set, gulong prop_id, KSMULTIPLE_ITEM ** items, gulong * error);
 
-gboolean ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id, gulong prop_flags, gpointer * value, gulong * value_size);
-gboolean ks_object_get_property (HANDLE handle, GUID prop_set, gulong prop_id, gpointer * value, gulong * value_size);
-gboolean ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id, gpointer value, gulong value_size);
+gboolean ks_object_query_property (HANDLE handle, GUID prop_set, gulong prop_id, gulong prop_flags, gpointer * value, gulong * value_size, gulong * error);
+gboolean ks_object_get_property (HANDLE handle, GUID prop_set, gulong prop_id, gpointer * value, gulong * value_size, gulong * error);
+gboolean ks_object_set_property (HANDLE handle, GUID prop_set, gulong prop_id, gpointer value, gulong value_size, gulong * error);
 
 gboolean ks_object_get_supported_property_sets (HANDLE handle, GUID ** propsets, gulong * len);
 
-gboolean ks_object_set_connection_state (HANDLE handle, KSSTATE state);
+gboolean ks_object_set_connection_state (HANDLE handle, KSSTATE state, gulong * error);
 
 gchar * ks_guid_to_string (const GUID * guid);
 const gchar * ks_state_to_string (KSSTATE state);
index e93f71b..69b4311 100644 (file)
@@ -427,7 +427,7 @@ ks_video_probe_filter_for_caps (HANDLE filter_handle)
   guint pin_id;
 
   if (!ks_filter_get_pin_property (filter_handle, 0, KSPROPSETID_Pin,
-          KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count)))
+          KSPROPERTY_PIN_CTYPES, &pin_count, sizeof (pin_count), NULL))
     goto beach;
 
   GST_DEBUG ("pin_count = %d", pin_count);
@@ -438,15 +438,15 @@ ks_video_probe_filter_for_caps (HANDLE filter_handle)
     GUID pin_cat;
 
     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
-            KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm)))
+            KSPROPERTY_PIN_COMMUNICATION, &pin_comm, sizeof (pin_comm), NULL))
       continue;
 
     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
-            KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow)))
+            KSPROPERTY_PIN_DATAFLOW, &pin_flow, sizeof (pin_flow), NULL))
       continue;
 
     if (!ks_filter_get_pin_property (filter_handle, pin_id, KSPROPSETID_Pin,
-            KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat)))
+            KSPROPERTY_PIN_CATEGORY, &pin_cat, sizeof (pin_cat), NULL))
       continue;
 
     GST_DEBUG ("pin[%u]: pin_comm=%d, pin_flow=%d", pin_id, pin_comm, pin_flow);
@@ -456,7 +456,7 @@ ks_video_probe_filter_for_caps (HANDLE filter_handle)
       KSMULTIPLE_ITEM *items;
 
       if (ks_filter_get_pin_property_multi (filter_handle, pin_id,
-              KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items)) {
+              KSPROPSETID_Pin, KSPROPERTY_PIN_DATARANGES, &items, NULL)) {
         KSDATARANGE *range = (KSDATARANGE *) (items + 1);
         guint i;