#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);
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
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,
"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;
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 =
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>");
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);
}
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;
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 = "";
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;
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,
}
} 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));
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;
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;
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 */