winks: improve error-handling

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.
This commit is contained in:
Ole André Vadla Ravnås 2009-10-12 17:26:15 +02:00
parent cddfa50d92
commit d282a1d380
7 changed files with 97 additions and 63 deletions

View 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;

View 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;
}
}

View 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);

View 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;
}

View 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 *

View 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);

View 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;