Commit becfa065 authored by Mario Chirinos Colunga's avatar Mario Chirinos Colunga 💬

mario

parent 6b4a2e43
...@@ -19,92 +19,70 @@ ...@@ -19,92 +19,70 @@
#include <cstring> #include <cstring>
using namespace std; using namespace std;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Constructor * Constructor
* @param source streaing url * @param source streaing url
* @param time split recording in segments of time seconds. * @param time split recording in segments of time seconds.
*/ */
StreamRecorder::StreamRecorder(const char* source, int time)
StreamRecorder::StreamRecorder(const char* source, int time) { {
int nFrames = ceil(time*STREAMRECORDER_SAMPLERATE/READSIZE); int nFrames = ceil(time*STREAMRECORDER_SAMPLERATE/READSIZE);
recordTime = nFrames*READSIZE/STREAMRECORDER_SAMPLERATE; recordTime = nFrames*READSIZE/STREAMRECORDER_SAMPLERATE;
cout << "record time: " << recordTime << endl; cout << "record time: " << recordTime << endl;
// buffer size
bufferSize=nFrames*READSIZE*STREAMRECORDER_BYTESPERSAMPLE; bufferSize=nFrames*READSIZE*STREAMRECORDER_BYTESPERSAMPLE;
// buffer that ig going to contain the audio
audioBuffer = new unsigned char[bufferSize]; audioBuffer = new unsigned char[bufferSize];
memset(audioBuffer, 0, bufferSize);
// Puts all the elements in audio buffer in 0
memset (audioBuffer, 0, bufferSize);
// set the pointer to the actual position of the buffer;
audioBufferPosition=audioBuffer; audioBufferPosition=audioBuffer;
// Bytes saved counter
nBytes=0; nBytes=0;
// flag that save the conncetion state
isConnectionLost=false; isConnectionLost=false;
// Create the elements and sets capabilities
createMainPipeline(); createMainPipeline();
// Connec with the URI
connect(source); connect(source);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Connect to the stream * Connect to the stream
* @param uri streaing uri * @param uri streaing uri
* @return unimplemented * @return unimplemented
*/ */
int StreamRecorder::connect(const char *uri)
int StreamRecorder::connect(const char *uri) { {
disconnect(); disconnect();
cout << "connecting to " << uri << endl; cout << "connecting to " << uri << endl;
// Uri destiny
pluginUri = (char*)uri; pluginUri = (char*)uri;
gst_element_set_state (mainPipeline, GST_STATE_NULL); gst_element_set_state (mainPipeline, GST_STATE_NULL);
gst_element_set_state (mainPipeline, GST_STATE_READY); gst_element_set_state (mainPipeline, GST_STATE_READY);
// Assign the uri property
g_object_set (G_OBJECT (streamSrc), "uri", uri, NULL); g_object_set (G_OBJECT (streamSrc), "uri", uri, NULL);
gst_element_link (streamSrc, audioConvert); gst_element_link (streamSrc, audioConvert);
// Main pipeline starts to work
gst_element_set_state (mainPipeline, GST_STATE_PLAYING); gst_element_set_state (mainPipeline, GST_STATE_PLAYING);
return 0; return 0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* disconnect from the stream * disconnect from the stream
* @return unimplemented * @return unimplemented
*/ */
int StreamRecorder::disconnect()
int StreamRecorder::disconnect() { {
gst_element_unlink (streamSrc, audioConvert); gst_element_unlink (streamSrc, audioConvert);
gst_element_set_state (mainPipeline, GST_STATE_NULL); gst_element_set_state (mainPipeline, GST_STATE_NULL);
return 0; return 0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Create main pipeline * Create main pipeline
* @return 0 on success else on error * @return 0 on success else on error
*/ */
int StreamRecorder::createMainPipeline()
int StreamRecorder::createMainPipeline() { {
mainPipeline = gst_pipeline_new("stream-recorder"); mainPipeline = gst_pipeline_new("stream-recorder");
GstBus* bus; GstBus* bus;
...@@ -137,7 +115,8 @@ int StreamRecorder::createMainPipeline() { ...@@ -137,7 +115,8 @@ int StreamRecorder::createMainPipeline() {
//audioSink = gst_element_factory_make("autoaudiosink", "speaker"); //audioSink = gst_element_factory_make("autoaudiosink", "speaker");
gst_bin_add_many (GST_BIN (mainPipeline), streamSrc, audioConvert, filterCaps, queue0, filter,queue1, fakeSink, NULL); gst_bin_add_many (GST_BIN (mainPipeline), streamSrc, audioConvert, filterCaps, queue0, filter,queue1, fakeSink, NULL);
if(!gst_element_link_many(audioConvert, filterCaps, queue0, filter, queue1, fakeSink, NULL)){ if(!gst_element_link_many(audioConvert, filterCaps, queue0, filter, queue1, fakeSink, NULL))
{
//gst_bin_add_many (GST_BIN (mainPipeline), streamSrc, audioConvert, filterCaps, queue0, filter, queue1, audioSink, NULL); //gst_bin_add_many (GST_BIN (mainPipeline), streamSrc, audioConvert, filterCaps, queue0, filter, queue1, audioSink, NULL);
// if(!gst_element_link_many(audioConvert, filterCaps, queue0, filter, queue1, audioSink, NULL)){ // if(!gst_element_link_many(audioConvert, filterCaps, queue0, filter, queue1, audioSink, NULL)){
...@@ -150,17 +129,14 @@ int StreamRecorder::createMainPipeline() { ...@@ -150,17 +129,14 @@ int StreamRecorder::createMainPipeline() {
return 0; return 0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
gboolean StreamRecorder::reconnectURIStream(void *instance)
gboolean StreamRecorder::reconnectURIStream(void *instance){ {
cout << "Restarting the main pipeline" << endl; cout << "reconnectURIStream" << endl;
((StreamRecorder*)instance)->connect(((StreamRecorder*)instance)->pluginUri); ((StreamRecorder*)instance)->connect(((StreamRecorder*)instance)->pluginUri);
return FALSE; return FALSE;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* disconnect from the stream * disconnect from the stream
* @param the GstBus that sent the message * @param the GstBus that sent the message
...@@ -168,87 +144,64 @@ gboolean StreamRecorder::reconnectURIStream(void *instance){ ...@@ -168,87 +144,64 @@ gboolean StreamRecorder::reconnectURIStream(void *instance){
* @param user_data NULL * @param user_data NULL
* @return unimplemented * @return unimplemented
*/ */
int StreamRecorder::bus_callback (GstBus *bus, GstMessage *message, void *user_data)
int StreamRecorder::bus_callback (GstBus *bus, GstMessage *message, void *user_data) { {
//printf("StreamRecorder got %s message\n", GST_MESSAGE_TYPE_NAME (message)); //printf("StreamRecorder got %s message\n", GST_MESSAGE_TYPE_NAME (message));
if(GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS)
if(GST_MESSAGE_TYPE (message) == GST_MESSAGE_EOS){ {
((StreamRecorder*)user_data)->isConnectionLost = true; ((StreamRecorder*)user_data)->isConnectionLost = true;
} }
switch (GST_MESSAGE_TYPE (message)) { switch (GST_MESSAGE_TYPE (message))
{
case GST_MESSAGE_EOS: case GST_MESSAGE_EOS:
cout << "End of stream" << endl; cout << "End of stream" << endl;
cout << "End sometimes src" << endl; cout << "End sometimes src" << endl;
break; break;
case GST_MESSAGE_ERROR: case GST_MESSAGE_ERROR:
gchar *debug; gchar *debug;
GError *error; GError *error;
gst_message_parse_error (message, &error, &debug); gst_message_parse_error (message, &error, &debug);
g_free (debug); g_free (debug);
// Print specific error cerr << "Error: "<< error->message << endl; //Print specific error
cerr << "Error: "<< error->message << endl;
g_error_free (error); g_error_free (error);
// Try to reconnect with the uri stream g_timeout_add(60*1000, reconnectURIStream, user_data); //Try to reconnect with the uri stream
g_timeout_add(60*1000, reconnectURIStream, user_data);
// Enter only if the connection is lost if(((StreamRecorder*)user_data)->isConnectionLost) //Enter only if the connection is lost
if(((StreamRecorder*)user_data)->isConnectionLost){ {
savePartialBuffer(user_data); savePartialBuffer(user_data);
((StreamRecorder*)user_data)->isConnectionLost = false; ((StreamRecorder*)user_data)->isConnectionLost = false;
} }
break; break;
default: default:
break; break;
} }
return TRUE; return TRUE;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void StreamRecorder::savePartialBuffer(void *user_data)
void StreamRecorder::savePartialBuffer(void *user_data){ {
// Calculate the number of bytes that are missing for reach the max buffer size
// The buffer size is obtained based on the maximum recording time
int missingBytes = ((StreamRecorder*)user_data)->bufferSize - ((StreamRecorder*)user_data)->nBytes; int missingBytes = ((StreamRecorder*)user_data)->bufferSize - ((StreamRecorder*)user_data)->nBytes;
// Put the buffer position in the last position of the buffer
((StreamRecorder*)user_data)->audioBufferPosition+=missingBytes; ((StreamRecorder*)user_data)->audioBufferPosition+=missingBytes;
// Save in flac format
((StreamRecorder*)user_data)->compressBuffer(); ((StreamRecorder*)user_data)->compressBuffer();
// Restart the possition pointer
((StreamRecorder*)user_data)->audioBufferPosition=((StreamRecorder*)user_data)->audioBuffer; ((StreamRecorder*)user_data)->audioBufferPosition=((StreamRecorder*)user_data)->audioBuffer;
// Restart the buffer default values
memset (((StreamRecorder*)user_data)->audioBuffer, 0, ((StreamRecorder*)user_data)->bufferSize); memset (((StreamRecorder*)user_data)->audioBuffer, 0, ((StreamRecorder*)user_data)->bufferSize);
((StreamRecorder*)user_data)->nBytes=0; ((StreamRecorder*)user_data)->nBytes=0;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* CallBack to link the pads created by uridecodebin * CallBack to link the pads created by uridecodebin
* @param element The uridecodebin element * @param element The uridecodebin element
* @param pad The pad added * @param pad The pad added
* @param data this * @param data this
*/ */
void StreamRecorder::srcNewPad_callback(GstElement *element, GstPad *pad, void *data)
void StreamRecorder::srcNewPad_callback(GstElement *element, GstPad *pad, void *data) { {
cout << gst_element_get_name(element)<< " adding pad.." << gst_pad_get_name (pad) << endl; cout << gst_element_get_name(element)<< " adding pad.." << gst_pad_get_name (pad) << endl;
cout << "Pad Name: " << gst_pad_get_name (pad) << endl; cout << "Pad Name: " << gst_pad_get_name (pad) << endl;
...@@ -262,29 +215,28 @@ void StreamRecorder::srcNewPad_callback(GstElement *element, GstPad *pad, void * ...@@ -262,29 +215,28 @@ void StreamRecorder::srcNewPad_callback(GstElement *element, GstPad *pad, void *
GstStructure *new_pad_struct = gst_caps_get_structure (new_pad_caps, 0); GstStructure *new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
const gchar *new_pad_type = gst_structure_get_name (new_pad_struct); const gchar *new_pad_type = gst_structure_get_name (new_pad_struct);
if (g_str_has_prefix (new_pad_type, "audio/x-raw")) { if (g_str_has_prefix (new_pad_type, "audio/x-raw"))
{
cout << "linking " << new_pad_type << endl; cout << "linking " << new_pad_type << endl;
GstElement *nextElement = ((StreamRecorder*)data)->audioConvert; GstElement *nextElement = ((StreamRecorder*)data)->audioConvert;
sinkpad = gst_element_get_static_pad (nextElement, "sink"); sinkpad = gst_element_get_static_pad (nextElement, "sink");
if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad))) { if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad)))
{
cerr << "Type is "<< new_pad_type <<" but link failed." << endl; cerr << "Type is "<< new_pad_type <<" but link failed." << endl;
exit(0); exit(0);
} }
else { else
cout <<"Link succeeded " << new_pad_type << endl; cout <<"Link succeeded " << new_pad_type << endl;
} }
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Save audio data (audioBuffer) in flac format * Save audio data (audioBuffer) in flac format
* @return unimplemented * @return unimplemented
*/ */
int StreamRecorder::compressBuffer()
int StreamRecorder::compressBuffer() { {
long int currentTime = time(NULL); long int currentTime = time(NULL);
stringstream ss; stringstream ss;
...@@ -303,7 +255,8 @@ int StreamRecorder::compressBuffer() { ...@@ -303,7 +255,8 @@ int StreamRecorder::compressBuffer() {
FLAC__StreamEncoderInitStatus init_status; FLAC__StreamEncoderInitStatus init_status;
/* allocate the encoder */ /* allocate the encoder */
if((encoder = FLAC__stream_encoder_new()) == NULL) { if((encoder = FLAC__stream_encoder_new()) == NULL)
{
fprintf(stderr, "ERROR: allocating encoder\n"); fprintf(stderr, "ERROR: allocating encoder\n");
return 1; return 1;
} }
...@@ -316,7 +269,8 @@ int StreamRecorder::compressBuffer() { ...@@ -316,7 +269,8 @@ int StreamRecorder::compressBuffer() {
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, nBytes/STREAMRECORDER_BYTESPERSAMPLE); ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, nBytes/STREAMRECORDER_BYTESPERSAMPLE);
/* now add some metadata; we'll add some tags and a padding block */ /* now add some metadata; we'll add some tags and a padding block */
if(ok) { if(ok)
{
if( if(
(metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL || (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
(metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL || (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
...@@ -330,9 +284,7 @@ int StreamRecorder::compressBuffer() { ...@@ -330,9 +284,7 @@ int StreamRecorder::compressBuffer() {
fprintf(stderr, "ERROR: out of memory or tag error\n"); fprintf(stderr, "ERROR: out of memory or tag error\n");
ok = false; ok = false;
} }
metadata[1]->length = 1234; /* set the padding length */ metadata[1]->length = 1234; /* set the padding length */
ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2); ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
} }
...@@ -354,16 +306,18 @@ int StreamRecorder::compressBuffer() { ...@@ -354,16 +306,18 @@ int StreamRecorder::compressBuffer() {
int* pcm = new int[readsize*channels]; int* pcm = new int[readsize*channels];
/* read blocks of samples from WAVE file and feed to encoder */ /* read blocks of samples from WAVE file and feed to encoder */
if(ok) { if(ok)
{
int left = nBytes; int left = nBytes;
while(left&&ok)
while(left&&ok) { {
int need = (left>readsize? readsize : left); int need = (left>readsize? readsize : left);
memcpy(buffer, audioBufferTmp, need);//*sizeof(short)); memcpy(buffer, audioBufferTmp, need);//*sizeof(short));
audioBufferTmp+=need;//*sizeof(short); audioBufferTmp+=need;//*sizeof(short);
// /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */ // /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
for(int i=0; i < need*channels; i++) { for(int i=0; i < need*channels; i++)
{
/* inefficient but simple and works on big- or little-endian machines */ /* inefficient but simple and works on big- or little-endian machines */
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]); pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
} }
...@@ -372,9 +326,8 @@ int StreamRecorder::compressBuffer() { ...@@ -372,9 +326,8 @@ int StreamRecorder::compressBuffer() {
left -= need; left -= need;
} }
} }
else { else
cout << "-ERROR-" << endl; cout << "-ERROR-" << endl;
}
ok &= FLAC__stream_encoder_finish(encoder); ok &= FLAC__stream_encoder_finish(encoder);
...@@ -394,14 +347,12 @@ int StreamRecorder::compressBuffer() { ...@@ -394,14 +347,12 @@ int StreamRecorder::compressBuffer() {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* Add audio data to audioBuffer * Add audio data to audioBuffer
* @param data Audio data to add * @param data Audio data to add
* @param length Data length * @param length Data length
* @return Bytes writen * @return Bytes writen
*/ */
int StreamRecorder::addToBuffer(unsigned char* data, int length) { int StreamRecorder::addToBuffer(unsigned char* data, int length) {
//cout << "addToBuffer(" << length << ")" << endl; //cout << "addToBuffer(" << length << ")" << endl;
...@@ -415,7 +366,8 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) { ...@@ -415,7 +366,8 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) {
cout << "Bytes readed " << nBytes << endl; cout << "Bytes readed " << nBytes << endl;
cout << "Buffer size " << bufferSize << endl; cout << "Buffer size " << bufferSize << endl;
if(nBytes >= bufferSize) { if(nBytes >= bufferSize)
{
compressBuffer(); compressBuffer();
audioBufferPosition=audioBuffer; audioBufferPosition=audioBuffer;
memset (audioBuffer, 0, bufferSize); memset (audioBuffer, 0, bufferSize);
...@@ -423,11 +375,8 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) { ...@@ -423,11 +375,8 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) {
} }
return nBytes; return nBytes;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** /**
* CallBack for handoff signal of identity filter * CallBack for handoff signal of identity filter
* @param filter Identity filter * @param filter Identity filter
...@@ -435,12 +384,13 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) { ...@@ -435,12 +384,13 @@ int StreamRecorder::addToBuffer(unsigned char* data, int length) {
* @param user_data this * @param user_data this
* @return unimplemented * @return unimplemented
*/ */
int StreamRecorder::filter_handoff_callback(GstElement* filter, GstBuffer* buffer, void* user_data)
int StreamRecorder::filter_handoff_callback(GstElement* filter, GstBuffer* buffer, void* user_data) { {
cout << "LLEGO INFO" << endl; cout << "LLEGO INFO" << endl;
GstMapInfo info; GstMapInfo info;
if(!gst_buffer_map (buffer, &info, GST_MAP_READ)) { if(!gst_buffer_map (buffer, &info, GST_MAP_READ))
{
cout << "ERROR: MAPPING IS NOT VALID" << endl; cout << "ERROR: MAPPING IS NOT VALID" << endl;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment