2012-05-21 3 views
7

Моя цель - передать * .wav-файл по локальной сети без задержки или с минимальным.Как я могу воспроизводить потоковое аудио через Ethernet в Qt?

Также мы читаем файл на сервере mashin по частям 320 байт. После этого мы отправляем пакеты по Udp и записываем прием в jitter-buffer. Размер джиттер-буфера равен 10. Какие задержки я должен установить на таймеры для чистого звука.

здесь отправитель:

void MainWindow::on_start_tx_triggered() 
{ 
    timer1 = new QTimer (this); 
    udpSocketout = new QUdpSocket(this); 
    qDebug()<<"Start"; 
    for (int i = 0; i < playlist.size(); ++i) 
    { 
     inputFile.setFileName(playlist.at(i)); 
     qDebug()<<inputFile.fileName(); 
     if (!inputFile.open(QIODevice::ReadOnly)) 
     { 
      qDebug()<< "file not found;"; 
     } 
    } 
    connect(timer1, SIGNAL(timeout()),this, SLOT(writeDatagrams())); 
    timer1->start(5); 
} 

void MainWindow::writeDatagrams() 
{  
    if(!inputFile.atEnd()){ 
     payloadout = inputFile.read(320); 
    } 
    qDebug()<<payloadout; 
    QDataStream out(&datagramout, QIODevice::WriteOnly); 
    out.setVersion(QDataStream::Qt_4_7); 
    out << qint64(0); 
    out << payloadout; 
    out.device()->seek(qint64(0)); 
    out << qint64(datagramout.size() - sizeof(qint64)); 
    qint64 writtenBytes = udpSocketout->writeDatagram(datagramout, remoteHOST, remotePORT); 
    qDebug() << "Sent " << writtenBytes << " bytes."; 
} 

здесь приемник и проигрыватель:

void MainWindow::on_start_rx_triggered() 
{ 
    udpSocketin = new QUdpSocket(this); 
    udpSocketin->bind(localHOST, localPORT); 
    connect(udpSocketin, SIGNAL(readyRead()), 
      this, SLOT(readDatagrams())); 
    QDataStream out(&datagramout, QIODevice::WriteOnly); 
    out.setVersion(QDataStream::Qt_4_7); 
    timer2 = new QTimer (this); 
    connect(timer2, SIGNAL(timeout()),this, SLOT(playbuff())); 
    timer2->start(50); 
    audioout = new QAudioOutput(format, this); 
} 

void MainWindow::readDatagrams() 
{ 
    datagramin.resize(udpSocketin->pendingDatagramSize()); 
    qint64 receiveBytes = udpSocketin->readDatagram(datagramin.data(),datagramin.size()); 
    qDebug() << "Receive " << receiveBytes << " bytes."; 
    QDataStream in(&datagramin, QIODevice::ReadOnly); 
    in.setVersion(QDataStream::Qt_4_7); 
    quint64 size = 0; 
    if(in.device()->size() > sizeof(quint64)) 
    { 
     in >> size; 
    } 
    else return; 
    if(in.device()->size() < size) return; 
    in >> payloadin; 
    qDebug()<<payloadin.size(); 
    emit jitterbuff(); 
} 

void MainWindow::jitterbuff() 
{ 
    if (buff_pos < SIZE_OF_BUF) 
    { 
     QDataStream out(&buffered, QIODevice::WriteOnly); 
     out.setVersion(QDataStream::Qt_4_7); 
     out << payloadin; 
     buff_pos++; 
    } 
    else buff_pos=0; 
} 

void MainWindow::playbuff() 
{ 
    qDebug()<<"YES!!!"; 
    buffer = new QBuffer(&buffered); 
    buffer->open(QIODevice::ReadOnly); 
    audioout->start(buffer); 
    QEventLoop loop; 
    QTimer::singleShot(50,&loop,SLOT(quit())); 
    loop.exec(); 
    buffer->close(); 
} 
+0

Я не смотрел ваш код, потому что я не знаком с Qt, но некоторые общие замечания о передаче аудио через lans: 1. Хотя потеря пакетов низкая, вы все равно должны быть готовы к случайным потерям пакетов. 2. У меня нет большого опыта работы с lans, но я бы предположил, что вы можете получить около 100 мс латентности или меньше. –

+0

100 мс это так высокая латентность для потокового аудио ... Да, я готовлю к потере пакетов, потому что я использую UDP. Но я хочу получить четкий звук на выходе. Я использую данные буферизации (например, на last.fm это делает) – HoBBiT

+0

Также, как я понимаю, если я использую: sampleRate = 8000 кГц sampleSize = 8 бит и читать из файла 320 байтами, то у меня есть 5 мс звука в данных , например, размер буфера дрожания - 10 ячеек, тогда у меня есть задержка 5 * 10 мс для буфера дрожания + 5 мс при пакетировании. в результате у меня будет общая задержка в 55 мс. не так ли? Сообщите мне, если это неправильно. – HoBBiT

ответ

6

Эта проблема была решена. QAdioOutput имеет два режима: «push» и «pull». Я указываю на QIODevice и записываю данные прямо в это. Решение:

чтение UDP сокет:

void MainWindow::on_start_rx_triggered() 
{ 
    udpSocketin = new QUdpSocket(this); 
    udpSocketin->bind(localPORT); 
    connect(udpSocketin, SIGNAL(readyRead()),this, SLOT(readDatagrams())); 
    QDataStream out(&datagramout, QIODevice::WriteOnly); 
    out.setVersion(QDataStream::Qt_4_7); 
    timer2 = new QTimer (this); 
    connect(timer2, SIGNAL(timeout()),this, SLOT(playbuff())); 
    timer2->setInterval(15*9); 
    audioout = new QAudioOutput(format, this); 
    input = audioout->start(); 
    } 
void MainWindow::readDatagrams() 
    { 
     if (udpSocketin->hasPendingDatagrams()){ 
     datagramin.resize(udpSocketin->pendingDatagramSize()); 
     qint64 receiveBytes = udpSocketin->readDatagram(datagramin.data(),datagramin.size()); 
     if (receiveBytes<=0) 
     { 
      msg.warning(this,"File ERROR","The end!",QMessageBox::Ok); 
      emit on_stop_rx_triggered(); 
     } 
     QDataStream in(&datagramin, QIODevice::ReadOnly); 
     in.setVersion(QDataStream::Qt_4_7); 
     quint64 size = 0; 
     if(in.device()->size() > sizeof(quint64)) 
     { 
      in >> size; 
     } 
     else return; 
     in >> rxfilename; 
     in >> name; 
     in >> payloadin; 
    emit jitterbuff(); 
    } 
    void MainWindow::jitterbuff() 
     { 
      if (buff_pos < SIZE_OF_BUF) 
      { 
       buffered.append(payloadin); 
       buff_pos++; 
      } 
      else 
      { 
       timer2->start(); 
       buffered.clear(); 
       buff_pos=0; 
      } 
     } 

     void MainWindow::playbuff() 
     { 
      if (!buffered.isEmpty()) 
      { 
       buffer = new QBuffer(&buffered); 
       buffer->open(QIODevice::ReadOnly); 
       input->write(buffered); 
       buffer->close(); 
      } 
     } 

запись в сокет UDP:

void MainWindow::on_start_tx_triggered() 
{ 
    timer1 = new QTimer (this); 
    udpSocketout = new QUdpSocket(this); 
    inputFile.setFileName(playlist.at(playIDfile)); 
     if (!inputFile.open(QIODevice::ReadOnly)) 
     { 
      msg.warning(this,"File ERROR","File not found!",QMessageBox::Ok); 
      return; 
     } 
    fileinfo = new QFileInfo (inputFile); 
    txfilename = fileinfo->fileName(); 
    ui->playedFile->setText("Now played: " + txfilename); 
    connect(timer1, SIGNAL(timeout()),this, SLOT(writeDatagrams())); 
    timer1->start(15); 
} 
void MainWindow::writeDatagrams() 
{ 

    if(!inputFile.atEnd()){ 
     payloadout = inputFile.read(SIZE_OF_SOUND); 
     QDataStream out(&datagramout, QIODevice::WriteOnly); 
     out.setVersion(QDataStream::Qt_4_7); 
     out << qint64(0); 
     out << txfilename; 
     out << name; 
     out << payloadout; 
     out.device()->seek(qint64(0)); 
     out << qint64(datagramout.size() - sizeof(qint64)); 
     qint64 writtenBytes = udpSocketout->writeDatagram(datagramout, remoteHOST, remotePORT); 
    } 
} 

Если кто-то есть, кажется, проблема, я постараюсь помочь ему.

+0

Привет, я знаю, что это более 3 лет назад, но у вас все еще есть полный код проекта? Не могли бы вы поделиться со мной кодом? Спасибо. –

Смежные вопросы