我已經使用PulseAudio和Qt5.4的QAudioOutput在Raspberry Pi上的3.5mm耳機插孔模擬輸出上成功播放了音頻。音頻通過8位採樣率的8KHz的XBee鏈路從遠端麥克風成功傳輸。配置ALSA接收和播放Raspberry Pi上的原始PCM模擬輸出
PulseAudio有一個巨大的延遲,所以我決定鏈接到libasound(ALSA)並直接播放音頻。我的代碼在下面,併成功打開並播放聲音,但幾乎無法辨認,有很多crack啪聲和吱吱聲。如果我對着遠端麥克風說話,我很快就會聽到從Pi發出的高音劃傷和吱吱聲(但它不是很好的音頻)。我想我有我的參數搞砸了。
1.)數據以BigEndian傳輸 - QAudioOutput允許您通知它樣本是BigEndian。但這些是U8樣本,我需要擔心排序嗎? 2.)你能看到下面我的配置有什麼問題嗎? 3.)如何找出Pi上輸出的ALSA的片段大小? 4.)有人可以解釋我應該如何將我的緩衝區寫入音頻設備?
謝謝!
這裏是我的代碼:
UdpReceiver::UdpReceiver(QObject *parent) :
QObject(parent)
{
// Debug
qDebug() << "Setting up a UDP Socket...";
// Create a socket
m_Socket = new QUdpSocket(this);
// Bind to the 2616 port
bool didBind = m_Socket->bind(QHostAddress::Any, 0x2616);
if (!didBind) {
qDebug() << "Error - could not bind to UDP Port!";
}
else {
qDebug() << "Success binding to port 0x2616!";
}
// Get notified that data is incoming to the socket
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
// Init to Zero
m_NumberUDPPacketsReceived = 0;
}
void UdpReceiver::readyRead() {
// When data comes in
QByteArray buffer;
buffer.resize(m_Socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
// Cap buffer size
int lenToRead = buffer.size();
if (buffer.size() > NOMINAL_AUDIO_BUFFER_SIZE) {
lenToRead = NOMINAL_AUDIO_BUFFER_SIZE;
}
// Read the data from the UDP Port
m_Socket->readDatagram(buffer.data(), lenToRead,
&sender, &senderPort);
// Kick off audio playback
if (m_NumberUDPPacketsReceived == 0) {
qDebug() << "Received Data - Setting up ALSA Now....";
// Error handling
int err;
// Device to Write to
char *snd_device_out = "hw:0,0";
if ((err = snd_pcm_open (&playback_handle, snd_device_out, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf (stderr, "cannot open audio device %s (%s)\n",
snd_device_out,
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, 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 (playback_handle, hw_params, SND_PCM_FORMAT_U8)) < 0) { // Unsigned 8 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_near (playback_handle, hw_params, &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 (playback_handle, hw_params, 1)) < 0) { // 1 Channel Mono
fprintf (stderr, "cannot set channel count (%s)\n",
snd_strerror (err));
exit (1);
}
if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
fprintf (stderr, "cannot set parameters (%s)\n",
snd_strerror (err));
exit (1);
}
snd_pcm_hw_params_free (hw_params);
// Flush handle prepare for playback
snd_pcm_drop(playback_handle);
if ((err = snd_pcm_prepare (playback_handle)) < 0) {
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
snd_strerror (err));
exit (1);
}
qDebug() << "Done Setting up ALSA....";
}
// Grab the buffer
m_Buffer = buffer.data();
// Write the data to the ALSA device
int error;
for (int i = 0; i < 10; ++i) {
if ((error = snd_pcm_writei (playback_handle, m_Buffer, NOMINAL_AUDIO_BUFFER_SIZE)) != NOMINAL_AUDIO_BUFFER_SIZE) {
fprintf (stderr, "write to audio interface failed (%s)\n",
snd_strerror (error));
exit (1);
}
}
// Count up
m_NumberUDPPacketsReceived++;
}
請問您如何評論我如何重新取樣我收到的UDP樣本?我能不能只將ALSA設置爲我的配置,然後在每次從UDP接收更多音頻數據時寫入它的緩衝區?謝謝。 – PhilBot 2015-02-08 23:31:58
發送者和接收者的時鐘將以稍微不同的速率運行。 – 2015-02-09 07:33:29