Results 1 to 8 of 8

Thread: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

  1. #1
    Join Date
    Jun 2015
    Posts
    5
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Hi folks!

    I am programming a tactical radio application that communicates via LAN. It is basically a voice communication application in which you can set a frequency and only participants who have set the same frequency, can hear and speak to this frequency. Also you can set multiple radios in my application, so that you can listen and talk to multiple frequencies. You hear every frequency you have set, but can only speak on one frequency set as active.

    The microphone packages are sent by a qudpsocket to the Broadcast Address, so every participant receives every voice package. This means I have to append the frequency to every voice package sent, so that every receiving radio can filter the incoming datagrams and only playback those with the correct frequencies.

    I wrote a line like QString("frequency:100000") to the socket, when the transmission starts, but when more people talk the packages get mixed up. Thats why I need to add a string to every single audio package sent. Though I don't know how, because "QAudioInput::start(socket);" takes care of all the recording and sending via udp.


    I hope this states my problem sufficiently and would appreciate any advice.


    Qt Code:
    1. #include ...
    2.  
    3. class Audio_receive : public QObject
    4. {
    5. Q_OBJECT
    6.  
    7. private:
    8. Widget_radio* parent;
    9. QAudioOutput*output;
    10. QUdpSocket* socket;
    11. QIODevice* device;
    12. QTimer* timer;
    13. public:
    14. Audio_receive(Widget_radio* parent);
    15. ~Audio_receive();
    16. private slots :
    17. void receive();
    18. void updateRx();
    19. };
    20.  
    21. #include ...
    22.  
    23. Audio_send::Audio_send()
    24. {
    25. QAudioFormat format;
    26. format.setCodec("audio/PCM");
    27. format.setSampleRate(16000); //128000
    28. format.setSampleSize(16);
    29. format.setChannelCount(1);
    30. format.setByteOrder(QAudioFormat::LittleEndian);
    31. format.setSampleType(QAudioFormat::UnSignedInt);
    32. input = new QAudioInput(format);
    33.  
    34. QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    35. if (!info.isFormatSupported(format))
    36. format = info.nearestFormat(format);
    37.  
    38. socket = new QUdpSocket();
    39. socket->connectToHost(QHostAddress::LocalHost, Config_manager::getInstance()->getPort());
    40. }
    41.  
    42. Audio_send::~Audio_send()
    43. {
    44.  
    45. }
    46.  
    47. void Audio_send::transmit(bool state)
    48. {
    49. if (state)
    50. {
    51. // Frequency Header
    52. //QByteArray datagram("frequency:100000");
    53. //socket->write(datagram);
    54. input->start(socket);
    55. }
    56. else
    57. input->stop();
    58. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Don't connect the audio device directly to the socket. Use the QIODevice returned by start() to populate an internal buffer as data becomes available. You then manage sending from that buffer to the socket with a channel indicator, and whatever other metadata is required, at the top of each frame (I would suggest a fixed size integer channel number rather than a string).

  3. The following user says thank you to ChrisW67 for this useful post:

    Zandare (9th June 2015)

  4. #3
    Join Date
    Jun 2015
    Posts
    5
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Thank you for the good advice. I am new to qt. I will read about QIodevice and let you know how it went.

  5. #4
    Join Date
    Jun 2015
    Posts
    5
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Finally I could spend some time with my project again. I tried to work your ideas in my class, but my transmit function is only executed for one iteration, so not all my voice data is sent. In fact, only the first package.

    EDIT: I changed line 63 to: "} while (input->bytesReady() > 4076);" and now data is sent as long as I press the speak button. Though the receiving client only gets a humming noise that varies by changing the audio data size. Voice is also transmitted.. very distorted...
    Anyway I checked the packages via wireshark and now every transmission contains my frequency string. Is it possible that the humming noise comes from that string? It is not removed yet from the package in the receiving class.

    This is what I came up with:
    Qt Code:
    1. // audio_send.h
    2.  
    3. class QUdpSocket;
    4. class QAudioInput;
    5. class QIODevice;
    6.  
    7. class Audio_send : QObject
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Audio_send();
    13. ~Audio_send();
    14. void setRecording(bool);
    15.  
    16. public slots:
    17. void transmit();
    18.  
    19. private:
    20. QAudioInput *input;
    21. QUdpSocket *socket;
    22. QIODevice* device;
    23. };
    24.  
    25.  
    26. // audio_send.cpp
    27.  
    28. Audio_send::Audio_send()
    29. {
    30. QAudioFormat format;
    31. format.setCodec("audio/PCM");
    32. format.setSampleRate(16000); //128000
    33. format.setSampleSize(16);
    34. format.setChannelCount(1);
    35. format.setByteOrder(QAudioFormat::LittleEndian);
    36. format.setSampleType(QAudioFormat::UnSignedInt);
    37. input = new QAudioInput(format);
    38. //input->setBufferSize(262144); //TODO: find best buffersize
    39.  
    40. QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    41. if (!info.isFormatSupported(format))
    42. format = info.nearestFormat(format);
    43.  
    44. socket = new QUdpSocket();
    45. socket->connectToHost(QHostAddress::LocalHost, Config_manager::getInstance()->getPort());
    46. }
    47.  
    48. Audio_send::~Audio_send()
    49. {
    50.  
    51. }
    52.  
    53. void Audio_send::transmit()
    54. {
    55. do
    56. {
    57. QByteArray buffer;
    58.  
    59. buffer.append("frequency:001000000;"); // 20 chars == 20 byte
    60. buffer.append(device->read(qint64(236))); // == 236 byte
    61.  
    62. socket->write(buffer); // 256 byte
    63. } while (device->bytesAvailable() > 235);
    64. }
    65.  
    66. void Audio_send::setRecording(bool state)
    67. {
    68. if (state)
    69. {
    70. device = input->start();
    71. connect(device, SIGNAL(readyRead()), this, SLOT(transmit()));
    72. }
    73. else
    74. input->stop();
    75. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by Zandare; 11th June 2015 at 20:39.

  6. #5
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    What happens in transmit() when only 30 bytes are available to read?
    How about when 300 bytes are ready? What happens to excess bytes? What is the lifetime of your buffer?

    Start thnking about collecting data from the mic and sending data as two separate processes connected only by a shared data buffer that is persistent.

    You also need to understand Why the User Datagram Protocol (UDP) is sometimes called the Unreliable datagram protocol. What happens to a UDP datagram larger than the maximum transferrable unit on your network interface? Does UDP make guranatees about arrival or order of arrival of transmitted data?

  7. #6
    Join Date
    Jun 2015
    Posts
    5
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Well, I believe when 30 bytes are available, nothing is sent. This only happens when a transmission is about to stop in the last package. I think not sending the very last package does not make a difference, because only some milliseconds in the end will be missing.
    When there a 300 bytes and more, my understanding is that only the first 236 bytes are taken and transmitted. transmit() then waits until more than 236 bytes have been written to "device" or are available and then sends another package via udp.

    I have put the buffer outside of the loop and clear it everytime its content is written to the socket. By processes do you mean threads or a signal slot connection?

    Qt Code:
    1. void Audio_send::transmit()
    2. {
    3. QByteArray buffer;
    4. while (input->bytesReady() > 500)
    5. {
    6.  
    7. buffer.append("f:100000000;"); // 12 chars == 12 byte
    8. buffer.append(device->read(qint64(500))); // == 4076 byte
    9.  
    10. socket->write(buffer); // == 4096 byte datagrams
    11. buffer.clear();
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    I know that udp supports no handshake and is simply sending the packages "out". Package loss is not critical in my application in my view. Varying the package size results in different background noises, but everytime my voice is distorted. A package size of 256 byte should be no problem for LAN or WiFi, right?

  8. #7
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Qt Code:
    1. do { stuff; } while(cond);
    To copy to clipboard, switch view to plain text mode 
    will always execute stuff once before it evaluates cond. If transmit() is called because 30 bytes arrive from the audio card then they are read and sent with 20 bytes on the front. If those 20 bytes are not being removed at the receiver then they are a lot of noise in short packets. It seems you have changed that logic anyway.

    Regardless of whether datagrams get fragmented, which would happen with a 4096 byte datagram, the datagrams can still arrive out of order, several times, or not at all. Not highly likely on a LAN, but certainly possible. If you do not detect these conditions then garbling may result.

    I do not mean threads. I would look at logic to retrieve data from the audio device and buffer it, separately from logic that unbuffers data and sends it on a fixed cycle time. The two logics are only related by the content of a shared buffer.

  9. #8
    Join Date
    Jun 2015
    Posts
    5
    Thanks
    1
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows Android

    Default Re: QAudioInput & QUdpSocket. Adding Identifier(String) to sent datagrams possible?

    Finally success. I have clear voice transmission via udp and can filter the packets by the string I put in the buffer. The while loop seemed to be a mistake, as packets got sent multiple times.

    I will add the transmitted ip and a package counter to the string later to make sure late packets won't be played. Thank you Chris, you were a big help.

    Any further suggestions are still appreciated. Here is my working class:

    Qt Code:
    1. #include "audio_send.h"
    2.  
    3. #include "config_manager.h"
    4.  
    5. #include <QIODevice>
    6. #include <QUdpSocket>
    7. #include <QAudioFormat>
    8. #include <QAudioDeviceInfo>
    9. #include <QAudioInput>
    10.  
    11. #define BUFFERSIZE 1024
    12.  
    13. AudioSend::AudioSend()
    14. {
    15. QAudioFormat format;
    16. // Set up the desired format, for example:
    17. format.setSampleRate(16000);
    18. format.setChannelCount(1);
    19. format.setSampleSize(8);
    20. format.setCodec("audio/pcm");
    21. format.setByteOrder(QAudioFormat::LittleEndian);
    22. format.setSampleType(QAudioFormat::UnSignedInt);
    23.  
    24.  
    25. QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    26. if (!info.isFormatSupported(format))
    27. format = info.nearestFormat(format);
    28.  
    29. input = new QAudioInput(format, this);
    30. //input->setBufferSize(262144); //TODO: find best buffersize
    31. input->setVolume(1.0);
    32.  
    33. socket = new QUdpSocket(this);
    34. socket->connectToHost(QHostAddress::LocalHost, ConfigManager::getInstance()->getPort());
    35. }
    36.  
    37. AudioSend::~AudioSend()
    38. {
    39. delete input;
    40. delete socket;
    41. delete device;
    42. }
    43.  
    44. void AudioSend::transmit()
    45. {
    46. qDebug("transmit()");
    47. if (!input)
    48. return;
    49.  
    50. qint64 len = input->bytesReady();
    51. if (len > BUFFERSIZE)
    52. len = BUFFERSIZE;
    53.  
    54. if (len > 0)
    55. {
    56. QByteArray buffer;
    57. buffer.append("f:100000000;"); // 12 chars == 12 byte
    58. buffer.append(device->read(len));
    59.  
    60. socket->write(buffer.constData());
    61. }
    62. }
    63.  
    64. void AudioSend::setRecording(bool state)
    65. {
    66. if (state)
    67. {
    68. qDebug("setRecording()");
    69. device = input->start();
    70. if (device != NULL)
    71. connect(device, SIGNAL(readyRead()), this, SLOT(transmit()));
    72. }
    73. else
    74. {
    75. input->reset();
    76. input->stop();
    77. }
    78. }
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. Replies: 1
    Last Post: 14th August 2012, 16:58
  2. What is needed to use the QAudioInput??
    By Gokulnathvc in forum Newbie
    Replies: 1
    Last Post: 16th March 2011, 12:48
  3. QAudioInput && QTcpSocket help !
    By Con Nít in forum Qt Programming
    Replies: 14
    Last Post: 4th March 2011, 10:03
  4. QAudioInput and QtcpSocket help!!!
    By XavierQT in forum General Programming
    Replies: 1
    Last Post: 13th July 2010, 20:15
  5. Splitting data so it fits into datagrams
    By toratora in forum Qt Programming
    Replies: 4
    Last Post: 27th April 2007, 19:01

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.