mirror of
https://github.com/ars3niy/tdlib-purple
synced 2025-08-22 01:49:29 +00:00
Started adding voice call support with libtgvoip
This commit is contained in:
parent
8368563615
commit
78846fb133
@ -13,6 +13,8 @@ set(NoWebp FALSE CACHE BOOL "Do not decode webp stickers")
|
||||
set(NoBundledLottie FALSE CACHE BOOL "Do not use bundled rlottie library")
|
||||
set(NoLottie FALSE CACHE BOOL "Disable animated sticker conversion")
|
||||
set(NoTranslations FALSE CACHE BOOL "Disable translation support")
|
||||
set(tgvoip_INCLUDE_DIRS "" CACHE STRING "Path to libtgvoip headers")
|
||||
set(tgvoip_LIBRARIES "tgvoip" CACHE STRING "tgvoip library to link against")
|
||||
set(API_ID 94575 CACHE STRING "API id")
|
||||
set(API_HASH a3406de8d171bb422bb6ddf3bbd800e2 CACHE STRING "API hash")
|
||||
set(STUFF "" CACHE STRING "")
|
||||
@ -51,6 +53,7 @@ add_library(telegram-tdlib SHARED
|
||||
format.cpp
|
||||
sticker.cpp
|
||||
file-transfer.cpp
|
||||
call.cpp
|
||||
)
|
||||
|
||||
# libpurple uses the deprecated glib-type `GParameter` and the deprecated glib-macro `G_CONST_RETURN`, which
|
||||
@ -113,6 +116,13 @@ if (NOT NoTranslations)
|
||||
target_link_libraries(telegram-tdlib PRIVATE ${Intl_LIBRARIES})
|
||||
endif (NOT NoTranslations)
|
||||
|
||||
if (NOT tgvoip_INCLUDE_DIRS STREQUAL "")
|
||||
target_include_directories(telegram-tdlib SYSTEM PRIVATE ${tgvoip_INCLUDE_DIRS})
|
||||
endif (NOT tgvoip_INCLUDE_DIRS STREQUAL "")
|
||||
if (NOT NoVoip)
|
||||
target_link_libraries(telegram-tdlib PRIVATE ${tgvoip_LIBRARIES})
|
||||
endif (NOT NoVoip)
|
||||
|
||||
if (DEFINED STANDARD_LIBRARIES_EXTRA)
|
||||
set (CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} ${STANDARD_LIBRARIES_EXTRA}")
|
||||
endif (DEFINED STANDARD_LIBRARIES_EXTRA)
|
||||
|
@ -47,6 +47,8 @@ make install DESTDIR=/path/to/tdlib
|
||||
```
|
||||
Also see [building](https://github.com/tdlib/td#building) for additional details on TDLib building.
|
||||
|
||||
libtgvoip is required for voice calls.
|
||||
|
||||
Building this plugin:
|
||||
```
|
||||
mkdir build
|
||||
@ -68,6 +70,13 @@ Building without animated sticker decoding: `-DNoLottie=True`
|
||||
|
||||
Building without localization: `-DNoTranslations=True`
|
||||
|
||||
Building without voice call support: `-DNoVoip=True`
|
||||
|
||||
If libtgvoip is not installed in include/library path then build with
|
||||
```
|
||||
-Dtgvoip_INCLUDE_DIRS=/path/to/tgvoip/include -Dtgvoip_LIBRARIES=/path/to/libtgvoip.a
|
||||
```
|
||||
|
||||
## Proper user names in bitlbee
|
||||
|
||||
```
|
||||
|
@ -702,3 +702,24 @@ TdAccountData::getBasicGroupsWithMember(int32_t userId)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TdAccountData::hasActiveCall()
|
||||
{
|
||||
return (m_callData != nullptr);
|
||||
}
|
||||
|
||||
void TdAccountData::setActiveCall()
|
||||
{
|
||||
if (!m_callData)
|
||||
m_callData = std::make_unique<tgvoip::VoIPController>();
|
||||
}
|
||||
|
||||
tgvoip::VoIPController *TdAccountData::getCallData()
|
||||
{
|
||||
return m_callData.get();
|
||||
}
|
||||
|
||||
void TdAccountData::removeActiveCall()
|
||||
{
|
||||
m_callData.reset();
|
||||
}
|
||||
|
@ -2,11 +2,21 @@
|
||||
#define _ACCOUNT_DATA_H
|
||||
|
||||
#include <td/telegram/td_api.h>
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <purple.h>
|
||||
|
||||
#ifndef NoVoip
|
||||
#include <tgvoip/VoIPController.h>
|
||||
#else
|
||||
|
||||
namespace tgvoip {
|
||||
struct VoIPController {};
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isPhoneNumber(const char *s);
|
||||
const char *getCanonicalPhoneNumber(const char *s);
|
||||
int32_t stringToUserId(const char *s);
|
||||
@ -277,6 +287,11 @@ public:
|
||||
|
||||
auto getBasicGroupsWithMember(int32_t userId) ->
|
||||
std::vector<std::pair<int32_t, const td::td_api::basicGroupFullInfo *>>;
|
||||
|
||||
bool hasActiveCall();
|
||||
void setActiveCall();
|
||||
tgvoip::VoIPController *getCallData();
|
||||
void removeActiveCall();
|
||||
private:
|
||||
TdAccountData(const TdAccountData &other) = delete;
|
||||
TdAccountData &operator=(const TdAccountData &other) = delete;
|
||||
@ -341,6 +356,9 @@ private:
|
||||
// Currently active file transfers for which PurpleXfer is used
|
||||
std::vector<FileTransferInfo> m_fileTransfers;
|
||||
|
||||
// Voice call data
|
||||
std::unique_ptr<tgvoip::VoIPController> m_callData;
|
||||
|
||||
std::unique_ptr<PendingRequest> getPendingRequestImpl(uint64_t requestId);
|
||||
PendingRequest * findPendingRequestImpl(uint64_t requestId);
|
||||
};
|
||||
|
@ -11,4 +11,6 @@
|
||||
|
||||
#cmakedefine NoTranslations
|
||||
|
||||
#cmakedefine NoVoip
|
||||
|
||||
#endif
|
||||
|
48
call.cpp
Normal file
48
call.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "call.h"
|
||||
#include "client-utils.h"
|
||||
#include "config.h"
|
||||
#include "buildopt.h"
|
||||
|
||||
static td::td_api::object_ptr<td::td_api::callProtocol> getCallProtocol()
|
||||
{
|
||||
auto protocol = td::td_api::make_object<td::td_api::callProtocol>();
|
||||
protocol->udp_p2p_ = true;
|
||||
protocol->udp_reflector_ = true;
|
||||
protocol->min_layer_ = 65;
|
||||
protocol->max_layer_ = 65;
|
||||
return protocol;
|
||||
}
|
||||
|
||||
bool initiateCall(int32_t userId, TdAccountData &account, TdTransceiver &transceiver)
|
||||
{
|
||||
if (account.hasActiveCall())
|
||||
return false;
|
||||
|
||||
td::td_api::object_ptr<td::td_api::createCall> callRequest = td::td_api::make_object<td::td_api::createCall>();
|
||||
callRequest->user_id_ = userId;
|
||||
callRequest->protocol_ = getCallProtocol();
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateCall(const td::td_api::call &call, TdAccountData &account, TdTransceiver &transceiver)
|
||||
{
|
||||
PurpleMediaManager *mediaManager = purple_media_manager_get();
|
||||
PurpleMediaCaps capabilities = purple_media_manager_get_ui_caps(mediaManager);
|
||||
if (!(capabilities & PURPLE_MEDIA_CAPS_AUDIO) && !(capabilities & PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION)) {
|
||||
purple_debug_misc(config::pluginId, "Ignoring incoming call: no audio capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!call.is_outgoing_) {
|
||||
/*if (not already in this call && call.state_ && (call.state_->get_id() == td::td_api::callStatePending::ID)) {
|
||||
const td::td_api::user *user = account.getUser(call.user_id_);
|
||||
if (!user) return;
|
||||
request call
|
||||
if accepted:
|
||||
td::td_api::object_ptr<td::td_api::acceptCall> acceptReq = td::td_api::make_object<td::td_api::acceptCall>();
|
||||
acceptReq->call_id_ = GPOINTER_TO_INT(purple_media_get_prpl_data(media));
|
||||
acceptReq->protocol_ = getCallProtocol();
|
||||
transceiver->sendQuery(std::move(acceptReq), nullptr);
|
||||
}*/
|
||||
}
|
||||
}
|
10
call.h
Normal file
10
call.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _CALL_H
|
||||
#define _CALL_H
|
||||
|
||||
#include "transceiver.h"
|
||||
#include "account-data.h"
|
||||
|
||||
bool initiateCall(int32_t userId, TdAccountData &account, TdTransceiver &transceiver);
|
||||
void updateCall(const td::td_api::call &call, TdAccountData &account, TdTransceiver &transceiver);
|
||||
|
||||
#endif
|
@ -85,6 +85,7 @@ cmake -DCMAKE_SYSTEM_NAME=Windows \
|
||||
-DIntl_LIBRARY=$PWD/../../deps/win32-dev/gtk_2_0-2.14/lib/libintl.dll.a \
|
||||
-DGLIB_LIBRARIES="$PWD/../../deps/win32-dev/gtk_2_0-2.14/lib/libglib-2.0.dll.a;$PWD/../../deps/win32-dev/gtk_2_0-2.14/lib/libgthread-2.0.dll.a" \
|
||||
-DSTANDARD_LIBRARIES_EXTRA="-Wl,-Bstatic -lpthread -Wl,-Bdynamic" \
|
||||
-DNoVoip=True \
|
||||
-DCMAKE_BUILD_TYPE=Release ..
|
||||
|
||||
make
|
||||
@ -119,5 +120,5 @@ WS2_32.dll
|
||||
## Regression test
|
||||
|
||||
```
|
||||
WINEPATH=$PWD/../deps/win32-dev/gtk_2_0-2.14/bin wine test/tests
|
||||
WINEPATH=$PWD/../../deps/win32-dev/gtk_2_0-2.14/bin wine test/tests
|
||||
```
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "format.h"
|
||||
#include "sticker.h"
|
||||
#include "file-transfer.h"
|
||||
#include "call.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
@ -195,6 +196,18 @@ void PurpleTdClient::processUpdate(td::td_api::Object &update)
|
||||
break;
|
||||
};
|
||||
|
||||
case td::td_api::updateCall::ID: {
|
||||
auto &callUpdate = static_cast<const td::td_api::updateCall &>(update);
|
||||
if (callUpdate.call_) {
|
||||
purple_debug_misc(config::pluginId, "Call update: id %d, outgoing=%d, user id %d, state %d\n",
|
||||
callUpdate.call_->id_, callUpdate.call_->user_id_,
|
||||
(int)callUpdate.call_->is_outgoing_,
|
||||
callUpdate.call_->state_ ? callUpdate.call_->state_->get_id() : 0);
|
||||
updateCall(*callUpdate.call_, m_data, m_transceiver);
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
default:
|
||||
purple_debug_misc(config::pluginId, "Incoming update: ignorig ID=%d\n", update.get_id());
|
||||
break;
|
||||
@ -2412,3 +2425,20 @@ void PurpleTdClient::cancelUpload(PurpleXfer *xfer)
|
||||
// in which case nothing more should be done.
|
||||
}
|
||||
}
|
||||
|
||||
bool PurpleTdClient::startVoiceCall(const char *buddyName)
|
||||
{
|
||||
std::vector<const td::td_api::user *> users = getUsersByPurpleName(buddyName, m_data, "start voice call");
|
||||
if (users.size() != 1) {
|
||||
// Unlikely error messages not worth translating
|
||||
std::string errorMessage;
|
||||
if (users.empty())
|
||||
errorMessage = "User not found";
|
||||
else
|
||||
errorMessage = formatMessage("More than one user known with name '{}'", std::string(buddyName));
|
||||
showMessageTextIm(m_data, buddyName, NULL, errorMessage.c_str(), time(NULL), PURPLE_MESSAGE_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return initiateCall(users.front()->id_, m_data, m_transceiver);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
void sendFileToChat(PurpleXfer *xfer, const char *purpleName, PurpleConversationType type,
|
||||
int purpleChatId);
|
||||
void cancelUpload(PurpleXfer *xfer);
|
||||
bool startVoiceCall(const char *buddyName);
|
||||
private:
|
||||
using TdObjectPtr = td::td_api::object_ptr<td::td_api::Object>;
|
||||
using ResponseCb = void (PurpleTdClient::*)(uint64_t requestId, TdObjectPtr object);
|
||||
|
@ -599,6 +599,31 @@ static PurpleCmdRet tgprpl_cmd_kick(PurpleConversation *conv, const gchar *cmd,
|
||||
return PURPLE_CMD_RET_OK;
|
||||
}
|
||||
|
||||
static PurpleMediaCaps getMediaCaps(PurpleAccount *account, const char *who)
|
||||
{
|
||||
#ifndef NoVoip
|
||||
return PURPLE_MEDIA_CAPS_AUDIO;
|
||||
#else
|
||||
return PURPLE_MEDIA_CAPS_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean initiateMedia(PurpleAccount *account, const char *who, PurpleMediaSessionType type)
|
||||
{
|
||||
#ifndef NoVoip
|
||||
if (!(type & PURPLE_MEDIA_AUDIO))
|
||||
return FALSE;
|
||||
|
||||
PurpleTdClient *tdClient = getTdClient(account);
|
||||
if (tdClient)
|
||||
return tdClient->startVoiceCall(who) ? TRUE : FALSE;
|
||||
else
|
||||
return FALSE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char png[] = "png";
|
||||
|
||||
static PurplePluginProtocolInfo prpl_info = {
|
||||
@ -679,8 +704,8 @@ static PurplePluginProtocolInfo prpl_info = {
|
||||
.get_attention_types = NULL,
|
||||
.struct_size = sizeof(PurplePluginProtocolInfo),
|
||||
.get_account_text_table = tgprpl_get_account_text_table,
|
||||
.initiate_media = NULL,
|
||||
.get_media_caps = NULL,
|
||||
.initiate_media = initiateMedia,
|
||||
.get_media_caps = getMediaCaps,
|
||||
.get_moods = NULL,
|
||||
.set_public_alias = NULL,
|
||||
.get_public_alias = NULL,
|
||||
|
@ -30,6 +30,7 @@ add_executable(tests EXCLUDE_FROM_ALL
|
||||
../format.cpp
|
||||
../sticker.cpp
|
||||
../file-transfer.cpp
|
||||
../call.cpp
|
||||
)
|
||||
|
||||
set_property(TARGET tests PROPERTY CXX_STANDARD 14)
|
||||
@ -58,4 +59,11 @@ if (NOT NoTranslations)
|
||||
target_link_libraries(tests PRIVATE ${Intl_LIBRARIES})
|
||||
endif (NOT NoTranslations)
|
||||
|
||||
if (NOT tgvoip_INCLUDE_DIRS STREQUAL "")
|
||||
target_include_directories(tests SYSTEM PRIVATE ${tgvoip_INCLUDE_DIRS})
|
||||
endif (NOT tgvoip_INCLUDE_DIRS STREQUAL "")
|
||||
if (NOT NoVoip)
|
||||
target_link_libraries(tests PRIVATE ${tgvoip_LIBRARIES})
|
||||
endif (NOT NoVoip)
|
||||
|
||||
add_custom_target(run-tests ${CMAKE_CURRENT_BINARY_DIR}/tests DEPENDS tests)
|
||||
|
@ -1421,4 +1421,14 @@ PurpleCmdId purple_cmd_register(const gchar *cmd, const gchar *args, PurpleCmdPr
|
||||
return 0;
|
||||
}
|
||||
|
||||
PurpleMediaManager *purple_media_manager_get(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PurpleMediaCaps purple_media_manager_get_ui_caps(PurpleMediaManager *manager)
|
||||
{
|
||||
return PURPLE_MEDIA_CAPS_NONE;
|
||||
}
|
||||
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user