Merge branch 'tizen' into tizen_gst_1.19.2
[platform/upstream/gstreamer.git] / ext / openal / gstopenalsink.c
index 871e671..027aca4 100644 (file)
@@ -64,6 +64,10 @@ GST_DEBUG_CATEGORY_EXTERN (openal_debug);
 #include "gstopenalelements.h"
 #include "gstopenalsink.h"
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+#include <math.h>
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
 static void gst_openal_sink_dispose (GObject * object);
 static void gst_openal_sink_finalize (GObject * object);
 
@@ -83,6 +87,17 @@ static gint gst_openal_sink_write (GstAudioSink * audiosink, gpointer data,
 static guint gst_openal_sink_delay (GstAudioSink * audiosink);
 static void gst_openal_sink_reset (GstAudioSink * audiosink);
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+void set_angles (GstElement * element, float absolute_angle_x,
+    float absolute_angle_y, float absolute_angle_z);
+void apply_rotation (GstElement * element, float rotation_x, float rotation_y,
+    float rotation_z);
+static gboolean gst_openal_sink_src_event (GstElement * element,
+    GstEvent * event);
+
+gfloat source_rotation_y_old = 0;
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
 #define OPENAL_DEFAULT_DEVICE NULL
 
 #define OPENAL_MIN_RATE 8000
@@ -97,9 +112,56 @@ enum
 
   PROP_USER_DEVICE,
   PROP_USER_CONTEXT,
+#ifndef TIZEN_FEATURE_OALSINK_MODIFICATION
   PROP_USER_SOURCE
+#else
+  PROP_USER_SOURCE,
+
+  PROP_USE_STREAM_INFO,
+  PROP_STREAM_INFO,
+
+  PROP_SOURCE_ORIENTATION_X_AXIS,
+  PROP_SOURCE_ORIENTATION_Y_AXIS,
+  PROP_SOURCE_ORIENTATION_Z_AXIS,
+
+  PROP_SOURCE_AMBISONIC_TYPE
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
 };
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+/* Register GTtypes for custom enums */
+#define GST_TYPE_AMBISONICS_TYPE (gst_openalsink_ambisonicstype_get_type ())
+
+static GType
+gst_openalsink_ambisonicstype_get_type (void)
+{
+  static GType ambisonics_type = 0;
+
+  if (!ambisonics_type) {
+    static GEnumValue ambisonics_types[] = {
+      { AMBISONICS_TYPE_UNKNOWN, "Ambisonics type is not determined", "unknown" },
+      { AMBISONICS_TYPE_PERIPHONIC, "Periphonic ambisonics", "periphonic" },
+      { AMBISONICS_TYPE_NON_PERIPHONIC, "Non-periphonic ambisonics", "non-periphonic" },
+      { 0, NULL, NULL },
+    };
+
+    ambisonics_type =
+      g_enum_register_static ("GstOpenalsinkAmbisonicsType", ambisonics_types);
+  }
+
+  return ambisonics_type;
+}
+
+enum
+{
+  /* action signals */
+  ROTATE,
+  /* emit signals */
+  LAST_SIGNAL
+};
+static guint openalsink_signals[LAST_SIGNAL];
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
 static GstStaticPadTemplate openalsink_factory =
     GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
@@ -111,15 +173,7 @@ static GstStaticPadTemplate openalsink_factory =
         "audio/x-raw, " "format = (string) " GST_AUDIO_NE (S16) ", "
         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
         "audio/x-raw, " "format = (string) " G_STRINGIFY (U8) ", "
-        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
-        /* These caps do not work on my card */
-        // "audio/x-adpcm, " "layout = (string) ima, "
-        // "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
-        // "audio/x-alaw, " "rate = (int) [ 1, MAX ], "
-        // "channels = (int) [ 1, 2 ]; "
-        // "audio/x-mulaw, " "rate = (int) [ 1, MAX ], "
-        // "channels = (int) [ 1, MAX ]"
-    )
+        "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; ")
     );
 
 static PFNALCSETTHREADCONTEXTPROC palcSetThreadContext;
@@ -188,6 +242,12 @@ gst_openal_sink_class_init (GstOpenALSinkClass * klass)
     palcGetThreadContext = alcGetProcAddress (NULL, "alcGetThreadContext");
   }
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  klass->rotate = set_angles;
+
+  gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_openal_sink_src_event);
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_openal_sink_dispose);
   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_openal_sink_finalize);
   gobject_class->set_property =
@@ -228,6 +288,44 @@ gst_openal_sink_class_init (GstOpenALSinkClass * klass)
       g_param_spec_uint ("user-source", "ALsource", "User source", 0, UINT_MAX,
           0, G_PARAM_READWRITE));
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  g_object_class_install_property (gobject_class, PROP_USE_STREAM_INFO,
+      g_param_spec_uint ("use-stream-info", "UseTizenAudioStreamInfo",
+          "Option to use stream info (0 | 1)", 0, 1, 0, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_STREAM_INFO,
+      g_param_spec_pointer ("stream-info", "TizenAudioStreamInfo", "Stream info",
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SOURCE_AMBISONIC_TYPE,
+      g_param_spec_enum ("source-ambisonics-type", "ALsourceAmbisonicType",
+          "Type of Ambisonics (Unknown | Periphonic | Non-periphonic)",
+          GST_TYPE_AMBISONICS_TYPE, AMBISONICS_TYPE_UNKNOWN,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SOURCE_ORIENTATION_X_AXIS,
+      g_param_spec_int ("source-orientation-x", "ALSourceOrientationX",
+          "Source orientation (rotation angle) against X axis, deg.", -90, 90,
+          0, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_SOURCE_ORIENTATION_Y_AXIS,
+      g_param_spec_int ("source-orientation-y", "ALSourceOrientationY",
+          "Source orientation (rotation angle) against Y axis, deg.", -180, 180,
+          0, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_SOURCE_ORIENTATION_Z_AXIS,
+      g_param_spec_int ("source-orientation-z", "ALSourceOrientationZ",
+          "Source orientation (rotation angle) against Z axis, deg.", -180, 180,
+          0, G_PARAM_READWRITE));
+
+  openalsink_signals[ROTATE] =
+      g_signal_new ("rotate",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstOpenALSinkClass, rotate), NULL, NULL, NULL,
+          G_TYPE_NONE, 3, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_FLOAT);
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   gst_element_class_set_static_metadata (gstelement_class, "OpenAL Audio Sink",
       "Sink/Audio", "Output audio through OpenAL",
       "Juan Manuel Borges CaƱo <juanmabcmail@gmail.com>");
@@ -260,6 +358,16 @@ gst_openal_sink_init (GstOpenALSink * sink)
   sink->write_reset = AL_FALSE;
   sink->probed_caps = NULL;
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  sink->use_stream_info = 0;
+  sink->stream_info = NULL;
+
+  sink->ambisonic_type = AMBISONICS_TYPE_UNKNOWN;
+  sink->source_rotation_x = 0.f;
+  sink->source_rotation_y = 0.f;
+  sink->source_rotation_z = 0.f;
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   g_mutex_init (&sink->openal_lock);
 }
 
@@ -302,6 +410,29 @@ gst_openal_sink_set_property (GObject * object, guint prop_id,
         sink->user_source = g_value_get_uint (value);
       break;
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+    case PROP_USE_STREAM_INFO:
+      sink->use_stream_info = g_value_get_uint (value);
+      break;
+    case PROP_STREAM_INFO:
+      if (!sink->stream_info)
+        sink->stream_info = g_value_get_pointer (value);
+      break;
+    case PROP_SOURCE_AMBISONIC_TYPE:
+      sink->ambisonic_type = g_value_get_enum (value);
+      GST_DEBUG_OBJECT (sink, "sink->user_source %d", sink->user_source);
+      break;
+    case PROP_SOURCE_ORIENTATION_X_AXIS:
+      sink->source_rotation_x = (ALfloat)g_value_get_int (value) / 180 * M_PI;
+      break;
+    case PROP_SOURCE_ORIENTATION_Y_AXIS:
+      sink->source_rotation_y = (ALfloat)g_value_get_int (value) / 180 * M_PI;
+      break;
+    case PROP_SOURCE_ORIENTATION_Z_AXIS:
+      sink->source_rotation_z = (ALfloat)g_value_get_int (value) / 180 * M_PI;
+      break;
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -318,6 +449,10 @@ gst_openal_sink_get_property (GObject * object, guint prop_id, GValue * value,
   ALCcontext *context = sink->default_context;
   ALuint source = sink->default_source;
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  sound_stream_info_h stream_info = sink->stream_info;
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   switch (prop_id) {
     case PROP_DEVICE_NAME:
       device_name = "";
@@ -343,6 +478,29 @@ gst_openal_sink_get_property (GObject * object, guint prop_id, GValue * value,
       g_value_set_uint (value, source);
       break;
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+    case PROP_USE_STREAM_INFO:
+      g_value_set_uint (value, sink->use_stream_info);
+      break;
+    case PROP_STREAM_INFO:
+      if (!stream_info)
+        stream_info = sink->stream_info;
+      g_value_set_pointer (value, stream_info);
+      break;
+    case PROP_SOURCE_AMBISONIC_TYPE:
+      g_value_set_enum (value, sink->ambisonic_type);
+      break;
+    case PROP_SOURCE_ORIENTATION_X_AXIS:
+      g_value_set_int (value, (int)(sink->source_rotation_x / M_PI * 180));
+      break;
+    case PROP_SOURCE_ORIENTATION_Y_AXIS:
+      g_value_set_int (value, (int)(sink->source_rotation_y / M_PI * 180));
+      break;
+    case PROP_SOURCE_ORIENTATION_Z_AXIS:
+      g_value_set_int (value, (int)(sink->source_rotation_z / M_PI * 180));
+      break;
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -520,6 +678,24 @@ gst_openal_helper_probe_caps (ALCcontext * context)
     gst_caps_append_structure (caps, structure);
   }
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  if (alIsExtensionPresent ("AL_EXT_BFORMAT")) {
+    guint64 channel_mask = GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
+        GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
+        GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
+        GST_AUDIO_CHANNEL_POSITION_MASK (REAR_CENTER);
+
+    structure =
+        gst_structure_new ("audio/x-raw",
+        "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
+        "rate", GST_TYPE_INT_RANGE, OPENAL_MIN_RATE, OPENAL_MAX_RATE,
+        "channels", G_TYPE_INT, 4, NULL);
+    gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
+        channel_mask, NULL);
+    gst_caps_append_structure (caps, structure);
+  }
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   if (alIsExtensionPresent ("AL_EXT_ALAW")) {
     structure =
         gst_structure_new ("audio/x-alaw", "rate", GST_TYPE_INT_RANGE,
@@ -631,8 +807,27 @@ gst_openal_sink_open (GstAudioSink * audiosink)
     }
   } else if (sink->user_context)
     sink->default_device = alcGetContextsDevice (sink->user_context);
+
+#ifndef TIZEN_FEATURE_OALSINK_MODIFICATION
   else
     sink->default_device = alcOpenDevice (sink->device_name);
+#else /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+  else {
+    if (sink->use_stream_info) {
+      GST_DEBUG_OBJECT (sink, "The Tizen Stream Policy API is used.");
+      if (!sink->stream_info) {
+        GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
+          ("Unable to process stream info."), GST_ALC_ERROR (sink->default_device));
+        return FALSE;
+      }
+      sink->default_device = alcOpenDeviceNew (sink->device_name, sink->stream_info);
+    } else {
+      GST_DEBUG_OBJECT (sink, "The Tizen Stream Policy API is not used.");
+        sink->default_device = alcOpenDevice (sink->device_name);
+    }
+  }
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   if (!sink->default_device) {
     GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
         ("Could not open device."), GST_ALC_ERROR (sink->default_device));
@@ -714,6 +909,10 @@ gst_openal_sink_parse_spec (GstOpenALSink * sink,
               break;
             case 4:
               format = AL_FORMAT_QUAD16;
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+              if (sink->ambisonic_type == 1)
+                format = AL_FORMAT_BFORMAT3D_16;        /*FIXME (m.alieskieie): Implement B-format support in more extended way */
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
               break;
             case 6:
               format = AL_FORMAT_51CHN16;
@@ -970,11 +1169,34 @@ gst_openal_sink_write (GstAudioSink * audiosink, gpointer data, guint length)
   ALint processed, queued, state;
   ALCcontext *old;
   gulong rest_us;
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  ALfloat sourceOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
 
   g_assert (length == sink->buffer_length);
 
   old = pushContext (sink->default_context);
 
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+  if (sink->ambisonic_type == 1) {
+    sink->format = AL_FORMAT_BFORMAT3D_16;
+    if (sink->source_rotation_y != source_rotation_y_old) {
+      /* FIXME (m.alieskieie): Implement more appropriate
+         Euler angles -> AL Source orientation transform algorithm */
+      // sourceOri[0] = (-1) * sin (sink->source_rotation_y);
+      // sourceOri[2] = (-1) * cos (sink->source_rotation_y);
+      GST_DEBUG_OBJECT (sink,
+          "Source_rotation_y = %g    atx = %g    atz = %g\n",
+          sink->source_rotation_y, sourceOri[0], sourceOri[2]);
+      alSourcefv (sink->default_source, AL_ORIENTATION, sourceOri);
+      if (alGetError () != AL_NO_ERROR)
+        GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+            ("Failed to set Source's orientation"));
+      source_rotation_y_old = sink->source_rotation_y;
+    }
+  }
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */
+
   rest_us =
       (guint64) (sink->buffer_length / sink->bytes_per_sample) *
       G_USEC_PER_SEC / sink->rate / sink->channels;
@@ -1097,3 +1319,70 @@ gst_openal_sink_reset (GstAudioSink * audiosink)
   popContext (old, sink->default_context);
   GST_OPENAL_SINK_UNLOCK (sink);
 }
+
+#ifdef TIZEN_FEATURE_OALSINK_MODIFICATION
+void
+set_angles (GstElement * element, float abs_angle_x, float abs_angle_y,
+    float abs_angle_z)
+{
+  GstOpenALSink *sink = GST_OPENAL_SINK (element);
+  sink->source_rotation_x = abs_angle_x;
+  sink->source_rotation_y = abs_angle_y;
+  sink->source_rotation_z = abs_angle_z;
+  GST_DEBUG_OBJECT (sink, "\nAbsolute angles have been set directly:\n"
+      "x = %g (%g deg.)\n"
+      "y = %g (%g deg.)\n"
+      "z = %g (%g deg.)",
+      sink->source_rotation_x, sink->source_rotation_x / M_PI * 180,
+      sink->source_rotation_y, sink->source_rotation_y / M_PI * 180,
+      sink->source_rotation_z, sink->source_rotation_z / M_PI * 180);
+}
+
+void
+apply_rotation (GstElement * element, float rotation_x, float rotation_y,
+    float rotation_z)
+{
+  GstOpenALSink *sink = GST_OPENAL_SINK (element);
+  sink->source_rotation_x += rotation_x;
+  sink->source_rotation_y += rotation_y;
+  sink->source_rotation_z += rotation_z;
+
+  GST_DEBUG_OBJECT (sink, "\nAbsolute angles have been changed to:\n"
+      "x = %g (%g deg.)    delta = %g (%g deg.)\n"
+      "y = %g (%g deg.)    delta = %g (%g deg.)\n"
+      "z = %g (%g deg.)    delta = %g (%g deg.)",
+      sink->source_rotation_x, sink->source_rotation_x / M_PI * 180,
+      rotation_x, rotation_x / M_PI * 180,
+      sink->source_rotation_y, sink->source_rotation_y / M_PI * 180,
+      rotation_y, rotation_y / M_PI * 180,
+      sink->source_rotation_z, sink->source_rotation_z / M_PI * 180,
+      rotation_z, rotation_z / M_PI * 180);
+}
+
+static gboolean
+gst_openal_sink_src_event (GstElement * element, GstEvent * event)
+{
+  GstOpenALSink *sink = GST_OPENAL_SINK (element);
+  gdouble yaw, pitch, roll;
+
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION) {
+    if (gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_MOUSE_MOVE) {
+      GstStructure *structure = (GstStructure *) gst_event_get_structure (event);
+      if (gst_structure_get_double (structure, "yaw", &yaw) &&
+          gst_structure_get_double (structure, "pitch", &pitch) &&
+          gst_structure_get_double (structure, "roll", &roll)) {
+
+          GST_DEBUG_OBJECT (sink, "yaw   = %g (%g deg.)\n", yaw, yaw / M_PI * 180);
+          GST_DEBUG_OBJECT (sink, "pitch = %g (%g deg.)\n", pitch, pitch / M_PI * 180);
+          GST_DEBUG_OBJECT (sink, "roll  = %g (%g deg.)\n", roll, roll / M_PI * 180);
+
+          set_angles(element, pitch, yaw, -roll);
+      }
+    }
+  }
+
+  return GST_ELEMENT_CLASS (gst_openal_sink_parent_class)->send_event (element,
+      event);
+}
+#endif /* TIZEN_FEATURE_OALSINK_MODIFICATION */