Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZeroMQ #55

Merged
merged 14 commits into from
Jul 21, 2021
Merged

ZeroMQ #55

merged 14 commits into from
Jul 21, 2021

Conversation

jeroenbeijer
Copy link
Contributor

Hi Jonti!

As mentioned earlier I have done some work with ZeroMQ and JAERO. I will drop you an email as well.

ignore the .pro file I guess, just need to add libzmq.

BR

Jeroen

@jontio jontio changed the base branch from master to dev-zmq July 21, 2021 21:58
@jontio
Copy link
Owner

jontio commented Jul 21, 2021

Thanks for that. There are a lot of changes. I've had a quick look through them but haven't looked at them in detail yet. Yup I'll ignore the pro file. I've never tried it but you could try telling git not to commit the pro file by saying that the pro file has not been changed with something like git update-index --assume-unchanged "JAERO/JAERO.pro".

I've created a feature branch for the pull request called dev-zmq that way the we can test things work as expected before the merge into master. I'll do the merge into dev-zmq now then I may need to ask a few questions and change a few things.

@jontio jontio merged commit c5df4df into jontio:dev-zmq Jul 21, 2021
@jontio
Copy link
Owner

jontio commented Jul 22, 2021

There is a problem with the 10500bps burst demodulation

dev-zmq with 10500bps burst ...

image

master with 10500bps burst ...

image

Sometimes it works other times it doesn't.

@jontio
Copy link
Owner

jontio commented Jul 22, 2021

Seems the commenting out of "//audioburstoqpskdemodulatorsettings.Fs=48000;" and "//audioburstoqpskdemodulator->setSettings(audioburstoqpskdemodulatorsettings);" in mainwindow.cpp are at least part of the cause. I just realized they were commented out in master too.

@jontio
Copy link
Owner

jontio commented Jul 22, 2021

Hmm when I click between burst 10500 and non burst 10500 the settings aren't applying for the burst. I shall do some more looking.

@jontio
Copy link
Owner

jontio commented Jul 22, 2021

It seems like the lines 846 to 857 you added to mainwindow.cpp...

        if(!settingsdialog->widebandwidthenable)
        {
        audioburstoqpskdemodulatorsettings.Fs=48000;

        }else
        {
            audioburstoqpskdemodulatorsettings.Fs=96000;

        }

make the problem appair. When I remove them things work as normal. I'm not sure why BurstOqpskDemodulator or AudioBurstOqpskDemodulator can't deal with 96000kHz. You only added these lines for oqpskburst is there any reason for that?

I'm not really sure that the widebandwidthenable setting is makes sense anymore. I put it in when there was just MSK and nothing else seems to use it as far as I can tell. Maybe we should remove it as a setting?

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 22, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 22, 2021

Hi Jeroen,

The deletion of the thread you created was the next thing I was going to look at. I only see the deletion in mainwindow.cpp so far around line 717...

    if(pRecThrd!=0 && pRecThrd->running)
    {
         emit ZMQaudioStop();
         delete pRecThrd;
    }

I don't see any deletion in MainWindow::connectZMQ(). I've pushed my current local copy of your merge to https://github.com/jontio/JAERO/tree/a1f0470b2646a103c7ee1d8d780d3ab65acc4aa1 on the dev-zmq branch so you can see what I'm looking at. I haven't done much just looking through things.

I did notice some changes in ReturnResult updateMSK(int bit) aerol.h that I wondered about. Some 8s are now 11 etc., are you sure this function still works as intended? Was there any reason for the changes in that function. It's been ages since I've looked into the details of the bits so I'm rather rusty.

Yes I built your SDRReceiver and had to build rtl-sdr. the following is how I build and installed it after cloning https://github.com/osmocom/rtl-sdr ...

mkdir build && cd build
cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=/mingw64/ ..
mingw32-make
mingw32-make DESTDIR=/../ install

I had to make some changes to the pro file as well having to define byte.

I haven't had time to run it properly yet as it doesn't seem to run without an ini file and I haven't created one yet.

I'm off to bed now but will continue working on it tomorrow.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 22, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 22, 2021

Hi Jeroen,

Yup without the 96k in the oqpsk burst setting all the settings seem to be working correctly.

I have been looking at the thread destruction this morning and the AudioReceiver object is not being deleted until the program finishes. The...

connect(pRecThrd, SIGNAL (finished()), pRecThrd, SLOT (deleteLater()));
connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater()));

don't seem to do anything. The ZMQaudioStop() signal in MainWindow still calls all the AudioReceiver objects that are created. So putting a debug line std::cout<<"AudioReceiver::ZMQaudioStop "<<this<<std::endl<<std::flush; in AudioReceiver::ZMQaudioStop I get the following when selecting back and forth between audio and zmq ...

AudioReceiver::ZMQaudioStop 0x1ddfe43d7f0
AudioReceiver::ZMQaudioStop 0x1ddfe43d520
AudioReceiver::ZMQaudioStop 0x1ddfe43d200

Also if you write a destructor for AudioReceiver it doesn't get run when you select back and forth between audio and zmq.

I have a feeling is not working because there's no event loop in the new thread but I could be wrong.

Anyway I'll figure out a solution hopefully by the end of the day. I vaguely remember something about making a member function of a class run in a separate thread rather than moving the whole object into a separate thread.

I don't see an ini attachment. I guess it's because you're replying to github via email and I assume they filter out attachments. However, I do see in your samples folder one called "CBAND_143E.ini" I'll try that. I don't have my big dish up anymore so it will just be L band.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

Hi Jeroen,

Thanks.

I didn't get much done today as I flaked about halfway through the day due to getting over this RSV virus.

Yes dealing with thread creation in QT seems to lack good documentation and on the web there is definitely some misleading information. I too have struggled with it and I think I have done it in the same way as you have from time to time. I remembered the function I was thinking of QtConcurrent::run https://doc.qt.io/qt-5/qtconcurrentrun.html . I am going to have a look at using that to run void AudioReceiver::process() when necessary rather than creating and deleting AudioReceiver objects all the time. As I recall I've had success with that.

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

I've started using qtconcurrentrun and have realized on windows at least setting running = false; doesn't cause void AudioReceiver::process() to finish as it I would have expected. I assume it would if I had a zmq source going as it would loop and check the flag every so often. So that's a problem, we need a way of tell the thread to stop even if there is no zmq source. Either zmq_recv(subscriber, topic, 20, 0); or int received = zmq_recv(subscriber, buf, recsize, ZMQ_DONTWAIT); is blocking so running is never checked. We need a way to interrupt zmq_recv, do you know a way to do this? I'll have a look at the zmq api but zmq is new to me so I'm not sure how I'll get on.

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

zmq_disconnect(subscriber, _address.toStdString().c_str());
zmq_ctx_destroy(context);

from another thread seem to interrupt zmq_recv but I'm not sure if that's a safe thing to do.

edit: nope seems to have issues and I'm getting more freezing

Maybe this might work...

zmq_close (subscriber);
zmq_ctx_destroy(context);

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

the loop in you pull request looks like ...

   while(running){


       zmq_recv(subscriber, topic, 20, 0);
       int received = zmq_recv(subscriber, buf, recsize, ZMQ_DONTWAIT);

       QByteArray qdata(buf, received);

       emit recAudio(qdata);
   }

is that right? one of the calls to zmq_recv doesn't have the ZMQ_DONTWAIT flag, that's where it blocking. It looks a little odd and I'm not sure what it does.

Yup I've used the same link (
https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ ) for creating threads. I think it wasn't working due to the blocking nature of zmq_recv(subscriber, topic, 20, 0) and not the event loop as I first though.

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

Just a quick question before bed. So if I understand it correctly you are alternating between sending topic and audio? I could see that being a synchronization problem. Wouldn't it be better to have a prepended byte (a header) on the message telling the receiver whether or not it's a topic message or an audio message ? Either that or prepend each audio message with the topic. Then the nonblocking zmq_recv can be used and there is only one zmq_recv call as well as no synchronization issues.

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 23, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 23, 2021

Hi Jeroen,

Thanks I'll have a look. Yes the zmq_close (subscriber); zmq_ctx_destroy(context); from another thread seems to stop zmq. I hope that's safe.

I had a look at https://www.programmersought.com/article/74596969429/ I see they do the same block then non-block thing. That doesn't seem right to me, what if the receiver joins in after the topic has been sent but before the audio has been sent, then the receiver will be getting the audio for the topic and the topic for the audio and be out of sync. I'm finding ZeroMQ hard going. I had a look at https://zguide.zeromq.org/docs/chapter5/ which just gave me brain overload. Anyway I think I'll ignore that until I understand ZeroMQ better.

I'll do some more testing, checking, and tidying today.

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 24, 2021

I finally got the RTL dongle working. The USB cable is too long and I really struggle keeping it going for even a few seconds, I need a better cable or a shorter one but then it wouldn't reach outside. Anyway I found another problem. With my current setup I only just managed to get 600bps. Initially I had it on wideband mode (the setting that I want to get rid of) and the sample rate that your program was outputting at a different rate than what JAERO was expecting. After I realized this I turned off the wideband mode and it worked fine for 600bps. Not quite sure what to do about this problem but it's definitely another reason to get rid of that wideband mode.

600 bps without wideband mode
image

600 bps with wideband mode
image

@jontio
Copy link
Owner

jontio commented Jul 24, 2021

I've pushed a new commit f5b5778 to dev-zmq. I have gotten rid of all the thread stuff and replaced it with QtConcurrent::run . It simplifies things considerably so I do suggest you have a look at what I've done and if you could test that it works just like your code that would be good. Currently I can only test 600bps in real life so that's not a particularly big test. I am going to call it a day for today and deal with the wideband setting mode problem tomorrow.

@jontio
Copy link
Owner

jontio commented Jul 24, 2021

As well as the topic if the ZMQ sender could also send the audio data rate that would solve the issue and that would mean JAERO would know the audio data rate should be using, so...

Topic, audio rate, audio data

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 24, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 25, 2021

Hi Jeroen,

Thanks for that I'll add that dev-zmq tomorrow. Today I got nothing done.

For the wideband setting I think in the interim I'll make it so when zmq audio in is enabled then that'll disable wideband setting. Also if the incoming audio rate isn't something JAERO can deal with I'll make a message show and maybe also drop the audio input if this happens. I also want to have a look at the zmq sender in mainwindow.cpp and put that in a separate class then we have two classes for zmq one for sending data and one for receiving data.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 25, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 25, 2021

Hi Jeroen,

I've added the bitrate message to the code and also a way of dealing when the zmq samplerate doesn't match the decoder samplerate for the mskdemodulator. It's super simple and not fancy but should be fine. If the rate is different it tries to change the settings to the incoming samplerate. Currently only the mskdemodulator supports different samplerate so I didn't do anything else with the other demodulators but if you want to add multiple samplerate support for other demodulators such as for oqpsk at 96khz it shows the idea about how it's done. The commit for this is eb76851

I'll do the class for the zmq sender next.

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 26, 2021

Hi Jeroen,

I've moved the zmq compressed audio sender code to a class and done some tidying ( commit 7b87374 ). I've got nothing to test the sender class so I hope it works. If you could test it that would be good.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 27, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 27, 2021

Hi Jeroen,

Thanks for that. I'll do a final clean, a test on Linux, test the github build works for both Win and Linux then merge into master.

When stopping audio demodulators I noticed that you had things like...

    if(!settings.zmqAudio)
    {
    if(m_audioInput)m_audioInput->stop();

    }
    OqpskDemodulator::stop();

and other times...

    if(m_audioInput)m_audioInput->stop();
    if(!settings.zmqAudio)
    {

    BurstOqpskDemodulator::stop();
    }

Calls to stop that are already stopped shouldn't cause an issue so I removed them in commit d9794d4 if doing this caused a problem then there is something wrong with the stop procedure of the demodulator. I tried various demodulators and didn't see any issue so I think this should be fine but if you find a problem with me doing that let me know.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 28, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 28, 2021

Hi Jeroen,

I'm have some issues on Linux. On ubuntu 20.04 I sometimes get freezing when switching between zmq audio input and soundcard audio input but not always. I also got a crash on exiting...

Assertion failed: pfd.revents & POLLIN (src/signaler.cpp:261)
/usr/local/bin/jaero: line 2:  4015 Aborted                 (core dumped) /opt/jaero/JAERO

On ubuntu 21.04 qt5-default have been removed and the binaries that github made do other strange things such as the leds not turning off and JAERO randomly crashing. Github uses 20.04 so that's not surprising. So I'll pass on dealing with 21.04 and just focus on 20.04.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 28, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 29, 2021

Hi Jeroen,

It seems to be freezing on zmq_ctx_destroy I tried zmq_ctx_term and same happens.
putting a delay between the calls I get more assertions fails messages Assertion failed: pfd.revents & POLLIN (src/signaler.cpp:261) witch crash and they happen on zmq_ctx_destroy too...

    if(subscriber)zmq_close(subscriber);
    usleep(1000000);
    if(context)zmq_ctx_destroy(context);

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 29, 2021

Hi Jeroen,

I don't see a way that zmq can be stopped nicely when a call is made blocking, I think it's going to have to be non blocking and make it polling, something like...

void ZMQAudioReceiver::process()
{
    // allocate enough for 96Khz sampling with 1 buffer per second
    int recsize = 192000;
    context = zmq_ctx_new();
    subscriber = zmq_socket(context, ZMQ_SUB);

    zmqStatus = zmq_connect(subscriber, _address.toStdString().c_str());
    zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, _topic.toStdString().c_str(), 5);

    char buf [recsize];
    unsigned char rate[4];
    quint32 sampleRate;
    int received;

    running = true;

    while(running)
    {

        //blocking call alternative for topic, here we wait for the topic. we don't use the topic so don't bother loading it into memory.
        //I guess the sleep has to be less then the idle period between messages???
        while(((received = zmq_recv(subscriber,  nullptr, 0, ZMQ_DONTWAIT))<0)&&running)
        {
            usleep(10000);
        }
        if(!running)break;

        //rate message is next
        received = zmq_recv(subscriber, rate, 4, ZMQ_DONTWAIT);
        if(!running)break;
        memcpy(&sampleRate, rate, 4);

        //then audio data
        received = zmq_recv(subscriber, buf, recsize, ZMQ_DONTWAIT);
        if(!running)break;
        if(received>=0)
        {
            QByteArray qdata(buf, received);
            emit recAudio(qdata,sampleRate);
        }

    }

    if(subscriber)zmq_close(subscriber);
    if(context)zmq_ctx_destroy(context);
    subscriber=nullptr;
    context=nullptr;
}

You said you had errors when doing this kind of non blocking way though?

I find zmq odd you set a filter ZMQ_SUBSCRIBE with the topic when setting the socket options zmq_setsockopt but then the first message you receive is the topic. I guess that would be useful if you subscribe to multiple publishers. However if you are just subscribing to one publication then you don't need to look at the first message and you can just use zmq_recv(subscriber, nullptr, 0, ZMQ_DONTWAIT)) I think. I do wonder if the syncing the way this code is written needs a timing pause between sets of messages. Maybe the best way would be look at each messages and compare it with the topic for syncing purposes.

Cheers,
Jonti

@jeroenbeijer
Copy link
Contributor Author

jeroenbeijer commented Jul 29, 2021 via email

@jontio
Copy link
Owner

jontio commented Jul 29, 2021

Hi Jeroen,

If there is buffering that causes no delay between sets of the 3 messages that should still be OK because eventually there will be a pause between the sets which will sync the messages. Once it is in sync and as long as no message is dropped then synchronization should still be maintained. Also if we are expecting the topic message and it's already available then the code won't call the usleep function until it's flushed all buffered messages. So it should be OK.

If we cater for other implementations of an SDR maybe adding a check that the topic message matches to be sure about syncronization.

As one can call two zmq_recv calls with ZMQ_DONTWAIT without any delay between them it looks like zmq knows that all three messages should be available before mentioning to the user that data is available.

I'll do some testing tomorrow and let you know how it goes.

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 29, 2021

Hi Jeroen,

Yup that seems to work fine and I have no issues with stopping starting or sync.

I however have noticed another issue. The audio playback class AudioOutDevice has noticeable dropouts due to the sample rate offset. I'll see if I can figure out a way to deal with the sample rate offset issue.

Cheers,
Jonti

@jontio
Copy link
Owner

jontio commented Jul 30, 2021

Seems like might just be zmq not being able to keep up over an internet connection. I'll put it down as that and won't make any modifications to AudioOutDevice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants