mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-10 08:51:12 +00:00
Merge branch 'dev' of https://github.com/telegramdesktop/tdesktop into dev
This commit is contained in:
commit
175023b2dc
@ -1,10 +1,10 @@
|
||||
@echo OFF
|
||||
|
||||
set "AppVersion=8017"
|
||||
set "AppVersionStrSmall=0.8.17"
|
||||
set "AppVersionStr=0.8.17"
|
||||
set "AppVersionStrFull=0.8.17.0"
|
||||
set "DevChannel=0"
|
||||
set "AppVersion=8018"
|
||||
set "AppVersionStrSmall=0.8.18"
|
||||
set "AppVersionStr=0.8.18"
|
||||
set "AppVersionStrFull=0.8.18.0"
|
||||
set "DevChannel=1"
|
||||
|
||||
if %DevChannel% neq 0 goto preparedev
|
||||
|
||||
|
@ -1543,6 +1543,7 @@ namespace App {
|
||||
cSetStickerSets(StickerSets());
|
||||
cSetStickerSetsOrder(StickerSetsOrder());
|
||||
cSetLastStickersUpdate(0);
|
||||
LOG(("Stickers: cleared everything!"));
|
||||
::videoItems.clear();
|
||||
::audioItems.clear();
|
||||
::documentItems.clear();
|
||||
|
@ -96,6 +96,7 @@ bool _checkALError() {
|
||||
void audioInit() {
|
||||
if (!capture) {
|
||||
capture = new AudioCapture();
|
||||
cSetHasAudioCapture(capture->check());
|
||||
}
|
||||
|
||||
uint64 ms = getms();
|
||||
@ -202,6 +203,7 @@ void audioInit() {
|
||||
avcodec_register_all();
|
||||
|
||||
LOG(("Audio init time: %1").arg(getms() - ms));
|
||||
cSetHasAudioPlayer(true);
|
||||
}
|
||||
|
||||
void audioPlayNotify() {
|
||||
@ -240,6 +242,9 @@ void audioFinish() {
|
||||
alcCloseDevice(audioDevice);
|
||||
audioDevice = 0;
|
||||
}
|
||||
|
||||
cSetHasAudioCapture(false);
|
||||
cSetHasAudioPlayer(false);
|
||||
}
|
||||
|
||||
AudioPlayer::AudioPlayer() : _current(0),
|
||||
@ -421,6 +426,16 @@ void AudioCapture::stop(bool needResult) {
|
||||
emit captureOnStop(needResult);
|
||||
}
|
||||
|
||||
bool AudioCapture::check() {
|
||||
if (const ALCchar *def = alcGetString(0, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)) {
|
||||
if (ALCdevice *dev = alcCaptureOpenDevice(def, AudioVoiceMsgFrequency, AL_FORMAT_MONO16, AudioVoiceMsgFrequency / 5)) {
|
||||
alcCaptureCloseDevice(dev);
|
||||
return _checkALCError();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioCapture::~AudioCapture() {
|
||||
capture = 0;
|
||||
_captureThread.quit();
|
||||
|
@ -119,6 +119,8 @@ public:
|
||||
void start();
|
||||
void stop(bool needResult);
|
||||
|
||||
bool check();
|
||||
|
||||
~AudioCapture();
|
||||
|
||||
signals:
|
||||
|
@ -17,9 +17,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 8017;
|
||||
static const wchar_t *AppVersionStr = L"0.8.17";
|
||||
static const bool DevChannel = false;
|
||||
static const int32 AppVersion = 8018;
|
||||
static const wchar_t *AppVersionStr = L"0.8.18";
|
||||
static const bool DevChannel = true;
|
||||
|
||||
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
|
||||
static const wchar_t *AppName = L"Telegram Desktop";
|
||||
|
@ -1384,6 +1384,8 @@ void StickerPanInner::refreshStickers() {
|
||||
_hovers.clear(); _hovers.reserve(sets.size() + 1);
|
||||
_titles.clear(); _titles.reserve(sets.size() + 1);
|
||||
|
||||
LOG(("Stickers: refreshing pan, sets size: %1").arg(sets.size()));
|
||||
|
||||
refreshRecent(false);
|
||||
|
||||
appendSet(CustomStickerSetId);
|
||||
@ -1429,10 +1431,12 @@ void StickerPanInner::preloadImages() {
|
||||
}
|
||||
|
||||
void StickerPanInner::appendSet(uint64 setId) {
|
||||
LOG(("Stickers: appending set %1..").arg(setId));
|
||||
const StickerSets &sets(cStickerSets());
|
||||
StickerSets::const_iterator it = sets.constFind(setId);
|
||||
if (it == sets.cend() || it->stickers.isEmpty()) return;
|
||||
|
||||
LOG(("Stickers: set %1 found! %2 stickers there.").arg(setId).arg(it->stickers.size()));
|
||||
StickerPack pack;
|
||||
pack.reserve(it->stickers.size());
|
||||
for (int32 i = 0, l = it->stickers.size(); i < l; ++i) {
|
||||
@ -1448,6 +1452,7 @@ void StickerPanInner::appendSet(uint64 setId) {
|
||||
void StickerPanInner::refreshRecent(bool performResize) {
|
||||
clearSelection(true);
|
||||
if (cGetRecentStickers().isEmpty()) {
|
||||
LOG(("Stickers: no recent!"));
|
||||
if (!_setIds.isEmpty() && _setIds.at(0) == RecentStickerSetId) {
|
||||
_setIds.pop_front();
|
||||
_sets.pop_front();
|
||||
@ -1455,6 +1460,7 @@ void StickerPanInner::refreshRecent(bool performResize) {
|
||||
_titles.pop_front();
|
||||
}
|
||||
} else {
|
||||
LOG(("Stickers: %1 recent stickers!").arg(cGetRecentStickers().size()));
|
||||
StickerPack recent;
|
||||
recent.reserve(cGetRecentStickers().size());
|
||||
for (int32 i = 0, l = cGetRecentStickers().size(); i < l; ++i) {
|
||||
@ -2044,6 +2050,7 @@ void EmojiPan::onRemoveSetSure() {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
LOG(("Stickers: removed one set, %1.").arg(_removingSetId));
|
||||
cRefStickerSets().erase(it);
|
||||
cRefStickerSetsOrder().removeOne(_removingSetId);
|
||||
cSetStickersHash(QByteArray());
|
||||
|
@ -1710,18 +1710,20 @@ void HistoryWidget::start() {
|
||||
void HistoryWidget::onTextChange() {
|
||||
updateTyping();
|
||||
|
||||
if (_field.getLastText().isEmpty()) {
|
||||
_previewCancelled = false;
|
||||
_send.hide();
|
||||
setMouseTracking(true);
|
||||
mouseMoveEvent(0);
|
||||
} else if (!_field.isHidden()) {
|
||||
_send.show();
|
||||
setMouseTracking(false);
|
||||
_recordAnim.stop();
|
||||
_inRecord = _inField = false;
|
||||
a_recordOver = a_recordDown = anim::fvalue(0, 0);
|
||||
a_recordCancel = anim::cvalue(st::recordCancel->c, st::recordCancel->c);
|
||||
if (cHasAudioCapture()) {
|
||||
if (_field.getLastText().isEmpty()) {
|
||||
_previewCancelled = false;
|
||||
_send.hide();
|
||||
setMouseTracking(true);
|
||||
mouseMoveEvent(0);
|
||||
} else if (!_field.isHidden() && _send.isHidden()) {
|
||||
_send.show();
|
||||
setMouseTracking(false);
|
||||
_recordAnim.stop();
|
||||
_inRecord = _inField = false;
|
||||
a_recordOver = a_recordDown = anim::fvalue(0, 0);
|
||||
a_recordCancel = anim::cvalue(st::recordCancel->c, st::recordCancel->c);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hist || _synthedTextUpdate) return;
|
||||
@ -1849,6 +1851,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
||||
cSetLastStickersUpdate(getms(true));
|
||||
_stickersUpdateRequest = 0;
|
||||
|
||||
LOG(("Stickers: got from server!"));
|
||||
|
||||
if (stickers.type() != mtpc_messages_allStickers) return;
|
||||
const MTPDmessages_allStickers &d(stickers.c_messages_allStickers());
|
||||
|
||||
@ -1857,6 +1861,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
||||
const QVector<MTPDocument> &d_docs(d.vdocuments.c_vector().v);
|
||||
const QVector<MTPStickerSet> &d_sets(d.vsets.c_vector().v);
|
||||
|
||||
LOG(("Stickers: clearing everything, got all stickers"));
|
||||
|
||||
QByteArray wasHash = cStickersHash();
|
||||
cSetStickersHash(qba(d.vhash));
|
||||
|
||||
@ -1995,10 +2001,13 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(("Stickers: now %1 sets, %2 recent").arg(sets.size()).arg(recent.size()));
|
||||
if (added || removed || cStickersHash() != wasHash) {
|
||||
LOG(("Stickers: writing stickers from gotAll!"));
|
||||
Local::writeStickers();
|
||||
}
|
||||
if (writeRecent) {
|
||||
LOG(("Stickers: writing recent stickers from gotAll!"));
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
|
||||
@ -2047,6 +2056,8 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
||||
bool HistoryWidget::stickersFailed(const RPCError &error) {
|
||||
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
|
||||
|
||||
LOG(("App Fail: Failed to get stickers!"));
|
||||
|
||||
cSetLastStickersUpdate(getms(true));
|
||||
_stickersUpdateRequest = 0;
|
||||
return true;
|
||||
@ -2329,7 +2340,7 @@ void HistoryWidget::updateControlsVisibility() {
|
||||
_toHistoryEnd.show();
|
||||
}
|
||||
if (!histPeer->chat || !histPeer->asChat()->forbidden) {
|
||||
if (_field.getLastText().isEmpty()) {
|
||||
if (cHasAudioCapture() && _field.getLastText().isEmpty()) {
|
||||
_send.hide();
|
||||
setMouseTracking(true);
|
||||
mouseMoveEvent(0);
|
||||
@ -3019,7 +3030,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_attachDrag = DragStateNone;
|
||||
updateDragAreas();
|
||||
}
|
||||
if (_recording && audioCapture()) {
|
||||
if (_recording && cHasAudioCapture()) {
|
||||
stopRecording(_inField);
|
||||
}
|
||||
}
|
||||
@ -3796,7 +3807,7 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) {
|
||||
_replyForwardPressed = QRect(0, _field.y() - st::replyHeight, st::replySkip, st::replyHeight).contains(e->pos());
|
||||
if (_replyForwardPressed && !_replyForwardPreviewCancel.isHidden()) {
|
||||
update(0, _field.y() - st::sendPadding - st::replyHeight, width(), st::replyHeight);
|
||||
} else if (_inRecord && audioCapture()) {
|
||||
} else if (_inRecord && cHasAudioCapture()) {
|
||||
audioCapture()->start();
|
||||
|
||||
_recording = _inField = true;
|
||||
|
@ -105,7 +105,7 @@ void LocalImageLoaderPrivate::prepareImages() {
|
||||
}
|
||||
if (mime == "image/jpeg") {
|
||||
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
|
||||
} else if (mime == "application/ogg" && type == ToPrepareAudio) {
|
||||
} else if (type == ToPrepareAudio) {
|
||||
filename = filedialogDefaultName(qsl("audio"), qsl(".ogg"), QString(), true);
|
||||
mime = "audio/ogg";
|
||||
} else {
|
||||
|
@ -2278,16 +2278,20 @@ namespace Local {
|
||||
}
|
||||
|
||||
void importOldRecentStickers() {
|
||||
LOG(("Stickers: importOldStickers()"));
|
||||
if (!_recentStickersKeyOld) return;
|
||||
|
||||
FileReadDescriptor stickers;
|
||||
if (!readEncryptedFile(stickers, _recentStickersKeyOld)) {
|
||||
LOG(("Stickers: could not readEncryptedFile(_recentStickersKeyOld)!"));
|
||||
clearKey(_recentStickersKeyOld);
|
||||
_recentStickersKeyOld = 0;
|
||||
_writeMap();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("Stickers: clearing everything in import-old!"));
|
||||
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
sets.clear();
|
||||
cSetStickerSetsOrder(StickerSetsOrder());
|
||||
@ -2334,6 +2338,7 @@ namespace Local {
|
||||
}
|
||||
if (recent.size() < StickerPanPerRow * StickerPanRowsPerPage && qAbs(value) > 1) recent.push_back(qMakePair(doc, qAbs(value)));
|
||||
}
|
||||
LOG(("Stickers: read %1 default stickers and %2 custom stickers").arg(def.stickers.size()).arg(custom.stickers.size()));
|
||||
if (def.stickers.isEmpty()) sets.remove(DefaultStickerSetId);
|
||||
if (custom.stickers.isEmpty()) sets.remove(CustomStickerSetId);
|
||||
|
||||
@ -2343,21 +2348,25 @@ namespace Local {
|
||||
clearKey(_recentStickersKeyOld);
|
||||
_recentStickersKeyOld = 0;
|
||||
_writeMap();
|
||||
LOG(("Stickers: writing stickers and clearing old-stickers"));
|
||||
}
|
||||
|
||||
void readStickers() {
|
||||
LOG(("Stickers: readStickers()"));
|
||||
if (!_stickersKey) {
|
||||
return importOldRecentStickers();
|
||||
}
|
||||
|
||||
FileReadDescriptor stickers;
|
||||
if (!readEncryptedFile(stickers, _stickersKey)) {
|
||||
LOG(("Stickers: could not readEncryptedFile(_stickersKey)!"));
|
||||
clearKey(_stickersKey);
|
||||
_stickersKey = 0;
|
||||
_writeMap();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("Stickers: clearing everything in read"));
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
sets.clear();
|
||||
|
||||
@ -2432,6 +2441,8 @@ namespace Local {
|
||||
}
|
||||
|
||||
cSetStickersHash(hash);
|
||||
|
||||
LOG(("Stickers: read %1 sets").arg(sets.size()));
|
||||
}
|
||||
|
||||
void writeBackground(int32 id, const QImage &img) {
|
||||
|
@ -66,6 +66,7 @@ void debugLogWrite(const char *file, int32 line, const QString &v) {
|
||||
|
||||
{
|
||||
QMutexLocker lock(&debugLogMutex);
|
||||
if (!cDebug() || !debugLogStream) return;
|
||||
|
||||
logsInitDebug(); // maybe need to reopen new file
|
||||
|
||||
@ -87,6 +88,7 @@ void tcpLogWrite(const QString &v) {
|
||||
|
||||
{
|
||||
QMutexLocker lock(&debugLogMutex);
|
||||
if (!cDebug() || !tcpLogStream) return;
|
||||
|
||||
logsInitDebug(); // maybe need to reopen new file
|
||||
|
||||
@ -100,6 +102,7 @@ void mtpLogWrite(int32 dc, const QString &v) {
|
||||
|
||||
{
|
||||
QMutexLocker lock(&debugLogMutex);
|
||||
if (!cDebug() || !mtpLogStream) return;
|
||||
|
||||
logsInitDebug(); // maybe need to reopen new file
|
||||
|
||||
@ -109,7 +112,7 @@ void mtpLogWrite(int32 dc, const QString &v) {
|
||||
}
|
||||
|
||||
void logWrite(const QString &v) {
|
||||
if (!mainLog.isOpen()) return;
|
||||
if (!mainLogStream) return;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm tm;
|
||||
@ -117,6 +120,8 @@ void logWrite(const QString &v) {
|
||||
|
||||
{
|
||||
QMutexLocker lock(&mainLogMutex);
|
||||
if (!mainLogStream) return;
|
||||
|
||||
QString msg(QString("[%1.%2.%3 %4:%5:%6] %7\n").arg(tm.tm_year + 1900).arg(tm.tm_mon + 1, 2, 10, zero).arg(tm.tm_mday, 2, 10, zero).arg(tm.tm_hour, 2, 10, zero).arg(tm.tm_min, 2, 10, zero).arg(tm.tm_sec, 2, 10, zero).arg(v));
|
||||
(*mainLogStream) << msg;
|
||||
mainLogStream->flush();
|
||||
|
@ -84,6 +84,9 @@ QString gTimeFormat = qsl("hh:mm");
|
||||
int32 gAutoLock = 3600;
|
||||
bool gHasPasscode = false;
|
||||
|
||||
bool gHasAudioPlayer = true;
|
||||
bool gHasAudioCapture = true;
|
||||
|
||||
DBIEmojiTab gEmojiTab = dbietRecent;
|
||||
RecentEmojiPack gRecentEmojis;
|
||||
RecentEmojisPreload gRecentEmojisPreload;
|
||||
|
@ -134,6 +134,9 @@ DeclareSetting(QString, TimeFormat);
|
||||
DeclareSetting(int32, AutoLock);
|
||||
DeclareSetting(bool, HasPasscode);
|
||||
|
||||
DeclareSetting(bool, HasAudioPlayer);
|
||||
DeclareSetting(bool, HasAudioCapture);
|
||||
|
||||
inline void cChangeTimeFormat(const QString &newFormat) {
|
||||
if (!newFormat.isEmpty()) cSetTimeFormat(newFormat);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.8.17</string>
|
||||
<string>0.8.18</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
Binary file not shown.
@ -107,8 +107,8 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)$(ProjectName).exe</OutputFile>
|
||||
<AdditionalLibraryDirectories>.\..\..\Libraries\lzma\C\Util\LzmaLib\Release;.\..\..\Libraries\libexif-0.6.20\win32\Release;.\..\..\Libraries\libogg-1.3.2\win32\VS2010\Win32\Release;.\..\..\Libraries\opus\win32\VS2010\Win32\Release;.\..\..\Libraries\opusfile\win32\VS2010\Win32\Release;.\..\..\Libraries\mpg123-1.22.1\ports\MSVC++\2010\libmpg123\Release;.\..\..\Libraries\faad2-2.7\libfaad\Release;.\..\..\Libraries\faad2-2.7\common\mp4ff\Release;.\..\..\Libraries\ffmpeg-2.6.3;.\..\..\Libraries\openal-soft\build\Release;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmain.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5Widgets.lib;Qt5Network.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;imageformats\qwebp.lib;libeay32MT.lib;ssleay32MT.lib;Crypt32.lib;zlibstat.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;LzmaLib.lib;OpenAL32.lib;common.lib;opusfile.lib;opus.lib;libogg_static.lib;libmpg123.lib;libfaad.lib;mp4ff.lib;libavformat\libavformat.a;libavcodec\libavcodec.a;libavutil\libavutil.a;libswresample\libswresample.a;celt.lib;silk_common.lib;silk_float.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>.\..\..\Libraries\lzma\C\Util\LzmaLib\Release;.\..\..\Libraries\libexif-0.6.20\win32\Release;.\..\..\Libraries\ffmpeg-2.6.3;.\..\..\Libraries\opus\win32\VS2010\Win32\Release;.\..\..\Libraries\openal-soft\build\Release;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmain.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5Widgets.lib;Qt5Network.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;imageformats\qwebp.lib;libeay32MT.lib;ssleay32MT.lib;Crypt32.lib;zlibstat.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;LzmaLib.lib;OpenAL32.lib;common.lib;libavformat\libavformat.a;libavcodec\libavcodec.a;libavutil\libavutil.a;libswresample\libswresample.a;opus.lib;celt.lib;silk_common.lib;silk_float.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers />
|
||||
<ImportLibrary>$(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib</ImportLibrary>
|
||||
<ProfileGuidedDatabase>$(IntDir)$(TargetName).pgd</ProfileGuidedDatabase>
|
||||
@ -134,8 +134,8 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OutputFile>$(OutDir)$(ProjectName).exe</OutputFile>
|
||||
<AdditionalLibraryDirectories>.\..\..\Libraries\lzma\C\Util\LzmaLib\Release;.\..\..\Libraries\libexif-0.6.20\win32\Release;.\..\..\Libraries\ffmpeg-2.6.3;.\..\..\Libraries\openal-soft\build\Release;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmain.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5Widgets.lib;Qt5Network.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;imageformats\qwebp.lib;libeay32MT.lib;ssleay32MT.lib;Crypt32.lib;zlibstat.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;LzmaLib.lib;OpenAL32.lib;common.lib;libavformat\libavformat.a;libavcodec\libavcodec.a;libavutil\libavutil.a;libswresample\libswresample.a;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>.\..\..\Libraries\lzma\C\Util\LzmaLib\Release;.\..\..\Libraries\libexif-0.6.20\win32\Release;.\..\..\Libraries\ffmpeg-2.6.3;.\..\..\Libraries\opus\win32\VS2010\Win32\Release;.\..\..\Libraries\openal-soft\build\Release;.\..\..\Libraries\zlib-1.2.8\contrib\vstudio\vc11\x86\ZlibStatRelease;.\..\..\Libraries\OpenSSL-Win32\lib\VC\static;$(QTDIR)\lib;$(QTDIR)\plugins;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;gdi32.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;qtmain.lib;glu32.lib;opengl32.lib;Strmiids.lib;Qt5Core.lib;Qt5Gui.lib;qtharfbuzzng.lib;Qt5Widgets.lib;Qt5Network.lib;Qt5PlatformSupport.lib;platforms\qwindows.lib;imageformats\qwebp.lib;libeay32MT.lib;ssleay32MT.lib;Crypt32.lib;zlibstat.lib;lib_exif.lib;UxTheme.lib;DbgHelp.lib;LzmaLib.lib;OpenAL32.lib;common.lib;libavformat\libavformat.a;libavcodec\libavcodec.a;libavutil\libavutil.a;libswresample\libswresample.a;opus.lib;celt.lib;silk_common.lib;silk_float.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ImageHasSafeExceptionHandlers>
|
||||
</ImageHasSafeExceptionHandlers>
|
||||
<ImportLibrary>$(SolutionDir)$(Platform)\$(Configuration)Intermediate\$(TargetName).lib</ImportLibrary>
|
||||
|
@ -1693,7 +1693,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.17;
|
||||
CURRENT_PROJECT_VERSION = 0.8.18;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@ -1711,7 +1711,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.8.17;
|
||||
CURRENT_PROJECT_VERSION = 0.8.18;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
|
||||
@ -1737,10 +1737,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.17;
|
||||
CURRENT_PROJECT_VERSION = 0.8.18;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.8;
|
||||
DYLIB_CURRENT_VERSION = 0.8.17;
|
||||
DYLIB_CURRENT_VERSION = 0.8.18;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@ -1764,14 +1764,9 @@
|
||||
./SourceFiles,
|
||||
./GeneratedFiles,
|
||||
/usr/local/include,
|
||||
"./../../Libraries/libogg-1.3.2/include",
|
||||
./../../Libraries/opus/include,
|
||||
./../../Libraries/opusfile/include,
|
||||
"./../../Libraries/openal-soft/include",
|
||||
"./../../Libraries/mpg123-1.22.1/src/libmpg123",
|
||||
"./../../Libraries/libexif-0.6.20",
|
||||
"./../../Libraries/faad2-2.7/include",
|
||||
"./../../Libraries/faad2-2.7/common/mp4ff",
|
||||
"/usr/local/Qt-5.4.0/include",
|
||||
"/usr/local/Qt-5.4.0/include/QtMultimedia",
|
||||
"/usr/local/Qt-5.4.0/include/QtWidgets",
|
||||
@ -1855,14 +1850,9 @@
|
||||
"-lz",
|
||||
"-lm",
|
||||
/usr/local/lib/libopenal.a,
|
||||
/usr/local/lib/libopusfile.a,
|
||||
/usr/local/lib/libopus.a,
|
||||
/usr/local/lib/libogg.a,
|
||||
/usr/local/lib/liblzma.a,
|
||||
/usr/local/lib/libexif.a,
|
||||
/usr/local/lib/libmpg123.a,
|
||||
/usr/local/lib/libfaad.a,
|
||||
/usr/local/lib/libmp4ff.a,
|
||||
/usr/local/lib/libavcodec.a,
|
||||
/usr/local/lib/libavformat.a,
|
||||
/usr/local/lib/libswresample.a,
|
||||
@ -1890,10 +1880,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.17;
|
||||
CURRENT_PROJECT_VERSION = 0.8.18;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.8;
|
||||
DYLIB_CURRENT_VERSION = 0.8.17;
|
||||
DYLIB_CURRENT_VERSION = 0.8.18;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@ -1917,14 +1907,9 @@
|
||||
./SourceFiles,
|
||||
./GeneratedFiles,
|
||||
/usr/local/include,
|
||||
"./../../Libraries/libogg-1.3.2/include",
|
||||
./../../Libraries/opus/include,
|
||||
./../../Libraries/opusfile/include,
|
||||
"./../../Libraries/openal-soft/include",
|
||||
"./../../Libraries/mpg123-1.22.1/src/libmpg123",
|
||||
"./../../Libraries/libexif-0.6.20",
|
||||
"./../../Libraries/faad2-2.7/include",
|
||||
"./../../Libraries/faad2-2.7/common/mp4ff",
|
||||
"/usr/local/Qt-5.4.0/include",
|
||||
"/usr/local/Qt-5.4.0/include/QtMultimedia",
|
||||
"/usr/local/Qt-5.4.0/include/QtWidgets",
|
||||
@ -2007,14 +1992,9 @@
|
||||
"-lz",
|
||||
"-lm",
|
||||
/usr/local/lib/libopenal.a,
|
||||
/usr/local/lib/libopusfile.a,
|
||||
/usr/local/lib/libopus.a,
|
||||
/usr/local/lib/libogg.a,
|
||||
/usr/local/lib/liblzma.a,
|
||||
/usr/local/lib/libexif.a,
|
||||
/usr/local/lib/libmpg123.a,
|
||||
/usr/local/lib/libfaad.a,
|
||||
/usr/local/lib/libmp4ff.a,
|
||||
/usr/local/lib/libavcodec.a,
|
||||
/usr/local/lib/libavformat.a,
|
||||
/usr/local/lib/libswresample.a,
|
||||
|
@ -1,2 +1,2 @@
|
||||
echo 8017 0.8.17 0
|
||||
echo 8018 0.8.18 1
|
||||
# AppVersion AppVersionStr DevChannel
|
||||
|
716
Telegram/_openal_patch/Alc/backends/winmm.c
Normal file
716
Telegram/_openal_patch/Alc/backends/winmm.c
Normal file
@ -0,0 +1,716 @@
|
||||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "alMain.h"
|
||||
#include "alu.h"
|
||||
#include "threads.h"
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
// MMSYSTEM Device
|
||||
volatile ALboolean killNow;
|
||||
althrd_t thread;
|
||||
|
||||
RefCount WaveBuffersCommitted;
|
||||
WAVEHDR WaveBuffer[4];
|
||||
|
||||
union {
|
||||
HWAVEIN In;
|
||||
HWAVEOUT Out;
|
||||
} WaveHandle;
|
||||
|
||||
WAVEFORMATEX Format;
|
||||
|
||||
RingBuffer *Ring;
|
||||
} WinMMData;
|
||||
|
||||
|
||||
TYPEDEF_VECTOR(al_string, vector_al_string)
|
||||
static vector_al_string PlaybackDevices;
|
||||
static vector_al_string CaptureDevices;
|
||||
|
||||
static void clear_devlist(vector_al_string *list)
|
||||
{
|
||||
VECTOR_FOR_EACH(al_string, *list, al_string_deinit);
|
||||
VECTOR_RESIZE(*list, 0);
|
||||
}
|
||||
|
||||
|
||||
static void ProbePlaybackDevices(void)
|
||||
{
|
||||
al_string *iter, *end;
|
||||
ALuint numdevs;
|
||||
ALuint i;
|
||||
|
||||
clear_devlist(&PlaybackDevices);
|
||||
|
||||
numdevs = waveOutGetNumDevs();
|
||||
VECTOR_RESERVE(PlaybackDevices, numdevs);
|
||||
for(i = 0;i < numdevs;i++)
|
||||
{
|
||||
WAVEOUTCAPSW WaveCaps;
|
||||
al_string dname;
|
||||
|
||||
AL_STRING_INIT(dname);
|
||||
if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
|
||||
{
|
||||
ALuint count = 0;
|
||||
do {
|
||||
al_string_copy_wcstr(&dname, WaveCaps.szPname);
|
||||
if(count != 0)
|
||||
{
|
||||
char str[64];
|
||||
snprintf(str, sizeof(str), " #%d", count+1);
|
||||
al_string_append_cstr(&dname, str);
|
||||
}
|
||||
count++;
|
||||
|
||||
iter = VECTOR_ITER_BEGIN(PlaybackDevices);
|
||||
end = VECTOR_ITER_END(PlaybackDevices);
|
||||
for(;iter != end;iter++)
|
||||
{
|
||||
if(al_string_cmp(*iter, dname) == 0)
|
||||
break;
|
||||
}
|
||||
} while(iter != end);
|
||||
|
||||
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
|
||||
}
|
||||
VECTOR_PUSH_BACK(PlaybackDevices, dname);
|
||||
}
|
||||
}
|
||||
|
||||
static void ProbeCaptureDevices(void)
|
||||
{
|
||||
al_string *iter, *end;
|
||||
ALuint numdevs;
|
||||
ALuint i;
|
||||
|
||||
clear_devlist(&CaptureDevices);
|
||||
|
||||
numdevs = waveInGetNumDevs();
|
||||
VECTOR_RESERVE(CaptureDevices, numdevs);
|
||||
for(i = 0;i < numdevs;i++)
|
||||
{
|
||||
WAVEINCAPSW WaveCaps;
|
||||
al_string dname;
|
||||
|
||||
AL_STRING_INIT(dname);
|
||||
if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
|
||||
{
|
||||
ALuint count = 0;
|
||||
do {
|
||||
al_string_copy_wcstr(&dname, WaveCaps.szPname);
|
||||
if(count != 0)
|
||||
{
|
||||
char str[64];
|
||||
snprintf(str, sizeof(str), " #%d", count+1);
|
||||
al_string_append_cstr(&dname, str);
|
||||
}
|
||||
count++;
|
||||
|
||||
iter = VECTOR_ITER_BEGIN(CaptureDevices);
|
||||
end = VECTOR_ITER_END(CaptureDevices);
|
||||
for(;iter != end;iter++)
|
||||
{
|
||||
if(al_string_cmp(*iter, dname) == 0)
|
||||
break;
|
||||
}
|
||||
} while(iter != end);
|
||||
|
||||
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
|
||||
}
|
||||
VECTOR_PUSH_BACK(CaptureDevices, dname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
WaveOutProc
|
||||
|
||||
Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
|
||||
returns to the application (for more data)
|
||||
*/
|
||||
static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
|
||||
{
|
||||
ALCdevice *Device = (ALCdevice*)instance;
|
||||
WinMMData *data = Device->ExtraData;
|
||||
|
||||
if(msg != WOM_DONE)
|
||||
return;
|
||||
|
||||
DecrementRef(&data->WaveBuffersCommitted);
|
||||
PostThreadMessage(data->thread, msg, 0, param1);
|
||||
}
|
||||
|
||||
FORCE_ALIGN static int PlaybackThreadProc(void *arg)
|
||||
{
|
||||
ALCdevice *Device = (ALCdevice*)arg;
|
||||
WinMMData *data = Device->ExtraData;
|
||||
WAVEHDR *WaveHdr;
|
||||
MSG msg;
|
||||
|
||||
SetRTPriority();
|
||||
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
|
||||
|
||||
while(GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if(msg.message != WOM_DONE)
|
||||
continue;
|
||||
|
||||
if(data->killNow)
|
||||
{
|
||||
if(ReadRef(&data->WaveBuffersCommitted) == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
WaveHdr = ((WAVEHDR*)msg.lParam);
|
||||
aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength /
|
||||
data->Format.nBlockAlign);
|
||||
|
||||
// Send buffer back to play more data
|
||||
waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR));
|
||||
IncrementRef(&data->WaveBuffersCommitted);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
WaveInProc
|
||||
|
||||
Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
|
||||
returns to the application (with more data)
|
||||
*/
|
||||
static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
|
||||
{
|
||||
ALCdevice *Device = (ALCdevice*)instance;
|
||||
WinMMData *data = Device->ExtraData;
|
||||
|
||||
if(msg != WIM_DATA)
|
||||
return;
|
||||
|
||||
DecrementRef(&data->WaveBuffersCommitted);
|
||||
PostThreadMessage(data->thread, msg, 0, param1);
|
||||
}
|
||||
|
||||
static int CaptureThreadProc(void *arg)
|
||||
{
|
||||
ALCdevice *Device = (ALCdevice*)arg;
|
||||
WinMMData *data = Device->ExtraData;
|
||||
WAVEHDR *WaveHdr;
|
||||
MSG msg;
|
||||
|
||||
althrd_setname(althrd_current(), "alsoft-record");
|
||||
|
||||
if (!data->killNow) while(GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if(msg.message != WIM_DATA)
|
||||
continue;
|
||||
/* Don't wait for other buffers to finish before quitting. We're
|
||||
* closing so we don't need them. */
|
||||
if(data->killNow)
|
||||
break;
|
||||
|
||||
WaveHdr = ((WAVEHDR*)msg.lParam);
|
||||
WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData,
|
||||
WaveHdr->dwBytesRecorded/data->Format.nBlockAlign);
|
||||
|
||||
// Send buffer back to capture more data
|
||||
waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR));
|
||||
IncrementRef(&data->WaveBuffersCommitted);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
|
||||
{
|
||||
WinMMData *data = NULL;
|
||||
const al_string *iter, *end;
|
||||
UINT DeviceID;
|
||||
MMRESULT res;
|
||||
|
||||
if(VECTOR_SIZE(PlaybackDevices) == 0)
|
||||
ProbePlaybackDevices();
|
||||
|
||||
// Find the Device ID matching the deviceName if valid
|
||||
iter = VECTOR_ITER_BEGIN(PlaybackDevices);
|
||||
end = VECTOR_ITER_END(PlaybackDevices);
|
||||
for(;iter != end;iter++)
|
||||
{
|
||||
if(!al_string_empty(*iter) &&
|
||||
(!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
|
||||
{
|
||||
DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(iter == end)
|
||||
return ALC_INVALID_VALUE;
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if(!data)
|
||||
return ALC_OUT_OF_MEMORY;
|
||||
Device->ExtraData = data;
|
||||
|
||||
retry_open:
|
||||
memset(&data->Format, 0, sizeof(WAVEFORMATEX));
|
||||
if(Device->FmtType == DevFmtFloat)
|
||||
{
|
||||
data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
data->Format.wBitsPerSample = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte)
|
||||
data->Format.wBitsPerSample = 8;
|
||||
else
|
||||
data->Format.wBitsPerSample = 16;
|
||||
}
|
||||
data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2);
|
||||
data->Format.nBlockAlign = data->Format.wBitsPerSample *
|
||||
data->Format.nChannels / 8;
|
||||
data->Format.nSamplesPerSec = Device->Frequency;
|
||||
data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
|
||||
data->Format.nBlockAlign;
|
||||
data->Format.cbSize = 0;
|
||||
|
||||
if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
|
||||
{
|
||||
if(Device->FmtType == DevFmtFloat)
|
||||
{
|
||||
Device->FmtType = DevFmtShort;
|
||||
goto retry_open;
|
||||
}
|
||||
ERR("waveOutOpen failed: %u\n", res);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
|
||||
return ALC_NO_ERROR;
|
||||
|
||||
failure:
|
||||
if(data->WaveHandle.Out)
|
||||
waveOutClose(data->WaveHandle.Out);
|
||||
|
||||
free(data);
|
||||
Device->ExtraData = NULL;
|
||||
return ALC_INVALID_VALUE;
|
||||
}
|
||||
|
||||
static void WinMMClosePlayback(ALCdevice *device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)device->ExtraData;
|
||||
|
||||
// Close the Wave device
|
||||
waveOutClose(data->WaveHandle.Out);
|
||||
data->WaveHandle.Out = 0;
|
||||
|
||||
free(data);
|
||||
device->ExtraData = NULL;
|
||||
}
|
||||
|
||||
static ALCboolean WinMMResetPlayback(ALCdevice *device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)device->ExtraData;
|
||||
|
||||
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
|
||||
data->Format.nSamplesPerSec /
|
||||
device->Frequency);
|
||||
device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
|
||||
device->NumUpdates = 4;
|
||||
device->Frequency = data->Format.nSamplesPerSec;
|
||||
|
||||
if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
|
||||
{
|
||||
if(data->Format.wBitsPerSample == 32)
|
||||
device->FmtType = DevFmtFloat;
|
||||
else
|
||||
{
|
||||
ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample);
|
||||
return ALC_FALSE;
|
||||
}
|
||||
}
|
||||
else if(data->Format.wFormatTag == WAVE_FORMAT_PCM)
|
||||
{
|
||||
if(data->Format.wBitsPerSample == 16)
|
||||
device->FmtType = DevFmtShort;
|
||||
else if(data->Format.wBitsPerSample == 8)
|
||||
device->FmtType = DevFmtUByte;
|
||||
else
|
||||
{
|
||||
ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample);
|
||||
return ALC_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag);
|
||||
return ALC_FALSE;
|
||||
}
|
||||
|
||||
if(data->Format.nChannels == 2)
|
||||
device->FmtChans = DevFmtStereo;
|
||||
else if(data->Format.nChannels == 1)
|
||||
device->FmtChans = DevFmtMono;
|
||||
else
|
||||
{
|
||||
ERR("Unhandled channel count: %d\n", data->Format.nChannels);
|
||||
return ALC_FALSE;
|
||||
}
|
||||
SetDefaultWFXChannelOrder(device);
|
||||
|
||||
return ALC_TRUE;
|
||||
}
|
||||
|
||||
static ALCboolean WinMMStartPlayback(ALCdevice *device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)device->ExtraData;
|
||||
ALbyte *BufferData;
|
||||
ALint BufferSize;
|
||||
ALuint i;
|
||||
|
||||
data->killNow = AL_FALSE;
|
||||
if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success)
|
||||
return ALC_FALSE;
|
||||
|
||||
InitRef(&data->WaveBuffersCommitted, 0);
|
||||
|
||||
// Create 4 Buffers
|
||||
BufferSize = device->UpdateSize*device->NumUpdates / 4;
|
||||
BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
|
||||
|
||||
BufferData = calloc(4, BufferSize);
|
||||
for(i = 0;i < 4;i++)
|
||||
{
|
||||
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
|
||||
data->WaveBuffer[i].dwBufferLength = BufferSize;
|
||||
data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
|
||||
(data->WaveBuffer[i-1].lpData +
|
||||
data->WaveBuffer[i-1].dwBufferLength));
|
||||
waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
IncrementRef(&data->WaveBuffersCommitted);
|
||||
}
|
||||
|
||||
return ALC_TRUE;
|
||||
}
|
||||
|
||||
static void WinMMStopPlayback(ALCdevice *device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)device->ExtraData;
|
||||
void *buffer = NULL;
|
||||
int i;
|
||||
|
||||
if(data->killNow)
|
||||
return;
|
||||
|
||||
// Set flag to stop processing headers
|
||||
data->killNow = AL_TRUE;
|
||||
althrd_join(data->thread, &i);
|
||||
|
||||
// Release the wave buffers
|
||||
for(i = 0;i < 4;i++)
|
||||
{
|
||||
waveOutUnprepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
if(i == 0) buffer = data->WaveBuffer[i].lpData;
|
||||
data->WaveBuffer[i].lpData = NULL;
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
|
||||
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
|
||||
{
|
||||
const al_string *iter, *end;
|
||||
ALbyte *BufferData = NULL;
|
||||
DWORD CapturedDataSize;
|
||||
WinMMData *data = NULL;
|
||||
ALint BufferSize;
|
||||
UINT DeviceID;
|
||||
MMRESULT res;
|
||||
ALuint i;
|
||||
|
||||
if(VECTOR_SIZE(CaptureDevices) == 0)
|
||||
ProbeCaptureDevices();
|
||||
|
||||
// Find the Device ID matching the deviceName if valid
|
||||
iter = VECTOR_ITER_BEGIN(CaptureDevices);
|
||||
end = VECTOR_ITER_END(CaptureDevices);
|
||||
for(;iter != end;iter++)
|
||||
{
|
||||
if(!al_string_empty(*iter) &&
|
||||
(!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
|
||||
{
|
||||
DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(iter == end)
|
||||
return ALC_INVALID_VALUE;
|
||||
|
||||
switch(Device->FmtChans)
|
||||
{
|
||||
case DevFmtMono:
|
||||
case DevFmtStereo:
|
||||
break;
|
||||
|
||||
case DevFmtQuad:
|
||||
case DevFmtX51:
|
||||
case DevFmtX51Side:
|
||||
case DevFmtX61:
|
||||
case DevFmtX71:
|
||||
return ALC_INVALID_ENUM;
|
||||
}
|
||||
|
||||
switch(Device->FmtType)
|
||||
{
|
||||
case DevFmtUByte:
|
||||
case DevFmtShort:
|
||||
case DevFmtInt:
|
||||
case DevFmtFloat:
|
||||
break;
|
||||
|
||||
case DevFmtByte:
|
||||
case DevFmtUShort:
|
||||
case DevFmtUInt:
|
||||
return ALC_INVALID_ENUM;
|
||||
}
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if(!data)
|
||||
return ALC_OUT_OF_MEMORY;
|
||||
Device->ExtraData = data;
|
||||
|
||||
memset(&data->Format, 0, sizeof(WAVEFORMATEX));
|
||||
data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ?
|
||||
WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
|
||||
data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans);
|
||||
data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
|
||||
data->Format.nBlockAlign = data->Format.wBitsPerSample *
|
||||
data->Format.nChannels / 8;
|
||||
data->Format.nSamplesPerSec = Device->Frequency;
|
||||
data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
|
||||
data->Format.nBlockAlign;
|
||||
data->Format.cbSize = 0;
|
||||
|
||||
if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
|
||||
{
|
||||
ERR("waveInOpen failed: %u\n", res);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Allocate circular memory buffer for the captured audio
|
||||
CapturedDataSize = Device->UpdateSize*Device->NumUpdates;
|
||||
|
||||
// Make sure circular buffer is at least 100ms in size
|
||||
if(CapturedDataSize < (data->Format.nSamplesPerSec / 10))
|
||||
CapturedDataSize = data->Format.nSamplesPerSec / 10;
|
||||
|
||||
data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize);
|
||||
if(!data->Ring)
|
||||
goto failure;
|
||||
|
||||
InitRef(&data->WaveBuffersCommitted, 0);
|
||||
|
||||
// Create 4 Buffers of 50ms each
|
||||
BufferSize = data->Format.nAvgBytesPerSec / 20;
|
||||
BufferSize -= (BufferSize % data->Format.nBlockAlign);
|
||||
|
||||
BufferData = calloc(4, BufferSize);
|
||||
if(!BufferData)
|
||||
goto failure;
|
||||
|
||||
for(i = 0;i < 4;i++)
|
||||
{
|
||||
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
|
||||
data->WaveBuffer[i].dwBufferLength = BufferSize;
|
||||
data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
|
||||
(data->WaveBuffer[i-1].lpData +
|
||||
data->WaveBuffer[i-1].dwBufferLength));
|
||||
data->WaveBuffer[i].dwFlags = 0;
|
||||
data->WaveBuffer[i].dwLoops = 0;
|
||||
waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
IncrementRef(&data->WaveBuffersCommitted);
|
||||
}
|
||||
|
||||
if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success)
|
||||
goto failure;
|
||||
|
||||
al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
|
||||
return ALC_NO_ERROR;
|
||||
|
||||
failure:
|
||||
if(BufferData)
|
||||
{
|
||||
for(i = 0;i < 4;i++)
|
||||
waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
free(BufferData);
|
||||
}
|
||||
|
||||
if(data->Ring)
|
||||
DestroyRingBuffer(data->Ring);
|
||||
|
||||
if(data->WaveHandle.In)
|
||||
waveInClose(data->WaveHandle.In);
|
||||
|
||||
free(data);
|
||||
Device->ExtraData = NULL;
|
||||
return ALC_INVALID_VALUE;
|
||||
}
|
||||
|
||||
static void WinMMCloseCapture(ALCdevice *Device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)Device->ExtraData;
|
||||
void *buffer = NULL;
|
||||
int i;
|
||||
|
||||
/* Tell the processing thread to quit and wait for it to do so. */
|
||||
data->killNow = AL_TRUE;
|
||||
PostThreadMessage(data->thread, WM_QUIT, 0, 0);
|
||||
|
||||
althrd_join(data->thread, &i);
|
||||
|
||||
/* Make sure capture is stopped and all pending buffers are flushed. */
|
||||
waveInReset(data->WaveHandle.In);
|
||||
|
||||
// Release the wave buffers
|
||||
for(i = 0;i < 4;i++)
|
||||
{
|
||||
waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
|
||||
if(i == 0) buffer = data->WaveBuffer[i].lpData;
|
||||
data->WaveBuffer[i].lpData = NULL;
|
||||
}
|
||||
free(buffer);
|
||||
|
||||
DestroyRingBuffer(data->Ring);
|
||||
data->Ring = NULL;
|
||||
|
||||
// Close the Wave device
|
||||
waveInClose(data->WaveHandle.In);
|
||||
data->WaveHandle.In = 0;
|
||||
|
||||
free(data);
|
||||
Device->ExtraData = NULL;
|
||||
}
|
||||
|
||||
static void WinMMStartCapture(ALCdevice *Device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)Device->ExtraData;
|
||||
waveInStart(data->WaveHandle.In);
|
||||
}
|
||||
|
||||
static void WinMMStopCapture(ALCdevice *Device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)Device->ExtraData;
|
||||
waveInStop(data->WaveHandle.In);
|
||||
}
|
||||
|
||||
static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)Device->ExtraData;
|
||||
ReadRingBuffer(data->Ring, Buffer, Samples);
|
||||
return ALC_NO_ERROR;
|
||||
}
|
||||
|
||||
static ALCuint WinMMAvailableSamples(ALCdevice *Device)
|
||||
{
|
||||
WinMMData *data = (WinMMData*)Device->ExtraData;
|
||||
return RingBufferSize(data->Ring);
|
||||
}
|
||||
|
||||
|
||||
static inline void AppendAllDevicesList2(const al_string *name)
|
||||
{
|
||||
if(!al_string_empty(*name))
|
||||
AppendAllDevicesList(al_string_get_cstr(*name));
|
||||
}
|
||||
static inline void AppendCaptureDeviceList2(const al_string *name)
|
||||
{
|
||||
if(!al_string_empty(*name))
|
||||
AppendCaptureDeviceList(al_string_get_cstr(*name));
|
||||
}
|
||||
|
||||
static const BackendFuncs WinMMFuncs = {
|
||||
WinMMOpenPlayback,
|
||||
WinMMClosePlayback,
|
||||
WinMMResetPlayback,
|
||||
WinMMStartPlayback,
|
||||
WinMMStopPlayback,
|
||||
WinMMOpenCapture,
|
||||
WinMMCloseCapture,
|
||||
WinMMStartCapture,
|
||||
WinMMStopCapture,
|
||||
WinMMCaptureSamples,
|
||||
WinMMAvailableSamples,
|
||||
ALCdevice_GetLatencyDefault
|
||||
};
|
||||
|
||||
ALCboolean alcWinMMInit(BackendFuncs *FuncList)
|
||||
{
|
||||
VECTOR_INIT(PlaybackDevices);
|
||||
VECTOR_INIT(CaptureDevices);
|
||||
|
||||
*FuncList = WinMMFuncs;
|
||||
return ALC_TRUE;
|
||||
}
|
||||
|
||||
void alcWinMMDeinit()
|
||||
{
|
||||
clear_devlist(&PlaybackDevices);
|
||||
VECTOR_DEINIT(PlaybackDevices);
|
||||
|
||||
clear_devlist(&CaptureDevices);
|
||||
VECTOR_DEINIT(CaptureDevices);
|
||||
}
|
||||
|
||||
void alcWinMMProbe(enum DevProbe type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ALL_DEVICE_PROBE:
|
||||
ProbePlaybackDevices();
|
||||
VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
|
||||
break;
|
||||
|
||||
case CAPTURE_DEVICE_PROBE:
|
||||
ProbeCaptureDevices();
|
||||
VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user