[Interest] is it ok to push audio on a background thread, not a timer?
David M. Cotter
dave at kjams.com
Wed May 20 04:03:39 CEST 2020
>> 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:
OSStatus CAudioUnit::Start(
#if _QT_
QIODevice **ioPP
#endif
) {
OSStatus err = 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;
}
void CAudioUnit::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_AudioDeviceID devID = 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)
{
OSStatus err = noErr;
CAPlayThroughController *controllerP = CAPlayThroughController::Get();
QAudioDeviceInfo devInfo(QAudioDevice_GetFromID(QAudio::AudioOutput, devID));
CF_ASSERT(i_outUnitP);
QAudioFormat format;
if (Is_ASBD_Blank(i_outUnitP->i_inASBD)) {
Get_ASBD_Generic(&i_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));
}
More information about the Interest
mailing list