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

Add PulseAudio support #194

Merged
merged 96 commits into from
Feb 5, 2022
Merged

Add PulseAudio support #194

merged 96 commits into from
Feb 5, 2022

Conversation

tmiw
Copy link
Collaborator

@tmiw tmiw commented Dec 21, 2021

This PR is to eventually support PulseAudio in FreeDV. Once merged, this will resolve #16 and #191.

TODO:

  1. Create library-independent audio subsystem Done, see IAudioEngine.h et al
  2. Use IAudioEngine for Audio Options dialog Done
  3. Use IAudioEngine for main encode/decode pipeline Done
  4. Remove all PortAudio specific UI elements. Done
  5. Write PulseAudioEngine classes and compile into codebase. Done
  6. Update Create "Easy Setup" dialog to simplify initial setup. #189 to use IAudioEngine. PR on hold, we can proceed without it for now
  7. Update user manual and other documentation. Done, see 47d5b60
  8. Resolve bugs:
    • Stereo results in incorrect speed .wav playback for PulseAudio
    • Incorrect plots when using test buttons in Audio Options (PulseAudio) Done, see d584579
    • Noise immediately on playback/record start (PulseAudio and PortAudio) Done, see d584579
    • Poor quality audio in single card mode May be a local/VMware issue, will need others to confirm Partially resolved by d14f6a6 Possible full resolution by ff88cf1 and 9d24a41
    • Device detection issues with some Windows machines Done

Test Plan:

Feature macOS Linux PortAudio Linux PulseAudio Windows
Audio Config: 1 sound card
Audio Config: 2 sound cards
WAV file playback w/1 card
WAV file playback w/2 cards
OTA decode, RX only
OTA decode, RX + TX
OTA TX

@tmiw
Copy link
Collaborator Author

tmiw commented Dec 21, 2021

@drowe67, this is nowhere near done but due to the significant code changes involved, it's worth testing here before proceeding with the actual PulseAudio implementation. Also, please feel free to add anything to the test plan that I missed.

@Tyrbiter
Copy link

Tyrbiter commented Dec 21, 2021

I have built and installed Fedora 35 rpms for freedv using this code and as far as I can tell it works essentially the same as before, the audio config and PTT setup dialogs work normally, I can receive and transmit (not found an on-air freedv signal but I don't see it would make any difference) so I'd say so far, so good.

I see Qt Pulseaudio entries in the audio dialogs now, but so far have not tried selecting them (assume they are stubs at present), I normally use JACK at 48kbps which interfaces with pipewire through the JACK compatibility libraries.

@drowe67
Copy link
Owner

drowe67 commented Dec 21, 2021

@tmiw wow this is great 🥇 ! I'm taking a look at the code now. I'm a bit busy (my) today, but will also run it over the next few days.

delete m_rxOutPa;
m_RxRunning = false;
Pa_Terminate();

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So nice to clean all this up 👍 I really was "feeling my way" when I wrote this (about 10 years ago now).

src/main.cpp Outdated
{
// RX-only setup.
// Note: we assume 2 channels, but IAudioEngine will automatically downgrade to 1 channel if needed.
rxInSoundDevice = engine->getAudioDevice(std::string(wxGetApp().m_soundCard1InDeviceName.ToUTF8()), IAudioEngine::IN, g_soundCard1SampleRate, 2);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that's a neat trick!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's something handled on the AudioEngine side, so there'll need to be similar logic internally for both PulseAudio and PortAudio. I'm not sure if there's a way to not have to duplicate such logic, but at least it'll be contained to AudioEngine and its classes.

CallAfter([&]() {
wxMessageBox(wxString::Format("Error encountered while processing audio: %s", error), wxT("Error"), wxOK);
});
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not across this C++ syntax to understand this fully - but is this popping up a Dialog in the thread/context of a callback? If so, I'm wondering it that's OK? It would be a good idea to exercise any code that generates a MessageBox.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, CallAfter() is provided by wxWidgets to ensure that all GUI related actions happen on the GUI thread. Bad things happen on the wxWidgets side otherwise.

Copy link
Collaborator Author

@tmiw tmiw Dec 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW the [&] ... syntax is a C++11 lambda function.

src/main.cpp Outdated Show resolved Hide resolved
src/main.cpp Outdated Show resolved Hide resolved
@tmiw
Copy link
Collaborator Author

tmiw commented Dec 21, 2021

I have built and installed Fedora 35 rpms for freedv using this code and as far as I can tell it works essentially the same as before, the audio config and PTT setup dialogs work normally, I can receive and transmit (not found an on-air freedv signal but I don't see it would make any difference) so I'd say so far, so good.

I see Qt Pulseaudio entries in the audio dialogs now, but so far have not tried selecting them (assume they are stubs at present), I normally use JACK at 48kbps which interfaces with pipewire through the JACK compatibility libraries.

Interesting, maybe Fedora 35 somehow has a version of PortAudio that has the proposed Pulse support? IIRC that PR still hasn't been merged up to their master.

src/main.cpp Outdated
std::unique_lock<std::mutex> lk(cbData->infifo1Mutex);
if (codec2_fifo_write(cbData->infifo1, indata, size))
{
g_infifo1_full++;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow if I understand this - the callbacks are now declared inline. That's pretty compact. Just a minor style comment, if you use this style:

if () {
}

about 30% of the lines would be removed from the source, making it more compact to read. Having said that, style is not a huge issue for me. Your call 🙂

For simple for loops I'm also leaning towards:

for (i=0; i<10; i++) x[i] = i++;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, they're inline. By virtue of there being one for each device (vs. how txCallback and rxCallback were shared across all four), it also makes it easier to understand what's going on. 👍

@drowe67
Copy link
Owner

drowe67 commented Dec 21, 2021

Nice work @tmiw, the interface is nice and neat 👍

Is the audio engine choice set in the persistent config? Or is it hard coded say according to operating system? I'm wondering if I can select PortAudio or Pulse if I'm running Linux (ie two audio engines available). Sorry if I missed that in the source somewhere.

@tmiw
Copy link
Collaborator Author

tmiw commented Dec 21, 2021

Nice work @tmiw, the interface is nice and neat 👍

Is the audio engine choice set in the persistent config? Or is it hard coded say according to operating system? I'm wondering if I can select PortAudio or Pulse if I'm running Linux (ie two audio engines available). Sorry if I missed that in the source somewhere.

The intention is for that to be something that happens at compile time (e.g. cmake -DUSE_PULSEAUDIO). It probably could be something that's selectable at runtime but you'd likely need to restart the FreeDV process entirely for it to take effect.

@drowe67
Copy link
Owner

drowe67 commented Dec 21, 2021

The intention is for that to be something that happens at compile time (e.g. cmake -DUSE_PULSEAUDIO). It probably could be something that's selectable at runtime but you'd likely need to restart the FreeDV process entirely for it to take effect.

That's fine as a first pass and first PR. If its necessary or desirable to have more than one AE per OS, we can add that feature later. It would be far simpler to standardise on one AE per OS for support purposes and simplicity.

@Tyrbiter
Copy link

Tyrbiter commented Dec 21, 2021

Interesting, maybe Fedora 35 somehow has a version of PortAudio that has the proposed Pulse support? IIRC that PR still hasn't been merged up to their master.

On looking a bit further it shows the QtPulseAudio devices as being supported via the JACK API so it looks like PortAudio is not providing a Pulseaudio interface. It should be easy to see what is supported in the PA changelog in the relevant place on koji.

The PA code used in Fedora 35 packages (unchanged since July) is this version pa_stable_v190700_20210406 from April.

The only devices freedv now offers are either via ALSA or JACK.

That's all I know.

@Tyrbiter
Copy link

I have now rebuilt again with the code from late today and it all seems just fine with no obvious changes from the removal of mutexes etc.

@Tyrbiter
Copy link

This latest change has introduced a nasty motor-boating sound to the audio, it's constant and repetitive at about 20Hz I'd say.
Revert time!

Unfortunate as the previous change actually re-fixed a previous issue that came back when I upgraded PipeWire in my VM environment. Will have to think some more.

Do you hear the same thing @tmiw I don't see why this would only affect me.

@Tyrbiter
Copy link

Tyrbiter commented Jan 20, 2022

Finally found some freedv at good signal levels on 80m this afternoon, I can now confirm that there is still some clicking in the audio with the current git version after the last revert. I don't know how to identify it any better but I can hear it even listening to analogue noise, the freedv signals are at about 7-10dB SNR with BERs of 0.7% and below. Of course these are off-air signals with 2 stations using different radios and unknown freedv versions and audio interfaces. They have different IF filtering set up too from what I hear, one is using a Flex SDR. Plenty of fading across the signal bandwidth, typically 2 notches across the 700E modulation spectrum from 750-2250Hz. 700D might be better, but the fades sometimes use up all the SNR improvement when I hear 700D on air. One station is showing a fairly large and variable clock offset, the other is much more stable. Maybe too little PC horsepower.

This is usable, but there is definitely something where extra errors are getting into the audio stream for no obvious reason.

@tmiw
Copy link
Collaborator Author

tmiw commented Jan 20, 2022

Finally found some freedv at good signal levels on 80m this afternoon, I can now confirm that there is still some clicking in the audio with the current git version after the last revert. I don't know how to identify it any better but I can hear it even listening to analogue noise, the freedv signals are at about 7-10dB SNR with BERs of 0.7% and below. Of course these are off-air signals with 2 stations using different radios and unknown freedv versions and audio interfaces. They have different IF filtering set up too from what I hear, one is using a Flex SDR. Plenty of fading across the signal bandwidth, typically 2 notches across the 700E modulation spectrum from 750-2250Hz. 700D might be better, but the fades sometimes use up all the SNR improvement when I hear 700D on air. One station is showing a fairly large and variable clock offset, the other is much more stable. Maybe too little PC horsepower.

This is usable, but there is definitely something where extra errors are getting into the audio stream for no obvious reason.

Are you hearing this when playing the sample .wav files over the RX sound device as well? (e.g. paplay -d ... ve9qrp_700d.wav)

@tmiw
Copy link
Collaborator Author

tmiw commented Jan 21, 2022

@Tyrbiter, I played with my other VM environment tonight (Parallels, M1 Mac) and I think I was able to duplicate what you were experiencing. I refactored the PulseAudio logic and it seems to be better, plus I can use much lower latencies than previously. Let me know if that works better for you. 👍

(If not, I also added some additional debugging output on the console that may help.)

@Tyrbiter
Copy link

Hi @tmiw Yes this new version does seem much better, I will see if I can find the normal freedv net on 80m on air later today but the analogue output noise and the recorded wav files all sound good to me.

I wonder if it is worth including some sort of dynamic buffer usage display within freedv, not sure how difficult that would be.

@Tyrbiter
Copy link

An update, just listened to the daily 80m net and the new code in git has performed very much better, good audio, no obvious artefacts of bit or burst errors other than those provided by the RF channel.

Here is a screenshot of the waterfall during an over from the stronger of the 2 stations active today:

700E_80m

It looks interesting, you can see the fading moving cyclically through the audio spectrum. SNR was about 5-8dB.

If this performance is common to other platforms and audio sub-systems I would be happy to see this go for wider testing to confirm that on varied hardware.

@tmiw
Copy link
Collaborator Author

tmiw commented Jan 21, 2022

Hi @tmiw Yes this new version does seem much better, I will see if I can find the normal freedv net on 80m on air later today but the analogue output noise and the recorded wav files all sound good to me.

I wonder if it is worth including some sort of dynamic buffer usage display within freedv, not sure how difficult that would be.

Hmm, I'm not sure we'd want anything API specific in the GUI. Ideally the behavior of each subsystem would be transparent.

However, perhaps buffer usage (along with targets as of now) can be included in the console output? If good, that can easily be disabled again before merging.

An update, just listened to the daily 80m net and the new code in git has performed very much better, good audio, no obvious artefacts of bit or burst errors other than those provided by the RF channel.

Excellent!

@Tyrbiter
Copy link

Tyrbiter commented Jan 21, 2022

I wonder if it is worth including some sort of dynamic buffer usage display within freedv, not sure how difficult that would be.

Hmm, I'm not sure we'd want anything API specific in the GUI. Ideally the behavior of each subsystem would be transparent.

However, perhaps buffer usage (along with targets as of now) can be included in the console output? If good, that can easily be disabled again before merging.

Really just some warnings if things are getting a bit near the knuckle from freedv's point of view. And only there if the debug options are enabled. That's all I think is needed so people can tell if their system is up to the processing load if they hear odd behaviour. Maybe the existing debug does that, but it can be a bit difficult to interpret.

@Tyrbiter
Copy link

An update, just listened to the daily 80m net and the new code in git has performed very much better, good audio, no obvious artefacts of bit or burst errors other than those provided by the RF channel.

Excellent!

Oh yes, and CPU usage seems to be significantly lower too, don't have exact numbers but I can see numbers as low as 3% whereas in the past it's been pretty much 10% minimum.

@drowe67
Copy link
Owner

drowe67 commented Jan 22, 2022

Sounds like good progress, well done 👍

@tmiw
Copy link
Collaborator Author

tmiw commented Feb 4, 2022

So, the 1.7.0 test build has been out for a bit and I haven't heard of any issues with it. I'd say we can merge this up and make an official release once #207 and #208 are merged and we update the manual/release notes accordingly. 👍

@Tyrbiter
Copy link

Tyrbiter commented Feb 4, 2022

So, the 1.7.0 test build has been out for a bit and I haven't heard of any issues with it. I'd say we can merge this up and make an official release once #207 and #208 are merged and we update the manual/release notes accordingly. +1

I think that's a fair suggestion, +1

@drowe67
Copy link
Owner

drowe67 commented Feb 4, 2022

@tmiw - could you please remind me what the 1.7.0 test build was demonstrating/tetsing? For example:

  1. Is it the Windows/PortAudio version of this code?
  2. Are people actually running the Linux/Pulse version over the air?

@tmiw
Copy link
Collaborator Author

tmiw commented Feb 5, 2022

@tmiw - could you please remind me what the 1.7.0 test build was demonstrating/tetsing? For example:

  1. Is it the Windows/PortAudio version of this code?
  2. Are people actually running the Linux/Pulse version over the air?

Yeah, most people have been using Windows or otherwise another OS with PortAudio. I've been using the PulseAudio version occasionally on the air and it seems okay, and @Tyrbiter above was able to tune into the UK 80 meter net with it too. I listed PulseAudio as optional in the release notes (as well as defaulting to PortAudio in build_linux.sh) and we can revisit making PulseAudio the default in a future PR after we've gotten some more runtime.

@Tyrbiter
Copy link

Tyrbiter commented Feb 5, 2022

Just tried the latest git, and I get this if I select the filter dialog:

Thread 1 "freedv" received signal SIGSEGV, Segmentation fault.
MainFrame::OnToolsFilter (this=0x55555579ad70, event=...) at /usr/src/debug/freedv-1.7.0-0.0.10.fc35.x86_64/src/ongui.cpp:82
82 m_filterDialog->Iconize(false);

More detail follows:

(gdb) bt full
#0 MainFrame::OnToolsFilter(wxCommandEvent&) (this=0x55555579ad70, event=...) at /usr/src/debug/freedv-1.7.0-0.0.10.fc35.x86_64/src/ongui.cpp:82
#1 0x00007ffff6c285d3 in wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&)
(event=..., handler=, entry=...) at ../src/common/event.cpp:1390
tableId1 =
tableId2 =
#2 wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) (entry=..., handler=, event=...)
at ../src/common/event.cpp:1365
tableId1 =
tableId2 =
#3 0x00007ffff6c2a802 in wxEvtHandler::SearchDynamicEventTable(wxEvent&) (this=this@entry=0x55555579ad70, event=...) at ../src/common/event.cpp:1749
handler =
entry = 0x555555bc2570
node = {m_ptr = 0x555555bc2500}
#4 0x00007ffff6c2a894 in wxEvtHandler::TryHereOnly(wxEvent&) (this=this@entry=0x55555579ad70, event=...) at ../src/common/event.cpp:1583
#5 0x00007ffff6c2a94f in wxEvtHandler::TryBeforeAndHere(wxEvent&) (event=..., this=0x55555579ad70) at ../include/wx/event.h:3690
#6 wxEvtHandler::TryBeforeAndHere(wxEvent&) (event=..., this=0x55555579ad70) at ../include/wx/event.h:3690
#7 wxEvtHandler::ProcessEventLocally(wxEvent&) (this=0x55555579ad70, event=...) at ../src/common/event.cpp:1520
#8 0x00007ffff6c2aa41 in wxEvtHandler::ProcessEvent(wxEvent&) (this=0x55555579ad70, event=...) at ../src/common/event.cpp:1493
#9 0x00007ffff70fb8aa in wxWindowBase::TryAfter(wxEvent&) (this=0x55555570bc40, event=...) at ../src/common/wincmn.cpp:3427
parent = 0x55555579ad70
#10 0x00007ffff6c287fb in wxEvtHandler::SafelyProcessEvent(wxEvent&) (this=, event=) at ../src/common/event.cpp:1611
#11 0x00007ffff70b50ae in wxMenuBase::SendEvent(int, int) (this=0x5555557a8400, itemid=, checked=)
at ../src/common/menucmn.cpp:666
event =
{ = { = {_vptr.wxObject = 0x7ffff72a7fb8 <vtable for wxCommandEvent+16>, static ms_classInfo = {m_className = 0x7ffff6c700a8 L"wxObject", m_objectSize = 16, m_objectConstructor = 0x0, m_baseInfo1 = 0x0, m_baseInfo2 = 0x0, static sm_first = 0x7ffff6aa32c0 wxPseudoTransparentFrame::ms_classInfo, m_next = 0x7ffff6cd3f80 wxProcessEvent::ms_classInfo, static sm_classTable = 0x5555556597b0}, m_refData = 0x0}, m_eventObject = 0x5555557a8400, m_eventType = 10112, m_timeStamp = 0, m_id = -2012, m_callbackUserData = 0x0, m_handlerToProcessOnlyIn = 0x0, m_propagationLevel = 2147483646, m_propagatedFrom = 0x55555570bc40, m_skipped = false, m_isCommandEvent = true, m_wasProcessed = true, m_willBeProcessedAgain = false, static ms_classInfo = {m_className = 0x7ffff6c6f968 L"wxEvent", m_objectSize = 88, m_objectConstructor = 0x0, m_baseInfo1 = 0x7ffff6cd4160 wxObject::ms_classInfo, m_baseInfo2 = 0x0, static sm_first = 0x7ffff6aa32c0 wxPseudoTransparentFrame::ms_classInfo, m_next = 0x7ffff6cd6560 wxEvtHandler::ms_classInfo}}, = {m_cmdString = {m_impl = L"", m_convertedToChar = {m_str = 0x0, m_len = 140737488341488}}, m_commandInt = -1, m_extraLong = 0}, m_clientData = 0x0, m_clientObject = 0x0, static ms_classInfo = {m_className = 0x7ffff71b4f68 L"wxCommandEvent", m_objectSize = 168, m_objectConstructor = 0x7ffff6f40600 wxCommandEvent::wxCreateObject(), m_baseInfo1 = 0x7ffff6cd6520 wxEvent::ms_classInfo, m_baseInfo2 = 0x0, static sm_first = 0x7ffff6aa32c0 wxPseudoTransparentFrame::ms_classInfo, m_next = 0x7ffff72cd7c0 wxImageList::ms_classInfo}}
win = 0x55555579ad70
mb = 0x55555570bc40
handler =
#12 0x00007ffff6fd9364 in menuitem_activate (item=0x555555802ff0) at ../src/gtk/menu.cpp:587
id = -2012
menu =
#13 menuitem_activate(GtkWidget*, wxMenuItem*) (item=0x555555802ff0) at ../src/gtk/menu.cpp:553
#17 0x00007ffff472ec03 in <emit signal ??? on instance ???> (instance=instance@entry=0x5555559a5d70, signal_id=, detail=detail@entry=0)
at ../gobject/gsignal.c:3553
var_args = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffccd0, reg_save_area = 0x7fffffffcc10}}
#14 0x00007ffff4710c7f in g_closure_invoke
(closure=0x5555557d7170, return_value=0x0, n_param_values=1, param_values=0x7fffffffca40, invocation_hint=0x7fffffffc9c0)
at ../gobject/gclosure.c:830
marshal = 0x7ffff4712bb0 <g_cclosure_marshal_VOID__VOID>
marshal_data = 0x0
in_marshal = 0
real_closure = 0x5555557d7150
--Type for more, q to quit, c to continue without paging--c
func = "g_closure_invoke"
#15 0x00007ffff472d126 in signal_emit_unlocked_R (node=node@entry=0x555555746380, detail=detail@entry=0, instance=instance@entry=0x5555559a5d70, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffca40) at ../gobject/gsignal.c:3742
tmp =
handler = 0x555555984700
accumulator = 0x0
emission = {next = 0x7fffffffce80, instance = 0x5555559a5d70, ihint = {signal_id = 126, detail = 0, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = 0x4}
hlist =
handler_list = 0x555555984700
return_accu = 0x0
accu = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
signal_id = 126
max_sequential_handler_number = 5494
return_value_altered = 1
#16 0x00007ffff472e9ea in g_signal_emit_valist (instance=, signal_id=, detail=, var_args=var_args@entry=0x7fffffffcbf0) at ../gobject/gsignal.c:3497
instance_and_params = 0x7fffffffca40
signal_return_type =
param_values = 0x7fffffffca58
node =
i =
n_params =
func = "g_signal_emit_valist"
#18 0x00007ffff4d9196c in gtk_widget_activate (widget=0x5555559a5d70) at ../gtk/gtkwidget.c:7845
func = "gtk_widget_activate"
#19 0x00007ffff4c4abfe in gtk_menu_shell_activate_item (menu_shell=0x5555559a65a0, menu_item=0x5555559a5d70, force_deactivate=) at ../gtk/gtkmenushell.c:1375
slist =
shells = 0x555555a263a0 = {0x5555559a65a0, 0x5555559a51a0}
deactivate =
func = "gtk_menu_shell_activate_item"
#20 0x00007ffff4c4b051 in gtk_menu_shell_button_release (widget=, event=) at ../gtk/gtkmenushell.c:791
menu_item = 0x5555559a5d70
deactivate = 1
menu_shell = 0x5555559a65a0
priv = 0x5555559a6440
#21 0x00007ffff4ac27d8 in _gtk_marshal_BOOLEAN__BOXEDv (closure=0x555555740240, return_value=0x7fffffffced0, instance=, args=, marshal_data=, n_params=, param_types=0x5555557315b0) at gtk/gtkmarshalers.c:130
data1 = 0x5555559a65a0
data2 =
callback = 0x7ffff4c3b530 <gtk_menu_button_release>
v_return =
arg0 = 0x5555556f5040
args_copy = {{gp_offset = 32, fp_offset = 48, overflow_arg_area = 0x7fffffffd060, reg_save_area = 0x7fffffffcfa0}}
func = "_gtk_marshal_BOOLEAN__BOXEDv"
#22 0x00007ffff472eaba in _g_closure_invoke_va (param_types=0x5555557315b0, n_params=, args=0x7fffffffcf80, instance=0x5555559a65a0, return_value=0x7fffffffced0, closure=0x555555740240) at ../gobject/gclosure.c:893
marshal =
marshal_data =
in_marshal = 0
real_closure = 0x555555740220
return_accu = 0x7fffffffced0
accu = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
accumulator = 0x5555557318d0
emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x0, instance = 0x5555559a65a0, ihint = {signal_id = 79, detail = 0, run_type = (G_SIGNAL_RUN_LAST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
signal_id = 79
instance_type = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str

    emission_return = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
    rtype = 0x14
    static_scope = 0
    fastpath_handler = <optimized out>
    closure = <optimized out>
    run_type = <optimized out>
    hlist = <optimized out>
    l = <optimized out>
    fastpath = 1
    instance_and_params = <optimized out>
    signal_return_type = <optimized out>
    param_values = <optimized out>
    node = <optimized out>
    i = <optimized out>
    n_params = <optimized out>
    __func__ = "g_signal_emit_valist"

#23 g_signal_emit_valist (instance=0x5555559a65a0, signal_id=, detail=0, var_args=var_args@entry=0x7fffffffcf80) at ../gobject/gsignal.c:3406
return_accu = 0x7fffffffced0
accu = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
accumulator = 0x5555557318d0
emission = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
{next = 0x0, instance = 0x5555559a65a0, ihint = {signal_id = 79, detail = 0, run_type = (G_SIGNAL_RUN_LAST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = }
signal_id = 79
instance_type = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str

    emission_return = {g_type = 0x14, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
    rtype = 0x14
    static_scope = 0
    fastpath_handler = <optimized out>
    closure = <optimized out>
    run_type = <optimized out>
    hlist = <optimized out>
    l = <optimized out>
    fastpath = 1
    instance_and_params = <optimized out>
    signal_return_type = <optimized out>
    param_values = <optimized out>
    node = <optimized out>
    i = <optimized out>
    n_params = <optimized out>
    __func__ = "g_signal_emit_valist"

#24 0x00007ffff472ec03 in g_signal_emit (instance=instance@entry=0x5555559a65a0, signal_id=, detail=detail@entry=0) at ../gobject/gsignal.c:3553
var_args = {{gp_offset = 24, fp_offset = 48, overflow_arg_area = 0x7fffffffd060, reg_save_area = 0x7fffffffcfa0}}
#25 0x00007ffff4da8644 in gtk_widget_event_internal.part.0.lto_priv.0 (widget=0x5555559a65a0, event=0x5555556f5040) at ../gtk/gtkwidget.c:7812
signal_num =
return_val =
handled = 0
#26 0x00007ffff4c33ee0 in propagate_event_up (topmost=, event=, widget=0x5555559a65a0) at ../gtk/gtkmain.c:2588
tmp =
handled_event =
handled_event = 0
#27 propagate_event (widget=widget@entry=0x5555559a5d70, event=event@entry=0x5555556f5040, captured=captured@entry=0, topmost=topmost@entry=0x0) at ../gtk/gtkmain.c:2691
handled_event = 0
#28 0x00007ffff4c34013 in gtk_propagate_event (widget=widget@entry=0x5555559a5d70, event=event@entry=0x5555556f5040) at ../gtk/gtkmain.c:2725
func = "gtk_propagate_event"
#29 0x00007ffff4c34cca in gtk_main_do_event (event=) at ../gtk/gtkmain.c:1921
grab_widget = 0x5555559a5d70
window_group = 0x555555e3d510
rewritten_event =
device = 0x5555557510e0
tmp_list =
event_widget =
topmost_widget =
func = "gtk_main_do_event"
#30 gtk_main_do_event (event=) at ../gtk/gtkmain.c:1691
func = "gtk_main_do_event"
#31 0x00007ffff4962543 in _gdk_event_emit (event=0x5555556f5040) at ../gdk/gdkevents.c:73
#32 _gdk_event_emit (event=0x5555556f5040) at ../gdk/gdkevents.c:67
#33 0x00007ffff4994af6 in gdk_event_source_dispatch (base=, callback=, data=) at ../gdk/wayland/gdkeventsource.c:124
source =
display =
event = 0x5555556f5040
#34 0x00007ffff461705f in g_main_dispatch (context=0x5555556db120) at ../glib/gmain.c:3381
dispatch = 0x7ffff4994ad0 <gdk_event_source_dispatch>
prev_source = 0x0
begin_time_nsec = 1213508764584
was_in_call =
user_data = 0x0
callback = 0x0
cb_funcs = 0x0
cb_data = 0x0
need_destroy =
source = 0x5555556f4c20
current = 0x5555556db1e0
i = 0
#35 g_main_context_dispatch (context=0x5555556db120) at ../glib/gmain.c:4099
#36 0x00007ffff466c2a8 in g_main_context_iterate.constprop.0 (context=0x5555556db120, block=block@entry=1, dispatch=dispatch@entry=1, self=) at ../glib/gmain.c:4175
max_priority = 2147483647
timeout = 5512
some_ready = 1
nfds = 4
allocated_nfds = 5
fds =
begin_time_nsec = 1213428904977
#37 0x00007ffff4616773 in g_main_loop_run (loop=0x555555711cf0) at ../glib/gmain.c:4373
func = "g_main_loop_run"
#38 0x00007ffff4c3043d in gtk_main () at ../gtk/gtkmain.c:1329
loop = 0x555555711cf0
#39 0x00007ffff6f6c315 in wxGUIEventLoop::DoRun() (this=0x55555574a940) at ../src/gtk/evtloop.cpp:65
loopLevel = 0
#40 0x00007ffff6b59601 in wxEventLoopBase::Run() (this=0x55555574a940) at ../src/common/evtloopcmn.cpp:78
activate = {m_evtLoopOld = 0x0}
#41 0x00007ffff6b33eea in wxAppConsoleBase::MainLoop() (this=0x5555556bb170) at ../src/common/appbase.cpp:334
#42 0x00007ffff6b95660 in wxEntry(int&, wchar_t**) (argc=, argv=) at ../src/common/init.cpp:506
initializer = {m_ok = }
#43 0x000055555559fdc2 in main(int, char**) (argc=, argv=) at /usr/src/debug/freedv-1.7.0-0.0.10.fc35.x86_64/src/main.cpp:176

Let me know if more is needed.

@tmiw
Copy link
Collaborator Author

tmiw commented Feb 5, 2022

@Tyrbiter, try again? Seems to have been a merge issue.

@drowe67
Copy link
Owner

drowe67 commented Feb 5, 2022

Thanks for explaining the 1.7.0 release @tmiw. Sounds like a fine approach. There were several Hams in #16 who were keen on Pulse, so hopefully they and others will try the build in --pulseaudio mode. Good work - it's been a huge effort for you and I appreciate it 👍

@tmiw
Copy link
Collaborator Author

tmiw commented Feb 5, 2022

@Tyrbiter confirmed on the QSO Finder that cb33436 works okay minus the already known issues with pipewire (which an issue is in for).

@drowe67, excellent. 👍 Does the PR look good otherwise?

@drowe67
Copy link
Owner

drowe67 commented Feb 5, 2022

@drowe67, excellent. +1 Does the PR look good otherwise?

Yes I've taken a few looks at the code over the life of the PR and commented along the way. So I'm happy if you are 🙂

@tmiw tmiw merged commit ca2e467 into master Feb 5, 2022
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.

PulseAudio Support
3 participants