Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorvald Natvig <slicer@users.sourceforge.net>2009-08-21 03:29:48 +0400
committerThorvald Natvig <slicer@users.sourceforge.net>2009-08-21 03:29:48 +0400
commit6479de347fa69a3872d6073a74eebf81f1ffa819 (patch)
tree492ba77858f876b97952627f8724141b81d62d5b /src
parent4ff39930dc8a91521d6217faca3b8f05253a4614 (diff)
Low bandwidth mode
Diffstat (limited to 'src')
-rw-r--r--src/Message.h2
-rw-r--r--src/mumble/Audio.cpp10
-rw-r--r--src/mumble/AudioInput.cpp177
-rw-r--r--src/mumble/AudioInput.h17
-rw-r--r--src/mumble/AudioOutput.cpp78
-rw-r--r--src/mumble/AudioOutput.h9
-rw-r--r--src/mumble/Global.cpp2
-rw-r--r--src/mumble/MainWindow.cpp10
-rw-r--r--src/mumble/Messages.cpp10
-rw-r--r--src/mumble/ServerHandler.cpp21
-rw-r--r--src/mumble/ServerHandler.h2
-rw-r--r--src/mumble/Settings.cpp2
-rw-r--r--src/mumble/WASAPI.cpp1
-rw-r--r--src/mumble/mumble.pro2
-rw-r--r--src/mumble/mumble_pch.hpp4
15 files changed, 251 insertions, 96 deletions
diff --git a/src/Message.h b/src/Message.h
index 2f4291c34..4eee97d69 100644
--- a/src/Message.h
+++ b/src/Message.h
@@ -58,7 +58,7 @@
class MessageHandler {
public:
- enum UDPMessageType { UDPVoice, UDPPing };
+ enum UDPMessageType { UDPVoiceCELT, UDPPing, UDPVoiceSpeex };
#define MUMBLE_MH_MSG(x) x,
enum MessageType {
diff --git a/src/mumble/Audio.cpp b/src/mumble/Audio.cpp
index 6c266d788..767968e65 100644
--- a/src/mumble/Audio.cpp
+++ b/src/mumble/Audio.cpp
@@ -77,7 +77,8 @@ void LoopUser::addFrame(const QByteArray &packet) {
if (qtLastFetch.elapsed() > 100) {
AudioOutputPtr ao = g.ao;
if (ao) {
- ao->addFrameToBuffer(this, QByteArray(), 0);
+ MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((packet.at(0) >> 5) & 0x7);
+ ao->addFrameToBuffer(this, QByteArray(), 0, msgType);
}
}
@@ -87,8 +88,9 @@ void LoopUser::fetchFrames() {
QMutexLocker l(&qmLock);
AudioOutputPtr ao = g.ao;
- if (!ao || qmPackets.isEmpty())
+ if (!ao || qmPackets.isEmpty()) {
return;
+ }
double cmp = qtTicker.elapsed();
@@ -111,7 +113,9 @@ void LoopUser::fetchFrames() {
qba.append(static_cast<char>(msgFlags));
qba.append(pds.dataBlock(pds.left()));
- ao->addFrameToBuffer(this, qba, iSeq);
+ MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((msgFlags >> 5) & 0x7);
+
+ ao->addFrameToBuffer(this, qba, iSeq, msgType);
i = qmPackets.erase(i);
}
diff --git a/src/mumble/AudioInput.cpp b/src/mumble/AudioInput.cpp
index 611046fa1..577f2276c 100644
--- a/src/mumble/AudioInput.cpp
+++ b/src/mumble/AudioInput.cpp
@@ -84,9 +84,51 @@ AudioInputPtr AudioInputRegistrar::newFromChoice(QString choice) {
AudioInput::AudioInput() {
- iFrameSize = SAMPLE_RATE / 100;
- cmMode = celt_mode_create(SAMPLE_RATE, 1, iFrameSize, NULL);
- ceEncoder = celt_encoder_create(cmMode);
+ adjustBandwidth(g.iMaxBandwidth, iAudioQuality, iAudioFrames);
+
+ if (preferCELT(iAudioQuality, iAudioFrames))
+ umtType = MessageHandler::UDPVoiceCELT;
+ else
+ umtType = MessageHandler::UDPVoiceSpeex;
+
+ if (umtType == MessageHandler::UDPVoiceCELT) {
+ iSampleRate = SAMPLE_RATE;
+ iFrameSize = SAMPLE_RATE / 100;
+
+ cmMode = celt_mode_create(SAMPLE_RATE, 1, iFrameSize, NULL);
+ ceEncoder = celt_encoder_create(cmMode);
+ esSpeex = NULL;
+ qWarning("AudioInput: %d bits/s, %d hz, %d sample CELT", iAudioQuality, iSampleRate, iFrameSize);
+ } else {
+ cmMode = NULL;
+ ceEncoder = NULL;
+
+ iAudioFrames /= 2;
+
+ speex_bits_init(&sbBits);
+ speex_bits_reset(&sbBits);
+ esSpeex = speex_encoder_init(&speex_uwb_mode);
+ speex_encoder_ctl(esSpeex,SPEEX_GET_FRAME_SIZE,&iFrameSize);
+ speex_encoder_ctl(esSpeex,SPEEX_GET_SAMPLING_RATE,&iSampleRate);
+
+ int iArg=1;
+ speex_encoder_ctl(esSpeex,SPEEX_SET_VBR, &iArg);
+
+ iArg = 0;
+ speex_encoder_ctl(esSpeex,SPEEX_SET_VAD, &iArg);
+ speex_encoder_ctl(esSpeex,SPEEX_SET_DTX, &iArg);
+
+ float fArg=8.0;
+ speex_encoder_ctl(esSpeex,SPEEX_SET_VBR_QUALITY, &fArg);
+
+ iArg = iAudioQuality;
+ speex_encoder_ctl(esSpeex, SPEEX_SET_VBR_MAX_BITRATE, &iArg);
+
+ iArg = 5;
+ speex_encoder_ctl(esSpeex,SPEEX_SET_COMPLEXITY, &iArg);
+ qWarning("AudioInput: %d bits/s, %d hz, %d sample Speex-UWB", iAudioQuality, iSampleRate, iFrameSize);
+ }
+ iEchoFreq = iMicFreq = iSampleRate;
mumble_drft_init(&fftTable, iFrameSize);
@@ -115,7 +157,6 @@ AudioInput::AudioInput() {
psSpeaker = NULL;
iEchoChannels = iMicChannels = 0;
- iEchoFreq = iMicFreq = SAMPLE_RATE;
iEchoFilled = iMicFilled = 0;
eMicFormat = eEchoFormat = SampleFloat;
iMicSampleSize = iEchoSampleSize = 0;
@@ -133,11 +174,6 @@ AudioInput::AudioInput() {
bRunning = false;
- if (g.sh && g.sh->isRunning())
- setMaxBandwidth(g.iMaxBandwidth);
- else
- iAudioQuality = g.s.iQuality;
-
connect(this, SIGNAL(doMute()), g.mw->qaAudioMute, SLOT(trigger()), Qt::QueuedConnection);
}
@@ -145,8 +181,13 @@ AudioInput::~AudioInput() {
bRunning = false;
wait();
- celt_encoder_destroy(ceEncoder);
- celt_mode_destroy(cmMode);
+ if (umtType == MessageHandler::UDPVoiceCELT) {
+ celt_encoder_destroy(ceEncoder);
+ celt_mode_destroy(cmMode);
+ } else {
+ speex_bits_destroy(&sbBits);
+ speex_encoder_destroy(esSpeex);
+ }
mumble_drft_clear(&fftTable);
jitter_buffer_destroy(jb);
@@ -300,10 +341,10 @@ void AudioInput::initializeMixer() {
if (pfOutput)
delete [] pfOutput;
- if (iMicFreq != SAMPLE_RATE)
- srsMic = speex_resampler_init(1, iMicFreq, SAMPLE_RATE, 3, &err);
+ if (iMicFreq != iSampleRate)
+ srsMic = speex_resampler_init(1, iMicFreq, iSampleRate, 3, &err);
- iMicLength = (iFrameSize * iMicFreq) / SAMPLE_RATE;
+ iMicLength = (iFrameSize * iMicFreq) / iSampleRate;
pfMicInput = new float[iMicLength];
pfOutput = new float[iFrameSize * qMax(1U,iEchoChannels)];
@@ -311,9 +352,9 @@ void AudioInput::initializeMixer() {
if (iEchoChannels > 0) {
psSpeaker = new short[iFrameSize * iEchoChannels];
bEchoMulti = g.s.bEchoMulti;
- if (iEchoFreq != SAMPLE_RATE)
- srsEcho = speex_resampler_init(bEchoMulti ? iEchoChannels : 1, iEchoFreq, SAMPLE_RATE, 3, &err);
- iEchoLength = (iFrameSize * iEchoFreq) / SAMPLE_RATE;
+ if (iEchoFreq != iSampleRate)
+ srsEcho = speex_resampler_init(bEchoMulti ? iEchoChannels : 1, iEchoFreq, iSampleRate, 3, &err);
+ iEchoLength = (iFrameSize * iEchoFreq) / iSampleRate;
iEchoMCLength = bEchoMulti ? iEchoLength * iEchoChannels : iEchoLength;
iEchoFrameSize = bEchoMulti ? iFrameSize * iEchoChannels : iFrameSize;
pfEchoInput = new float[iEchoMCLength];
@@ -433,31 +474,69 @@ void AudioInput::addEcho(const void *data, unsigned int nsamp) {
}
}
-int AudioInput::getMaxBandwidth() {
- // Overhead
- int overhead = 20 + 8 + 4 + 1 + 2;
-
- if (g.s.bTransmitPosition)
- overhead += 12;
+bool AudioInput::preferCELT(int bitrate, int frames) {
+ return ((bitrate >= 32000) || (frames == 1));
+}
- if (NetworkConfig::TcpModeEnabled())
- overhead += 12;
+void AudioInput::adjustBandwidth(int bitspersec, int &bitrate, int &frames) {
+ frames = g.s.iFramesPerPacket;
+ bitrate = g.s.iQuality;
- return (g.s.iQuality / 8) + (overhead * 100/g.s.iFramesPerPacket);
+ if (bitspersec == -1) {
+ // No limit
+ } else {
+ if (getNetworkBandwidth(bitrate, frames) >= bitspersec) {
+ if ((frames <= 4) && (bitspersec <= 32000))
+ frames = 4;
+ else if ((frames == 1) && (bitspersec <= 64000))
+ frames = 2;
+ else if ((frames == 2) && (bitspersec <= 48000))
+ frames = 4;
+ if (getNetworkBandwidth(bitrate, frames) >= bitspersec) {
+ do {
+ bitrate -= 1000;
+ } while ((bitrate > 8000) && (getNetworkBandwidth(bitrate, frames) >= bitspersec));
+ }
+ }
+ }
}
-void AudioInput::setMaxBandwidth(int bytespersec) {
- int overhead = 20 + 8 + 4 + 1 + 2 + (g.s.bTransmitPosition ? 12 : 0) + (NetworkConfig::TcpModeEnabled() ? 12 : 0);
- overhead *= (100 / g.s.iFramesPerPacket);
+void AudioInput::setMaxBandwidth(int bitspersec) {
+ if (bitspersec == g.iMaxBandwidth)
+ return;
- bytespersec -= overhead;
+ int frames;
+ int bitrate;
+ adjustBandwidth(bitspersec, bitrate, frames);
+
+ g.iMaxBandwidth = bitspersec;
+ g.iAudioBandwidth = bitrate;
+
+ if (bitspersec != -1) {
+ if ((bitrate != g.s.iQuality) || (frames != g.s.iFramesPerPacket))
+ g.mw->msgBox(tr("Server maximum network bandwidth is only %1 kbit/s. Audio quality auto-adjusted to %2 kbit/s (%3ms)").arg(bitspersec / 1000).arg(bitrate / 10000).arg(frames*10));
+ }
+
+ AudioInputPtr ai = g.ai;
+ if (ai && (preferCELT(bitrate, frames) == (ai->umtType == MessageHandler::UDPVoiceCELT))) {
+ ai->iAudioQuality = bitrate;
+ ai->iAudioFrames = frames;
+ return;
+ }
+ g.ai.reset();
+ while (! ai.unique()) {}
+ ai.reset();
+ g.ai = AudioInputRegistrar::newFromChoice(g.s.qsAudioInput);
+ if (g.ai)
+ g.ai->start(QThread::HighestPriority);
+}
- int target = qMin(bytespersec * 8, g.s.iQuality);
- if (target < 16000)
- target = 16000;
+int AudioInput::getNetworkBandwidth(int bitrate, int frames) {
+ int overhead = 20 + 8 + 4 + 1 + 2 + (g.s.bTransmitPosition ? 12 : 0) + (NetworkConfig::TcpModeEnabled() ? 12 : 0);
+ overhead *= (800 / frames);
+ int bw = overhead + bitrate;
- g.iAudioBandwidth = (target/8 + overhead);
- iAudioQuality = target;
+ return bw;
}
@@ -558,7 +637,7 @@ void AudioInput::encodeAudioFrame() {
if (sesEcho)
speex_echo_state_destroy(sesEcho);
- sppPreprocess = speex_preprocess_state_init(iFrameSize, SAMPLE_RATE);
+ sppPreprocess = speex_preprocess_state_init(iFrameSize, iSampleRate);
iArg = 1;
speex_preprocess_ctl(sppPreprocess, SPEEX_PREPROCESS_SET_VAD, &iArg);
@@ -578,7 +657,7 @@ void AudioInput::encodeAudioFrame() {
if (iEchoChannels > 0) {
sesEcho = speex_echo_state_init_mc(iFrameSize, iFrameSize*10, 1, bEchoMulti ? iEchoChannels : 1);
- iArg = SAMPLE_RATE;
+ iArg = iSampleRate;
speex_echo_ctl(sesEcho, SPEEX_ECHO_SET_SAMPLING_RATE, &iArg);
speex_preprocess_ctl(sppPreprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, sesEcho);
@@ -676,15 +755,27 @@ void AudioInput::encodeAudioFrame() {
*/
unsigned char buffer[512];
+ int len;
- celt_encoder_ctl(ceEncoder,CELT_SET_VBR_RATE(iAudioQuality));
-
+ if (umtType == MessageHandler::UDPVoiceCELT) {
+ celt_encoder_ctl(ceEncoder,CELT_SET_VBR_RATE(iAudioQuality));
+ len = celt_encode(ceEncoder, psSource, NULL, buffer, qMin(iAudioQuality / 800, 127));
+ } else {
+ int vbr = 0;
+ speex_encoder_ctl(esSpeex, SPEEX_GET_VBR_MAX_BITRATE, &vbr);
+ if (vbr != iAudioQuality) {
+ vbr = iAudioQuality;
+ speex_encoder_ctl(esSpeex, SPEEX_SET_VBR_MAX_BITRATE, &vbr);
+ }
- int len = celt_encode(ceEncoder, psSource, NULL, buffer, qMin(iAudioQuality / 800, 127));
+ speex_encode_int(esSpeex, psSource, &sbBits);
+ len = speex_bits_write(&sbBits, reinterpret_cast<char *>(buffer), 127);
+ speex_bits_reset(&sbBits);
+ }
iBitrate = len * 100 * 8;
-
flushCheck(QByteArray(reinterpret_cast<const char *>(buffer), len), ! iIsSpeech);
+
if (! iIsSpeech)
iBitrate = 0;
@@ -693,13 +784,15 @@ void AudioInput::encodeAudioFrame() {
void AudioInput::flushCheck(const QByteArray &qba, bool terminator) {
qlFrames << qba;
- if (! terminator && qlFrames.count() < g.s.iFramesPerPacket)
+ if (! terminator && qlFrames.count() < iAudioFrames)
return;
int flags = g.iTarget;
if (g.s.lmLoopMode == Settings::Server)
flags = 0x1f;
+ flags |= (umtType << 5);
+
char data[1024];
data[0] = static_cast<unsigned char>(flags);
diff --git a/src/mumble/AudioInput.h b/src/mumble/AudioInput.h
index 9740a78fd..a4375c202 100644
--- a/src/mumble/AudioInput.h
+++ b/src/mumble/AudioInput.h
@@ -34,6 +34,7 @@
#include "Audio.h"
#include "Settings.h"
#include "Timer.h"
+#include "Message.h"
#include "smallft.h"
class AudioInput;
@@ -63,11 +64,11 @@ class AudioInput : public QThread {
friend class AudioEchoWidget;
friend class AudioStats;
friend class AudioInputDialog;
- friend class FMODSystem;
private:
Q_OBJECT
Q_DISABLE_COPY(AudioInput)
protected:
+ typedef enum { CodecCELT, CodecSpeex } CodecFormat;
typedef enum { SampleShort, SampleFloat } SampleFormat;
typedef void (*inMixerFunc)(float * RESTRICT, const void * RESTRICT, unsigned int, unsigned int);
private:
@@ -78,8 +79,10 @@ class AudioInput : public QThread {
inMixerFunc imfMic, imfEcho;
inMixerFunc chooseMixer(const unsigned int nchan, SampleFormat sf);
protected:
+ MessageHandler::UDPMessageType umtType;
SampleFormat eMicFormat, eEchoFormat;
+ unsigned int iSampleRate;
unsigned int iMicChannels, iEchoChannels;
unsigned int iMicFreq, iEchoFreq;
unsigned int iMicLength, iEchoLength;
@@ -95,7 +98,12 @@ class AudioInput : public QThread {
CELTMode *cmMode;
CELTEncoder *ceEncoder;
+
+ SpeexBits sbBits;
+ void *esSpeex;
+
int iAudioQuality;
+ int iAudioFrames;
drft_lookup fftTable;
@@ -122,6 +130,9 @@ class AudioInput : public QThread {
void flushCheck(const QByteArray &, bool terminator);
void initializeMixer();
+
+ static bool preferCELT(int bitrate, int frames);
+ static void adjustBandwidth(int bitspersec, int &bitrate, int &frames);
signals:
void doMute();
public:
@@ -137,8 +148,8 @@ class AudioInput : public QThread {
return bPreviousVoice;
};
- static int getMaxBandwidth();
- void setMaxBandwidth(int bytespersec);
+ static int getNetworkBandwidth(int bitrate, int frames);
+ static void setMaxBandwidth(int bitspersec);
AudioInput();
~AudioInput();
diff --git a/src/mumble/AudioOutput.cpp b/src/mumble/AudioOutput.cpp
index 834f35d2a..e81b5509a 100644
--- a/src/mumble/AudioOutput.cpp
+++ b/src/mumble/AudioOutput.cpp
@@ -345,20 +345,39 @@ bool AudioOutputSample::needSamples(unsigned int snum) {
return !eof;
}
-AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq) : AudioOutputUser(user->qsName) {
+AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq, MessageHandler::UDPMessageType type) : AudioOutputUser(user->qsName) {
int err;
p = user;
+ umtType = type;
- iFrameSize = SAMPLE_RATE / 100;
- cmMode = celt_mode_create(SAMPLE_RATE, 1, iFrameSize, NULL);
- cdDecoder = celt_decoder_create(cmMode);
+ int srate = 0;
+
+ if (umtType == MessageHandler::UDPVoiceCELT) {
+ srate = SAMPLE_RATE;
+ iFrameSize = srate / 100;
+ cmMode = celt_mode_create(srate, 1, iFrameSize, NULL);
+ cdDecoder = celt_decoder_create(cmMode);
+
+ dsSpeex = NULL;
+ } else {
+ cmMode = NULL;
+ cdDecoder = NULL;
+
+ speex_bits_init(&sbBits);
+
+ dsSpeex = speex_decoder_init(&speex_uwb_mode);
+ int iArg=1;
+ speex_decoder_ctl(dsSpeex, SPEEX_SET_ENH, &iArg);
+ speex_decoder_ctl(dsSpeex, SPEEX_GET_FRAME_SIZE, &iFrameSize);
+ speex_decoder_ctl(dsSpeex, SPEEX_GET_SAMPLING_RATE, &srate);
+ }
- if (freq != SAMPLE_RATE)
- srs = speex_resampler_init(1, SAMPLE_RATE, freq, 3, &err);
+ if (freq != srate)
+ srs = speex_resampler_init(1, srate, freq, 3, &err);
else
srs = NULL;
- iOutputSize = iroundf(ceilf(static_cast<float>(iFrameSize * freq) / static_cast<float>(SAMPLE_RATE)));
+ iOutputSize = iroundf(ceilf(static_cast<float>(iFrameSize * freq) / static_cast<float>(srate)));
iBufferOffset = iBufferFilled = iLastConsume = 0;
bLastAlive = true;
@@ -379,8 +398,13 @@ AudioOutputSpeech::AudioOutputSpeech(ClientUser *user, unsigned int freq) : Audi
}
AudioOutputSpeech::~AudioOutputSpeech() {
- celt_decoder_destroy(cdDecoder);
- celt_mode_destroy(cmMode);
+ if (umtType == MessageHandler::UDPVoiceCELT) {
+ celt_decoder_destroy(cdDecoder);
+ celt_mode_destroy(cmMode);
+ } else {
+ speex_bits_destroy(&sbBits);
+ speex_decoder_destroy(dsSpeex);
+ }
jitter_buffer_destroy(jbJitter);
@@ -484,18 +508,39 @@ bool AudioOutputSpeech::needSamples(unsigned int snum) {
nextalive = false;
}
- jitter_buffer_update_delay(jbJitter, &jbp, NULL);
+ int activity;
+ if (umtType == MessageHandler::UDPVoiceCELT)
+ activity = 0;
+ else
+ speex_decoder_ctl(dsSpeex, SPEEX_GET_ACTIVITY, &activity);
+
+ if (activity < 30)
+ jitter_buffer_update_delay(jbJitter, &jbp, NULL);
}
jitter_buffer_tick(jbJitter);
if (! qlFrames.isEmpty()) {
const QByteArray &qba = qlFrames.takeFirst();
- celt_decode_float(cdDecoder, reinterpret_cast<const unsigned char *>(qba.data()), qba.size(), pOut);
+ if (umtType == MessageHandler::UDPVoiceCELT)
+ celt_decode_float(cdDecoder, reinterpret_cast<const unsigned char *>(qba.constData()), qba.size(), pOut);
+ else {
+ speex_bits_read_from(&sbBits, qba.constData(), qba.size());
+ speex_decode(dsSpeex, &sbBits, pOut);
+ for(unsigned int i=0;i<iFrameSize;++i)
+ pOut[i] *= (1.0f / 32767.f);
+ }
+
if (qlFrames.isEmpty() && bHasTerminator)
nextalive = false;
} else {
- celt_decode_float(cdDecoder, NULL, 0, pOut);
+ if (umtType == MessageHandler::UDPVoiceCELT)
+ celt_decode_float(cdDecoder, NULL, 0, pOut);
+ else {
+ speex_decode(dsSpeex, NULL, pOut);
+ for(unsigned int i=0;i<iFrameSize;++i)
+ pOut[i] *= (1.0f / 32767.f);
+ }
}
if (! nextalive) {
@@ -618,22 +663,25 @@ AudioOutputSample *AudioOutput::playSample(const QString &filename, bool loop) {
}
-void AudioOutput::addFrameToBuffer(ClientUser *user, const QByteArray &qbaPacket, unsigned int iSeq) {
+void AudioOutput::addFrameToBuffer(ClientUser *user, const QByteArray &qbaPacket, unsigned int iSeq, MessageHandler::UDPMessageType type) {
if (iChannels == 0)
return;
qrwlOutputs.lockForRead();
AudioOutputSpeech *aop = dynamic_cast<AudioOutputSpeech *>(qmOutputs.value(user));
- if (! aop) {
+ if (! aop || (aop->umtType != type)) {
qrwlOutputs.unlock();
+ if (aop)
+ removeBuffer(aop);
+
while ((iMixerFreq == 0) && bRunning) {}
if (! iMixerFreq)
return;
qrwlOutputs.lockForWrite();
- aop = new AudioOutputSpeech(user, iMixerFreq);
+ aop = new AudioOutputSpeech(user, iMixerFreq, type);
qmOutputs.replace(user,aop);
}
diff --git a/src/mumble/AudioOutput.h b/src/mumble/AudioOutput.h
index 94feb3e9f..9d2317afa 100644
--- a/src/mumble/AudioOutput.h
+++ b/src/mumble/AudioOutput.h
@@ -60,6 +60,7 @@
#include "Audio.h"
#include "Settings.h"
+#include "Message.h"
#include "smallft.h"
class AudioOutput;
@@ -111,6 +112,7 @@ class AudioOutputSpeech : public AudioOutputUser {
Q_OBJECT
Q_DISABLE_COPY(AudioOutputSpeech)
protected:
+ MessageHandler::UDPMessageType umtType;
unsigned int iBufferOffset;
unsigned int iBufferFilled;
unsigned int iOutputSize;
@@ -131,6 +133,9 @@ class AudioOutputSpeech : public AudioOutputUser {
CELTMode *cmMode;
CELTDecoder *cdDecoder;
+ SpeexBits sbBits;
+ void *dsSpeex;
+
QList<QByteArray> qlFrames;
unsigned char ucFlags;
@@ -141,7 +146,7 @@ class AudioOutputSpeech : public AudioOutputUser {
virtual bool needSamples(unsigned int snum);
void addFrameToBuffer(const QByteArray &, unsigned int iBaseSeq);
- AudioOutputSpeech(ClientUser *, unsigned int freq);
+ AudioOutputSpeech(ClientUser *, unsigned int freq, MessageHandler::UDPMessageType type);
~AudioOutputSpeech();
};
@@ -220,7 +225,7 @@ class AudioOutput : public QThread {
AudioOutput();
~AudioOutput();
- void addFrameToBuffer(ClientUser *, const QByteArray &, unsigned int iSeq);
+ void addFrameToBuffer(ClientUser *, const QByteArray &, unsigned int iSeq, MessageHandler::UDPMessageType type);
void removeBuffer(const ClientUser *);
AudioOutputSample *playSample(const QString &filename, bool loop = false);
void run() = 0;
diff --git a/src/mumble/Global.cpp b/src/mumble/Global.cpp
index c9c1700e5..a02f2928d 100644
--- a/src/mumble/Global.cpp
+++ b/src/mumble/Global.cpp
@@ -46,7 +46,7 @@ Global::Global() {
bCenterPosition = false;
bPosTest = false;
iAudioPathTime = 0;
- iMaxBandwidth = 0;
+ iMaxBandwidth = -1;
QString apppath = QCoreApplication::instance()->applicationDirPath();
QFile inifile(QString::fromLatin1("%1/mumble.ini").arg(apppath));
diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp
index 4c8f3e88c..a0e7f6b6b 100644
--- a/src/mumble/MainWindow.cpp
+++ b/src/mumble/MainWindow.cpp
@@ -693,7 +693,7 @@ void MainWindow::on_qaServerInformation_triggered() {
.arg(cs.uiRemoteGood).arg(cs.uiRemoteLate).arg(cs.uiRemoteLost).arg(cs.uiRemoteResync)
.arg(cs.uiGood).arg(cs.uiLate).arg(cs.uiLost).arg(cs.uiResync);
}
- qsAudio=tr("<h2>Audio bandwidth</h2><p>Maximum %1 kbit/s<br />Current %2 kbit/s</p>").arg(g.iMaxBandwidth / 125.0,0,'f',1).arg(g.iAudioBandwidth / 125.0,0,'f',1);
+ qsAudio=tr("<h2>Audio bandwidth</h2><p>Maximum %1 kbit/s<br />Current %2 kbit/s</p>").arg(g.iMaxBandwidth / 1000.0,0,'f',1).arg(g.iAudioBandwidth / 1000.0,0,'f',1);
QMessageBox qmb(QMessageBox::Information, tr("Mumble Server Information"), qsVersion + qsControl + qsVoice + qsCrypt + qsAudio, QMessageBox::Ok, this);
qmb.setDefaultButton(QMessageBox::Ok);
@@ -1739,6 +1739,7 @@ void MainWindow::serverDisconnected(QString reason) {
qtReconnect->start();
}
}
+ AudioInput::setMaxBandwidth(-1);
}
void MainWindow::on_Icon_activated(QSystemTrayIcon::ActivationReason reason) {
@@ -1757,14 +1758,13 @@ void MainWindow::customEvent(QEvent *evt) {
if (evt->type() == TI_QEVENT) {
hide();
return;
- }
- if (evt->type() == MB_QEVENT) {
+ } else if (evt->type() == MB_QEVENT) {
MessageBoxEvent *mbe=static_cast<MessageBoxEvent *>(evt);
g.l->log(Log::Information, mbe->msg);
return;
- }
- if (evt->type() != SERVERSEND_EVENT)
+ } else if (evt->type() != SERVERSEND_EVENT) {
return;
+ }
ServerHandlerMessageEvent *shme=static_cast<ServerHandlerMessageEvent *>(evt);
diff --git a/src/mumble/Messages.cpp b/src/mumble/Messages.cpp
index f80b35831..6e58f16bb 100644
--- a/src/mumble/Messages.cpp
+++ b/src/mumble/Messages.cpp
@@ -88,7 +88,6 @@ void MainWindow::msgReject(const MumbleProto::Reject &msg) {
}
void MainWindow::msgServerSync(const MumbleProto::ServerSync &msg) {
- g.iMaxBandwidth = msg.max_bandwidth();
g.uiSession = msg.session();
g.pPermissions = static_cast<ChanACL::Permissions>(msg.permissions());
g.l->clearIgnore();
@@ -103,14 +102,7 @@ void MainWindow::msgServerSync(const MumbleProto::ServerSync &msg) {
}
iTargetCounter = 100;
- AudioInputPtr ai = g.ai;
- if (ai) {
- int bw = ai->getMaxBandwidth();
- if (bw > g.iMaxBandwidth) {
- g.l->log(Log::Information, tr("Server maximum bandwidth is only %1 kbit/s. Quality auto-adjusted.").arg(g.iMaxBandwidth / 125));
- }
- ai->setMaxBandwidth(g.iMaxBandwidth);
- }
+ AudioInput::setMaxBandwidth(msg.max_bandwidth());
findDesiredChannel();
diff --git a/src/mumble/ServerHandler.cpp b/src/mumble/ServerHandler.cpp
index a083845ea..1f7beff68 100644
--- a/src/mumble/ServerHandler.cpp
+++ b/src/mumble/ServerHandler.cpp
@@ -150,20 +150,22 @@ void ServerHandler::udpReady() {
PacketDataStream pds(buffer + 1, buflen-5);
- unsigned int msgType = (buffer[0] >> 5) & 0x7;
+ MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((buffer[0] >> 5) & 0x7);
unsigned int msgFlags = buffer[0] & 0x1f;
if (msgType == MessageHandler::UDPPing) {
quint64 t;
pds >> t;
accUDP(static_cast<double>(tTimestamp.elapsed() - t) / 1000.0);
- } else if (msgType == MessageHandler::UDPVoice) {
- handleVoicePacket(msgFlags, pds);
+ } else if (msgType == MessageHandler::UDPVoiceCELT) {
+ handleVoicePacket(msgFlags, pds, msgType);
+ } else if (msgType == MessageHandler::UDPVoiceSpeex) {
+ handleVoicePacket(msgFlags, pds, msgType);
}
}
}
-void ServerHandler::handleVoicePacket(unsigned int msgFlags, PacketDataStream &pds) {
+void ServerHandler::handleVoicePacket(unsigned int msgFlags, PacketDataStream &pds, MessageHandler::UDPMessageType type) {
unsigned int uiSession;
pds >> uiSession;
ClientUser *p = ClientUser::get(uiSession);
@@ -176,7 +178,7 @@ void ServerHandler::handleVoicePacket(unsigned int msgFlags, PacketDataStream &p
qba.append(static_cast<char>(msgFlags));
qba.append(pds.dataBlock(pds.left()));
- ao->addFrameToBuffer(p, qba, iSeq);
+ ao->addFrameToBuffer(p, qba, iSeq, type);
}
}
@@ -330,13 +332,14 @@ void ServerHandler::message(unsigned int msgType, const QByteArray &qbaMsg) {
if (qbaMsg.length() < 1)
return;
- unsigned int msgUDPType = (ptr[0] >> 5) & 0x7;
+ MessageHandler::UDPMessageType msgType = static_cast<MessageHandler::UDPMessageType>((ptr[0] >> 5) & 0x7);
unsigned int msgFlags = ptr[0] & 0x1f;
PacketDataStream pds(qbaMsg.constData() + 1, qbaMsg.size());
- if (msgUDPType == MessageHandler::UDPVoice) {
- handleVoicePacket(msgFlags, pds);
- }
+ if (msgType == MessageHandler::UDPVoiceCELT)
+ handleVoicePacket(msgFlags, pds, msgType);
+ else if (msgType == MessageHandler::UDPVoiceSpeex)
+ handleVoicePacket(msgFlags, pds, msgType);
} else if (msgType == MessageHandler::Ping) {
MumbleProto::Ping msg;
if (msg.ParseFromArray(qbaMsg.constData(), qbaMsg.size())) {
diff --git a/src/mumble/ServerHandler.h b/src/mumble/ServerHandler.h
index 822e129a7..4ca7b8810 100644
--- a/src/mumble/ServerHandler.h
+++ b/src/mumble/ServerHandler.h
@@ -72,7 +72,7 @@ class ServerHandler : public QThread {
QUdpSocket *qusUdp;
QMutex qmUdp;
- void handleVoicePacket(unsigned int msgFlags, PacketDataStream &pds);
+ void handleVoicePacket(unsigned int msgFlags, PacketDataStream &pds, MessageHandler::UDPMessageType type);
public:
Timer tTimestamp;
QList<QSslError> qlErrors;
diff --git a/src/mumble/Settings.cpp b/src/mumble/Settings.cpp
index 722d01056..bde7125de 100644
--- a/src/mumble/Settings.cpp
+++ b/src/mumble/Settings.cpp
@@ -217,7 +217,7 @@ Settings::Settings() {
iMaxImageHeight = 1024;
bSuppressIdentity = false;
-#if defined(AUDIO_TEST)
+#if defined(AUDIO_TEST) || 1
lmLoopMode = Local;
#else
lmLoopMode = None;
diff --git a/src/mumble/WASAPI.cpp b/src/mumble/WASAPI.cpp
index 2eaab8073..6bd36e409 100644
--- a/src/mumble/WASAPI.cpp
+++ b/src/mumble/WASAPI.cpp
@@ -547,7 +547,6 @@ void WASAPIOutput::setVolumes(IMMDevice *pDevice, bool talking) {
if (SUCCEEDED(hr = pEnumerator->GetCount(&max))) {
for (int i=0;i<max;++i) {
IAudioSessionControl *pControl = NULL;
- IUnknown *pUnknown = NULL;
if (SUCCEEDED(hr = pEnumerator->GetSession(i, &pControl))) {
IAudioSessionControl2 *pControl2 = NULL;
if (SUCCEEDED(hr = pControl->QueryInterface(version ? __uuidof(IAudioSessionControl2) : __uuidof(IVistaAudioSessionControl2), (void **) &pControl2))) {
diff --git a/src/mumble/mumble.pro b/src/mumble/mumble.pro
index 97ca61a9d..e510a7241 100644
--- a/src/mumble/mumble.pro
+++ b/src/mumble/mumble.pro
@@ -23,7 +23,7 @@ unix:!CONFIG(bundled-speex):system(pkg-config --atleast-version=1.2 speexdsp) {
}
CONFIG(no-bundled-speex) {
- PKGCONFIG *= speexdsp
+ PKGCONFIG *= speex speexdsp
}
!CONFIG(no-bundled-speex) {
diff --git a/src/mumble/mumble_pch.hpp b/src/mumble/mumble_pch.hpp
index 030d2c530..18c1bc2c6 100644
--- a/src/mumble/mumble_pch.hpp
+++ b/src/mumble/mumble_pch.hpp
@@ -51,10 +51,10 @@
#include <celt_header.h>
#else
#include <ogg/ogg.h>
-#include <speex/speex.h>
-#include <speex/speex_header.h>
#include <speex/speex_callbacks.h>
#endif
+#include <speex/speex.h>
+#include <speex/speex_header.h>
#include <speex/speex_jitter.h>
#include <speex/speex_preprocess.h>
#include <speex/speex_echo.h>