mumlib.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #include "mumlib/CryptState.hpp"
  2. #include "mumlib/VarInt.hpp"
  3. #include "mumlib/enums.hpp"
  4. #include "mumlib/Transport.hpp"
  5. #include "mumlib/Audio.hpp"
  6. #include "mumlib.hpp"
  7. #include <boost/asio.hpp>
  8. #include <boost/bind.hpp>
  9. #include <log4cpp/Category.hh>
  10. #include <Mumble.pb.h>
  11. using namespace std;
  12. using namespace boost::asio;
  13. using namespace mumlib;
  14. namespace mumlib {
  15. struct _Mumlib_Private : boost::noncopyable {
  16. log4cpp::Category &logger = log4cpp::Category::getInstance("mumlib.Mumlib");
  17. bool externalIoService;
  18. io_service &ioService;
  19. Callback &callback;
  20. Transport transport;
  21. Audio audio;
  22. int sessionId = 0;
  23. int channelId = 0;
  24. _Mumlib_Private(Callback &callback, MumlibConfiguration &configuration)
  25. : _Mumlib_Private(callback, *(new io_service()), configuration) {
  26. externalIoService = false;
  27. }
  28. _Mumlib_Private(Callback &callback, io_service &ioService, MumlibConfiguration &configuration)
  29. : callback(callback),
  30. ioService(ioService),
  31. externalIoService(true),
  32. transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3),
  33. boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)) {
  34. audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate);
  35. }
  36. virtual ~_Mumlib_Private() {
  37. if (not externalIoService) {
  38. delete &ioService;
  39. }
  40. }
  41. bool processAudioPacket(AudioPacketType type, uint8_t *buffer, int length) {
  42. logger.info("Got %d B of encoded audio data.", length);
  43. try {
  44. auto incomingAudioPacket = audio.decodeIncomingAudioPacket(buffer, length);
  45. if (type == AudioPacketType::OPUS) {
  46. int16_t pcmData[5000];
  47. auto status = audio.decodeOpusPayload(incomingAudioPacket.audioPayload,
  48. incomingAudioPacket.audioPayloadLength,
  49. pcmData,
  50. 5000);
  51. callback.audio(incomingAudioPacket.target,
  52. incomingAudioPacket.sessionId,
  53. incomingAudioPacket.sequenceNumber,
  54. pcmData,
  55. status.first);
  56. } else {
  57. logger.warn("Incoming audio packet doesn't contain Opus data, calling unsupportedAudio callback.");
  58. callback.unsupportedAudio(incomingAudioPacket.target,
  59. incomingAudioPacket.sessionId,
  60. incomingAudioPacket.sequenceNumber,
  61. incomingAudioPacket.audioPayload,
  62. incomingAudioPacket.audioPayloadLength);
  63. }
  64. } catch (mumlib::AudioException &exp) {
  65. logger.error("Audio decode error: %s.", exp.what());
  66. }
  67. return true;
  68. }
  69. private:
  70. bool processIncomingTcpMessage(MessageType messageType, uint8_t *buffer, int length) {
  71. logger.debug("Process incoming message: type %d, length: %d.", messageType, length);
  72. switch (messageType) {
  73. case MessageType::VERSION: {
  74. MumbleProto::Version version;
  75. version.ParseFromArray(buffer, length);
  76. callback.version(
  77. version.version() >> 16,
  78. version.version() >> 8 & 0xff,
  79. version.version() & 0xff,
  80. version.release(),
  81. version.os(),
  82. version.os_version());
  83. }
  84. break;
  85. case MessageType::SERVERSYNC: {
  86. MumbleProto::ServerSync serverSync;
  87. serverSync.ParseFromArray(buffer, length);
  88. sessionId = serverSync.session();
  89. callback.serverSync(
  90. serverSync.welcome_text(),
  91. serverSync.session(),
  92. serverSync.max_bandwidth(),
  93. serverSync.permissions()
  94. );
  95. }
  96. break;
  97. case MessageType::CHANNELREMOVE: {
  98. MumbleProto::ChannelRemove channelRemove;
  99. channelRemove.ParseFromArray(buffer, length);
  100. callback.channelRemove(channelRemove.channel_id());
  101. }
  102. break;
  103. case MessageType::CHANNELSTATE: {
  104. MumbleProto::ChannelState channelState;
  105. channelState.ParseFromArray(buffer, length);
  106. int32_t channel_id = channelState.has_channel_id() ? channelState.channel_id() : -1;
  107. int32_t parent = channelState.has_parent() ? channelState.parent() : -1;
  108. bool temporary = channelState.has_temporary() ? channelState.temporary()
  109. : false; //todo make sure it's correct to assume it's false
  110. int position = channelState.has_position() ? channelState.position() : 0;
  111. vector<uint32_t> links;
  112. for (int i = 0; i < channelState.links_size(); ++i) {
  113. links.push_back(channelState.links(i));
  114. }
  115. vector<uint32_t> links_add;
  116. for (int i = 0; i < channelState.links_add_size(); ++i) {
  117. links_add.push_back(channelState.links_add(i));
  118. }
  119. vector<uint32_t> links_remove;
  120. for (int i = 0; i < channelState.links_remove_size(); ++i) {
  121. links_remove.push_back(channelState.links_remove(i));
  122. }
  123. this->channelId = channel_id;
  124. callback.channelState(
  125. channelState.name(),
  126. channel_id,
  127. parent,
  128. channelState.description(),
  129. links,
  130. links_add,
  131. links_remove,
  132. temporary,
  133. position
  134. );
  135. }
  136. break;
  137. case MessageType::USERREMOVE: {
  138. MumbleProto::UserRemove user_remove;
  139. user_remove.ParseFromArray(buffer, length);
  140. int32_t actor = user_remove.has_actor() ? user_remove.actor() : -1;
  141. bool ban = user_remove.has_ban() ? user_remove.ban()
  142. : false; //todo make sure it's correct to assume it's false
  143. callback.userRemove(
  144. user_remove.session(),
  145. actor,
  146. user_remove.reason(),
  147. ban
  148. );
  149. }
  150. break;
  151. case MessageType::USERSTATE: {
  152. MumbleProto::UserState userState;
  153. userState.ParseFromArray(buffer, length);
  154. // There are far too many things in this structure. Culling to the ones that are probably important
  155. int32_t session = userState.has_session() ? userState.session() : -1;
  156. int32_t actor = userState.has_actor() ? userState.actor() : -1;
  157. int32_t user_id = userState.has_user_id() ? userState.user_id() : -1;
  158. int32_t channel_id = userState.has_channel_id() ? userState.channel_id() : -1;
  159. int32_t mute = userState.has_mute() ? userState.mute() : -1;
  160. int32_t deaf = userState.has_deaf() ? userState.deaf() : -1;
  161. int32_t suppress = userState.has_suppress() ? userState.suppress() : -1;
  162. int32_t self_mute = userState.has_self_mute() ? userState.self_mute() : -1;
  163. int32_t self_deaf = userState.has_self_deaf() ? userState.self_deaf() : -1;
  164. int32_t priority_speaker = userState.has_priority_speaker() ? userState.priority_speaker() : -1;
  165. int32_t recording = userState.has_recording() ? userState.recording() : -1;
  166. callback.userState(session,
  167. actor,
  168. userState.name(),
  169. user_id,
  170. channel_id,
  171. mute,
  172. deaf,
  173. suppress,
  174. self_mute,
  175. self_deaf,
  176. userState.comment(),
  177. priority_speaker,
  178. recording);
  179. }
  180. break;
  181. case MessageType::BANLIST: {
  182. MumbleProto::BanList ban_list;
  183. ban_list.ParseFromArray(buffer, length);
  184. for (int i = 0; i < ban_list.bans_size(); i++) {
  185. auto ban = ban_list.bans(i);
  186. const uint8_t *ip_data = reinterpret_cast<const uint8_t *>(ban.address().c_str());
  187. uint32_t ip_data_size = ban.address().size();
  188. int32_t duration = ban.has_duration() ? ban.duration() : -1;
  189. callback.banList(
  190. ip_data,
  191. ip_data_size,
  192. ban.mask(),
  193. ban.name(),
  194. ban.hash(),
  195. ban.reason(),
  196. ban.start(),
  197. duration);
  198. }
  199. }
  200. break;
  201. case MessageType::TEXTMESSAGE: {
  202. MumbleProto::TextMessage text_message;
  203. text_message.ParseFromArray(buffer, length);
  204. int32_t actor = text_message.has_actor() ? text_message.actor() : -1;
  205. vector<uint32_t> sessions;
  206. for (int i = 0; i < text_message.session_size(); ++i) {
  207. sessions.push_back(text_message.session(i));
  208. }
  209. vector<uint32_t> channel_ids;
  210. for (int i = 0; i < text_message.channel_id_size(); ++i) {
  211. channel_ids.push_back(text_message.channel_id(i));
  212. }
  213. vector<uint32_t> tree_ids;
  214. for (int i = 0; i < text_message.tree_id_size(); ++i) {
  215. tree_ids.push_back(text_message.tree_id(i));
  216. }
  217. callback.textMessage(actor, sessions, channel_ids, tree_ids, text_message.message());
  218. }
  219. break;
  220. case MessageType::PERMISSIONDENIED: // 12
  221. logger.warn("PermissionDenied Message: support not implemented yet");
  222. break;
  223. case MessageType::ACL: // 13
  224. logger.warn("ACL Message: support not implemented yet.");
  225. break;
  226. case MessageType::QUERYUSERS: // 14
  227. logger.warn("QueryUsers Message: support not implemented yet");
  228. break;
  229. case MessageType::CONTEXTACTIONMODIFY: // 16
  230. logger.warn("ContextActionModify Message: support not implemented yet");
  231. break;
  232. case MessageType::CONTEXTACTION: // 17
  233. logger.warn("ContextAction Message: support not implemented yet");
  234. break;
  235. case MessageType::USERLIST: // 18
  236. logger.warn("UserList Message: support not implemented yet");
  237. break;
  238. case MessageType::VOICETARGET:
  239. logger.warn("VoiceTarget Message: I don't think the server ever sends this structure.");
  240. break;
  241. case MessageType::PERMISSIONQUERY: {
  242. MumbleProto::PermissionQuery permissionQuery;
  243. permissionQuery.ParseFromArray(buffer, length);
  244. int32_t channel_id = permissionQuery.has_channel_id() ? permissionQuery.channel_id() : -1;
  245. uint32_t permissions = permissionQuery.has_permissions() ? permissionQuery.permissions() : 0;
  246. uint32_t flush = permissionQuery.has_flush() ? permissionQuery.flush() : -1;
  247. callback.permissionQuery(channel_id, permissions, flush);
  248. }
  249. break;
  250. case MessageType::CODECVERSION: {
  251. MumbleProto::CodecVersion codecVersion;
  252. codecVersion.ParseFromArray(buffer, length);
  253. int32_t alpha = codecVersion.alpha();
  254. int32_t beta = codecVersion.beta();
  255. uint32_t prefer_alpha = codecVersion.prefer_alpha();
  256. int32_t opus = codecVersion.has_opus() ? codecVersion.opus() : 0;
  257. callback.codecVersion(alpha, beta, prefer_alpha, opus);
  258. }
  259. break;
  260. case MessageType::USERSTATS:
  261. logger.warn("UserStats Message: support not implemented yet");
  262. break;
  263. case MessageType::REQUESTBLOB: // 23
  264. logger.warn("RequestBlob Message: I don't think this is sent by the server.");
  265. break;
  266. case MessageType::SERVERCONFIG: {
  267. MumbleProto::ServerConfig serverConfig;
  268. serverConfig.ParseFromArray(buffer, length);
  269. uint32_t max_bandwidth = serverConfig.has_max_bandwidth() ? serverConfig.max_bandwidth() : 0;
  270. uint32_t allow_html = serverConfig.has_allow_html() ? serverConfig.allow_html() : 0;
  271. uint32_t message_length = serverConfig.has_message_length() ? serverConfig.message_length() : 0;
  272. uint32_t image_message_length = serverConfig.has_image_message_length()
  273. ? serverConfig.image_message_length() : 0;
  274. callback.serverConfig(max_bandwidth, serverConfig.welcome_text(), allow_html, message_length,
  275. image_message_length);
  276. }
  277. break;
  278. case MessageType::SUGGESTCONFIG: // 25
  279. logger.warn("SuggestConfig Message: support not implemented yet");
  280. break;
  281. default:
  282. throw MumlibException("unknown message type: " + to_string(static_cast<int>(messageType)));
  283. }
  284. return true;
  285. }
  286. };
  287. Mumlib::Mumlib(Callback &callback) {
  288. MumlibConfiguration conf;
  289. impl = new _Mumlib_Private(callback, conf);
  290. }
  291. Mumlib::Mumlib(Callback &callback, io_service &ioService) {
  292. MumlibConfiguration conf;
  293. impl = new _Mumlib_Private(callback, ioService, conf);
  294. }
  295. Mumlib::Mumlib(Callback &callback, MumlibConfiguration &configuration)
  296. : impl(new _Mumlib_Private(callback, configuration)) { }
  297. Mumlib::Mumlib(Callback &callback, io_service &ioService, MumlibConfiguration &configuration)
  298. : impl(new _Mumlib_Private(callback, ioService, configuration)) { }
  299. Mumlib::~Mumlib() {
  300. disconnect();
  301. delete impl;
  302. }
  303. ConnectionState Mumlib::getConnectionState() {
  304. return impl->transport.getConnectionState();
  305. }
  306. void Mumlib::connect(string host, int port, string user, string password) {
  307. impl->transport.connect(host, port, user, password);
  308. }
  309. void Mumlib::disconnect() {
  310. if (not impl->externalIoService) {
  311. impl->ioService.reset();
  312. }
  313. if (impl->transport.getConnectionState() != ConnectionState::NOT_CONNECTED) {
  314. impl->transport.disconnect();
  315. }
  316. }
  317. void Mumlib::run() {
  318. if (impl->externalIoService) {
  319. throw MumlibException("can't call run() when using external io_service");
  320. }
  321. impl->ioService.run();
  322. }
  323. void Mumlib::sendAudioData(int16_t *pcmData, int pcmLength) {
  324. uint8_t encodedData[5000];
  325. int length = impl->audio.encodeAudioPacket(0, pcmData, pcmLength, encodedData, 5000);
  326. impl->transport.sendEncodedAudioPacket(encodedData, length);
  327. }
  328. void Mumlib::sendTextMessage(string message) {
  329. MumbleProto::TextMessage textMessage;
  330. textMessage.set_actor(impl->sessionId);
  331. textMessage.add_channel_id(impl->channelId);
  332. textMessage.set_message(message);
  333. impl->transport.sendControlMessage(MessageType::TEXTMESSAGE, textMessage);
  334. }
  335. void Mumlib::joinChannel(int channelId) {
  336. MumbleProto::UserState userState;
  337. userState.set_channel_id(channelId);
  338. impl->transport.sendControlMessage(MessageType::USERSTATE, userState);
  339. impl->channelId = channelId;
  340. }
  341. }