1 /* GStreamer android.hardware.Sensor Source
2 * Copyright (C) 2016 SurroundIO
3 * Author: Martin Kelly <martin@surround.io>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 /**
21 * SECTION:element-ahssrc
22 * @title: gstahssrc
23 *
24 * The ahssrc element reads data from Android device sensors
25 * (android.hardware.Sensor).
26 *
27 * ## Example launch line
28 * |[
29 * gst-launch -v ahssrc ! fakesink
30 * ]|
31 * Push Android sensor data into a fakesink.
32 *
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <string.h>
40
41 #include <gst/gst.h>
42 #include <gst/gstclock.h>
43 #include <gst/base/gstbasesrc.h>
44 #include <gst/base/gstpushsrc.h>
45 #include "gstjniutils.h"
46 #include "gst-android-hardware-sensor.h"
47 #include "gstahssrc.h"
48 #include "gstsensors.h"
49
50 GST_DEBUG_CATEGORY_STATIC (gst_ahs_src_debug);
51 #define GST_CAT_DEFAULT gst_ahs_src_debug
52
53 #define parent_class gst_ahs_src_parent_class
54
55 /* GObject */
56 static void gst_ahs_src_set_property (GObject * object, guint prop_id,
57 const GValue * value, GParamSpec * pspec);
58 static void gst_ahs_src_get_property (GObject * object, guint prop_id,
59 GValue * value, GParamSpec * pspec);
60 static void gst_ahs_src_dispose (GObject * object);
61
62 /* GstBaseSrc */
63 static gboolean gst_ahs_src_set_caps (GstBaseSrc * src, GstCaps * caps);
64 static gboolean gst_ahs_src_start (GstBaseSrc * src);
65 static gboolean gst_ahs_src_stop (GstBaseSrc * src);
66 static gboolean gst_ahs_src_get_size (GstBaseSrc * src, guint64 * size);
67 static gboolean gst_ahs_src_is_seekable (GstBaseSrc * src);
68 static gboolean gst_ahs_src_unlock (GstBaseSrc * src);
69 static gboolean gst_ahs_src_unlock_stop (GstBaseSrc * src);
70
71 /* GstPushSrc */
72 static GstFlowReturn gst_ahs_src_create (GstPushSrc * src, GstBuffer ** buf);
73
74 /* GstAHSSrc */
75 static void gst_ahs_src_on_sensor_changed (jobject sensor_event,
76 gpointer user_data);
77 static void gst_ahs_src_on_accuracy_changed (jobject sensor, gint accuracy,
78 gpointer user_data);
79 static gboolean gst_ahs_src_register_callback (GstAHSSrc * self);
80
81 enum
82 {
83 PROP_0,
84 PROP_SENSOR_DELAY,
85 PROP_ALPHA,
86 PROP_SAMPLE_INTERVAL,
87 PROP_LAST
88 };
89
90 static GParamSpec *properties[PROP_LAST];
91
92 #define GST_AHS_SRC_CAPS_STR GST_SENSOR_CAPS_MAKE (GST_SENSOR_FORMATS_ALL)
93
94 static GstStaticPadTemplate gst_ahs_src_template =
95 GST_STATIC_PAD_TEMPLATE ("src",
96 GST_PAD_SRC,
97 GST_PAD_ALWAYS,
98 GST_STATIC_CAPS (GST_AHS_SRC_CAPS_STR));
99
100
101 G_DEFINE_TYPE_WITH_CODE (GstAHSSrc, gst_ahs_src, GST_TYPE_PUSH_SRC,
102 GST_DEBUG_CATEGORY_INIT (gst_ahs_src_debug, "ahssrc", 0,
103 "Android hardware sensors"));
104
105 #define GST_TYPE_AHS_SENSOR_DELAY (gst_ahs_src_get_sensor_delay ())
106 static GType
gst_ahs_src_get_sensor_delay(void)107 gst_ahs_src_get_sensor_delay (void)
108 {
109 static GType ahs_src_sensor_delay = 0;
110
111 if (!ahs_src_sensor_delay) {
112 static GEnumValue sensor_delay[5];
113 sensor_delay[0].value = AHS_SENSOR_DELAY_FASTEST;
114 sensor_delay[0].value_name = "fastest";
115 sensor_delay[0].value_nick = "fastest";
116 sensor_delay[1].value = AHS_SENSOR_DELAY_GAME;
117 sensor_delay[1].value_name = "game";
118 sensor_delay[1].value_nick = "game";
119 sensor_delay[2].value = AHS_SENSOR_DELAY_NORMAL;
120 sensor_delay[2].value_name = "normal";
121 sensor_delay[2].value_nick = "normal";
122 sensor_delay[3].value = AHS_SENSOR_DELAY_UI;
123 sensor_delay[3].value_name = "ui";
124 sensor_delay[3].value_nick = "ui";
125 sensor_delay[4].value = 0;
126 sensor_delay[4].value_name = NULL;
127 sensor_delay[4].value_nick = NULL;
128
129 ahs_src_sensor_delay =
130 g_enum_register_static ("GstAhsSrcSensorDelay", sensor_delay);
131 }
132
133 return ahs_src_sensor_delay;
134 }
135
136 #define GST_TYPE_AHS_SENSOR_TYPE (gst_ahs_src_get_sensor_type ())
137 static GType
gst_ahs_src_get_sensor_type(void)138 gst_ahs_src_get_sensor_type (void)
139 {
140 static GType ahs_src_sensor_type = 0;
141
142 if (!ahs_src_sensor_type) {
143 static const GEnumValue sensor_types[] = {
144 {AHS_SENSOR_TYPE_ACCELEROMETER, "accelerometer"},
145 {AHS_SENSOR_TYPE_AMBIENT_TEMPERATURE, "ambient-temperature"},
146 {AHS_SENSOR_TYPE_GAME_ROTATION_VECTOR, "game-rotation-vector"},
147 {AHS_SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR,
148 "geomagnetic-rotation-vector"},
149 {AHS_SENSOR_TYPE_GRAVITY, "gravity"},
150 {AHS_SENSOR_TYPE_GYROSCOPE, "gyroscope"},
151 {AHS_SENSOR_TYPE_GYROSCOPE_UNCALIBRATED, "gyroscope-uncalibrated"},
152 {AHS_SENSOR_TYPE_HEART_RATE, "heart-rate"},
153 {AHS_SENSOR_TYPE_LIGHT, "light"},
154 {AHS_SENSOR_TYPE_LINEAR_ACCELERATION, "linear-acceleration"},
155 {AHS_SENSOR_TYPE_MAGNETIC_FIELD, "magnetic-field"},
156 {AHS_SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
157 "magnetic-field-uncalibrated"},
158 {AHS_SENSOR_TYPE_ORIENTATION, "orientation"},
159 {AHS_SENSOR_TYPE_PRESSURE, "pressure"},
160 {AHS_SENSOR_TYPE_PROXIMITY, "proximity"},
161 {AHS_SENSOR_TYPE_RELATIVE_HUMIDITY, "relative-humidity"},
162 {AHS_SENSOR_TYPE_ROTATION_VECTOR, "rotation-vector"},
163 {AHS_SENSOR_TYPE_STEP_COUNTER, "step-counter"},
164 {AHS_SENSOR_TYPE_STEP_DETECTOR, "step-detector"},
165 {0, NULL, NULL}
166 };
167
168 ahs_src_sensor_type =
169 g_enum_register_static ("GstAhsSrcSensorType", sensor_types);
170 }
171
172 return ahs_src_sensor_type;
173 }
174
175 static void
gst_ahs_src_class_init(GstAHSSrcClass * klass)176 gst_ahs_src_class_init (GstAHSSrcClass * klass)
177 {
178 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
179 GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass);
180 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
181 GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass);
182
183 gobject_class->set_property = gst_ahs_src_set_property;
184 gobject_class->get_property = gst_ahs_src_get_property;
185 gobject_class->dispose = gst_ahs_src_dispose;
186
187 base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_ahs_src_set_caps);
188 base_src_class->start = GST_DEBUG_FUNCPTR (gst_ahs_src_start);
189 base_src_class->stop = GST_DEBUG_FUNCPTR (gst_ahs_src_stop);
190 base_src_class->get_size = GST_DEBUG_FUNCPTR (gst_ahs_src_get_size);
191 base_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_ahs_src_is_seekable);
192 base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_ahs_src_unlock);
193 base_src_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_ahs_src_unlock_stop);
194
195 push_src_class->create = GST_DEBUG_FUNCPTR (gst_ahs_src_create);
196
197 gst_element_class_add_pad_template (element_class,
198 gst_static_pad_template_get (&gst_ahs_src_template));
199
200 properties[PROP_SENSOR_DELAY] = g_param_spec_enum ("sensor-delay",
201 "Sensor delay", "Configure the sensor rate", GST_TYPE_AHS_SENSOR_DELAY,
202 AHS_SENSOR_DELAY_NORMAL,
203 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
204 g_object_class_install_property (gobject_class, PROP_SENSOR_DELAY,
205 properties[PROP_SENSOR_DELAY]);
206
207 properties[PROP_ALPHA] = g_param_spec_double ("alpha", "Alpha",
208 "Alpha value used for exponential smoothing (between 0.0 and 1.0)", 0.0,
209 1.0, 0.2, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
210 g_object_class_install_property (gobject_class, PROP_ALPHA,
211 properties[PROP_ALPHA]);
212
213 properties[PROP_SAMPLE_INTERVAL] = g_param_spec_uint ("sample-interval",
214 "Sample interval",
215 "Sample interval (for interval n, will output a smoothed average every "
216 "nth sample)", 1, G_MAXUINT, 1,
217 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
218 g_object_class_install_property (gobject_class, PROP_SAMPLE_INTERVAL,
219 properties[PROP_SAMPLE_INTERVAL]);
220
221 gst_element_class_set_static_metadata (element_class,
222 "Android hardware sensors", "Source/Sensor/Device",
223 "Source for Android hardware sensor data",
224 "Martin Kelly <martin@surround.io>");
225 }
226
227 static gboolean
_data_queue_check_full(GstDataQueue * queue,guint visible,guint bytes,guint64 time,gpointer checkdata)228 _data_queue_check_full (GstDataQueue * queue, guint visible,
229 guint bytes, guint64 time, gpointer checkdata)
230 {
231 return FALSE;
232 }
233
234 static void
gst_ahs_src_init(GstAHSSrc * self)235 gst_ahs_src_init (GstAHSSrc * self)
236 {
237 gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
238 gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
239 gst_base_src_set_do_timestamp (GST_BASE_SRC (self), FALSE);
240
241 self->sensor_enum_class = g_type_class_ref (GST_TYPE_AHS_SENSOR_TYPE);
242 self->sensor_type_name = NULL;
243
244 self->manager = NULL;
245 self->sensor = NULL;
246 self->listener = NULL;
247 self->callback_registered = FALSE;
248
249 self->queue = gst_data_queue_new (_data_queue_check_full, NULL, NULL, NULL);
250
251 self->previous_time = GST_CLOCK_TIME_NONE;
252 self->sample_index = 0;
253 self->current_sample = NULL;
254 }
255
256 static void
gst_ahs_src_dispose(GObject * object)257 gst_ahs_src_dispose (GObject * object)
258 {
259 JNIEnv *env = gst_amc_jni_get_env ();
260 GstAHSSrc *self = GST_AHS_SRC (object);
261
262 if (self->manager) {
263 gst_amc_jni_object_unref (env, self->manager->object);
264 g_slice_free (GstAHSensorManager, self->manager);
265 self->manager = NULL;
266 }
267
268 if (self->sensor) {
269 gst_amc_jni_object_unref (env, self->sensor->object);
270 g_slice_free (GstAHSensor, self->sensor);
271 self->sensor = NULL;
272 }
273
274 if (self->listener) {
275 gst_amc_jni_object_unref (env, self->listener->object);
276 g_slice_free (GstAHSensorEventListener, self->listener);
277 self->listener = NULL;
278 }
279
280 if (self->current_sample) {
281 g_free (self->current_sample);
282 self->current_sample = NULL;
283 }
284
285 if (self->sensor_enum_class) {
286 g_type_class_unref (self->sensor_enum_class);
287 self->sensor_enum_class = NULL;
288 }
289
290 if (self->sensor_type_name) {
291 g_free ((gpointer) self->sensor_type_name);
292 self->sensor_type_name = NULL;
293 }
294
295 if (self->queue) {
296 g_object_unref (self->queue);
297 self->queue = NULL;
298 }
299
300 G_OBJECT_CLASS (parent_class)->dispose (object);
301 }
302
303 static void
gst_ahs_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)304 gst_ahs_src_set_property (GObject * object, guint prop_id,
305 const GValue * value, GParamSpec * pspec)
306 {
307 GstAHSSrc *self = GST_AHS_SRC (object);
308
309 /*
310 * Take the mutex to protect against callbacks or changes to the properties
311 * that the callback uses (e.g. caps changes).
312 */
313 GST_OBJECT_LOCK (self);
314
315 switch (prop_id) {
316 case PROP_SENSOR_DELAY:
317 self->sensor_delay = g_value_get_enum (value);
318 /*
319 * If we already have a callback running, reregister with the new delay.
320 * Otherwise, wait for the pipeline to start before we register.
321 */
322 if (self->callback_registered)
323 gst_ahs_src_register_callback (self);
324 break;
325 case PROP_ALPHA:
326 self->alpha = g_value_get_double (value);
327 break;
328 case PROP_SAMPLE_INTERVAL:
329 self->sample_interval = g_value_get_uint (value);
330 break;
331 default:
332 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333 break;
334 }
335
336 GST_OBJECT_UNLOCK (self);
337 }
338
339 static void
gst_ahs_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)340 gst_ahs_src_get_property (GObject * object, guint prop_id,
341 GValue * value, GParamSpec * pspec)
342 {
343 GstAHSSrc *self = GST_AHS_SRC (object);
344
345 switch (prop_id) {
346 case PROP_SENSOR_DELAY:
347 g_value_set_enum (value, self->sensor_delay);
348 case PROP_ALPHA:
349 g_value_set_double (value, self->alpha);
350 break;
351 case PROP_SAMPLE_INTERVAL:
352 g_value_set_uint (value, self->sample_interval);
353 break;
354 default:
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
356 }
357 }
358
359 static gboolean
gst_ahs_src_register_callback(GstAHSSrc * self)360 gst_ahs_src_register_callback (GstAHSSrc * self)
361 {
362 if (self->callback_registered) {
363 gst_ah_sensor_unregister_listener (self->manager, self->listener);
364 self->callback_registered = FALSE;
365 }
366 if (!gst_ah_sensor_register_listener (self->manager, self->listener,
367 self->sensor, self->sensor_delay)) {
368 return FALSE;
369 }
370 self->callback_registered = TRUE;
371
372 return TRUE;
373 }
374
375 static gboolean
gst_ahs_src_change_sensor_type(GstAHSSrc * self,const gchar * type_str,gint type)376 gst_ahs_src_change_sensor_type (GstAHSSrc * self, const gchar * type_str,
377 gint type)
378 {
379 JNIEnv *env = gst_amc_jni_get_env ();
380
381 /* Replace sensor type. */
382 if (self->sensor_type_name)
383 g_free ((gpointer) self->sensor_type_name);
384 self->sensor_type_name = type_str;
385 self->sensor_type = type;
386
387 /* Adjust buffer and buffer size. */
388 self->buffer_size = gst_ah_sensor_get_sensor_data_size (self->sensor_type);
389 g_assert (self->buffer_size != 0);
390 self->sample_length = self->buffer_size / sizeof (*self->current_sample);
391 self->current_sample = g_realloc (self->current_sample, self->buffer_size);
392
393 /* Make sure we have a manager. */
394 if (!self->manager) {
395 self->manager = gst_ah_sensor_get_manager ();
396 if (!self->manager) {
397 GST_ERROR_OBJECT (self, "Failed to get sensor manager");
398 goto error_sensor_type_name;
399 }
400 }
401
402 /* Replace sensor object. */
403 if (self->sensor) {
404 gst_amc_jni_object_unref (env, self->sensor->object);
405 g_slice_free (GstAHSensor, self->sensor);
406 }
407 self->sensor = gst_ah_sensor_get_default_sensor (self->manager,
408 self->sensor_type);
409 if (!self->sensor) {
410 GST_ERROR_OBJECT (self, "Failed to get sensor type %s",
411 self->sensor_type_name);
412 goto error_manager;
413 }
414
415 /* Register for the callback, unregistering first if necessary. */
416 if (!gst_ahs_src_register_callback (self))
417 goto error_sensor;
418
419 return TRUE;
420
421 error_sensor:
422 gst_amc_jni_object_unref (env, self->sensor->object);
423 g_slice_free (GstAHSensor, self->sensor);
424 self->sensor = NULL;
425 error_manager:
426 gst_amc_jni_object_unref (env, self->manager->object);
427 g_slice_free (GstAHSensorManager, self->manager);
428 self->manager = NULL;
429 error_sensor_type_name:
430 g_free ((gpointer) self->sensor_type_name);
431 self->sensor_type_name = NULL;
432 return FALSE;
433 }
434
435 static gboolean
gst_ahs_src_set_caps(GstBaseSrc * src,GstCaps * caps)436 gst_ahs_src_set_caps (GstBaseSrc * src, GstCaps * caps)
437 {
438 const GstStructure *caps_struct;
439 GstAHSSrc *self = GST_AHS_SRC (src);
440 gboolean success;
441 gint type;
442 const gchar *type_str;
443 GEnumValue *value;
444
445 caps_struct = gst_caps_get_structure (caps, 0);
446 type_str = gst_structure_get_string (caps_struct, "type");
447 value = g_enum_get_value_by_name (self->sensor_enum_class, type_str);
448 if (!value) {
449 GST_ERROR_OBJECT (self, "Failed to lookup sensor type %s", type_str);
450 return FALSE;
451 }
452 type_str = g_strdup (type_str);
453 type = value->value;
454
455 /*
456 * Take the mutex while changing the sensor type in case there are concurrent
457 * callbacks being processed.
458 */
459 GST_OBJECT_LOCK (self);
460 success = gst_ahs_src_change_sensor_type (self, type_str, type);
461 GST_OBJECT_UNLOCK (self);
462
463 if (!success)
464 return FALSE;
465
466 return TRUE;
467 }
468
469 static gboolean
gst_ahs_src_start(GstBaseSrc * src)470 gst_ahs_src_start (GstBaseSrc * src)
471 {
472 JNIEnv *env = gst_amc_jni_get_env ();
473 GstAHSSrc *self = GST_AHS_SRC (src);
474
475 g_assert_null (self->manager);
476 g_assert_null (self->listener);
477
478 self->manager = gst_ah_sensor_get_manager ();
479 if (!self->manager) {
480 GST_ERROR_OBJECT (self, "Failed to get sensor manager");
481 goto error;
482 }
483
484 self->previous_time = GST_CLOCK_TIME_NONE;
485
486 self->listener = gst_ah_sensor_create_listener (gst_ahs_src_on_sensor_changed,
487 gst_ahs_src_on_accuracy_changed, self);
488 if (!self->listener) {
489 GST_ERROR_OBJECT (self, "Failed to create sensor listener");
490 goto error_manager;
491 }
492
493 return TRUE;
494
495 error_manager:
496 gst_amc_jni_object_unref (env, self->manager->object);
497 g_slice_free (GstAHSensorManager, self->manager);
498 self->manager = NULL;
499 error:
500 return FALSE;
501 }
502
503 static gboolean
gst_ahs_src_stop(GstBaseSrc * src)504 gst_ahs_src_stop (GstBaseSrc * src)
505 {
506 GstAHSSrc *self = GST_AHS_SRC (src);
507
508 g_assert_nonnull (self->manager);
509 g_assert_nonnull (self->sensor);
510 g_assert_nonnull (self->listener);
511
512 gst_ah_sensor_unregister_listener (self->manager, self->listener);
513 self->previous_time = GST_CLOCK_TIME_NONE;
514
515 return TRUE;
516 }
517
518 static gboolean
gst_ahs_src_get_size(GstBaseSrc * src,guint64 * size)519 gst_ahs_src_get_size (GstBaseSrc * src, guint64 * size)
520 {
521 GstAHSSrc *self = GST_AHS_SRC (src);
522
523 return self->buffer_size;
524 }
525
526 static gboolean
gst_ahs_src_is_seekable(GstBaseSrc * src)527 gst_ahs_src_is_seekable (GstBaseSrc * src)
528 {
529 return FALSE;
530 }
531
532 static gboolean
gst_ahs_src_unlock(GstBaseSrc * src)533 gst_ahs_src_unlock (GstBaseSrc * src)
534 {
535 GstAHSSrc *self = GST_AHS_SRC (src);
536
537 gst_data_queue_set_flushing (self->queue, TRUE);
538
539 return TRUE;
540 }
541
542 static gboolean
gst_ahs_src_unlock_stop(GstBaseSrc * src)543 gst_ahs_src_unlock_stop (GstBaseSrc * src)
544 {
545 GstAHSSrc *self = GST_AHS_SRC (src);
546
547 gst_data_queue_set_flushing (self->queue, FALSE);
548
549 return TRUE;
550 }
551
552 static GstFlowReturn
gst_ahs_src_create(GstPushSrc * src,GstBuffer ** buffer)553 gst_ahs_src_create (GstPushSrc * src, GstBuffer ** buffer)
554 {
555 GstAHSSrc *self = GST_AHS_SRC (src);
556 GstDataQueueItem *item;
557
558 if (!gst_data_queue_pop (self->queue, &item)) {
559 GST_INFO_OBJECT (self, "data queue is empty");
560 return GST_FLOW_FLUSHING;
561 }
562
563 GST_DEBUG_OBJECT (self, "creating buffer %p->%p", item, item->object);
564
565 *buffer = GST_BUFFER (item->object);
566 g_slice_free (GstDataQueueItem, item);
567
568 return GST_FLOW_OK;
569 }
570
571 static void
gst_ahs_src_free_data_queue_item(GstDataQueueItem * item)572 gst_ahs_src_free_data_queue_item (GstDataQueueItem * item)
573 {
574 gst_buffer_unref (GST_BUFFER (item->object));
575 g_slice_free (GstDataQueueItem, item);
576 }
577
578 static void
gst_ahs_src_update_smoothing(GstAHSSrc * self,const GstAHSensorEvent * event)579 gst_ahs_src_update_smoothing (GstAHSSrc * self, const GstAHSensorEvent * event)
580 {
581 gint i;
582
583 /*
584 * Since we're doing exponential smoothing, the first sample needs to be
585 * special-cased to prevent it from being artificially lowered by the alpha
586 * smoothing factor.
587 */
588 if (self->sample_index == 0) {
589 for (i = 0; i < self->sample_length; i++) {
590 self->current_sample[i] = event->data.values[i];
591 }
592 } else {
593 for (i = 0; i < self->sample_length; i++)
594 self->current_sample[i] =
595 (1 - self->alpha) * self->current_sample[i] +
596 self->alpha * event->data.values[i];
597 }
598 }
599
600 static void
gst_ahs_src_on_sensor_changed(jobject event_object,gpointer user_data)601 gst_ahs_src_on_sensor_changed (jobject event_object, gpointer user_data)
602 {
603 GstBuffer *buffer;
604 GstClockTime buffer_time;
605 gfloat *data;
606 GstAHSensorEvent event;
607 GstDataQueueItem *item;
608 GstClock *pipeline_clock;
609 GstAHSSrc *self = GST_AHS_SRC (user_data);
610 gboolean success;
611
612 GST_OBJECT_LOCK (self);
613
614 pipeline_clock = GST_ELEMENT_CLOCK (self);
615 /* If the clock is NULL, the pipeline is not yet set to PLAYING. */
616 if (pipeline_clock == NULL)
617 goto done;
618
619 /*
620 * Unfortunately, the timestamp reported in the Android SensorEvent timestamp
621 * is not guaranteed to use any particular clock. On some device models, it
622 * uses system time, and on other models, it uses monotonic time. In addition,
623 * in some cases, the units are microseconds, and in other cases they are
624 * nanoseconds. Thus we cannot slave it to the pipeline clock or use any
625 * similar strategy that would allow us to correlate the two clocks. So
626 * instead, we approximate the buffer timestamp using the pipeline clock.
627 *
628 * See here for more details on issues with the Android SensorEvent timestamp:
629 * https://code.google.com/p/android/issues/detail?id=7981
630 */
631 buffer_time =
632 gst_clock_get_time (pipeline_clock) - GST_ELEMENT_CAST (self)->base_time;
633
634 success =
635 gst_ah_sensor_populate_event (&event, event_object, self->buffer_size);
636 if (!success) {
637 GST_ERROR_OBJECT (self, "Failed to populate sensor event");
638 goto done;
639 }
640
641 gst_ahs_src_update_smoothing (self, &event);
642 gst_ah_sensor_free_sensor_data (&event.data);
643 self->sample_index++;
644 if (self->sample_index < self->sample_interval)
645 goto done;
646 self->sample_index = 0;
647
648 /*
649 * We want to send off this sample; copy it into a separate data struct so we
650 * can continue using current_sample for aggregating future samples.
651 */
652 data = g_malloc (self->buffer_size);
653 memcpy (data, self->current_sample, self->buffer_size);
654
655 /* Wrap the datapoint with a buffer and add it to the queue. */
656 buffer = gst_buffer_new_wrapped (data, self->buffer_size);
657 GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
658 GST_BUFFER_PTS (buffer) = buffer_time;
659
660 item = g_slice_new (GstDataQueueItem);
661 item->object = GST_MINI_OBJECT (buffer);
662 item->size = gst_buffer_get_size (buffer);
663 item->duration = GST_BUFFER_DURATION (buffer);
664 item->visible = TRUE;
665 item->destroy = (GDestroyNotify) gst_ahs_src_free_data_queue_item;
666
667 success = gst_data_queue_push (self->queue, item);
668 if (!success) {
669 GST_ERROR_OBJECT (self, "Could not add buffer to queue");
670 gst_ahs_src_free_data_queue_item (item);
671 goto done;
672 }
673
674 done:
675 GST_OBJECT_UNLOCK (self);
676 }
677
678 static void
gst_ahs_src_on_accuracy_changed(jobject sensor,gint accuracy,gpointer user_data)679 gst_ahs_src_on_accuracy_changed (jobject sensor, gint accuracy,
680 gpointer user_data)
681 {
682 GstAHSSrc *self = GST_AHS_SRC (user_data);
683
684 /* TODO: Perhaps we should do something more with this information. */
685 GST_DEBUG_OBJECT (self, "Accuracy changed on sensor %p and is now %d", sensor,
686 accuracy);
687 }
688