I think I'm configuring PortAudio on Raspberry Pi correctly to gather data from my USB Microphone and configure them for XBee wireless transmission. The problem is the following line:
inputParameters.sampleFormat = paUInt8; // paInt16; // paUInt8 SOME REASON CAUSES ALWAYS IDENTICAL BUFFERS;
I want to record in Mono at 8KHz with 8-bit samples for telephony quality, but if I set the sampleFormat of the stream to paUInt8, then I alway get identical buffers in the callback. I check this by calculating the MD5Sum of the QByteArray. If I set the format to anything other than paUInt8, then I get different buffers. I have tried various values for the 'framesPerBuffer' size in the callback as well but nothing changes the values in the buffer. This exact behavior must be achievable because I have accomplished decent sound at the desired rates/sample types with ALSA and Qt5's QAudioInput ( with the same USB Microphone ).. It just seems to be PortAudio that I cannot configure properly - What am I doing wrong? Thanks!
Here is the code:
#include "audiorecorder.h"
// Startup audio capture
AudioRecorder::AudioRecorder()
{
// Debug
qDebug() << "Setting up Audio Recording Now";
// Do the Audio setup
doSetup();
}
// Do the setup
void AudioRecorder::doSetup() {
// Variables for configuration
int err;
int indevice;
const PaDeviceInfo *info;
PaStream *stream;
// Set up PortAudio
err = Pa_Initialize();
if ( err != paNoError ) {
handlePaError(101,err,"Error initializing PortAudio: %s\n");
}
// Learn about default input device and look for usb device
int numDevices = Pa_GetDeviceCount();
int index;
bool foundUSB = false;
int foundUsbIndex = -1;
for ( index = 0; index < numDevices; index++ )
{
deviceInfo = Pa_GetDeviceInfo( index );
printf( "[%d] %s #in=%d #out=%d\n",
index, deviceInfo->name,
deviceInfo->maxInputChannels,
deviceInfo->maxOutputChannels );
QString portName = QString::fromUtf8(deviceInfo->name);
if ( portName.contains("USB") ) {
qDebug() << "Found USB Microphone: " << portName << " At index: " << index;
foundUsbIndex = index;
foundUSB = true;
}
}
// Did we find the USB Microphone?
if ( !foundUSB ) {
qDebug() << "Could not find USB Microphone... Using default device...";
indevice = Pa_GetDefaultInputDevice();
}
else {
qDebug() << "Found USB Microphone!" << foundUsbIndex << Pa_GetDefaultInputDevice();
indevice = foundUsbIndex;
}
if (indevice == paNoDevice) {
handlePaError(200,0,"No default input device\n");
}
info = Pa_GetDeviceInfo(indevice);
if ( !info ) {
handlePaError(201,0,"Can't read audio input device info\n");
}
qDebug() << "Selected device name: " << info->name;
qDebug() << "Selected device input channels: " << info->maxInputChannels;
qDebug() << "Selected device default sample rate: " << info->defaultSampleRate;
// Setup the input params
PaStreamParameters inputParameters;
bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields
inputParameters.channelCount = 1;
inputParameters.device = Pa_GetDefaultInputDevice();
inputParameters.hostApiSpecificStreamInfo = NULL;
inputParameters.sampleFormat = paUInt8; // paInt16; // paUInt8 SOME REASON CAUSES ALWAYS IDENTICAL BUFFERS;
inputParameters.suggestedLatency = Pa_GetDeviceInfo(indevice)->defaultHighInputLatency ;
inputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
// Open Specific input
err = Pa_OpenStream(&stream,&inputParameters,NULL,8000.0,64.0,paNoFlag,paCallback,NULL);
if ( err != paNoError ) {
handlePaError(102,err,"Error opening audio stream: %s\n");
}
// Create a XBee object
m_RouterApi = new XBeeApi();
// Start stream
err = Pa_StartStream(stream);
if (err!=paNoError) {
handlePaError(104,err,"Error starting audio stream: %s\n");
}
Pa_Sleep(10000); // This is how long to collect data in ms
// Stop
err = Pa_StopStream(stream);
if ( err != paNoError ) {
handlePaError(104,err,"Error stopping audio stream: %s\n");
}
// Close down
err = Pa_CloseStream(stream);
if (err!=paNoError) {
handlePaError(105,err,"Error closing audio stream: %s\n");
}
// Done with PortAudio
err = Pa_Terminate();
if (err!=paNoError) {
handlePaError(103,err,"Error terminating PortAudio: %s\n");
}
}
// Audio data comes in through this callback
int AudioRecorder::paCallback(const void *in, void *out, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeinfo,
PaStreamCallbackFlags statusFlags,
void *userdata)
{
qDebug() << "********* Got this many 'frames': " << framesPerBuffer;
const char* buffer_ptr = (const char*)in;
//Copy data to user buffer
QByteArray data;
for(int i = 0; i < framesPerBuffer; ++i) {
data.append(buffer_ptr + i);
}
// Always the same if the Format is PaUInt8
qDebug() << QString(QCryptographicHash::hash(data,QCryptographicHash::Md5).toHex());
// This is a singleton which is the current one
// AudioRecorder *currentOne = &Singleton<AudioRecorder>::Instance();
// currentOne->transmitData(data);
// Done
return 0;
}
// Data ready for XBee transport
void AudioRecorder::transmitData(QByteArray data) {
// Start the timer on the first go-around
if ( m_CycleCounter == 0 ) {
m_RateTimer.start();
}
// Create a ByteArray
QByteArray toSendBytes(data.data(), data.size());
// Create packet
QString toSend = "";
for ( int s = 0 ; s < toSendBytes.length() ; s++ ) {
// Create Hex String
QString hexadecimal;
hexadecimal.setNum((quint8)toSendBytes.at(s),16);
QString toAppend = QString("%1").arg(hexadecimal);
QString paddedString = QString(" %1").arg(toAppend.rightJustified(2, '0').toUpper());
toSend.append(paddedString);
}
toSend = m_RouterApi->createPacket(toSend.toUpper());
//toSend = "7E 00 11 20 00 0A 0A 0A 01 26 16 00 00 01 00 48 45 4C 4C 4F 0F"; // TEST MESSAGE
//qDebug() << toSend;
int amount = m_RouterApi->writeToXBee(toSend);
m_CycleCounter++;
m_BytesSent += amount;
if ( m_CycleCounter % 100 == 0 ) {
QString update = QString("Transmitting Now!\nXBee Bytes / Sec\n = %1 / %2\n = %3 B/s").arg((int)m_BytesSent).arg((int)((int)m_RateTimer.elapsed() / (int)1000.0f)).arg((int)((int)m_BytesSent/((int)m_RateTimer.elapsed() / (int)1000.0f)));
qDebug() << "Update: " << update;
emit updateScreen(update);
}
// Clear it out
toSend = "";
}
// Generic error routine
void AudioRecorder::handlePaError(int n,int err,char *s)
{
fprintf(stderr,s,Pa_GetErrorText(err));
Pa_Terminate(); // already had an error so quit checking
exit(n);
}
did u find a solution for this problem ???
RépondreSupprimer