kopia lustrzana https://gitlab.com/eliggett/wfview
Stop audiohandler re-enumerating devices on connect.
rodzic
aab453a782
commit
0bbb9017c9
|
@ -758,7 +758,7 @@ audioHandler::~audioHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool ulaw, const bool isinput, QString port, quint8 resampleQuality)
|
bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool ulaw, const bool isinput, QAudioDeviceInfo port, quint8 resampleQuality)
|
||||||
{
|
{
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -789,14 +789,8 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16
|
||||||
if (isInput) {
|
if (isInput) {
|
||||||
resampler = wf_resampler_init(radioChannels, INTERNAL_SAMPLE_RATE, samplerate, resampleQuality, &resample_error);
|
resampler = wf_resampler_init(radioChannels, INTERNAL_SAMPLE_RATE, samplerate, resampleQuality, &resample_error);
|
||||||
|
|
||||||
const auto deviceInfos = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
|
isInitialized = setDevice(port);
|
||||||
for (const QAudioDeviceInfo& deviceInfo : deviceInfos) {
|
|
||||||
if (deviceInfo.deviceName() == port) {
|
|
||||||
qInfo(logAudio()) << "Input Audio Device name: " << deviceInfo.deviceName();
|
|
||||||
isInitialized = setDevice(deviceInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
qInfo(logAudio()) << "Input device " << deviceInfo.deviceName() << " not found, using default";
|
qInfo(logAudio()) << "Input device " << deviceInfo.deviceName() << " not found, using default";
|
||||||
isInitialized = setDevice(QAudioDeviceInfo::defaultInputDevice());
|
isInitialized = setDevice(QAudioDeviceInfo::defaultInputDevice());
|
||||||
|
@ -806,14 +800,8 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16
|
||||||
{
|
{
|
||||||
resampler = wf_resampler_init(radioChannels, samplerate, INTERNAL_SAMPLE_RATE, resampleQuality, &resample_error);
|
resampler = wf_resampler_init(radioChannels, samplerate, INTERNAL_SAMPLE_RATE, resampleQuality, &resample_error);
|
||||||
|
|
||||||
const auto deviceInfos = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
isInitialized = setDevice(port);
|
||||||
for (const QAudioDeviceInfo& deviceInfo : deviceInfos) {
|
|
||||||
if (deviceInfo.deviceName() == port) {
|
|
||||||
qInfo(logAudio()) << "Output Audio Device name: " << deviceInfo.deviceName();
|
|
||||||
isInitialized = setDevice(deviceInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
qInfo(logAudio()) << "Output device " << deviceInfo.deviceName() << " not found, using default";
|
qInfo(logAudio()) << "Output device " << deviceInfo.deviceName() << " not found, using default";
|
||||||
isInitialized = setDevice(QAudioDeviceInfo::defaultOutputDevice());
|
isInitialized = setDevice(QAudioDeviceInfo::defaultOutputDevice());
|
||||||
|
@ -823,7 +811,7 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16
|
||||||
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
|
wf_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
|
||||||
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "wf_resampler_init() returned: " << resample_error << " ratioNum" << ratioNum << " ratioDen" << ratioDen;
|
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "wf_resampler_init() returned: " << resample_error << " ratioNum" << ratioNum << " ratioDen" << ratioDen;
|
||||||
|
|
||||||
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "audio port name: " << port;
|
qInfo(logAudio()) << (isInput ? "Input" : "Output") << "audio port name: " << port.deviceName();
|
||||||
return isInitialized;
|
return isInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
void getNextAudioChunk(QByteArray &data);
|
void getNextAudioChunk(QByteArray &data);
|
||||||
bool isChunkAvailable();
|
bool isChunkAvailable();
|
||||||
public slots:
|
public slots:
|
||||||
bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isulaw, const bool isinput, QString port, quint8 resampleQuality);
|
bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isulaw, const bool isinput, QAudioDeviceInfo port, quint8 resampleQuality);
|
||||||
void incomingAudio(const audioPacket data);
|
void incomingAudio(const audioPacket data);
|
||||||
void changeLatency(const quint16 newSize);
|
void changeLatency(const quint16 newSize);
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ udpHandler::udpHandler(udpPreferences prefs) :
|
||||||
txLatency(prefs.audioTXLatency),
|
txLatency(prefs.audioTXLatency),
|
||||||
rxCodec(prefs.audioRXCodec),
|
rxCodec(prefs.audioRXCodec),
|
||||||
txCodec(prefs.audioTXCodec),
|
txCodec(prefs.audioTXCodec),
|
||||||
audioInputPort(prefs.audioInput),
|
audioInputPort(prefs.inputDevice),
|
||||||
audioOutputPort(prefs.audioOutput),
|
audioOutputPort(prefs.outputDevice),
|
||||||
resampleQuality(prefs.resampleQuality)
|
resampleQuality(prefs.resampleQuality)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -687,7 +687,7 @@ void udpCivData::dataReceived()
|
||||||
|
|
||||||
|
|
||||||
// Audio stream
|
// Audio stream
|
||||||
udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, QString outputPort, QString inputPort,quint8 resampleQuality)
|
udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, QAudioDeviceInfo outputPort, QAudioDeviceInfo inputPort,quint8 resampleQuality)
|
||||||
{
|
{
|
||||||
qInfo(logUdp()) << "Starting udpAudio";
|
qInfo(logUdp()) << "Starting udpAudio";
|
||||||
this->localIP = local;
|
this->localIP = local;
|
||||||
|
@ -736,7 +736,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
|
||||||
|
|
||||||
rxAudioThread->start();
|
rxAudioThread->start();
|
||||||
|
|
||||||
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool,QString, quint8)));
|
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, QAudioDeviceInfo, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool,QAudioDeviceInfo, quint8)));
|
||||||
|
|
||||||
connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket)));
|
connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket)));
|
||||||
connect(this, SIGNAL(haveChangeLatency(quint16)), rxaudio, SLOT(changeLatency(quint16)));
|
connect(this, SIGNAL(haveChangeLatency(quint16)), rxaudio, SLOT(changeLatency(quint16)));
|
||||||
|
@ -758,7 +758,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint
|
||||||
|
|
||||||
txAudioThread->start();
|
txAudioThread->start();
|
||||||
|
|
||||||
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool,QString,quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool,QString,quint8)));
|
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool,QAudioDeviceInfo,quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool,QAudioDeviceInfo,quint8)));
|
||||||
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
||||||
|
|
||||||
sendControl(false, 0x03, 0x00); // First connect packet
|
sendControl(false, 0x03, 0x00); // First connect packet
|
||||||
|
|
12
udphandler.h
12
udphandler.h
|
@ -43,6 +43,8 @@ struct udpPreferences {
|
||||||
QString password;
|
QString password;
|
||||||
QString audioOutput;
|
QString audioOutput;
|
||||||
QString audioInput;
|
QString audioInput;
|
||||||
|
QAudioDeviceInfo inputDevice;
|
||||||
|
QAudioDeviceInfo outputDevice;
|
||||||
quint16 audioRXLatency;
|
quint16 audioRXLatency;
|
||||||
quint16 audioTXLatency;
|
quint16 audioTXLatency;
|
||||||
quint16 audioRXSampleRate;
|
quint16 audioRXSampleRate;
|
||||||
|
@ -172,14 +174,14 @@ class udpAudio : public udpBase
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, QString outputPort, QString inputPort,quint8 resampleQuality);
|
udpAudio(QHostAddress local, QHostAddress ip, quint16 aport, quint16 rxlatency, quint16 txlatency, quint16 rxsample, quint8 rxcodec, quint16 txsample, quint8 txcodec, QAudioDeviceInfo outputPort, QAudioDeviceInfo inputPort,quint8 resampleQuality);
|
||||||
~udpAudio();
|
~udpAudio();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void haveAudioData(audioPacket data);
|
void haveAudioData(audioPacket data);
|
||||||
|
|
||||||
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QAudioDeviceInfo port, quint8 resampleQuality);
|
||||||
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QAudioDeviceInfo port, quint8 resampleQuality);
|
||||||
|
|
||||||
void haveChangeLatency(quint16 value);
|
void haveChangeLatency(quint16 value);
|
||||||
void haveSetVolume(unsigned char value);
|
void haveSetVolume(unsigned char value);
|
||||||
|
@ -286,8 +288,8 @@ private:
|
||||||
quint8 rxCodec;
|
quint8 rxCodec;
|
||||||
quint8 txCodec;
|
quint8 txCodec;
|
||||||
|
|
||||||
QString audioInputPort;
|
QAudioDeviceInfo audioInputPort;
|
||||||
QString audioOutputPort;
|
QAudioDeviceInfo audioOutputPort;
|
||||||
|
|
||||||
quint8 resampleQuality;
|
quint8 resampleQuality;
|
||||||
|
|
||||||
|
|
|
@ -392,10 +392,10 @@ void udpServer::controlReceived()
|
||||||
|
|
||||||
txAudioThread->start();
|
txAudioThread->start();
|
||||||
|
|
||||||
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)));
|
connect(this, SIGNAL(setupTxAudio(quint8, quint8, quint16, quint16, bool, bool, QAudioDeviceInfo, quint8)), txaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QAudioDeviceInfo, quint8)));
|
||||||
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater()));
|
||||||
|
|
||||||
emit setupTxAudio(samples, channels, current->txSampleRate, current->txBufferLen, uLaw, false, config.audioOutput, config.resampleQuality);
|
emit setupTxAudio(samples, channels, current->txSampleRate, current->txBufferLen, uLaw, false, config.outputDevice, config.resampleQuality);
|
||||||
hasTxAudio=datagram.senderAddress();
|
hasTxAudio=datagram.senderAddress();
|
||||||
|
|
||||||
connect(this, SIGNAL(haveAudioData(audioPacket)), txaudio, SLOT(incomingAudio(audioPacket)));
|
connect(this, SIGNAL(haveAudioData(audioPacket)), txaudio, SLOT(incomingAudio(audioPacket)));
|
||||||
|
@ -425,10 +425,10 @@ void udpServer::controlReceived()
|
||||||
rxaudio->moveToThread(rxAudioThread);
|
rxaudio->moveToThread(rxAudioThread);
|
||||||
rxAudioThread->start();
|
rxAudioThread->start();
|
||||||
|
|
||||||
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QString, quint8)));
|
connect(this, SIGNAL(setupRxAudio(quint8, quint8, quint16, quint16, bool, bool, QAudioDeviceInfo, quint8)), rxaudio, SLOT(init(quint8, quint8, quint16, quint16, bool, bool, QAudioDeviceInfo, quint8)));
|
||||||
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
|
connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater()));
|
||||||
|
|
||||||
emit setupRxAudio(samples, channels, current->rxSampleRate, 150, uLaw, true, config.audioInput, config.resampleQuality);
|
emit setupRxAudio(samples, channels, current->rxSampleRate, 150, uLaw, true, config.inputDevice, config.resampleQuality);
|
||||||
|
|
||||||
rxAudioTimer = new QTimer();
|
rxAudioTimer = new QTimer();
|
||||||
rxAudioTimer->setTimerType(Qt::PreciseTimer);
|
rxAudioTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
|
|
@ -50,8 +50,8 @@ public slots:
|
||||||
signals:
|
signals:
|
||||||
void haveDataFromServer(QByteArray);
|
void haveDataFromServer(QByteArray);
|
||||||
void haveAudioData(audioPacket data);
|
void haveAudioData(audioPacket data);
|
||||||
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
void setupTxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QAudioDeviceInfo port, quint8 resampleQuality);
|
||||||
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QString port, quint8 resampleQuality);
|
void setupRxAudio(const quint8 samples, const quint8 channels, const quint16 samplerate, const quint16 latency, const bool isUlaw, const bool isInput, QAudioDeviceInfo port, quint8 resampleQuality);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QAudioDeviceInfo>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
@ -22,6 +23,8 @@ struct SERVERCONFIG {
|
||||||
quint16 audioPort;
|
quint16 audioPort;
|
||||||
QString audioOutput;
|
QString audioOutput;
|
||||||
QString audioInput;
|
QString audioInput;
|
||||||
|
QAudioDeviceInfo inputDevice;
|
||||||
|
QAudioDeviceInfo outputDevice;
|
||||||
quint8 resampleQuality;
|
quint8 resampleQuality;
|
||||||
quint32 baudRate;
|
quint32 baudRate;
|
||||||
|
|
||||||
|
|
14
wfmain.cpp
14
wfmain.cpp
|
@ -171,11 +171,11 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
|
||||||
// Enumerate audio devices, need to do before settings are loaded.
|
// Enumerate audio devices, need to do before settings are loaded.
|
||||||
const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
const auto audioOutputs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
|
||||||
for (const QAudioDeviceInfo& deviceInfo : audioOutputs) {
|
for (const QAudioDeviceInfo& deviceInfo : audioOutputs) {
|
||||||
ui->audioOutputCombo->addItem(deviceInfo.deviceName());
|
ui->audioOutputCombo->addItem(deviceInfo.deviceName(),QVariant::fromValue(deviceInfo));
|
||||||
}
|
}
|
||||||
const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
|
const auto audioInputs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
|
||||||
for (const QAudioDeviceInfo& deviceInfo : audioInputs) {
|
for (const QAudioDeviceInfo& deviceInfo : audioInputs) {
|
||||||
ui->audioInputCombo->addItem(deviceInfo.deviceName());
|
ui->audioInputCombo->addItem(deviceInfo.deviceName(),QVariant::fromValue(deviceInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->serialDeviceListCombo->blockSignals(true);
|
ui->serialDeviceListCombo->blockSignals(true);
|
||||||
|
@ -266,6 +266,8 @@ wfmain::wfmain(const QString serialPortCL, const QString hostCL, const QString s
|
||||||
serverConfig.audioInput = udpPrefs.audioInput;
|
serverConfig.audioInput = udpPrefs.audioInput;
|
||||||
serverConfig.audioOutput = udpPrefs.audioOutput;
|
serverConfig.audioOutput = udpPrefs.audioOutput;
|
||||||
serverConfig.baudRate = prefs.serialPortBaud;
|
serverConfig.baudRate = prefs.serialPortBaud;
|
||||||
|
serverConfig.inputDevice = udpPrefs.inputDevice;
|
||||||
|
serverConfig.outputDevice = udpPrefs.outputDevice;
|
||||||
}
|
}
|
||||||
udp = new udpServer(serverConfig);
|
udp = new udpServer(serverConfig);
|
||||||
|
|
||||||
|
@ -1116,6 +1118,8 @@ void wfmain::loadSettings()
|
||||||
int audioOutputIndex = ui->audioOutputCombo->findText(udpPrefs.audioOutput);
|
int audioOutputIndex = ui->audioOutputCombo->findText(udpPrefs.audioOutput);
|
||||||
if (audioOutputIndex != -1) {
|
if (audioOutputIndex != -1) {
|
||||||
ui->audioOutputCombo->setCurrentIndex(audioOutputIndex);
|
ui->audioOutputCombo->setCurrentIndex(audioOutputIndex);
|
||||||
|
QVariant v = ui->audioOutputCombo->currentData();
|
||||||
|
udpPrefs.outputDevice = v.value<QAudioDeviceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
udpPrefs.audioInput = settings->value("AudioInput", udpDefPrefs.audioInput).toString();
|
udpPrefs.audioInput = settings->value("AudioInput", udpDefPrefs.audioInput).toString();
|
||||||
|
@ -1124,6 +1128,8 @@ void wfmain::loadSettings()
|
||||||
int audioInputIndex = ui->audioInputCombo->findText(udpPrefs.audioInput);
|
int audioInputIndex = ui->audioInputCombo->findText(udpPrefs.audioInput);
|
||||||
if (audioInputIndex != -1) {
|
if (audioInputIndex != -1) {
|
||||||
ui->audioInputCombo->setCurrentIndex(audioInputIndex);
|
ui->audioInputCombo->setCurrentIndex(audioInputIndex);
|
||||||
|
QVariant v = ui->audioInputCombo->currentData();
|
||||||
|
udpPrefs.inputDevice = v.value<QAudioDeviceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
udpPrefs.resampleQuality = settings->value("ResampleQuality", udpDefPrefs.resampleQuality).toInt();
|
udpPrefs.resampleQuality = settings->value("ResampleQuality", udpDefPrefs.resampleQuality).toInt();
|
||||||
|
@ -3536,11 +3542,15 @@ void wfmain::on_passwordTxt_textChanged(QString text)
|
||||||
void wfmain::on_audioOutputCombo_currentIndexChanged(QString text)
|
void wfmain::on_audioOutputCombo_currentIndexChanged(QString text)
|
||||||
{
|
{
|
||||||
udpPrefs.audioOutput = text;
|
udpPrefs.audioOutput = text;
|
||||||
|
QVariant v = ui->audioOutputCombo->currentData();
|
||||||
|
udpPrefs.outputDevice = v.value<QAudioDeviceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wfmain::on_audioInputCombo_currentIndexChanged(QString text)
|
void wfmain::on_audioInputCombo_currentIndexChanged(QString text)
|
||||||
{
|
{
|
||||||
udpPrefs.audioInput = text;
|
udpPrefs.audioInput = text;
|
||||||
|
QVariant v = ui->audioInputCombo->currentData();
|
||||||
|
udpPrefs.inputDevice = v.value<QAudioDeviceInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text)
|
void wfmain::on_audioSampleRateCombo_currentIndexChanged(QString text)
|
||||||
|
|
Ładowanie…
Reference in New Issue