Skip to content

Commit

Permalink
Merge pull request #628 from barry-ran/dev
Browse files Browse the repository at this point in the history
sync
  • Loading branch information
barry-ran committed Jun 20, 2022
2 parents d5e915d + cfc1775 commit 5d62f85
Show file tree
Hide file tree
Showing 30 changed files with 757 additions and 257 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04]
os: [ubuntu-22.04]
qt-ver: [5.15.1]
qt-arch-install: [gcc_64]
gcc-arch: [x64]
Expand Down
25 changes: 23 additions & 2 deletions QtScrcpy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network Multimedia REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network Multimedia REQUIRED)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(QT NAMES Qt6 Qt5 COMPONENTS X11Extras REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
Expand Down Expand Up @@ -108,6 +108,13 @@ set(QC_UIBASE_SOURCES
)
source_group(uibase FILES ${QC_UIBASE_SOURCES})

# audio
set(QC_AUDIO_SOURCES
audio/audiooutput.h
audio/audiooutput.cpp
)
source_group(audio FILES ${QC_AUDIO_SOURCES})

# ui
set(QC_UI_SOURCES
ui/toolform.h
Expand Down Expand Up @@ -199,6 +206,7 @@ set(QC_PROJECT_SOURCES
${QC_MAIN_SOURCES}
${QC_GROUP_CONTROLLER}
${QC_PLANTFORM_SOURCES}
${QC_AUDIO_SOURCES}
)

if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
Expand Down Expand Up @@ -242,6 +250,11 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
get_target_property(QSC_BIN_OUTPUT_PATH ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY)
set(QSC_DEPLOY_PATH ${QSC_BIN_OUTPUT_PATH})

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.bat" "${QSC_BIN_OUTPUT_PATH}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.apk" "${QSC_BIN_OUTPUT_PATH}"
)
endif()

# MacOS
Expand All @@ -255,6 +268,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
# config file copy to Contents/MacOS/config
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../config/config.ini" "${MACOS_BUNDLE_PATH}/MacOS/config/config.ini"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.sh" "${MACOS_BUNDLE_PATH}/MacOS"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.apk" "${MACOS_BUNDLE_PATH}/MacOS"
)

# Step 2. ues MACOSX_PACKAGE_LOCATION copy icns to Resources
Expand Down Expand Up @@ -284,6 +299,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
get_target_property(QSC_BIN_OUTPUT_PATH ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY)
set(QSC_DEPLOY_PATH ${QSC_BIN_OUTPUT_PATH})

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.sh" "${QSC_BIN_OUTPUT_PATH}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/sndcpy/sndcpy.apk" "${QSC_BIN_OUTPUT_PATH}"
)

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

Expand All @@ -309,5 +329,6 @@ add_subdirectory(QtScrcpyCore)
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Multimedia
QtScrcpyCore
)
2 changes: 1 addition & 1 deletion QtScrcpy/QtScrcpyCore
Submodule QtScrcpyCore updated 108 files
197 changes: 197 additions & 0 deletions QtScrcpy/audio/audiooutput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include <QTcpSocket>
#include <QHostAddress>
#include <QAudioOutput>
#include <QTime>
#include <QElapsedTimer>

#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, false);
}

bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
{
if (QProcess::NotRunning != m_sndcpy.state()) {
m_sndcpy.kill();
}

#ifdef Q_OS_WIN32
QStringList params;
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("sndcpy.bat", params);
#else
QStringList params;
params << "sndcpy.sh";
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("bash", params);
#endif

if (!wait) {
return true;
}

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::SignedInt);

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;

});
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
connect(audioSocket, &QTcpSocket::errorOccurred, audioSocket, [](QAbstractSocket::SocketError error) {
qInfo() << "AudioOutput::audio socket error occurred:" << error;
});
#else
connect(audioSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), audioSocket, [](QAbstractSocket::SocketError error) {
qInfo() << "AudioOutput::audio socket error occurred:" << error;
});
#endif

m_workerThread.start();
emit connectTo(port);
}

void AudioOutput::stopRecvData()
{
if (!m_workerThread.isRunning()) {
return;
}

m_workerThread.quit();
m_workerThread.wait();
}
41 changes: 41 additions & 0 deletions QtScrcpy/audio/audiooutput.h
Original file line number Diff line number Diff line change
@@ -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, bool wait = true);
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
15 changes: 9 additions & 6 deletions QtScrcpy/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,24 @@ int main(int argc, char *argv[])
{
// set env
#ifdef Q_OS_WIN32
qputenv("QTSCRCPY_ADB_PATH", "D:/android/sdk/platform-tools/adb.exe");
qputenv("QTSCRCPY_ADB_PATH", "../../../QtScrcpy/QtScrcpyCore/src/third_party/adb/win/adb.exe");
qputenv("QTSCRCPY_SERVER_PATH", "../../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../keymap");
qputenv("QTSCRCPY_CONFIG_PATH", "../../../config");
#endif

#ifdef Q_OS_OSX
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../../keymap");
qputenv("QTSCRCPY_ADB_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/adb/mac/adb");
qputenv("QTSCRCPY_SERVER_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../../../keymap");
qputenv("QTSCRCPY_CONFIG_PATH", "../../../../../../config");
#endif

#ifdef Q_OS_LINUX
qputenv("QTSCRCPY_ADB_PATH", "../../QtScrcpy/QtScrcpyCore/src/third_party/adb/linux/adb");
qputenv("QTSCRCPY_SERVER_PATH", "../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server");
qputenv("QTSCRCPY_CONFIG_PATH", "../../config");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../keymap");
qputenv("QTSCRCPY_ADB_PATH", "../../../QtScrcpy/QtScrcpyCore/src/third_party/adb/linux/adb");
qputenv("QTSCRCPY_SERVER_PATH", "../../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../keymap");
qputenv("QTSCRCPY_CONFIG_PATH", "../../../config");
#endif

g_msgType = covertLogLevel(Config::getInstance().getLogLevel());
Expand Down
Binary file modified QtScrcpy/res/i18n/en_US.qm
Binary file not shown.

0 comments on commit 5d62f85

Please sign in to comment.