parent
055315f411
commit
e70070c0d6
@ -0,0 +1,178 @@
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QAudioOutput>
|
||||
#include <QTime>
|
||||
|
||||
#include "audiooutput.h"
|
||||
|
||||
AudioOutput::AudioOutput(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
connect(&m_sndcpy, &QProcess::readyReadStandardOutput, this, [this]() {
|
||||
qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardOutput());
|
||||
});
|
||||
connect(&m_sndcpy, &QProcess::readyReadStandardError, this, [this]() {
|
||||
qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardError());
|
||||
});
|
||||
}
|
||||
|
||||
AudioOutput::~AudioOutput()
|
||||
{
|
||||
if (QProcess::NotRunning != m_sndcpy.state()) {
|
||||
m_sndcpy.kill();
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
bool AudioOutput::start(const QString& serial, int port)
|
||||
{
|
||||
if (m_running) {
|
||||
stop();
|
||||
}
|
||||
|
||||
QElapsedTimer timeConsumeCount;
|
||||
timeConsumeCount.start();
|
||||
bool ret = runSndcpyProcess(serial, port);
|
||||
qInfo() << "AudioOutput::run sndcpy cost:" << timeConsumeCount.elapsed() << "milliseconds";
|
||||
if (!ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
startAudioOutput();
|
||||
startRecvData(port);
|
||||
|
||||
m_running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioOutput::stop()
|
||||
{
|
||||
if (!m_running) {
|
||||
return;
|
||||
}
|
||||
m_running = false;
|
||||
|
||||
stopRecvData();
|
||||
stopAudioOutput();
|
||||
}
|
||||
|
||||
void AudioOutput::installonly(const QString &serial, int port)
|
||||
{
|
||||
runSndcpyProcess(serial, port);
|
||||
}
|
||||
|
||||
bool AudioOutput::runSndcpyProcess(const QString &serial, int port)
|
||||
{
|
||||
if (QProcess::NotRunning != m_sndcpy.state()) {
|
||||
m_sndcpy.kill();
|
||||
}
|
||||
|
||||
QStringList params;
|
||||
params << serial;
|
||||
params << QString("%1").arg(port);
|
||||
m_sndcpy.start("sndcpy.bat", params);
|
||||
/*
|
||||
if (!m_sndcpy.waitForStarted()) {
|
||||
qWarning() << "AudioOutput::start sndcpy.bat failed";
|
||||
return false;
|
||||
}
|
||||
if (!m_sndcpy.waitForFinished()) {
|
||||
qWarning() << "AudioOutput::sndcpy.bat crashed";
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void AudioOutput::startAudioOutput()
|
||||
{
|
||||
if (m_audioOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(48000);
|
||||
format.setChannelCount(2);
|
||||
format.setSampleSize(16);
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::UnSignedInt);
|
||||
|
||||
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
|
||||
if (!info.isFormatSupported(format)) {
|
||||
qWarning() << "AudioOutput::audio format not supported, cannot play audio.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_audioOutput = new QAudioOutput(format, this);
|
||||
connect(m_audioOutput, &QAudioOutput::stateChanged, this, [](QAudio::State state) {
|
||||
qInfo() << "AudioOutput::audio state changed:" << state;
|
||||
});
|
||||
m_audioOutput->setBufferSize(48000*2*15/1000 * 20);
|
||||
m_outputDevice = m_audioOutput->start();
|
||||
}
|
||||
|
||||
void AudioOutput::stopAudioOutput()
|
||||
{
|
||||
if (!m_audioOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_audioOutput->stop();
|
||||
delete m_audioOutput;
|
||||
m_audioOutput = nullptr;
|
||||
}
|
||||
|
||||
void AudioOutput::startRecvData(int port)
|
||||
{
|
||||
if (m_workerThread.isRunning()) {
|
||||
stopRecvData();
|
||||
}
|
||||
|
||||
auto audioSocket = new QTcpSocket();
|
||||
audioSocket->moveToThread(&m_workerThread);
|
||||
connect(&m_workerThread, &QThread::finished, audioSocket, &QObject::deleteLater);
|
||||
|
||||
connect(this, &AudioOutput::connectTo, audioSocket, [audioSocket](int port) {
|
||||
audioSocket->connectToHost(QHostAddress::LocalHost, port);
|
||||
if (!audioSocket->waitForConnected(500)) {
|
||||
qWarning("AudioOutput::audio socket connect failed");
|
||||
return;
|
||||
}
|
||||
qInfo("AudioOutput::audio socket connect success");
|
||||
});
|
||||
connect(audioSocket, &QIODevice::readyRead, audioSocket, [this, audioSocket]() {
|
||||
qint64 recv = audioSocket->bytesAvailable();
|
||||
//qDebug() << "AudioOutput::recv data:" << recv;
|
||||
|
||||
if (!m_outputDevice) {
|
||||
return;
|
||||
}
|
||||
if (m_buffer.capacity() < recv) {
|
||||
m_buffer.reserve(recv);
|
||||
}
|
||||
|
||||
qint64 count = audioSocket->read(m_buffer.data(), audioSocket->bytesAvailable());
|
||||
m_outputDevice->write(m_buffer.data(), count);
|
||||
});
|
||||
connect(audioSocket, &QTcpSocket::stateChanged, audioSocket, [](QAbstractSocket::SocketState state) {
|
||||
qInfo() << "AudioOutput::audio socket state changed:" << state;
|
||||
|
||||
});
|
||||
connect(audioSocket, &QTcpSocket::errorOccurred, audioSocket, [](QAbstractSocket::SocketError error) {
|
||||
qInfo() << "AudioOutput::audio socket error occurred:" << error;
|
||||
});
|
||||
|
||||
m_workerThread.start();
|
||||
emit connectTo(port);
|
||||
}
|
||||
|
||||
void AudioOutput::stopRecvData()
|
||||
{
|
||||
if (!m_workerThread.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_workerThread.quit();
|
||||
m_workerThread.wait();
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
#ifndef AUDIOOUTPUT_H
|
||||
#define AUDIOOUTPUT_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QProcess>
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
|
||||
class QAudioOutput;
|
||||
class QIODevice;
|
||||
class AudioOutput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioOutput(QObject *parent = nullptr);
|
||||
~AudioOutput();
|
||||
|
||||
bool start(const QString& serial, int port);
|
||||
void stop();
|
||||
void installonly(const QString& serial, int port);
|
||||
|
||||
private:
|
||||
bool runSndcpyProcess(const QString& serial, int port);
|
||||
void startAudioOutput();
|
||||
void stopAudioOutput();
|
||||
void startRecvData(int port);
|
||||
void stopRecvData();
|
||||
|
||||
signals:
|
||||
void connectTo(int port);
|
||||
|
||||
private:
|
||||
QAudioOutput* m_audioOutput = nullptr;
|
||||
QPointer<QIODevice> m_outputDevice;
|
||||
QThread m_workerThread;
|
||||
QProcess m_sndcpy;
|
||||
QVector<char> m_buffer;
|
||||
bool m_running = false;
|
||||
};
|
||||
|
||||
#endif // AUDIOOUTPUT_H
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,53 @@
|
||||
@echo off
|
||||
|
||||
echo Begin Runing...
|
||||
set SNDCPY_PORT=28200
|
||||
set SNDCPY_APK=sndcpy.apk
|
||||
set ADB=adb.exe
|
||||
|
||||
if not "%1"=="" (
|
||||
set serial=-s %1
|
||||
)
|
||||
if not "%2"=="" (
|
||||
set SNDCPY_PORT=%2
|
||||
)
|
||||
|
||||
echo Waiting for device %1...
|
||||
%ADB% %serial% wait-for-device || goto :error
|
||||
echo Find device %1
|
||||
|
||||
for /f "delims=" %%i in ('%ADB% %serial% shell pm path com.rom1v.sndcpy') do set sndcpy_installed=%%i
|
||||
if "%sndcpy_installed%"=="" (
|
||||
echo Install %SNDCPY_APK%...
|
||||
%ADB% %serial% uninstall com.rom1v.sndcpy || goto :error
|
||||
%ADB% %serial% install -t -r -g %SNDCPY_APK% || goto :error
|
||||
echo Install %SNDCPY_APK% success
|
||||
)
|
||||
|
||||
echo Request PROJECT_MEDIA permission...
|
||||
%ADB% %serial% shell appops set com.rom1v.sndcpy PROJECT_MEDIA allow
|
||||
|
||||
echo Forward port %SNDCPY_PORT%...
|
||||
%ADB% %serial% forward tcp:%SNDCPY_PORT% localabstract:sndcpy || goto :error
|
||||
|
||||
echo Start %SNDCPY_APK%...
|
||||
%ADB% %serial% shell am start com.rom1v.sndcpy/.MainActivity || goto :error
|
||||
|
||||
:check_start
|
||||
echo Waiting %SNDCPY_APK% start...
|
||||
::timeout /T 1 /NOBREAK > nul
|
||||
%ADB% %serial% shell sleep 0.1
|
||||
for /f "delims=" %%i in ("%ADB% shell 'ps | grep com.rom1v.sndcpy'") do set sndcpy_started=%%i
|
||||
if "%sndcpy_started%"=="" (
|
||||
goto :check_start
|
||||
)
|
||||
echo %SNDCPY_APK% started...
|
||||
|
||||
echo Ready playing...
|
||||
::vlc.exe -Idummy --demux rawaud --network-caching=0 --play-and-exit tcp://localhost:%SNDCPY_PORT%
|
||||
::ffplay.exe -nodisp -autoexit -probesize 32 -sync ext -f s16le -ar 48k -ac 2 tcp://localhost:%SNDCPY_PORT%
|
||||
goto :EOF
|
||||
|
||||
:error
|
||||
echo Failed with error #%errorlevel%.
|
||||
exit /b %errorlevel%
|
||||
Loading…
Reference in new issue