QAudioOutput always encountering UnderrunError - c++

I'm using Qt 4.8 with Qt Creator 2.4.1 on Windows 7 Ultimate x64.
I'm taking audio input using QAudioInput class and playing it using QAudioOutput. There is a 2 seconds timeout after which I stop taking input and then setup the output as follows:
class MainWindow
{
// ...
QByteArray output_data;
QBuffer output_data_buffer;
QAudioOutput *audio_out;
// ...
};
MainWindow::MainWindow(QWidget *parent)
{
// ...
output_data_buffer.setBuffer(&output_data);
// ...
}
void MainWindow::audioInputStopped(QByteArray data)
{
output_data = data;
output_data_buffer.open(QIODevice::ReadOnly);
audio_out = new QAudioOutput(audio_format, this);
connect(audio_out, SIGNAL(stateChanged(QAudio::State)),
SLOT(audioOutputStateChanged(QAudio::State)));
audio_out->start(&output_data_buffer);
}
The audio format I'm using is supported by both input and output devices. I checked them using QAudioDeviceInfo::isFormatSupported(). The 2 seconds audio (data in audioInputStopped()) always plays fine.
In the slot audioOutputStateChanged, I'm always encountering QAudio::UnderrunError error from audio_out->error() after the buffer is finished playing. After audio_out->start() is called, the state (passed as parameter in audioOutputStateChanged()) and error goes as follows:
No error. Active state.
No error. Stopped state.
Underrun error. Idle state.
Note that I'm stopping audio_out in idle state following this example. Why the code is encountering underrun error? Is this normal?

This may seem kind of odd, but I've seen where the built-in arrays in Qt handle better when constructed on the heap, or at least when their elements are constructed on the heap (so they are just an array of pointers). The memory management is a little bit trickier, but items pushed into them don't go out of scope. The Qt Object Model also promotes putting most things on the heap and parenting them correctly. This might help.
After reading a little bit up on buffer underruns, it sounds like there is something still trying to read from the audio source while something else is writing to it or vice-versa. Check out some of the links below. You could try disconnecting the audio_in part from the buffer before reading the buffer. This is more likely to fix the error.
I would also construct your QAudioOutput pointer in the constructor for your main window (more as a style thing). Following some of how it is organized in the examples in Qt, it seems like a better organization. Here is the cpp for the QAudioInput example.
If you had a more complete example, I could try more with it to recreate the error and debug it.
Here is someone else to commiserate with:
http://qt-project.org/forums/viewthread/16729
And a wiki article:
http://en.wikipedia.org/wiki/Buffer_underrun
And the list of Multimedia examples on Qt:
http://doc.qt.nokia.com/4.7-snapshot/examples-multimedia.html
Hope that helps.

Related

How to fix processor affinity for Qt 5.9 Thread on Windows with Ryzen 7

I have been developing a program for my Master's Thesis with OpenSceneGraph-3.4.0 and GUI from Qt 5.9 (otherwise in Visual Studio 2015 and 2017). At work everything works fine, but now that I have a new Computer at home I tried to get it running.
However, when I call the frame() method for the viewer, I get a Read Access Violation in QtThread.cpp at the setProcessorAffinity(unsigned int cpunum), specifically in the following line:
QtThreadPrivateData* pd = static_cast<QtThreadPrivateData*>(_prvData);
Here is the complete function (QtThread.cpp is part of OpenThreads of OSG):
// Description: set processor affinity for the thread
//
// Use: public
//
int Thread::setProcessorAffinity(unsigned int cpunum)
{
QtThreadPrivateData* pd = static_cast<QtThreadPrivateData*>(_prvData);
pd->cpunum = cpunum;
if (!pd->isRunning) return 0;
// FIXME:
// Qt doesn't have a platform-independent thread affinity method at present.
// Does it automatically configure threads on different processors, or we have to do it ourselves?
return -1;
}
The viewer in OSG is set to osgViewer::Viewer::SingleThreaded, but if I remove that line I get an error "Cannot make QOpenGLContext current in a different thread" in GraphicsWindowQt.cpp(which is part of OsgQt), so that's probably a dead end.
Edit for clarification
I call frame()on the osgViewer::Viewer object.
In this function, the viewer calls realize() (which is a function of the Viewer class).
In there setUpThreading()is called (which is a function of the Viewer Base class).
This in turn calls OpenThreads::SetProcessorAffinityOfCurrentThread(0)
In there, the following code is executed:
Thread* thread = Thread::CurrentThread();
if (thread)
return thread->setProcessorAffinity(cpunum);
thread (after the first line) has a value 0x00000000fdfdfdfd which looks like an error to me.
In any case, the last call is the one I posted in my original question.
I don't even have an idea of where to start fixing this. I assume, it's some processor related problem. My processor is a Ryzen 7 1700 (at work it's an Intel i7 3770k), so maybe that helps.
Otherwise, at home I'm using Windows 10, wheras at work it's Windows 7.
I'd be thankful for any help at all.
So in the end, it seems to be a problem with OpenThreads (and thus the OpenSceneGraph part, which I can do nothing about). When using cmake for the OpenSceneGraph source, there is an option "BUILD_OPENTHREADS_WITH_QT" that needs to be disabled.
I found the solution in this thread in the OSG forum, so thanks to this guy.

Qt crashes when picture from OpenCV is too large [duplicate]

This question already has an answer here:
How to efficiently display OpenCV video in Qt?
(1 answer)
Closed 6 years ago.
I've been trying to use OpenCV to capture a camera feed, and show it in Qt as a QLabel. Following a guide I found, this works to a certain degree. However, the application just outright crashes if I try to resize the Mat before making a QImage and setting the Pixmap. The crash is of the type "CameraSoftware.exe has stopped working", so it's hard to debug much other than finding out where it crashes.
Environment is 64 bit windows with QtCreator 3.6.0 (Qt 5.5.1) and OpenCV 3.10.
Here's the important bits of codes:
void VideoStreamOpenCVWorker::receiveGrabFrame()
{
if(!toggleStream) return;
(*cap) >> frameOriginal;
if(frameOriginal.empty()) return;
process();
qDebug() << frameProcessed.cols << "x" << frameProcessed.rows;
QImage output((const unsigned char *) frameProcessed.data, frameProcessed.cols, frameProcessed.rows, QImage::Format_RGBA8888);
emit sendFrame(output);
}
void VideoStreamOpenCVWorker::process()
{
cv::cvtColor(frameOriginal, frameProcessed, cv::COLOR_BGR2RGBA);
cv::Size size(641,481);
cv::resize(frameProcessed, frameProcessed, size);
}
This is sent back to a QLabel widget:
void VideoStreamWidget::receiveFrame(QImage frame){
this->setPixmap(QPixmap::fromImage(frame));
}
This is where it crashes specifically, on the "setpixmap" line.
The Qlabel is added to a QMainWindow with simply:
QVBoxLayout *pictureLayout = new QVBoxLayout;
VideoStreamWidget *video = new VideoStreamWidget();
pictureLayout->addWidget(video);
The original cap picture is 640x480 for whatever reason, the camera I'm using is a full HD camera. Any idea what's causing this? The Qt window size doesn't seem to matter, as I can add a large picture directly if I want to. I just can't resize anything without crashing.
If I haven't provided enough information, ask away.
EDIT: I updated my debugger and got this error message upon executing the setPixmap line:
The inferior stopped because it triggered an exception.
Stopped in thread 0 by: Exception at 0x7ffe38fdadbb, code: 0xc0000005:
read access violation at: 0x0, flags=0x0 (first chance).
Thanks to Mailerdaimon for providing the answer. Emitting the output as a copy
emit sendFrame(output.copy());
does the trick. I am still unsure why exactly this is happening in the first place and why this fixes the problem.

SDL_RenderCopy() has strange behavior on Raspberry PI

This is driving me up the wall..
I've got a very simple SDL2 program.
It has a array of 3 SDL_Texture pointers.
These textures are filled as follows:
SDL_Texture *myarray[15];
SDL_Surface *surface;
for(int i=0;i<3;i++)
{
char filename[] = "X.bmp";
filename[0] = i + '0';
surface = SDL_LoadBMP(filename);
myarray[i] = SDL_CreateTextureFromSurface(myrenderer,surface);
SDL_FreeSurface(surface);
}
This works, no errors.
In the main loop (which is just a standard event loop waiting for SDL_QUIT, keystrokes and a user-event which a SDL_Timer puts in the event queue every second) I just do (for the timer triggered event):
idx = (idx+1) % 3; // idx is global var initially 0.
SDL_RenderClear(myrenderer);
SDL_RenderCopy(myrenderer, myarray[idx], NULL, NULL);
SDL_RendererPresent(myrenderer);
This works fine for 0.bmp and 1.bmp, but the 3rd image (2.bmp) simply shows as a black field.
This is structural.
If I alternate the first 2 images they are both fine.
If I alternate the 2nd and 3rd image the 3rd image doesn't show.
If I use more than 3 images then 3 and upwards show as black.
Loading order doesn't matter. It starts going wrong with the 3rd image loaded from disk.
All images are properly formatted BMP's.
I even saved 2.bmp back to disk under a different name by using SDL_SaveBMP() after it was loaded to make sure it got loaded in memory OK. The new file is bit for bit identical to the original.
This program, without modifications and the same bmp files, works fine on OSX (XCode5) and Windows (VC++ 2012 Express).
The problem only shows on the Raspberry PI.
I have placed explicit error checks on every call that can leave a result/error-code (not shown in the samples above for brevity) but all of them show "no error".
I have used the latest stable source set of www.libsdl.org and compiled as instructed (configure, make, make install, etc.).
Anybody got any idea what could be going on ?
P.S.
Keyboard input doesn't seem to work either on my PI, but I haven't delved into that yet.
Answering myself as I finally figured it out myself...
I finally went back to the README-raspberrypi.txt that came with the SDL2 sources.
I didn't read it carefully enough the first time around...
Problem 1: I'am running on a FULL-HD display. The PI's default GPU memory is 64MB which is not enough for large displays and double-buffering. As suggested in the README I increased this to 128MB and this solved the black image problem.
Problem 2: Text input wasn't working because my user-account was not in the input group. I had added the default "pi" account to the input group initially, but when I later started using another account I forgot to add that user to the group.
In short: Caught by my own (too) quick skimming of the documentation.

Media file can not be switched and played

I am trying to play a music file on S60 5th edition with the following code:
_LIT(KMusicFilename, "C:\\Data\\Music.mp3");
TApaTaskList iTaskList(CCoeEnv::Static()->WsSession());
TBool iExists;
TApaTask iApaTask = iTaskList.FindApp(TUid::Uid(0x102072C3));
iExists = iApaTask.Exists();
if(iExists)
{
// Music player already running
iApaTask.SwitchOpenFile(KMusicFilename);
iApaTask.BringToForeground();
}
else
{
// music player is not running and needs to be launched
RApaLsSession iAplsSession;
User::LeaveIfError(iAplsSession.Connect());
TThreadId thread;
iAplsSession.StartDocument( KMusicFilename,
thread,
RApaLsSession::ESwitchFiles );
iAplsSession.Close();
}
The problem is that this code sample does not work if the music player is already running. The media file that was already playing keeps playing, the function SwitchOpenFile does not have any effect on it.
Is there a workaround for this?
Thank you.
I'm not sure why it doesn't work, but one thing I notice about your code: this call:
iApaTask.SwitchOpenFile(KMusicFilename);
does not check the error code; see if you get an non-zero error code and this may help determine what the problem is. (The same applies to the iAplsSession.StartDocument(...) call).

Deleting And Reconstructing Singleton in C++

I have an application which runs on a controlling hardware connected with different sensors. On loading the application, it checks the individual sensors one by one to see whether there is proper communication with the sensor according to predefined protocol or not.
Now, I have implemented the code for checking the individual sensor communication as a singleton thread and following is the run function, it used select system call and pipe for interprocess communication to signal the end of thread.
void SensorClass::run()
{
mFdWind=mPort->GetFileDescriptor();
fd_set readfs;
int max_fd = (mFdWind > gPipeFdWind[0] ? mFdWind : gPipeFdWind[0]) + 1;
int res;
mFrameCorrect=false;
qDebug("BEFORE WHILE");
while(true)
{
qDebug("\n IN WHILE LOOP");
usleep(50);
FD_ZERO(&readfs);
FD_SET(mFdWind,&readfs);
FD_SET(gPipeFdWind[0],&readfs);
res=select(max_fd,&readfs,NULL,NULL,NULL);
if(res < 0)
perror("Select Failed");
else if(res == 0)
puts("TIMEOUT");
else
{
if(FD_ISSET(mFdWind,&readfs))
{
puts("*************** RECEIVED DATA ****************");
mFrameCorrect=false;
FlushBuf();
//int n=mPort->ReadPort(mBuf,100);
int n=mPort->ReadPort(mBuf,100);
if(n>0)
{
Count++;
QString str((const char*)mBuf);
//qDebug("\n %s",qPrintable(str));
//See if the Header of the frame is valid
if(IsHeaderValid(str))
{
if( (!IsCommaCountOk(str)) || (!IsChecksumOk(str,mBuf)) || (!CalculateCommaIndexes(str)) )
{
qDebug("\n not ok");
mFrameCorrect=false;
} //if frame is incorrect
else
{
qDebug("\n OK");
mFrameCorrect=true;
}//if frame is correct(checksum etc are ok)
}//else if header is ok
}//if n > 0
}//if data received FD_ISSET
if(FD_ISSET(gPipeFdWind[0],&readfs))
break;
}//end nested else res not <= 0
}//infinite loop
}
The above thread is run started from the main GUI thread. This runs fine. The problem is I have given an option to the user to retest the subsystem at will. For this I delete the singleton instance using
delete SensorClass::instance();
and then restart the singleton using
SensorClass::instace()->start();
The problem is this time the control comes out of while loop in run() function immedeately upon entering the while loop, my guess is the pipe read has again read from the write pipe which was written to the last time. I have tried to use the fflush() to clear out the I/O but no luck.
My question is
Am I thinking on the right track?
If yes then how do we clear out the pipes?
If not can anyone suggest why is the selective retest not working?
Thanks in advance..
fflush clears the output buffer. If you want to clear the input buffer, you're going to need to read the data or seek to the end.
I'm not convinced the "Singleton" pattern is appropriate. There are other ways of ensuring at most one instance for each piece of hardware. What if you later want multiple threads, each working with a different sensor?
Let's assume that you're creating this thread by inheriting from QThread (which you don't specify). From the documentation of QThread::~QThread ():
Note that deleting a QThread object will not stop the execution of the thread it represents. Deleting a running QThread (i.e. isFinished() returns false) will probably result in a program crash.
So the statement delete SensorClass::instance(); is probably a really, really bad idea. In particular, it's going to be tough making any sense of this program's behavior given this flaw. Before continuing, you might want to find a way to remove the instance and ensure that the thread goes away, too.
Another problem comes to mind. When you run delete SensorClass::instance(), you get rid of some object (on the heap, one hopes). Who tells the singleton holder that its object is gone? E.g. so that the next call to SensorClass::instance() knows it needs to allocate another instance? Is this handled properly in SensorClass::~SensorClass?
Suppose that's not a problem. That likely means that the pointer to the instance is held in a global variable (or, e.g. a class level static member). It probably doesn't matter for this situation, but is access to that member properly synchronized? I.e. is there a mutex that's locked for each access to it?
You really don't want to run your initialization in thread. That is issue number one that dramatically complicates your problem and which is the kind of thing for some reason no one points out.
Just make the initialization its own function, then have a guard variable and lock, and have everything that uses it separately initialize it when they start up.
So you're signaling by writing something to the pipe, and the pipe is only created once - i.e. reused in the later threads?
Read the signaling away from the pipe. Assuming you signal by writing a single byte, then instead of just breaking out, you'd do something like (NB, no error checking etc below):
if(FD_ISSET(gPipeFdWind[0],&readfs)) {
char c;
read(gPipeFdWind[0], &c, 1);
break;
}
There are also Qt classes for handling socket I/O, e.g. QTcpSocket, which would make the code not only cleaner, also more cross-platform. Or at least QSocketNotifier to abstract the select away.