I want to make an audio streaming program (like phone) using the QMediaPlayer, QAudioProbe and QAudioOutput classes in Qt 5.3.0 MSVC2012 OpenGL 32bit.
This is my code:
musicPlayer = new QMediaPlayer();
musicProbe = new QAudioProbe();
musicProbe->setSource(musicPlayer);
connect(musicProbe, SIGNAL(audioBufferProbed(QAudioBuffer)),
this, SLOT(slotGetMusicData(QAudioBuffer)));
If audio data probed, the slot is actived.
void MusicPlayer::slotGetMusicData(QAudioBuffer musicBuffer)
{
/*QAudioBuffer to QByteArray*/
*musicDataBuffer = musicDataBuffer->fromRawData((char *)musicBuffer.data(),
,musicBuffer.byteCount());
/*Send Music Data*/
musicSocket->sendMudicData(*musicDataBuffer);
qDebug("send complete");
}
Using a socket, I send the data to another program.
The other program plays the music received.
QAudioOutput *audioOutput = new QAudioOutput(format, this);
QIoDevice *audioDevice = audioOutput->start();
and then, data received this slot is actived.
void BgmSocket::slotPlayBgm(QByteArray data)
{
audioDevice->write(data.data(), data.size());
}
The audio is playing well, but the sounds have a lot of static (pause sound).
How can I solve this problem?
The problem was a different frequency between the network and the playback buffer.
I solved this problem by creating a buffer with double buffering.
Related
I want to use QAudioRecorder to record an audio and save as a file and display the filepath to the user. I had tried using the the example from Qt but there's no feed on the buffer value when I tested it on Android. It works on my Desktop though. Below are part of my codes:
AudioRecord::AudioRecord(QWidget *parent)
{
audioRecorder = new QAudioRecorder(this);
probe = new QAudioProbe;
connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)),
this, SLOT(processBuffer(QAudioBuffer)));
probe->setSource(audioRecorder);
}
void AudioRecord::processBuffer(const QAudioBuffer& buffer)
{
qDebug()<<"Testing Successful";
}
The processBuffer function does not seems to be called. What should I do to get the buffer value work? Is there any other way around?
Thanks!
I've a SODAQ Mbili board with a LoRa bee. I've also a GPS sensor. Below you could find how I add the bee and the sensor.
On that board I make a JSON string with the GPS coordinates and I'll send that data over the LoRa network. But How could I do that.
In the source code I've download they use next code:
LoRaModemMicrochip modem(&MODEM_SERIAL, &debugSerial);
Device libTest(&modem, &debugSerial);
void readGPSData() {
GPSSensor gpsSens(4.3, 51.222, 15.5, 0);
dumpSendResult(gpsSens);
}
void dumpSendResult(Sensor& sns) {
bool sendResult = libTest.send(sns, true);
}
I'll change this code like code below so I could send my JSON data
LoRaModemMicrochip modem(&MODEM_SERIAL, &debugSerial);
Device libTest(&modem, &debugSerial);
void readGPSData() {
String json = "My JSON code";
dumpJsonResult(json);
}
void dumpJsonResult(String& text) {
bool sendResult = libTest.send(text, true);
}
But it gives me this error:
In function void dumpJsonResult(String&):
Error: no matching function for call to Device::send(String&, bool)
bool sendResult = libTest.send(text, true);
^
Did you know how I could send JSON data to the LoRaWAN?
If you have correct NWSessionKey and APPSessionKey and so on, you could try to onboard your device over Actility's free partner zone.
https://partners.thingpark.com/
Once you do that, you would need to:
Learn how to perform a downlink
Create your own payload mechanism, such as coding your GPS over signed ints for Lat, long and Alt.
Then decode it within your device
Your device could also send ack to an Applicative Server you would plug to Actility's solution (REST-POST/JSON)
Let us know how it goes
Best regards,
What are the libraries used? I haven't found LoRaModemMicrochip object definition on sodaq site.
Have you looked at http://support.sodaq.com/sodaq-one/lorabee/?
I would strongly suggest you to not used JSON with LoRa,as this is very verbose and will use a lot of air time, while the bands where LoRa run have strong duty cycle constrains.
I am trying to scan my serial ports periodically to see if my device is connected or not. Here is what I have done and it works well. I would like to see if there is a better and optimized way to do so.
I created the following timer in my constructor to check the serial port frequently. I made a method (scanSerialPorts()) and call it every 1 second.
QTimer *timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(scanSerialPorts()));
timer->start(1000);
This is my scanSerialPorts() implementation:
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
currentPortName = info.systemLocation();
}
if (currentPortName == "My Desired PortName" ) {
updateSettings();
if ( !serial->isOpen()){
qDebug() << "Serial Not Open";
openSerialPort();
}
} else
{
serial->close();
}
updateSettings(); // Fills up the serial port parameters.
openSerialPort(); //Opens up the serial port.
I used QT examples to write this. Please let me know what you think and how I can make it better.
As it is, you only scan the last port, since the rest of the code is outside the foreachloop;
You close the other (probably not opened) ports instead of the one you're opening
Most probably, availablePorts won't change during execution, so you could move it outside of the scan function to save some processing time in the timer. The same for updateSettings().
I need to send a long text to serial printer using Jssc library. After a few I get a full buffer error, so I thought it can be the flow control settings, because for smaller transmission everything works.
The printer can use XON/XOFF flow control configuration or CTS/RTS hardware signals.
SOFTWARE FLOW CONTROL
My jssc code to open the port is this:
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_XONXOFF_IN | SerialPort.FLOWCONTROL_XONXOFF_OUT);
This works only for a small text output, for longer output the printer throw a full buffer error.
HARDWARE FLOW CONTROL
I also try to switch printer to cts/rts flow control and change my code to this:
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE, true, false);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT);
But nothing changes. I still get the buffer error for long output.
Than I check with a COM monitor if my printer correctly sends XOFF chars or CTS signal before filling its buffer and it well works!
At the end I tried to manually manage the output stream stopping it while CTS signal is off (using an event handler) in this way everything works also with long output.... but this is not what the flowcontrol should do automatically?
MANUAL HARDWARE FLOW CONTROL TEST
This is my manual hardware flow control test.
It uses canSend boolean var to control the output stream.
private boolean canSend=true;
public void openPort(
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE, true, false);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
serialPort.addEventListener(new SerialPortReader(), SerialPort.MASK_CTS);
canSend=true;
}
public void write(byte[] content) throws Exception {
ByteArrayInputStream b= new ByteArrayInputStream (content);
byte[] bytes =new byte[OUT_BUFFER_SIZE];
int byteread=0;
while ((byteread=b.read(bytes, 0, bytes.length)) >= 0) {
if(byteread>0){
while(!canSend){
Thread.sleep(CTS_WAIT);
}
if(byteread<bytes.length){
byte[] tocopy=new byte[byteread];
System.arraycopy(bytes, 0, tocopy, 0, byteread);
serialPort.writeBytes(tocopy);
}else{
serialPort.writeBytes(bytes);
}
}
}
}
private class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isCTS()){
canSend=event.getEventValue() == 1;
}
}
}
Seems that the flowcontrol settings is completely ignored.
What can be? Is it a jssc error a windows driver error?
I also tries to check it with getFlowControlMode() and I correctly get a values of 3 for the hardware flow control test.
At the end the problems was not the jssc library but usb to serial adapter. Changing it with a FTDI chip based adapter it works. (Moreover seems that also the last driver's release of Prolific adapter works).
I tried using phonon to play the video but could not succeed. Off-late came to know through the Qt forums that even the latest version of Qt does not support phonon. That's when I started using Gstreamer. Any suggestions as to how to connect the Gstreamer window with the Qt widget? My aim is to play a video using Gstreamer on the Qt widget. So how do I link the Gstreamer window and the Qt widget?
I am successful in getting the Id of the widget through winid().
Further with the help of Gregory Pakosz, I have added the below 2 lines of code in my application -
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), widget->winId());
However am not able to link the Qt widget with the gstreamer video window.
This is what my sample code would look like :-
int main(int argc, char *argv[])
{
printf("winid=%d\n", w.winId());
gst_init (NULL,NULL);
/* create a new bin to hold the elements */
bin = gst_pipeline_new ("pipeline");
/* create a disk reader */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_assert (filesrc);
g_object_set (G_OBJECT (filesrc), "location", "PATH_TO_THE_EXECUTABLE", NULL);
demux = gst_element_factory_make ("mpegtsdemux", "demuxer");
if (!demux) {
g_print ("could not find plugin \"mpegtsmux\"");
return -1;
}
vdecoder = gst_element_factory_make ("mpeg2dec", "decode");
if (!vdecoder) {
g_print ("could not find plugin \"mpeg2dec\"");
return -1;
}
videosink = gst_element_factory_make ("xvimagesink", "play_video");
g_assert (videosink);
/* add objects to the main pipeline */
gst_bin_add_many (GST_BIN (bin), filesrc, demux, vdecoder, videosink, NULL);
/* link the elements */
gst_element_link_many (filesrc, demux, vdecoder, videosink, NULL);
gst_element_set_state(videosink, GST_STATE_READY);
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
/* start playing */
gst_element_set_state (bin, GST_STATE_PLAYING);
}
Could you explain more in detail about the usage of gst_x_overlay_set_xwindow_id() wrt my context?
Could I get any hint as to how I can integrate gstreamer under Qt?
Please help me solve this problem.
I just did this same thing using python. What I had to do was connect to 'sync-message::element' on the bus and listen for a message called 'prepare-xwindow-id' (disregard the name as it works on all platforms, not just X11) sent after the video sink is setup. It sends you the sink inside that message, and that is where you pass it the window id.
The sample code given above will link GStreamer video window to QtWidget provided the elements are linked correctly.
filesrc should be linked to the demuxer
decoder should be linked to the filesink
Finally, the demuxer should be linked to the decoder at runtime
// link filesrc to demuxer
gst_element_link(filesrc,demux)
// link vdecoder to filesink
gst_element_link_many(vdecoder,filesink,NULL)
/*
The demuxer will be linked to the decoder dynamically.
The source pad(s) will be created at run time,
by the demuxer when it detects the amount and nature of streams.
Connect a callback function which will be executed
when the "pad-added" is emitted.
*/
g_signal_connect(demux,"pad-added",G_CALLBACK(on_pad_added),vdecoder);
// callback definition
static void on_pad_added(GstElement* element,GstPad* pad,gpointer* data)
{
GstPad* sinkpad;
GstElement * decoder = (GstElement*)data;
GstCaps* caps;
GstStructure* str;
gchar* tex;
caps = gst_pad_get_caps(pad);
str = gst_caps_get_structure(caps,0);
tex = (gchar*)gst_structure_get_name(str);
if(g_strrstr(tex,"video"))
{
sinkpad = gst_element_get_static_pad(decoder,"sink");
gst_pad_link(pad,sinkpad);
gst_object_unref(sinkpad);
}
}
http://cgit.freedesktop.org/gstreamer/gst-plugins-base/tree/tests/examples/overlay
has a minimal Qt example.
In your code, you should probably set the window ID before you do the state change to ready (I'm not 100% sure this is the problem though).
For playback, you should idally use the playbin2 element, something like this (completely untested):
GstElement *playbin, *videosink;
gchar *uri;
playbin = gst_element_factory_make ("playbin2", "myplaybin");
videosink = gst_element_factory_make ("xvimagesink", NULL);
g_object_set (playbin, "video-sink", videosink, NULL);
uri = g_filename_to_uri ("/path/to/file", NULL, NULL);
g_object_set (playbin, "uri", uri, NULL);
g_free (uri);
/* NOTE: at this point your main window needs to be realized,
* ie visible on the screen, and you might need to make sure
* that your widget w indeed has a 'native window' (just some
* things to check for if it doesn't work; there should be Qt
* API for this kind of thing if needed) */
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
gst_element_set_state (playbin, GST_STATE_PLAYING);
.. check for messages like error/statechanges/tags/eos on pipeline/playbin bus
A project wrapping gstreamer into usable C++/Qt classes including example code:
http://code.google.com/p/qbtgstreamer/
I don't know about a direct approach, as I am not familiar with gstreamer itself.