dimanche 15 février 2015

Signed 16-bit ALSA PCM data to U8 Conversion on Linux

I'm attempting to convert 16-bit ALSA PCM Samples to Unsigned 8-bit PCM samples for wireless transmission on Linux. The receiving machine is playing the transmitted data successfully and the recorded voice is there and recognizable, but the quality is terrible and noisy. I've tried ALSA mixer on both ends to tune the stream but it doesn't seem to get much better with that. I believe there is something wrong with my conversion of the samples to 8-bit PCM but its just a simple shift so I'm not sure what could be the error. Does anyone have any suggestions or see anything wrong with my conversion code? Thanks.


Conversion Code:



// This byte array needs to be the packet size we wish to send
QByteArray prepareToSend;
prepareToSend.clear();

// Keep reading from ALSA until we fill one full frame
int frames = 1;
while ( prepareToSend.size() < TARGET_TX_BUFFER_SIZE ) {

// Create a ByteArray
QByteArray readBytes;
readBytes.resize(size);

// Read with ALSA
short sample[1]; // Data is signed 16-bit
int rc = snd_pcm_readi(m_PlaybackHandle, sample, frames);
if (rc == -EPIPE) {
/* EPIPE means overrun */
fprintf(stderr, "Overrun occurred\n");
snd_pcm_prepare(m_PlaybackHandle);
} else if (rc < 0) {
fprintf(stderr,
"Error from read: %s\n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "Short read, read %d frames\n", rc);
}
else {
// Copy bytes to the prepare to send buffer
//qDebug() << "Bytes for sample buffer: " << sizeof(sample);
prepareToSend.append((qint16)(sample[0]) >> 8); // signed 16-bit becomes u8
}

}


ALSA Configuration:



// Setup parameters
int size;
snd_pcm_t *m_PlaybackHandle;
snd_pcm_hw_params_t *m_HwParams;
char *buffer;

qDebug() << "Desire to Transmit Data - Setting up ALSA Now....";

// Error handling
int err;

// Device to Write to
const char *snd_device_in = "hw:1,0";

if ((err = snd_pcm_open (&m_PlaybackHandle, snd_device_in, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
fprintf (stderr, "Cannot open audio device %s (%s)\n",
snd_device_in,
snd_strerror (err));
exit (1);
}

/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&m_HwParams);

if ((err = snd_pcm_hw_params_malloc (&m_HwParams)) < 0) {
fprintf (stderr, "Cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}

if ((err = snd_pcm_hw_params_any (m_PlaybackHandle, m_HwParams)) < 0) {
fprintf (stderr, "Cannot initialize hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}

if ((err = snd_pcm_hw_params_set_access (m_PlaybackHandle, m_HwParams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
fprintf (stderr, "Cannot set access type (%s)\n",
snd_strerror (err));
exit (1);
}

if ((err = snd_pcm_hw_params_set_format(m_PlaybackHandle, m_HwParams, SND_PCM_FORMAT_S16)) < 0) { // Has to be 16 bit
fprintf (stderr, "Cannot set sample format (%s)\n",
snd_strerror (err));
exit (1);

}

uint sample_rate = 8000;
if ((err = snd_pcm_hw_params_set_rate (m_PlaybackHandle, m_HwParams, sample_rate, 0)) < 0) { // 8 KHz
fprintf (stderr, "Cannot set sample rate (%s)\n",
snd_strerror (err));
exit (1);
}

if ((err = snd_pcm_hw_params_set_channels (m_PlaybackHandle, m_HwParams, 1)) < 0) { // 1 Channel Mono
fprintf (stderr, "Cannot set channel count (%s)\n",
snd_strerror (err));
exit (1);
}

/*
Frames: samples x channels (i.e: stereo frames are composed of two samples, mono frames are composed of 1 sample,...)
Period: Number of samples tranferred after which the device acknowledges the transfer to the apllication (usually via an interrupt).
*/

/* Submit params to device */
if ((err = snd_pcm_hw_params(m_PlaybackHandle, m_HwParams)) < 0) {
fprintf (stderr, "Cannot set parameters (%s)\n",
snd_strerror (err));
exit (1);
}

/* Free the Struct */
snd_pcm_hw_params_free(m_HwParams);

// Flush handle prepare for record
snd_pcm_drop(m_PlaybackHandle);

if ((err = snd_pcm_prepare (m_PlaybackHandle)) < 0) {
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}

qDebug() << "Done Setting up ALSA....";

// Prepare the device
if ((err = snd_pcm_prepare (m_PlaybackHandle)) < 0) {
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}

Aucun commentaire:

Enregistrer un commentaire