1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #include "mumble_pch.hpp"
7 
8 #include "CELTCodec.h"
9 
10 #include "Audio.h"
11 #include "Version.h"
12 #include "MumbleApplication.h"
13 
14 #ifdef Q_CC_GNU
15 #define RESOLVE(var) { var = reinterpret_cast<__typeof__(var)>(qlCELT.resolve(#var)); bValid = bValid && (var != NULL); }
16 #else
17 #define RESOLVE(var) { * reinterpret_cast<void **>(&var) = static_cast<void *>(qlCELT.resolve(#var)); bValid = bValid && (var != NULL); }
18 #endif
19 
20 #ifdef Q_OS_WIN
21 extern "C" {
22 	void __cpuid(int a[4], int b);
23 };
24 #endif
25 
CELTCodec(const QString & celt_version)26 CELTCodec::CELTCodec(const QString &celt_version) {
27 	bValid = false;
28 	cmMode = NULL;
29 	qsVersion = celt_version;
30 	iBitstreamVersion = INT_MIN;
31 	qlCELT.setLoadHints(QLibrary::ResolveAllSymbolsHint);
32 
33 	QStringList alternatives;
34 #if defined(Q_OS_MAC)
35 	alternatives << QString::fromLatin1("libcelt0.%1.dylib").arg(celt_version);
36 	alternatives << QString::fromLatin1("celt0.%1.dylib").arg(celt_version);
37 	alternatives << QString::fromLatin1("libcelt.%1.dylib").arg(celt_version);
38 	alternatives << QString::fromLatin1("celt.%1.dylib").arg(celt_version);
39 #elif defined(Q_OS_UNIX)
40 	alternatives << QString::fromLatin1("libcelt0.so.%1").arg(celt_version);
41 	alternatives << QString::fromLatin1("libcelt.so.%1").arg(celt_version);
42 	alternatives << QString::fromLatin1("celt.so.%1").arg(celt_version);
43 	alternatives << QString::fromLatin1("libcelt-mumble.so.%1").arg(celt_version);
44 #else
45 	int cpuinfo[4];
46 	__cpuid(cpuinfo, 1);
47 	if (cpuinfo[3] & 0x02000000) {
48 		if (cpuinfo[3] & 0x04000000) {
49 			if (cpuinfo[2] & 0x00000001) {
50 				alternatives << QString::fromLatin1("celt0.%1.sse3.dll").arg(celt_version);
51 			}
52 			alternatives << QString::fromLatin1("celt0.%1.sse2.dll").arg(celt_version);
53 		}
54 		alternatives << QString::fromLatin1("celt0.%1.sse.dll").arg(celt_version);
55 	}
56 
57 	alternatives << QString::fromLatin1("celt0.%1.dll").arg(celt_version);
58 #endif
59 	foreach(const QString &lib, alternatives) {
60 		qlCELT.setFileName(MumbleApplication::instance()->applicationVersionRootPath() + QLatin1String("/") + lib);
61 		if (qlCELT.load()) {
62 			bValid = true;
63 			break;
64 		}
65 
66 #ifdef Q_OS_MAC
67 		qlCELT.setFileName(QApplication::instance()->applicationDirPath() + QLatin1String("/../Codecs/") + lib);
68 		if (qlCELT.load()) {
69 			bValid = true;
70 			break;
71 		}
72 #endif
73 
74 #ifdef PLUGIN_PATH
75 		qlCELT.setFileName(QLatin1String(MUMTEXT(PLUGIN_PATH) "/") + lib);
76 		if (qlCELT.load()) {
77 			bValid = true;
78 			break;
79 		}
80 #endif
81 
82 		qlCELT.setFileName(lib);
83 		if (qlCELT.load()) {
84 			bValid = true;
85 			break;
86 		}
87 	}
88 
89 	RESOLVE(celt_mode_destroy);
90 	RESOLVE(celt_mode_info);
91 
92 	RESOLVE(celt_encoder_destroy);
93 	RESOLVE(celt_encoder_ctl);
94 
95 	RESOLVE(celt_decoder_destroy);
96 	RESOLVE(celt_decoder_ctl);
97 }
98 
~CELTCodec()99 CELTCodec::~CELTCodec() {
100 	if (cmMode)
101 		celt_mode_destroy(const_cast<CELTMode *>(cmMode));
102 }
103 
isValid() const104 bool CELTCodec::isValid() const {
105 	return bValid;
106 }
107 
bitstreamVersion() const108 int CELTCodec::bitstreamVersion() const {
109 	if (cmMode && iBitstreamVersion == INT_MIN)
110 		celt_mode_info(cmMode, CELT_GET_BITSTREAM_VERSION, reinterpret_cast<celt_int32 *>(&iBitstreamVersion));
111 
112 	return iBitstreamVersion;
113 }
114 
version() const115 QString CELTCodec::version() const {
116 	return qsVersion;
117 }
118 
report() const119 void CELTCodec::report() const {
120 	qWarning("CELT bitstream %08x from %s", bitstreamVersion(), qPrintable(qlCELT.fileName()));
121 }
122 
CELTCodec070(const QString & celt_version)123 CELTCodec070::CELTCodec070(const QString &celt_version) : CELTCodec(celt_version) {
124 	RESOLVE(celt_mode_create);
125 	RESOLVE(celt_encoder_create);
126 	RESOLVE(celt_decoder_create);
127 	RESOLVE(celt_encode_float);
128 	RESOLVE(celt_encode);
129 	RESOLVE(celt_decode_float);
130 	RESOLVE(celt_decode);
131 	RESOLVE(celt_strerror);
132 
133 	if (bValid) {
134 		cmMode = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL);
135 	}
136 }
137 
encoderCreate()138 CELTEncoder *CELTCodec070::encoderCreate() {
139 	return celt_encoder_create(cmMode, 1, NULL);
140 }
141 
decoderCreate()142 CELTDecoder *CELTCodec070::decoderCreate() {
143 	return celt_decoder_create(cmMode, 1, NULL);
144 }
145 
encode(CELTEncoder * st,const celt_int16 * pcm,unsigned char * compressed,int nbCompressedBytes)146 int CELTCodec070::encode(CELTEncoder *st, const celt_int16 *pcm, unsigned char *compressed, int nbCompressedBytes) {
147 	return celt_encode(st, pcm, NULL, compressed, nbCompressedBytes);
148 }
149 
decode_float(CELTDecoder * st,const unsigned char * data,int len,float * pcm)150 int CELTCodec070::decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm) {
151 	return celt_decode_float(st, data, len, pcm);
152 }
153 
CELTCodec011(const QString & celt_version)154 CELTCodec011::CELTCodec011(const QString &celt_version) : CELTCodec(celt_version) {
155 	RESOLVE(celt_mode_create);
156 	RESOLVE(celt_encoder_create_custom);
157 	RESOLVE(celt_decoder_create_custom);
158 	RESOLVE(celt_encode_float);
159 	RESOLVE(celt_encode);
160 	RESOLVE(celt_decode_float);
161 	RESOLVE(celt_decode);
162 	RESOLVE(celt_strerror);
163 
164 	if (bValid) {
165 		cmMode = celt_mode_create(SAMPLE_RATE, SAMPLE_RATE / 100, NULL);
166 	}
167 }
168 
encoderCreate()169 CELTEncoder *CELTCodec011::encoderCreate() {
170 	return celt_encoder_create_custom(cmMode, 1, NULL);
171 }
172 
decoderCreate()173 CELTDecoder *CELTCodec011::decoderCreate() {
174 	return celt_decoder_create_custom(cmMode, 1, NULL);
175 }
176 
encode(CELTEncoder * st,const celt_int16 * pcm,unsigned char * compressed,int nbCompressedBytes)177 int CELTCodec011::encode(CELTEncoder *st, const celt_int16 *pcm, unsigned char *compressed, int nbCompressedBytes) {
178 	return celt_encode(st, pcm, SAMPLE_RATE / 100, compressed, nbCompressedBytes);
179 }
180 
decode_float(CELTDecoder * st,const unsigned char * data,int len,float * pcm)181 int CELTCodec011::decode_float(CELTDecoder *st, const unsigned char *data, int len, float *pcm) {
182 	return celt_decode_float(st, data, len, pcm, SAMPLE_RATE / 100);
183 }
184