Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-20 Thread Jérôme Godbout
If you are looking for some explanation of the QThread and how to use them 
properly, here a few other links:

  1.  https://www.kdab.com/multithreading-with-qt/
  2.  http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
  3.  http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-2/

The problems with QThread was the doc was lagging behind for a while (it's now 
fixed thanks to the people who updated it btw). Many people where using the 
QThread in a way that they where shooting themselves in the foot with the 
Thread affinity and the emit directly into the QThread object.
Since QThread is a QObject and it create the thread,  it doesn't itself reside 
into the created thread but in the thread that created the QThread object.

From: Interest  On Behalf Of David M. Cotter
Sent: May 19, 2020 7:11 PM
To: interest@qt-project.org
Subject: Re: [Interest] is it ok to push audio on a background thread, not a 
timer?

is it possible i'm just using QThread wrong?  and it HAPPENS to work fine on 
mac but fails on windows?

is this blogger really revealing the ONE TRUE NATURE of QThread:
https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

?

-dave


On May 19, 2020, at 4:05 PM, David M. Cotter 
mailto:d...@kjams.com>> wrote:

anybody have any other ideas?


On May 18, 2020, at 9:12 PM, David M. Cotter 
mailto:d...@kjams.com>> wrote:

Note that you do initialise the i_auP pointer in your constructor's 
initialisation list
which is not a QObject, it's my own wrapper class
Irrelevant what it derives from
then i'm not understanding what your objection is.

i thought your objection was that objects derived from QObject, if they are 
used on a back thread then they must be either allocated there or "moved" there.

but since this i_auP is NOT a QObject, it's my own class, that i'm fine to 
allocate it in one thread (main) and then use it on another thread (audio pump 
thread) (provided and assuming i am careful to mutex any access from the main 
thread)


Are you saying that this calls a function that returned null?
sorry, what is "this" and what function are you referring to that returns null?

if you mean GetCUnit_Out() it returns an object of my own (not a QObject) that 
has already been allocated and is guaranteed to not be NULL


I repeat my request for a compileable example.
i hear you loud and clear but let's assume that's not happening for now and see 
how far we get




___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread Thiago Macieira
On Tuesday, 19 May 2020 19:03:39 PDT David M. Cotter wrote:
> if you want the rest of the code here it is:

http://sscce.org/
Short, Self Contained, Correct (Compilable), Example

That means main() function with QCoreApplication. I don't need a .pro file or 
CMakeLists.txt if it's obvious how to compile (like "qmake -project 
QT+=multimedia").

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products



___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread David M. Cotter
>> but since this i_auP is NOT a QObject, it's my own class, that i'm fine to
>> allocate it in one thread (main) and then use it on another thread (audio
>> pump thread) (provided and assuming i am careful to mutex any access from
>> the main thread)
> 
> i_auP is not a QObject, but i_auP->i_qGeneratorP is.
> 
> How was *that* pointer obtained?
sorry, i thought i clarified that, saying that in addition to "i_qOutputP", i 
said:

> they are both QObjects, and are allocated with "new" during i_auP->Start()

which is on the background thread during  run(), the thread where they'll be 
used. not created on the main thread.

>>> Are you saying that this calls a function that returned null?
>> sorry, what is "this" and what function are you referring to that returns
>> null?
> The code I had pasted:
>i_auP(in_thiz->GetCUnit_Out())
> 
> Since you initialise i_auP using the same function (GetCUnit_Out) that later 
> you initialise auP in render() and then use auP->i_qGeneratorP, I have to ask 
> if at this time the generator pointer is already valid.
yes

the only QObjects are the thread object ( CT_AudioRender), and i_qGeneratorP 
and i_qOutputP

all other object are guaranteed to not be QObjects and guaranteed to correctly 
exist.

func GetCUnit_Out() just returns an existing, already allocated custom 
CAudioUnit object, that is not a QObject. it is guaranteed to exist before this 
code is executed.

the code executes, the pump starts, the render call calls back into my 
generator source, requests bytes, and sends them into the output audio device.
it just produces silence on windows (works fine on mac)


if you want the rest of the code here it is:

OSStatusCAudioUnit::Start(
#if _QT_
QIODevice **ioPP
#endif
) {
OSStatuserr = noErr;

if (i_name == kOutputPlatStr) {

#if OPT_AUDIO_UNITS
ERR(AudioOutputUnitStart(i_auRef));

#elif _QT_
ConfigureAsOutput();

CF_ASSERT(HasSource());

i_qGeneratorP->start();

//  push mode, returns the generator we'll use??
*ioPP = i_qGeneratorP->i_qOutputP->start();

i_qGeneratorP->i_qOutputP->resume();
#endif

if (!err) {
i_output_startedB = true;
}
} else {
CF_ASSERT(0);
err = kAudioUnitErr_NoConnection;
}

return err;
}

voidCAudioUnit::ConfigureAsOutput()
{
CAPlayThroughController *controllerP = 
CAPlayThroughController::Get();

if (controllerP == NULL) {
PostAlert(SSLocalize("There was a problem initializing audio 
output, you may want to quit and re-run", "oops").utf8Z());
} else {
controllerP->Reset(true);
kJ_AudioDeviceIDdevID = controllerP->GetOuputID();
SetProperty(kAudioOutputUnitProperty_CurrentDevice, devID);
}
}

 void   CAudioUnit::SetProperty(AudioUnitPropertyID paramID, const 
SuperString& str)
{
CF_ASSERT(paramID == kAudioOutputUnitProperty_CurrentDevice);

if (paramID == kAudioOutputUnitProperty_CurrentDevice) {
CF_ASSERT(!HasSource());
i_qGeneratorP = new QAudioGenerator(this);
i_qGeneratorP->init(str);
}
}

 void QAudioGenerator::init(kJ_AudioDeviceID devID)
{
OSStatuserr = noErr;
CAPlayThroughController *controllerP = 
CAPlayThroughController::Get();
QAudioDeviceInfo
devInfo(QAudioDevice_GetFromID(QAudio::AudioOutput, devID));

CF_ASSERT(i_outUnitP);

QAudioFormatformat;

if (Is_ASBD_Blank(i_outUnitP->i_inASBD)) {
Get_ASBD_Generic(_outUnitP->i_inASBD);
}

format = QAudioFormat_From_ASBD(i_outUnitP->i_inASBD);

if (!devInfo.isFormatSupported(format)) {
LogAudioDevice(devInfo);
format = devInfo.nearestFormat(format);
QAudioFormat_To_ASBD(format, i_outUnitP->i_inASBD);
}

i_qOutputP.reset(new QAudioOutput(devInfo, format));
}





___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread Thiago Macieira
On Monday, 18 May 2020 21:12:55 PDT David M. Cotter wrote:
> i thought your objection was that objects derived from QObject, if they are
> used on a back thread then they must be either allocated there or "moved"
> there.

Correct.

> but since this i_auP is NOT a QObject, it's my own class, that i'm fine to
> allocate it in one thread (main) and then use it on another thread (audio
> pump thread) (provided and assuming i am careful to mutex any access from
> the main thread)

i_auP is not a QObject, but i_auP->i_qGeneratorP is.

How was *that* pointer obtained?

> > Are you saying that this calls a function that returned null?
> 
> sorry, what is "this" and what function are you referring to that returns
> null?

The code I had pasted:
i_auP(in_thiz->GetCUnit_Out())

Since you initialise i_auP using the same function (GetCUnit_Out) that later 
you initialise auP in render() and then use auP->i_qGeneratorP, I have to ask 
if at this time the generator pointer is already valid.

And one more time: show the rest of the code. I'm not going to keep asking 
what the functions you called do if they are not shown. I want to see the 
lines that create ALL QObjects used in the thread.

> > I repeat my request for a compileable example.
> 
> i hear you loud and clear but let's assume that's not happening for now and
> see how far we get

That's easy: we're getting only this far. This is the last email until you 
show compileable code. There's a good chance the bug is not in the code you 
pasted.

I don't need to see your application. I need you to reduce it to a self-
contained, compileable example.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products



___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread Konstantin Shegunov
On Wed, May 20, 2020 at 2:13 AM David M. Cotter  wrote:

> is it possible i'm just using QThread wrong?  and it HAPPENS to work fine
> on mac but fails on windows?
>
> is this blogger really revealing the ONE TRUE NATURE of QThread:
>
> https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
> ?
>

The one true nature? Probably not, but the rather the habitual way of
threading an event driven piece of code (like some sort of QObject
controller class, a socket or w/e). One can derive from QThread, obviously,
for an imperative piece of code (like numbercrunching), however in case
you're going to use a worker object that's just not quite necessary (i.e.
just use composition). I've seen people derive from QThread, and initialize
objects in the run() method, and then call exec(), but as far as opinions
go, mine is that this is a poor choice of approach (correct if it may be).

Concretely, touching QAudioDeviceInfo::availableDevices() from a thread is
probably a race condition, as the function isn't marked as thread-safe. If
you really need to use its result, I'd say you'd need to pull the info
while you're in the main thread (say in your constructor) and then delegate
it on. However, a thing, which's worrying somewhat, is
that QAudioOutput's methods aren't marked as reentrant (unlike QObject's)
so unless that's a miss in the documentation you're not going to be able to
use it from a separate thread at all.
___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread David M. Cotter
is it possible i'm just using QThread wrong?  and it HAPPENS to work fine on 
mac but fails on windows?

is this blogger really revealing the ONE TRUE NATURE of QThread:
https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
 


?

-dave

> On May 19, 2020, at 4:05 PM, David M. Cotter  wrote:
> 
> anybody have any other ideas?
> 
>> On May 18, 2020, at 9:12 PM, David M. Cotter > > wrote:
>> 
> Note that you do initialise the i_auP pointer in your constructor's 
> initialisation list
 which is not a QObject, it's my own wrapper class
>>> Irrelevant what it derives from
>> then i'm not understanding what your objection is.
>> 
>> i thought your objection was that objects derived from QObject, if they are 
>> used on a back thread then they must be either allocated there or "moved" 
>> there.
>> 
>> but since this i_auP is NOT a QObject, it's my own class, that i'm fine to 
>> allocate it in one thread (main) and then use it on another thread (audio 
>> pump thread) (provided and assuming i am careful to mutex any access from 
>> the main thread)
>> 
>>> Are you saying that this calls a function that returned null?
>> sorry, what is "this" and what function are you referring to that returns 
>> null?
>> 
>> if you mean GetCUnit_Out() it returns an object of my own (not a QObject) 
>> that has already been allocated and is guaranteed to not be NULL
>> 
>>> I repeat my request for a compileable example.
>> i hear you loud and clear but let's assume that's not happening for now and 
>> see how far we get
>> 
>> 
> 

___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-19 Thread David M. Cotter
anybody have any other ideas?

> On May 18, 2020, at 9:12 PM, David M. Cotter  wrote:
> 
 Note that you do initialise the i_auP pointer in your constructor's 
 initialisation list
>>> which is not a QObject, it's my own wrapper class
>> Irrelevant what it derives from
> then i'm not understanding what your objection is.
> 
> i thought your objection was that objects derived from QObject, if they are 
> used on a back thread then they must be either allocated there or "moved" 
> there.
> 
> but since this i_auP is NOT a QObject, it's my own class, that i'm fine to 
> allocate it in one thread (main) and then use it on another thread (audio 
> pump thread) (provided and assuming i am careful to mutex any access from the 
> main thread)
> 
>> Are you saying that this calls a function that returned null?
> sorry, what is "this" and what function are you referring to that returns 
> null?
> 
> if you mean GetCUnit_Out() it returns an object of my own (not a QObject) 
> that has already been allocated and is guaranteed to not be NULL
> 
>> I repeat my request for a compileable example.
> i hear you loud and clear but let's assume that's not happening for now and 
> see how far we get
> 
> 

___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread David M. Cotter
>>> Note that you do initialise the i_auP pointer in your constructor's 
>>> initialisation list
>> which is not a QObject, it's my own wrapper class
> Irrelevant what it derives from
then i'm not understanding what your objection is.

i thought your objection was that objects derived from QObject, if they are 
used on a back thread then they must be either allocated there or "moved" there.

but since this i_auP is NOT a QObject, it's my own class, that i'm fine to 
allocate it in one thread (main) and then use it on another thread (audio pump 
thread) (provided and assuming i am careful to mutex any access from the main 
thread)

> Are you saying that this calls a function that returned null?
sorry, what is "this" and what function are you referring to that returns null?

if you mean GetCUnit_Out() it returns an object of my own (not a QObject) that 
has already been allocated and is guaranteed to not be NULL

> I repeat my request for a compileable example.
i hear you loud and clear but let's assume that's not happening for now and see 
how far we get


___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread Thiago Macieira
On Monday, 18 May 2020 19:33:03 PDT David M. Cotter wrote:
> >> Specifically: both i_qGeneratorP and i_qOutputP are allocated there. I
> >> think they're the only Qt objects use within the new thread?
> > 
> > If you say so, but I can't confirm that you've done the right thing since
> > I
> > can't see those classes
> 
> they are both QObjects, and are allocated with "new" during i_auP->Start()

Ok, that would be in the started thread.

> > Note that you do initialise the i_auP pointer in your constructor's
> > initialisation list
> which is not a QObject, it's my own wrapper class

Irrelevant what it derives from. Are you saying that this calls a function 
that returned null?

I repeat my request for a compileable example.

> no.  25 years ago, we use "i_" to indicate "instance (member) variables" in
> the "THINK Class Library" i've had that habit ever since

Most people use "m_" for that... No matter, it was just surprising?

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products



___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread David M. Cotter
>>> Like every QObject class, unless noted otherwise, you may not call methods
>>> on the object from outside the object's thread of affinity (the one it
>>> was created in or moved to with moveToThread). Your code is abusing the
>>> API in both cases if you're using the API from another thread.
>> 
>> To be clear: I'm not  initting any Qt objects in the constructor, that all 
>> happens inside the run() function, in the i_auP->Start(_outP); call.
> 
> That's not clear from your code:
>QAudioOutput   *audioOutput(auP->i_qGeneratorP->i_qOutputP.get());
> 
> The CAudioUnit class is not defined anywhere in your code.

that class is NOT a QObject, it's my own class, which does not care about 
thread affinity

>> Specifically: both i_qGeneratorP and i_qOutputP are allocated there. I think
>> they're the only Qt objects use within the new thread?
> 
> If you say so, but I can't confirm that you've done the right thing since I 
> can't see those classes
they are both QObjects, and are allocated with "new" during i_auP->Start()

> Note that you do initialise the i_auP pointer in your constructor's 
> initialisation list
which is not a QObject, it's my own wrapper class

> You call this GetCUnit_Out() function in both threads. I can't tell what this 
> function is doing, I don't know what i_qGeneratorP is
it's a QObject, specifically a  QIODevice

> and what thread its i_qOutputP pointer is filled in.
as i said, i_qOutputP is new'd during i_auP->Start(), and is of type  
QAudioOutput

> PS: if you're using Hungarian notation, doesn't the "i" prefix indicate 
> "integer"?
no.  25 years ago, we use "i_" to indicate "instance (member) variables" in the 
"THINK Class Library"
i've had that habit ever since

>  Why are you using it for pointers?
cuz it's an instance variable of a pointer

> Perhaps you're too young for proper Hungarian writing :-)
lol, i wonder if i'm older than you :)

:)
___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread Henry Skoglund

On 2020-05-19 03:19, Thiago Macieira wrote

PS: if you're using Hungarian notation, doesn't the "i" prefix indicate
"integer"? Why are you using it for pointers?

An "i" *after* the underscore would indicate an integer, yes, but the 
letter is before the underscore, so it indicates a scope, perhaps 
"i_..."  means an internal (not exported) class? Perhaps you're too 
young for proper Hungarian writing :-)


___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread Thiago Macieira
On Monday, 18 May 2020 17:42:10 PDT David M. Cotter wrote:
> > Like every QObject class, unless noted otherwise, you may not call methods
> > on the object from outside the object's thread of affinity (the one it
> > was created in or moved to with moveToThread). Your code is abusing the
> > API in both cases if you're using the API from another thread.
> 
> To be clear: I'm not  initting any Qt objects in the constructor, that all 
> happens inside the run() function, in the i_auP->Start(_outP); call.

That's not clear from your code:
QAudioOutput*audioOutput(auP->i_qGeneratorP->i_qOutputP.get());

The CAudioUnit class is not defined anywhere in your code.

> Specifically: both i_qGeneratorP and i_qOutputP are allocated there. I think
> they're the only Qt objects use within the new thread?

If you say so, but I can't confirm that you've done the right thing since I 
can't see those classes. Note that you do initialise the i_auP pointer in your 
constructor's initialisation list:
i_auP(in_thiz->GetCUnit_Out())

You call this GetCUnit_Out() function in both threads. I can't tell what this 
function is doing, I don't know what i_qGeneratorP is and what thread its 
i_qOutputP pointer is filled in.

Please make a small, self-contained and compileable example of the problem.

> Is there some other object you think is being cross-thread abused?
> 
> You mention "both cases", what cases are you referring to?

Mac and Windows.

PS: if you're using Hungarian notation, doesn't the "i" prefix indicate 
"integer"? Why are you using it for pointers?

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products



___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-18 Thread David M. Cotter
>> i have a cross platform (mac / win) app that plays audio.
>> i'm using the push method for audio PCM
>> instead of using a timer, i'm just running the pump on a background thread.
>> 
>> This works fine on mac, but produces silence on windows.
>> 
>> is this... a limitation?
> 
> No, it's a bug in your code.
> 
> Like every QObject class, unless noted otherwise, you may not call methods on 
> the object from outside the object's thread of affinity (the one it was 
> created in or moved to with moveToThread). Your code is abusing the API in 
> both cases if you're using the API from another thread.
To be clear: I'm not  initting any Qt objects in the constructor, that all  
happens inside the run() function, in the i_auP->Start(_outP); call.

Specifically: both i_qGeneratorP and i_qOutputP are allocated there. I think 
they're the only Qt objects use within the new thread?

Is there some other object you think is being cross-thread abused?

You mention "both cases", what cases are you referring to?

-dave___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


Re: [Interest] is it ok to push audio on a background thread, not a timer?

2020-05-17 Thread Thiago Macieira
On domingo, 17 de maio de 2020 16:10:08 PDT David M. Cotter wrote:
> i have a cross platform (mac / win) app that plays audio.
> i'm using the push method for audio PCM
> instead of using a timer, i'm just running the pump on a background thread.
> 
> This works fine on mac, but produces silence on windows.
> 
> is this... a limitation?

No, it's a bug in your code.

Like every QObject class, unless noted otherwise, you may not call methods on 
the object from outside the object's thread of affinity (the one it was 
created in or moved to with moveToThread). Your code is abusing the API in 
both cases if you're using the API from another thread.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products



___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest


[Interest] is it ok to push audio on a background thread, not a timer?

2020-05-17 Thread David M. Cotter
i have a cross platform (mac / win) app that plays audio.
i'm using the push method for audio PCM
instead of using a timer, i'm just running the pump on a background thread.

This works fine on mac, but produces silence on windows.

is this... a limitation?

more info here:
https://forum.qt.io/topic/114921/pumping-audio-on-a-background-thread-not-a-timer
 


-dave___
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest