diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-08-21 03:29:48 +0400 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-08-21 03:29:48 +0400 |
commit | 6479de347fa69a3872d6073a74eebf81f1ffa819 (patch) | |
tree | 492ba77858f876b97952627f8724141b81d62d5b | |
parent | 4ff39930dc8a91521d6217faca3b8f05253a4614 (diff) |
Low bandwidth mode
-rw-r--r-- | compiler.pri | 1 | ||||
-rw-r--r-- | speexbuild/speexbuild.pro | 7 | ||||
-rw-r--r-- | src/Message.h | 2 | ||||
-rw-r--r-- | src/mumble/Audio.cpp | 10 | ||||
-rw-r--r-- | src/mumble/AudioInput.cpp | 177 | ||||
-rw-r--r-- | src/mumble/AudioInput.h | 17 | ||||
-rw-r--r-- | src/mumble/AudioOutput.cpp | 78 | ||||
-rw-r--r-- | src/mumble/AudioOutput.h | 9 | ||||
-rw-r--r-- | src/mumble/Global.cpp | 2 | ||||
-rw-r--r-- | src/mumble/MainWindow.cpp | 10 | ||||
-rw-r--r-- | src/mumble/Messages.cpp | 10 | ||||
-rw-r--r-- | src/mumble/ServerHandler.cpp | 21 | ||||
-rw-r--r-- | src/mumble/ServerHandler.h | 2 | ||||
-rw-r--r-- | src/mumble/Settings.cpp | 2 | ||||
-rw-r--r-- | src/mumble/WASAPI.cpp | 1 | ||||
-rw-r--r-- | src/mumble/mumble.pro | 2 | ||||
-rw-r--r-- | src/mumble/mumble_pch.hpp | 4 |
17 files changed, 254 insertions, 101 deletions
diff --git a/compiler.pri b/compiler.pri index 60a7e8fca..fe09f76ee 100644 --- a/compiler.pri +++ b/compiler.pri @@ -48,7 +48,6 @@ win32 { } INCLUDEPATH *= "$$VLD_DIR/include" LIBPATH *= "$$VLD_DIR/lib" - DEFINES *= USE_VLD } } else { DEFINES *= RESTRICT=__restrict__ diff --git a/speexbuild/speexbuild.pro b/speexbuild/speexbuild.pro index b776a64a9..5753a21b3 100644 --- a/speexbuild/speexbuild.pro +++ b/speexbuild/speexbuild.pro @@ -39,11 +39,10 @@ macx { DIST = config.h speex.def speex/speex_config_types.h DEF_FILE = speex.def +# libspeexdsp SOURCES = mdf.c resample.c preprocess.c jitter.c filterbank.c fftwrap.c smallft.c - -!CONFIG(no-11x) { - SOURCES *= bits.c cb_search.c exc_10_16_table.c exc_10_32_table.c exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c exc_8_128_table.c filters.c gain_table.c gain_table_lbr.c hexc_10_32_table.c hexc_table.c high_lsp_tables.c lpc.c lsp.c lsp_tables_nb.c ltp.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c scal.c speex.c speex_callbacks.c speex_header.c stereo.c vbr.c vq.c kiss_fft.c kiss_fftr.c vorbis_psy.c window.c -} +# libspeex +SOURCES *= bits.c cb_search.c exc_10_16_table.c exc_10_32_table.c exc_20_32_table.c exc_5_256_table.c exc_5_64_table.c exc_8_128_table.c filters.c gain_table.c gain_table_lbr.c hexc_10_32_table.c hexc_table.c high_lsp_tables.c lpc.c lsp.c lsp_tables_nb.c ltp.c modes.c modes_wb.c nb_celp.c quant_lsp.c sb_celp.c scal.c speex.c speex_callbacks.c speex_header.c stereo.c vbr.c vq.c kiss_fft.c kiss_fftr.c vorbis_psy.c window.c CONFIG(debug, debug|release) { CONFIG += console 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> |