I'm trying to use Qt5 Multimedia to record audio with QAudioInput. I noticed, however, that when my QAudioInput starts, it raises the master volume of my sound device to 100%.
How can I prevent QAudioInput from changing the master volume?
My current development platform is Linux with PulseAudio (with flat audio disabled).
This is how I'm using QAudioInput:
QAudioDeviceInfo device_info = QAudioDeviceInfo::defaultInputDevice();
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16) ;
format.setCodec("audio/pcm");
format.setSampleType(QAudioFormat::SignedInt);
format.setByteOrder(QAudioFormat::LittleEndian);
std::cout << device_info.deviceName().toUtf8().constData() << std::endl;
QAudioInput *default_device = new QAudioInput(device_info, format);
QIODevice *default_io_device = default_device->start();
There is a QAudioInput.setVolume() method if you have not seen. Having said that, I tried using QAudioRecorder.setVolume() and Qt is telling me - "Setting volume while recording is not supported".
Related
When you load a file into a QMediaPlayer instance, it does not automatically buffer the file. The MediaStatus remains NoMedia until you play the file using play(), only after which it will end up as BufferedMedia. I can't find any way in the documentation to force the player to buffer the file without playing it - is there any way to do this?
Right now I'm planning on muting it, playing the file, then stopping it again and unmuting it, but it makes me feel dirty. Surely there is a better way to do this?
This is necessary, by the way, because I can't retrieve the duration until the file has been buffered, and I need the duration to select a position in the track to start playing from.
Thanks
The MediaStatus remains NoMedia until you play the file using play()
Not in Qt 5, and its not the reason you can't know 'duration' and set 'position'.
When you set the media with setMedia it does not wait for the media to finish loading (and does not check for errors). a signal mediaStatusChanged() is emitted when media is loaded, so listen to that signal and error() signal to be notified when the media loading is finished.
connect(player, &QMediaPlayer::mediaStatusChanged, this, [=]() {
qDebug() << "Media Status:" << player->mediaStatus();
});
I need the duration to select a position in the track to start playing
from.
Once the media file is loaded and before play, you can check the duration and you can set the player to your desired position, but this is best to do once the duration changes from 0 to the media duration after loading, so connect to signal durationChanged():
connect(player, &QMediaPlayer::durationChanged, this, [&](qint64 duration) {
qDebug() << "Media duration = " << duration;
player->setPosition(duration/2);
qDebug() << "Set position:" << player->position();
});
I can't find any way in the documentation to force the player to
buffer the file without playing it - is there any way to do this?
Yes, create a buffer from file then set media content to your buffer (but this is not required to do the above, it just provides a faster way to seek in media):
QString fileName=QFileDialog::getOpenFileName(this,"Select:","","( *.mp3)");
QFile mediafile(fileName);
mediafile.open(QIODevice::ReadOnly);
QByteArray *ba = new QByteArray();
ba->append(mediafile.readAll());
QBuffer *buffer = new QBuffer(ba);
buffer->open(QIODevice::ReadOnly);
buffer->reset(); //seek 0
player->setMedia(QMediaContent(), buffer);
I’m working under kubuntu 12.10 and developping an application into which i need to generate some sound into a QIODevice, then play it with QAudioOutput.
I’ve read all the litterature around speaking of how to properly do that, and I think to have done so.
So far I’ve done :
QVector <double> * soundData = SoundGenerator::getSound();
soundBuffer->open(QIODevice::ReadWrite);
QDataStream writeStream(soundBuffer);
foreach(double d, *soundData) {
char value = d * (2 << 7);
// qDebug() << "Value : " << (short int)value;
writeStream << value;
}
QAudioFormat format;
// Set up the format, eg.
format.setSampleRate(SoundGenerator::getAudioSampleRate());
format.setChannelCount(1);
format.setSampleSize(8);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
audio = new QAudioOutput(format, this);
if (audio->error() != QAudio::NoError) {
qDebug() << "Problem playing sound";
}
connect(audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(aboutToFinish(QAudio::State)));
I have also a call to
audio->start(soundBuffer)
—
from another slot
I do not have any error in the initialization of the QAudioOutput
And I have NO SOUND AT ALL (all other applications have sound, and I’m porting a Qt4 app to Qt5, in Qt4 everything is ok with Phonon)
The aboutToFinish slot is called at the beggining with ActiveState as state, and NoError when calling QAudioOutput::error, but it’s not called anymore, even if waiting far more than the expected generated sound duration.
The sound generation process is not to be put in question, it has been tested by writing wav files, and it works.
Moreover, I have built the multimedia example from Qt’s sources, when it comes to pure audio there is no output (for example in the sprectrum example), on another hand, video plays with the sound perfectly.
Is there any known issue concerning that ? Is that a bug ? Am I doing something wrong ?
Thanks in advance ;)
This does not work because you have set 8 bit sample size and signed integer format.
SOLUTION: You have to set the sample type to unsigned for 8-bit resolution:
format.setSampleType(QAudioFormat::UnsignedInt);
This is not a Qt bug. Why? The answer is that in the WAV spec', 8-bit samples are always unsigned, whereas 16-bit samples are always signed. Any other combination does not work.
So for 16-bit samples you would have to put:
format.setSampleType(QAudioFormat:SignedInt);
(IMHO the fact that Qt does not take care of handling these cases by forcing the correct format is a flaw but not a lack in functionnality).
You can learn more about this in the notes section of this page: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
And also the solution to this very similar question (same problem but with 16-bit): Qt QAudioOutput push mode
Try to add:
QEventLoop loop;
loop.exec();
I'm streaming a large file ( 1Gb ) via HTTP to my server in Qt on a very memory constrained embedded Linux device. When I first receive the header I determine where to write the data on the filesystem, create a QFile pointer to that location, and open the file for appending. There is an 'accumulate' function in the server that is called each time new data arrives to the socket. From that accumulate function I want to stream the data right to the file via write(). You can see my accumulate function below.
My problem is memory usage when doing this -- I run out of memory. Shouldn't I be able to flush() and fsync() each iteration of the accumulation and not have to worry about RAM usage? What am I doing wrong and how can I fix this? Thanks -
I open my file once before the accumulate function:
// Open the file
filePointerToWriteTo->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered)
Here is a portion of the accumulate function:
// Extract the QFile pointer from the QVariant
QFile *filePointerToWriteTo = (QFile *)(containerForPointer->pointer).value<void *>();
qDebug() << "APPENDING bytes: " << data.length();
// Write to the file and sync
filePointerToWriteTo->write(data);
filePointerToWriteTo->waitForBytesWritten(-1);
filePointerToWriteTo->flush(); // Flush
fsync(filePointerToWriteTo->handle()); // Make sure bytes are written to disk
EDIT:
I instrumented my code and the 'waitForBytesWritten(-1)' call ALWAYS return 'false'. The docs say this should wait until data is written to the device.
Also, If I uncomment only the 'write(data)' line, then my free memory never decreases. What could be going on? How does 'write' consume so much memory?
EDIT:
Now I am doing the following. I do not run out of memory, but my free memory drops to 2Mb and hovers there until the entire file is transferred. At which point, the memory is released. If I kill the transfer in the middle, the kernel seems to hold on to the memory because it stays around 2Mb free until I restart the process and try to write to the same file. I still think I should be able to use and flush the memory each iteration:
// Extract the QFile pointer from the QVariant
QFile *filePointerToWriteTo = (QFile *)(containerForPointer->pointer).value<void *>();
int numberOfBytesWritten = filePointerToWriteTo->write(data);
qDebug() << "APPENDING bytes: " << data.length() << " ACTUALLY WROTE: " << numberOfBytesWritten;
// Flush and sync
bool didWaitForWrite = filePointerToWriteTo->waitForBytesWritten(-1); // <----------------------- This ALWAYS returns false!
filePointerToWriteTo->flush(); // Flush
fsync(filePointerToWriteTo->handle()); // Make sure bytes are written to disk
fdatasync(filePointerToWriteTo->handle()); // Specific Sync
sync(); // Total sync
EDIT:
This kind of sounds like me misunderstanding Linux caching. After reading this post --> http://blog.scoutapp.com/articles/2010/10/06/determining-free-memory-on-linux, it's possible that I am misunderstanding the output of 'free -mt'. I have been watching the 'free' field in that output and see it drop to hover around 2MB on the massive file transfer. I would just like to see it return to high levels of free data when the file transfer is done.
I think Linux is just caching everything it can and frees what it can spare around the 2MB free memory limit. I do not run out of memory when receiving or sending out ~2Gb of files on a 512 MB RAM system. In my Qt program, after receiving all of the data, appending to file, and closing the file. I do the following in a QProcess to see my 'free' memory return in the 'free -mt' command in a separate terminal:
// Now we've returned a large file - so free up cache in linux
QProcess freeCachedMemory;
freeCachedMemory.start("sh");
freeCachedMemory.write("sync; echo 3 > /proc/sys/vm/drop_caches"); // Sync to disk and clear Linux cache
freeCachedMemory.waitForFinished();
freeCachedMemory.close();
I am using latest qt version 4.7,where i developed an application on Audio Recording.
I need to set the path to memory card(ie,mass memory),I have seen links based on carbide link->How to run C++ applications in symbian
But could not find any solution for this latest version.
Can anyone help me out in finding this!!
This is what i tried.
I used two methods but i am clueless….
But the audio file gets stored in simulator ,,but not in desired memory card location!!!
AudioBuffer::AudioBuffer()
{
audioSource = new QAudioCaptureSource();
capture = new QMediaRecorder(audioSource);
QAudioEncoderSettings audioSettings;
audioSettings.setCodec("audio/vorbis");
audioSettings.setQuality(QtMultimediaKit::HighQuality);
capture->setEncodingSettings(audioSettings);
capture->setOutputLocation(QUrl::fromLocalFile("test.wav"));
FileName path = PathInfo::MemoryCardRootPath();
path.Append( PathInfo::SoundsPath() );
// QFile file;
// QDir::setCurrent("/tmp");
// file.setFileName("test.wav");
// QDir::setCurrent("/home");
// file.open(QIODevice::ReadOnly);
}
I am using Symbian platform(Qt-Quick)
Regards,
Harish.
I don't develop applications for symbian platforms but IMHO you have to convert TDesC path to a QString (see Converting a Descriptor to a QString for details).
Internal memory is hardcoded to "E:/" and SD card is hardcoded to "F:/" on symbian.
Do a :
QDir d;
d.setPath("f:/");
if (d.exists()) {
[...]
}
to check the availability of the external storage
I created so much qpushbutton to represent the seat in the cinema. After user buy the seats I made these seats disabled. all I want to do is to see previously disabled button disabled. I saved this disabled button to a txt file and read their name but I could not assign it as my widget Qpushbuttons. Is there a way to solve it?
This is not as much a button issue as it is a data structure issue. You should somehow connect your buttons/seats to a data structure which aids in the bookkeeping of available and reserved seats. Once you close the program, you write out the data to a file or database, which you can subsequently read again when you open your application. You can then disable the buttons again of those seats which are reserved.
I've made some quick example with Qt, I hope this will help you:
// list of all seats in order (true means seat is taken, false seat is still free)
QList<bool> seats;
// set some test values
seats.append(true);
seats.append(true);
seats.append(false);
seats.append(true);
// file where the seats will be stored
QFile file("seats.dat");
// save to file
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << seats;
file.close();
// remove all seats (just for testing)
seats.clear();
// read from file
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in >> seats;
file.close();
// simple debug output off all seats
qDebug() << seats;
// you could set the buttons enabled state like this
QList<QPushButton*> buttons; // list of your buttons in the same order as the seat list of course
for (int i = 0; i < seats.count(); ++i)
buttons[i]->setEnabled(!seats.at(i)); // disables all seats which are already taken
This is off course just a simple solution using a QDataStream to serialize the complete List of seats, but you can play around with this if you are new to Qt/C++