/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000,2005 Wim Taymans <wim@fluendo.com>
*
* gstdevsoundsrc.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gqueue.h>
#include "common.h"
#include "gstdevsoundsrc.h"
#include <glib_global.h>
#include "gstg711encoderinterface.h"
#include "gstspeechencoderconfig.h"
#include "gstg729encoderinterface.h"
#include "gstilbcencoderinterface.h"
#include "string.h"
GST_DEBUG_CATEGORY_EXTERN (devsoundsrc_debug);
#ifdef GST_CAT_DEFAULT
#undef GST_CAT_DEFAULT
#endif
#define GST_CAT_DEFAULT devsoundsrc_debug
/* elementfactory information */
static const GstElementDetails gst_devsound_src_details=
GST_ELEMENT_DETAILS ("Audio Src (DEVSOUND)",
"Src/Audio",
"Record via Devsound",
" "
);
static void gst_devsound_src_base_init(gpointer g_class);
static void gst_devsound_src_class_init(GstDevsoundSrcClass * klass);
static void gst_devsound_src_init(GstDevsoundSrc * devsoundsrc);
static void gst_devsound_src_dispose(GObject * object);
static void gst_devsound_src_get_property(GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_devsound_src_set_property(GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static GstCaps *gst_devsound_src_getcaps(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_setcaps(GstBaseSrc *bsrc, GstCaps *caps);
static gboolean gst_devsound_src_start(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_stop(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_unlock(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_unlock_stop(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_is_seekable(GstBaseSrc * bsrc);
static gboolean gst_devsound_src_get_size(GstBaseSrc * src, guint64 * size);
static GstFlowReturn gst_devsound_src_create(GstBaseSrc *src, guint64 offset,
guint size, GstBuffer **buf);
static void *StartDevSoundThread(void *threadid);
static gboolean gst_devsound_src_event(GstBaseSrc * asrc, GstEvent * event);
static GstStateChangeReturn gst_devsound_src_change_state (GstElement * element,
GstStateChange transition);
/*********************************
* Speech Encoder Config Interface
* ******************************/
static void gst_speech_encoder_config_handler_init(gpointer g_iface,
gpointer iface_data);
static gint gst_get_speech_encoder_bit_rate(guint* aBitrate);
static gint gst_get_speech_encoder_supported_bit_rates(
GList** aSupportedBitrates);
static gint gst_get_speech_encoder_vad_mode(gboolean* aVadMode);
static gint gst_set_speech_encoder_bit_rate(guint aBitrate);
static gint gst_set_speech_encoder_vad_mode(gboolean aVadMode);
static void gst_Apply_SpeechEncoder_Update(GstDevsoundSrc *devsoundsrc );
/*************************
* G711 Encoder Interface
* ***********************/
static void gst_g711_encoder_handler_init(gpointer g_iface,
gpointer iface_data);
static gint gst_get_g711_encoder_vad_mode(gboolean* aVadMode);
static gint gst_set_g711_encoder_mode(enum TG711EncodeMode aEncodeMode);
static gint gst_set_g711_vad_mode(gboolean aVadMode);
static void gst_Apply_G711Encoder_Update(GstDevsoundSrc *devsoundsrc );
/*************************
* 729 Encoder Interface
* ***********************/
static void gst_g729_encoder_handler_init(gpointer g_iface,
gpointer iface_data);
static gint gst_set_g729_vad_mode(TBool aVadMode);
static gint gst_get_g729_vad_mode(TBool* aVadMode);
static void gst_Apply_G729Encoder_Update(GstDevsoundSrc *devsoundsrc );
/*************************
* ilbc Encoder Interface
* ***********************/
static void gst_ilbc_encoder_handler_init(gpointer g_iface,
gpointer iface_data);
static gint gst_set_ilbc_encoder_mode(enum TIlbcEncodeMode aEncodeMode);
static gint gst_set_ilbc_vad_mode(gboolean aVadMode);
static gint gst_get_ilbc_vad_mode(gboolean* aVadMode);
static void gst_Apply_IlbcEncoder_Update(GstDevsoundSrc *devsoundsrc );
static gint gst_devsound_src_get_rate(gint rate);
typedef struct _GstCustomIfaceUpdate GstCustomIfaceUpdate;
struct _GstCustomIfaceUpdate{
gboolean speechbitrateupdate;
gboolean speechvadmodeupdate;
gboolean g711encodermodeupdate;
gboolean g711vadmodeupdate;
gboolean g729vadmodeupdate;
gboolean ilbcencodermodeupdate;
gboolean ilbcvadmodeupdate;
};
GstCustomIfaceUpdate customInfaceUpdate = {0,0,0,0,0,0,0};
guint speechbitrate;
gboolean speechvadmode;
enum TG711EncodeMode g711encodemode;
gboolean g711vadmode;
GList* supportedbitrates;
gint numofbitrates;
gboolean g729vadmode;
enum TIlbcEncodeMode ilbcencodemode;
gboolean ilbcvadmode;
pthread_t ds_thread;
pthread_mutex_t create_mutex1;
pthread_cond_t create_condition1;
enum consumer_thread_state_enum {
CONSUMER_THREAD_UNINITIALIZED,
CONSUMER_THREAD_INITIALIZING,
CONSUMER_THREAD_INITIALIZED
};
enum consumer_thread_state_enum consumer_thread_state;
GQueue* dataqueue= NULL;
GstBuffer* popBuffer= NULL;
int dataleft = 0;
int dataCopied = 0;
enum command_to_consumer_thread_enum
{
OPEN = 2,
RECORDING,
PAUSE,
RESUME,
STOP,
/*UPDATE,*/
CLOSE
};
enum command_to_consumer_thread_enum cmd;
enum
{
LAST_SIGNAL
};
#define DEFAULT_DEVICE "default"
enum
{
PROP_0,
PROP_DEVICE,
GAIN,
MAXGAIN,
CHANNELS,
LEFTBALANCE,
RIGHTBALANCE,
RATE,
PRIORITY,
PREFERENCE,
SAMPLESRECORDED
};
static GstStaticPadTemplate devsound_src_factory=
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, "
"signed = (boolean) TRUE, "
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 8000, 48000 ],"
"channels = (int) [ 1, 2 ]; "
"audio/amr, "
"rate = (int) [ 8000, 48000 ], "
"channels = (int) [ 1, 2 ]; "
"audio/x-alaw, "
"rate = (int) [ 8000, 48000 ], "
"channels = (int) [ 1, 2 ]; "
"audio/g729, "
"rate = (int) [ 8000, 48000 ], "
"channels = (int) [ 1, 2 ]; "
"audio/ilbc, "
"rate = (int) [ 8000, 48000 ], "
"channels = (int) [ 1, 2 ]; "
"audio/x-mulaw, "
"rate = (int) [ 8000, 48000 ], "
"channels = (int) [ 1, 2 ]")
);
static GstElementClass *parent_class= NULL;
static void gst_devsound_src_base_init(gpointer g_class)
{
GstElementClass *element_class= GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details(element_class, &gst_devsound_src_details);
gst_element_class_add_pad_template(element_class,
gst_static_pad_template_get(&devsound_src_factory));
}
GType gst_devsound_src_get_type(void)
{
static GType devsoundsrc_type = 0;
if (!devsoundsrc_type)
{
static const GTypeInfo devsoundsrc_info =
{
sizeof(GstDevsoundSrcClass), gst_devsound_src_base_init, NULL,
(GClassInitFunc) gst_devsound_src_class_init, NULL, NULL,
sizeof(GstDevsoundSrc), 0,
(GInstanceInitFunc) gst_devsound_src_init
, };
static const GInterfaceInfo speech_encoder_config_info =
{
gst_speech_encoder_config_handler_init,
NULL,
NULL
};
static const GInterfaceInfo g711_encoder_info =
{
gst_g711_encoder_handler_init,
NULL,
NULL
};
static const GInterfaceInfo g729_encoder_info =
{
gst_g729_encoder_handler_init,
NULL,
NULL
};
static const GInterfaceInfo ilbc_encoder_info =
{
gst_ilbc_encoder_handler_init,
NULL,
NULL
};
devsoundsrc_type =
g_type_register_static (GST_TYPE_PUSH_SRC, "GstDevsoundSrc",
&devsoundsrc_info, (GTypeFlags)0);
g_type_add_interface_static (devsoundsrc_type, GST_TYPE_SPEECH_ENCODER_CONFIG,
&speech_encoder_config_info);
g_type_add_interface_static (devsoundsrc_type, GST_TYPE_G711_ENCODER,
&g711_encoder_info);
g_type_add_interface_static (devsoundsrc_type, GST_TYPE_G729_ENCODER,
&g729_encoder_info);
g_type_add_interface_static (devsoundsrc_type, GST_TYPE_ILBC_ENCODER,
&ilbc_encoder_info);
}
return devsoundsrc_type;
}
static void gst_devsound_src_dispose(GObject * object)
{
GstDevsoundSrc *devsoundsrc= GST_DEVSOUND_SRC (object);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void gst_devsound_src_class_init(GstDevsoundSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpushsrc_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpushsrc_class = (GstPushSrcClass *) klass;
parent_class = g_type_class_peek_parent(klass);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_devsound_src_dispose);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_devsound_src_get_property);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_devsound_src_set_property);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_devsound_src_change_state);
g_object_class_install_property(gobject_class, PROP_DEVICE,
g_param_spec_string("device", "Device", "Devsound device ",
DEFAULT_DEVICE, (GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, GAIN, g_param_spec_int(
"gain", "Gain", "Devsound src gain", -1, G_MAXINT, -1,
(GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, MAXGAIN, g_param_spec_int(
"maxgain", "MaxGain", "Devsound src max gain", -1, G_MAXINT, -1,
G_PARAM_READABLE));
g_object_class_install_property(gobject_class, LEFTBALANCE,
g_param_spec_int("leftbalance", "Left Balance", "Left Balance",
-1, G_MAXINT, -1, (GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, RIGHTBALANCE,
g_param_spec_int("rightbalance", "Right Balance",
"Right Balance", -1, G_MAXINT, -1, (GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, SAMPLESRECORDED,
g_param_spec_int("samplesrecorded", "Samples Recorded",
"Samples Recorded", -1, G_MAXINT, -1, G_PARAM_READABLE));
g_object_class_install_property(gobject_class, PRIORITY,
g_param_spec_int("priority", "Priority", "Priority ", -1,
G_MAXINT, -1,
(GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, PREFERENCE,
g_param_spec_int("preference", "Preference", "Preference ", -1,
G_MAXINT, -1,
(GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, RATE,
g_param_spec_int("rate", "Rate", "Rate ", -1,
G_MAXINT, -1,
(GParamFlags)G_PARAM_READWRITE));
g_object_class_install_property(gobject_class, CHANNELS,
g_param_spec_int("channels", "Channels", "Channels ", -1,
G_MAXINT, -1,
(GParamFlags)G_PARAM_READWRITE));
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_devsound_src_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_devsound_src_stop);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_devsound_src_getcaps);
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_devsound_src_setcaps);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_devsound_src_event);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_devsound_src_create);
}
static void gst_devsound_src_init(GstDevsoundSrc * devsoundsrc)
{
GST_DEBUG_OBJECT(devsoundsrc, "initializing devsoundsrc");
gst_base_src_set_live(GST_BASE_SRC(devsoundsrc), TRUE);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "gst_devsound_src_init ENTER ",NULL);
devsoundsrc->device = g_strdup(DEFAULT_DEVICE);
devsoundsrc->handle=NULL;
devsoundsrc->preference = 0; //default=>EMdaPriorityPreferenceNone;
devsoundsrc->priority = 0; //default=>EMdaPriorityNormal;
devsoundsrc->firstimecreatecalled = 0;
// pthread_mutex_init(&create_mutex1, NULL);
// pthread_cond_init(&create_condition1, NULL);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "gst_devsound_src_init EXIT ",NULL);
}
static void *StartDevSoundThread(void *threadarg)
{
GstDevsoundSrc *devsoundsrc= GST_DEVSOUND_SRC (threadarg);
int buffersize;
TUint8* gBuffer;
GstBuffer* pushBuffer= NULL;
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "StartDevSoundThread ",NULL);
open_devsound(&(devsoundsrc->handle));
getsupporteddatatypes(devsoundsrc);
// TODO obtain mutex to update variable here???
consumer_thread_state = CONSUMER_THREAD_INITIALIZED;
//pre_init_setconf(devsoundsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "After Record Init ",NULL);
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
// Wait until we receive a command from the main thread
// TODO obtain mutex to read variable here???
while ( cmd == OPEN )
{
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
}
// This could happen if client creates sink and deletes it
// without putting it to play state
if ( cmd != CLOSE )
{
initialize_devsound(devsoundsrc);
recordinit(devsoundsrc->handle);
initproperties(devsoundsrc);
}
while (TRUE)
{
switch (cmd)
{
case PAUSE:
pause_devsound(devsoundsrc);
break;
case RESUME:
resume_devsound(devsoundsrc);
break;
case STOP:
stop_devsound(devsoundsrc);
break;
case RECORDING:
{
pre_init_setconf(devsoundsrc);
gst_Apply_SpeechEncoder_Update(devsoundsrc);
gst_Apply_G711Encoder_Update(devsoundsrc);
gst_Apply_G729Encoder_Update(devsoundsrc );
gst_Apply_IlbcEncoder_Update(devsoundsrc );
populateproperties(devsoundsrc);
supportedbitrates = devsoundsrc->supportedbitrates;
//numofbitrates = devsoundsrc->numofbitrates;
speechbitrate = devsoundsrc->speechbitrate;
speechvadmode = devsoundsrc->speechvadmode;
g711vadmode = devsoundsrc->g711vadmode;
g729vadmode = devsoundsrc->g729vadmode;
ilbcvadmode = devsoundsrc->ilbcvadmode;
buffersize = get_databuffer_size(devsoundsrc->handle);
get_databuffer(devsoundsrc->handle, &gBuffer);
pushBuffer = gst_buffer_new_and_alloc(buffersize);
memcpy(GST_BUFFER_DATA(pushBuffer),gBuffer,buffersize);
GST_OBJECT_LOCK(devsoundsrc);
g_queue_push_head (dataqueue,pushBuffer);
GST_OBJECT_UNLOCK(devsoundsrc);
record_data(devsoundsrc->handle);
}
break;
case CLOSE:
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "Before Close DevSound ",NULL);
close_devsound(devsoundsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "After Close DevSound ",NULL);
devsoundsrc->handle= NULL;
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "After handle NULL ",NULL);
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
// TODO obtain mutex here
consumer_thread_state = CONSUMER_THREAD_UNINITIALIZED;
devsoundsrc->firstimecreatecalled = 0;
pthread_exit(NULL);
}
break;
default:
// TODO obtain mutex here
consumer_thread_state = CONSUMER_THREAD_UNINITIALIZED;
pthread_exit(NULL);
break;
}
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
}
}
static void gst_devsound_src_set_property(GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstDevsoundSrc *src;
src = GST_DEVSOUND_SRC (object);
switch (prop_id)
{
case PROP_DEVICE:
if (src->device)
g_free(src->device);
src->device = g_value_dup_string(value);
if (src->probed_caps)
{
gst_caps_unref(src->probed_caps);
src->probed_caps = NULL;
}
break;
case CHANNELS:
src->channels = g_value_get_int(value);
src->pending.channelsupdate = TRUE;
break;
case RATE:
src->rate = g_value_get_int(value);
//Convert rate to something devsound understands
src->rate = gst_devsound_src_get_rate(src->rate);
src->pending.rateupdate = TRUE;
break;
case GAIN:
src->gain = g_value_get_int(value);
src->pending.gainupdate = TRUE;
break;
case LEFTBALANCE:
src->leftbalance = g_value_get_int(value);
src->pending.leftbalanceupdate = TRUE;
break;
case RIGHTBALANCE:
src->rightbalance = g_value_get_int(value);
src->pending.rightbalanceupdate = TRUE;
break;
case PRIORITY:
src->priority = g_value_get_int(value);
src->pending.priorityupdate = TRUE;
break;
case PREFERENCE:
src->preference = g_value_get_int(value);
src->pending.preferenceupdate = TRUE;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void gst_devsound_src_get_property(GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstDevsoundSrc *src;
src = GST_DEVSOUND_SRC (object);
switch (prop_id)
{
case PROP_DEVICE:
g_value_set_string(value, src->device);
break;
case CHANNELS:
g_value_set_int(value, src->channels);
break;
case RATE:
g_value_set_int(value, src->rate);
break;
case GAIN:
g_value_set_int(value, src->gain);
break;
case MAXGAIN:
g_value_set_int(value, src->maxgain);
break;
case SAMPLESRECORDED:
g_value_set_int(value, src->samplesrecorded);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean gst_devsound_src_setcaps(GstBaseSrc *bsrc, GstCaps *caps)
{
GstDevsoundSrc *devsoundsrc;
GstStructure *structure;
const gchar *mimetype;
int rate;
int channel;
devsoundsrc = GST_DEVSOUND_SRC (bsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "gst_devsound_src_setcaps ENTER ",NULL);
structure = gst_caps_get_structure(caps, 0);
mimetype = gst_structure_get_name(structure);
gst_structure_get_int(structure, "rate", &rate);
gst_structure_get_int(structure, "channels", &channel);
devsoundsrc->rate = gst_devsound_src_get_rate(rate);
devsoundsrc->channels = channel;
set_channels(devsoundsrc->handle, devsoundsrc->channels);
set_rate(devsoundsrc->handle, devsoundsrc->rate);
if (!strncmp(mimetype, "audio/x-raw-int", 15))
{
devsoundsrc->fourcc = 0x36315020; //KMMFFourCCCodePCM16
}
else if (!strncmp(mimetype, "audio/amr", 9))
{
devsoundsrc->fourcc = 0x524d4120; //KMMFFourCCCodeAMR
}
else if (!strncmp(mimetype, "audio/x-mulaw", 13)||
!strncmp(mimetype,"audio/x-alaw", 12))
{
devsoundsrc->fourcc = 0x31313747; //KMccFourCCIdG711
}
else if (!strncmp(mimetype, "audio/ilbc", 10))
{
devsoundsrc->fourcc = 0x43424c49; //KMccFourCCIdILBC
}
else if (!strncmp(mimetype, "audio/g729", 10))
{
devsoundsrc->fourcc = 0x39323747; //KMccFourCCIdG729
}
else
{
devsoundsrc->fourcc = 0x36315020; //KMMFFourCCCodePCM16
}
set_fourcc(devsoundsrc->handle, devsoundsrc->fourcc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "Before Signal DevSound from STOP",NULL);
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "After Signal DevSound from STOP ",NULL);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "gst_devsound_src_setcaps EXIT ",NULL);
return TRUE;
}
static GstCaps * gst_devsound_src_getcaps(GstBaseSrc * bsrc)
{
GstDevsoundSrc *devsoundsrc;
GstCaps *caps;
GstPadTemplate *pad_template;
devsoundsrc = GST_DEVSOUND_SRC (bsrc);
GST_DEBUG_OBJECT(devsoundsrc, "getcaps called");
pad_template = gst_static_pad_template_get(&devsound_src_factory);
caps = gst_caps_copy(gst_pad_template_get_caps(pad_template));
gst_object_unref(pad_template);
return caps;
}
static gboolean gst_devsound_src_start(GstBaseSrc * bsrc)
{
GstBuffer *tmp_gstbuffer=NULL;
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_start ENTER ",NULL);
pthread_mutex_init(&create_mutex1, NULL);
pthread_cond_init(&create_condition1, NULL);
if(dataqueue)
{
while (g_queue_get_length(dataqueue))
{
tmp_gstbuffer = (GstBuffer*)g_queue_pop_tail(dataqueue);
gst_buffer_unref(tmp_gstbuffer);
}
g_queue_free(dataqueue);
dataqueue = NULL;
}
if(dataqueue == NULL)
{
dataqueue = g_queue_new();
}
consumer_thread_state = CONSUMER_THREAD_INITIALIZING;
cmd = OPEN;
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Before Thread Create ",NULL);
pthread_create(&ds_thread, NULL, StartDevSoundThread, (void *)src);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "After Thread Create ",NULL);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Before Mutex Wait in START ",NULL);
if (consumer_thread_state == CONSUMER_THREAD_INITIALIZING)
{
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "AFter Mutex Wait in START ",NULL);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_start EXIT ",NULL);
return TRUE;
/* ERRORS */
}
static gboolean gst_devsound_src_stop(GstBaseSrc * bsrc)
{
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_stop ENTER ");
cmd = CLOSE;
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
//GST_OBJECT_LOCK (src);
pthread_mutex_lock(&(create_mutex1));
pthread_cond_wait(&(create_condition1), &(create_mutex1));
pthread_mutex_unlock(&(create_mutex1));
//GST_OBJECT_UNLOCK (src);
if (popBuffer)
{
gst_buffer_unref(popBuffer);
popBuffer = NULL;
dataleft = 0; //Arun'S changes
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Before QUEUE Lock in STOP ");
GST_OBJECT_LOCK(src);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "After QUEUE Lock in STOP ");
while (g_queue_get_length(dataqueue))
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Removing DATAQUEUE elements ENTER ");
popBuffer = (GstBuffer*)g_queue_pop_tail(dataqueue);
gst_buffer_unref(popBuffer);
popBuffer = NULL;
dataleft = 0; //Arun'S changes
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Removing DATAQUEUE elements EXIT ");
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Before Queue FREE ");
g_queue_free(dataqueue);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "After Queue FREE ");
dataqueue = NULL;
GST_OBJECT_UNLOCK(src);
pthread_mutex_destroy(&create_mutex1);
pthread_cond_destroy(&(create_condition1));
g_free(src->device);
src->device = NULL;
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_stop EXIT ");
return TRUE;
}
static gboolean gst_devsound_src_unlock(GstBaseSrc * bsrc)
{
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
GST_LOG_OBJECT(src, "Flushing");
GST_OBJECT_LOCK (src);
GST_OBJECT_UNLOCK (src);
return TRUE;
}
static gboolean gst_devsound_src_unlock_stop(GstBaseSrc * bsrc)
{
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
GST_LOG_OBJECT(src, "No longer flushing");
return TRUE;
}
static GstFlowReturn gst_devsound_src_create(GstBaseSrc *src, guint64 offset,
guint size, GstBuffer **buf)
{
GstDevsoundSrc *dsrc= GST_DEVSOUND_SRC(src);
int bufferpos=0;
if(!g_queue_get_length(dataqueue) && (dsrc->eosreceived == TRUE))
{
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
return GST_FLOW_UNEXPECTED;
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "gst_devsound_src_create ENTER ");
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before Buffer Alloc in CREATE ",NULL);
*buf = gst_buffer_try_new_and_alloc(size);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFter Buffer Alloc in CREATE ",NULL);
while (size > 0)
{
if (dataleft >= size)
{
// if there is some data left in the popped buffer previously whose size
// is more then the buffer which is incoming fresh to get filled, fill it
//here. and if the data left in the popped buffer is 0, then unref it
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "dataleft >=size in CREATE ", NULL);
memcpy(GST_BUFFER_DATA(*buf)+bufferpos,GST_BUFFER_DATA(popBuffer)+dataCopied,size);
bufferpos+=size;
dataCopied += size;
dataleft = GST_BUFFER_SIZE(popBuffer) - dataCopied;
size = 0;
if (dataleft == 0)
{
dataCopied = 0;
gst_buffer_unref(popBuffer);
popBuffer = NULL;
}
}
else
{
// if the dataleft in the popped buffer is greater then 0 and less then
// the size of data needed for the fresh buffer. copy the remaining data
// from the popped buffer and then unref it.
if (dataleft > 0)
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "dataleft >0 in CREATE ",NULL);
memcpy(GST_BUFFER_DATA(*buf)+bufferpos,GST_BUFFER_DATA(popBuffer)+dataCopied,dataleft);
size -= dataleft;
bufferpos += dataleft;
dataCopied = 0;
dataleft = 0;
gst_buffer_unref(popBuffer);
popBuffer = NULL;
}
// we wait here if the dataqueue length is 0 and we need data
// to be filled in the queue from the DevSound Thread
if (!g_queue_get_length(dataqueue))
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before WAIT in CREATE ",NULL);
if(dsrc->eosreceived == TRUE)
{
return GST_FLOW_UNEXPECTED;
}
else
{
cmd = RECORDING;
pthread_mutex_lock(&(create_mutex1));
pthread_cond_signal(&(create_condition1));
pthread_mutex_unlock(&(create_mutex1));
pthread_mutex_lock(&(create_mutex1));
pthread_cond_wait(&(create_condition1), &(create_mutex1));
pthread_mutex_unlock(&(create_mutex1));
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER WAIT in CREATE ",NULL);
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before POP in CREATE ",NULL);
GST_OBJECT_LOCK(dsrc);
popBuffer = (GstBuffer*)g_queue_pop_tail(dataqueue);
GST_OBJECT_UNLOCK(dsrc);
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER POP in CREATE ",NULL);
if(!popBuffer)
{
return GST_FLOW_UNEXPECTED;
}
// copy the data from the popped buffer based on how much of the incoming
//buffer size is left to fill. we might have filled the fresh buffer somewhat
// where the size of the fresh buffer is more then the data remaining in the
// popped buffer.
if (size < GST_BUFFER_SIZE(popBuffer))
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "SIZE < POPBUFFER CREATE ",NULL);
memcpy(GST_BUFFER_DATA(*buf)+ bufferpos,GST_BUFFER_DATA(popBuffer),size);
bufferpos+=size;
dataCopied = size;
dataleft = GST_BUFFER_SIZE(popBuffer) - dataCopied;
size = 0;
}
else
{
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "SIZE >= POPBUFFER CREATE ",NULL);
memcpy(GST_BUFFER_DATA(*buf)+ bufferpos,GST_BUFFER_DATA(popBuffer),GST_BUFFER_SIZE(popBuffer));
bufferpos+=GST_BUFFER_SIZE(popBuffer);
dataCopied = 0;
dataleft = 0;
size = size - GST_BUFFER_SIZE(popBuffer);
}
if (!dataleft)
{
gst_buffer_unref(popBuffer);
popBuffer = NULL;
}
}
if( dsrc->firstimecreatecalled < 2 )
{/// nitin changes
++dsrc->firstimecreatecalled;
return GST_FLOW_OK;
}
}
//gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "gst_devsound_src_create EXIT ",NULL);
return GST_FLOW_OK;
}
static GstStateChangeReturn gst_devsound_src_change_state (GstElement * element,
GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstDevsoundSrc *src= GST_DEVSOUND_SRC (element);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
if(cmd == PAUSE)
{
cmd = RESUME;
pthread_mutex_lock(&create_mutex1);
pthread_cond_signal(&create_condition1);
pthread_mutex_unlock(&create_mutex1);
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
}
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE))
goto activate_failed;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
cmd = PAUSE;
pthread_mutex_lock(&create_mutex1);
pthread_cond_signal(&create_condition1);
pthread_mutex_unlock(&create_mutex1);
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
break;
default:
break;
}
return ret;
activate_failed:
{
GST_DEBUG_OBJECT (src,
"element failed to change states -- activation problem?");
return GST_STATE_CHANGE_FAILURE;
}
}
static gboolean gst_devsound_src_is_seekable(GstBaseSrc * bsrc)
{
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
return FALSE;
}
static gboolean gst_devsound_src_get_size(GstBaseSrc * bsrc, guint64 * size)
{
GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc);
return TRUE;
}
static void gst_speech_encoder_config_handler_init(gpointer g_iface,
gpointer iface_data)
{
GstSpeechEncoderConfigIntfc *iface =
(GstSpeechEncoderConfigIntfc *) g_iface;
iface->GetBitrate = gst_get_speech_encoder_bit_rate;
iface->GetSupportedBitrates = gst_get_speech_encoder_supported_bit_rates;
iface->GetVadMode = gst_get_speech_encoder_vad_mode;
iface->SetBitrate = gst_set_speech_encoder_bit_rate;
iface->SetVadMode = gst_set_speech_encoder_vad_mode;
}
static gint gst_get_speech_encoder_bit_rate(guint* aBitrate)
{
*aBitrate = speechbitrate;
return 0;
}
static gint gst_get_speech_encoder_supported_bit_rates(
GList** aSupportedBitrate)
{
*aSupportedBitrate = supportedbitrates;
return 0;
}
static gint gst_get_speech_encoder_vad_mode(gboolean* aVadMode)
{
*aVadMode = speechvadmode;
return 0;
}
static gint gst_set_speech_encoder_bit_rate(guint aBitrate)
{
speechbitrate = aBitrate;
customInfaceUpdate.speechbitrateupdate = TRUE;
return 0;
}
static gint gst_set_speech_encoder_vad_mode(gboolean aVadMode)
{
speechvadmode = aVadMode;
customInfaceUpdate.speechvadmodeupdate = TRUE;
return 0;
}
static void gst_Apply_SpeechEncoder_Update(GstDevsoundSrc *devsoundsrc )
{
if(customInfaceUpdate.speechbitrateupdate == TRUE)
{
set_speech_encoder_bit_rate(devsoundsrc->handle,speechbitrate);
customInfaceUpdate.speechbitrateupdate = FALSE;
}
if(customInfaceUpdate.speechvadmodeupdate == TRUE)
{
set_speech_encoder_vad_mode(devsoundsrc->handle,speechvadmode);
customInfaceUpdate.speechvadmodeupdate = FALSE;
}
}
static void gst_g711_encoder_handler_init(gpointer g_iface,
gpointer iface_data)
{
GstG711EncoderIntfc *iface = (GstG711EncoderIntfc *) g_iface;
iface->GetVadMode = gst_get_g711_encoder_vad_mode;
iface->SetEncoderMode = gst_set_g711_encoder_mode;
iface->SetVadMode = gst_set_g711_vad_mode;
}
static gint gst_get_g711_encoder_vad_mode(gboolean* aVadMode)
{
*aVadMode = g711vadmode;
return 0;
}
static gint gst_set_g711_encoder_mode(enum TG711EncodeMode aEncodeMode)
{
g711encodemode = aEncodeMode;
customInfaceUpdate.g711encodermodeupdate = TRUE;
return 0;
}
static gint gst_set_g711_vad_mode(gboolean aVadMode)
{
g711vadmode = aVadMode;
customInfaceUpdate.g711vadmodeupdate = TRUE;
return 0;
}
static void gst_Apply_G711Encoder_Update(GstDevsoundSrc *devsoundsrc )
{
if(customInfaceUpdate.g711encodermodeupdate == TRUE)
{
set_g711_encoder_mode(devsoundsrc->handle,g711encodemode);
customInfaceUpdate.g711encodermodeupdate = FALSE;
}
if(customInfaceUpdate.g711vadmodeupdate == TRUE)
{
set_g711_vad_mode(devsoundsrc->handle,g711vadmode);
customInfaceUpdate.g711vadmodeupdate = FALSE;
}
}
static void gst_g729_encoder_handler_init(gpointer g_iface,
gpointer iface_data)
{
GstG729EncoderIntfc *iface = (GstG729EncoderIntfc *) g_iface;
iface->GetVadMode = gst_get_g729_vad_mode;
iface->SetVadMode = gst_set_g729_vad_mode;
}
static gint gst_set_g729_vad_mode(TBool aVadMode)
{
g729vadmode = aVadMode;
customInfaceUpdate.g729vadmodeupdate = TRUE;
return 0;
}
static gint gst_get_g729_vad_mode(TBool* aVadMode)
{
*aVadMode = g729vadmode;
return 0;
}
static void gst_Apply_G729Encoder_Update(GstDevsoundSrc *devsoundsrc )
{
if(customInfaceUpdate.g729vadmodeupdate)
{
set_g729_vad_mode(devsoundsrc->handle,g729vadmode);
customInfaceUpdate.g729vadmodeupdate = FALSE;
}
}
static void gst_ilbc_encoder_handler_init(gpointer g_iface,
gpointer iface_data)
{
GstIlbcEncoderIntfc *iface = (GstIlbcEncoderIntfc *) g_iface;
iface->GetVadMode = gst_get_ilbc_vad_mode;
iface->SetEncoderMode = gst_set_ilbc_encoder_mode;
iface->SetVadMode = gst_set_ilbc_vad_mode;
}
static gint gst_set_ilbc_encoder_mode(enum TIlbcEncodeMode aEncodeMode)
{
ilbcencodemode = aEncodeMode;
return 0;
}
static gint gst_set_ilbc_vad_mode(gboolean aVadMode)
{
ilbcvadmode = aVadMode;
return 0;
}
static gint gst_get_ilbc_vad_mode(gboolean* aVadMode)
{
*aVadMode = ilbcvadmode;
return 0;
}
static void gst_Apply_IlbcEncoder_Update(GstDevsoundSrc *devsoundsrc )
{
if(customInfaceUpdate.ilbcencodermodeupdate)
{
set_ilbc_encoder_mode(devsoundsrc->handle,ilbcencodemode);
customInfaceUpdate.ilbcencodermodeupdate = FALSE;
}
if(customInfaceUpdate.ilbcvadmodeupdate)
{
set_ilbc_vad_mode(devsoundsrc->handle,ilbcvadmode);
customInfaceUpdate.ilbcvadmodeupdate = FALSE;
}
}
static gint gst_devsound_src_get_rate(gint rate)
{
gint result;
switch (rate)
{
case 8000:
result=0x00000001;//EMMFSampleRate8000Hz;
break;
case 11025:
result=0x00000002;//EMMFSampleRate11025Hz;
break;
case 16000:
result=0x00000004;//EMMFSampleRate16000Hz;
break;
case 22050:
result=0x00000008;//EMMFSampleRate22050Hz;
break;
case 32000:
result=0x00000010;//EMMFSampleRate32000Hz;
break;
case 44100:
result=0x00000020;//EMMFSampleRate44100Hz;
break;
case 48000:
result=0x00000040;//EMMFSampleRate48000Hz;
break;
case 88200:
result=0x00000080;//EMMFSampleRate88200Hz;
break;
case 96000:
result= 0x00000100;//EMMFSampleRate96000Hz;
break;
case 12000:
result=0x00000200;//EMMFSampleRate12000Hz;
break;
case 24000:
result=0x00000400;//EMMFSampleRate24000Hz;
break;
case 64000:
result=0x00000800; //EMMFSampleRate64000Hz;
break;
default:
result=0x00000001;//EMMFSampleRate8000Hz;
break;
}
return result;
}
static gboolean gst_devsound_src_event(GstBaseSrc *asrc, GstEvent *event)
{
int retValue = FALSE;
GstDevsoundSrc *src = GST_DEVSOUND_SRC(asrc);
switch (GST_EVENT_TYPE (event))
{
case GST_EVENT_EOS:
// end-of-stream, we should close down all stream leftovers here
//reset_devsound(sink->handle);
src->eosreceived = TRUE;
cmd = STOP;
pthread_mutex_lock(&create_mutex1);
pthread_cond_signal(&create_condition1);
pthread_mutex_unlock(&create_mutex1);
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
if(g_queue_get_length(dataqueue))
{
pthread_mutex_lock(&create_mutex1);
pthread_cond_wait(&create_condition1, &create_mutex1);
pthread_mutex_unlock(&create_mutex1);
}
gst_pad_push_event (asrc->srcpad, gst_event_new_eos ());
retValue = TRUE;
break;
default:
retValue = FALSE;
break;
}
return retValue;
}