From 5da95c8f396b7ac716f7ea61c9d8c5a0eee7e1ec Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Tue, 14 Apr 2015 17:55:10 +0000 Subject: Tox: first approach for audio support git-svn-id: http://svn.miranda-ng.org/main/trunk@12824 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Tox/Tox_12.vcxproj | 5 +- protocols/Tox/Tox_12.vcxproj.filters | 9 +++ protocols/Tox/res/resource.rc | 2 +- protocols/Tox/src/api_av.cpp | 110 +++++++++++++++++++++++++++++++++++ protocols/Tox/src/common.h | 4 +- protocols/Tox/src/tox_core.cpp | 24 +++++++- protocols/Tox/src/tox_multimedia.cpp | 92 +++++++++++++++++++++++++++++ protocols/Tox/src/tox_network.cpp | 1 + protocols/Tox/src/tox_options.cpp | 31 ++++++---- protocols/Tox/src/tox_options.h | 4 -- protocols/Tox/src/tox_proto.cpp | 3 +- protocols/Tox/src/tox_proto.h | 15 ++++- 12 files changed, 277 insertions(+), 23 deletions(-) create mode 100644 protocols/Tox/src/api_av.cpp create mode 100644 protocols/Tox/src/tox_multimedia.cpp diff --git a/protocols/Tox/Tox_12.vcxproj b/protocols/Tox/Tox_12.vcxproj index 8a594304bf..ccca25ba81 100644 --- a/protocols/Tox/Tox_12.vcxproj +++ b/protocols/Tox/Tox_12.vcxproj @@ -97,7 +97,7 @@ $(IntDir)$(TargetName).lib false false - dnsapi.lib;comctl32.lib;%(AdditionalDependencies) + dnsapi.lib;comctl32.lib;winmm.lib;%(AdditionalDependencies) _DEBUG;%(PreprocessorDefinitions) @@ -202,6 +202,7 @@ copy docs\tox.ini "$(SolutionDir)$(Configuration)64\Plugins" /y + @@ -217,6 +218,7 @@ copy docs\tox.ini "$(SolutionDir)$(Configuration)64\Plugins" /y + @@ -236,6 +238,7 @@ copy docs\tox.ini "$(SolutionDir)$(Configuration)64\Plugins" /y + diff --git a/protocols/Tox/Tox_12.vcxproj.filters b/protocols/Tox/Tox_12.vcxproj.filters index 8303981019..8eb7c5ef2e 100644 --- a/protocols/Tox/Tox_12.vcxproj.filters +++ b/protocols/Tox/Tox_12.vcxproj.filters @@ -63,6 +63,9 @@ Header Files + + Header Files\api + @@ -146,6 +149,12 @@ Source Files + + Source Files\api + + + Source Files + diff --git a/protocols/Tox/res/resource.rc b/protocols/Tox/res/resource.rc index b2f892f7ae..93c44fb49d 100644 --- a/protocols/Tox/res/resource.rc +++ b/protocols/Tox/res/resource.rc @@ -189,7 +189,7 @@ BEGIN COMBOBOX IDC_AUDIOINPUT,12,26,138,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP LTEXT "Audio output device",-1,12,42,65,8 COMBOBOX IDC_AUDIOOUTPUT,12,52,138,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP - CONTROL "Filter audio",IDC_AUDIOFILTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,157,28,51,10 + CONTROL "Filter audio",IDC_AUDIOFILTER,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,157,28,51,10 LTEXT "Video input device",-1,15,68,59,8,NOT WS_VISIBLE COMBOBOX IDC_COMBO_VIDEOINPUT,12,78,138,30,CBS_DROPDOWN | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP END diff --git a/protocols/Tox/src/api_av.cpp b/protocols/Tox/src/api_av.cpp new file mode 100644 index 0000000000..4f517187ac --- /dev/null +++ b/protocols/Tox/src/api_av.cpp @@ -0,0 +1,110 @@ +#include "common.h" + +/* COMMON A/V FUNCTIONS */ + +ToxAv *toxav_new(Tox *tox, int32_t max_calls) +{ + return CreateFunction(__FUNCTION__)(tox, max_calls); +} + +void toxav_kill(ToxAv *av) +{ + CreateFunction(__FUNCTION__)(av); +} + +uint32_t toxav_do_interval(ToxAv *av) +{ + return CreateFunction(__FUNCTION__)(av); +} + +void toxav_do(ToxAv *av) +{ + CreateFunction(__FUNCTION__)(av); +} + +void toxav_register_callstate_callback(ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata) +{ + CreateFunction(__FUNCTION__)(av, cb, id, userdata); +} + +int toxav_call(ToxAv *av, int32_t *call_index, int friend_id, const ToxAvCSettings *csettings, int ringing_seconds) +{ + return CreateFunction(__FUNCTION__)(av, call_index, friend_id, csettings, ringing_seconds); +} + +int toxav_hangup(ToxAv *av, int32_t call_index) +{ + return CreateFunction(__FUNCTION__)(av, call_index); +} + +int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) +{ + return CreateFunction(__FUNCTION__)(av, call_index, csettings); +} + +int toxav_reject(ToxAv *av, int32_t call_index, const char *reason) +{ + return CreateFunction(__FUNCTION__)(av, call_index, reason); +} + +int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason) +{ + return CreateFunction(__FUNCTION__)(av, call_index, peer_id, reason); +} + +int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) +{ + return CreateFunction(__FUNCTION__)(av, call_index, csettings); +} + +int toxav_stop_call(ToxAv *av, int32_t call_index) +{ + return CreateFunction(__FUNCTION__)(av, call_index); +} + +int toxav_prepare_transmission(ToxAv *av, int32_t call_index, int support_video) +{ + return CreateFunction(__FUNCTION__)(av, call_index, support_video); +} + +int toxav_kill_transmission(ToxAv *av, int32_t call_index) +{ + return CreateFunction(__FUNCTION__)(av, call_index); +} + +int toxav_get_peer_csettings(ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest) +{ + return CreateFunction(__FUNCTION__)(av, call_index, peer, dest); +} + +int toxav_get_peer_id(ToxAv *av, int32_t call_index, int peer) +{ + return CreateFunction(__FUNCTION__)(av, call_index, peer); +} + +ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) +{ + return CreateFunction(__FUNCTION__)(av, call_index); +} + +int toxav_capability_supported(ToxAv *av, int32_t call_index, ToxAvCapabilities capability) +{ + return CreateFunction(__FUNCTION__)(av, call_index, capability); +} + +Tox *toxav_get_tox(ToxAv *av) +{ + return CreateFunction(__FUNCTION__)(av); +} + +int toxav_get_active_count(ToxAv *av) +{ + return CreateFunction(__FUNCTION__)(av); +} + +/* AUDIO FUNCTIONS */ + +void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata) +{ + CreateFunction(__FUNCTION__)(av, cb, userdata); +} \ No newline at end of file diff --git a/protocols/Tox/src/common.h b/protocols/Tox/src/common.h index ae093169bf..ba70f43c92 100644 --- a/protocols/Tox/src/common.h +++ b/protocols/Tox/src/common.h @@ -38,9 +38,9 @@ #include #include +#include #include #include -#include struct CToxProto; @@ -64,6 +64,8 @@ extern HINSTANCE g_hInstance; #define TOX_MAX_CONNECT_RETRIES 300 #define TOX_MAX_DISCONNECT_RETRIES 300 +#define TOX_MAX_CALLS 1 + #define TOX_INI_PATH "%miranda_path%\\Plugins\\tox.ini" #define TOX_SETTINGS_ID "ToxID" diff --git a/protocols/Tox/src/tox_core.cpp b/protocols/Tox/src/tox_core.cpp index a23939713e..769383c9cb 100644 --- a/protocols/Tox/src/tox_core.cpp +++ b/protocols/Tox/src/tox_core.cpp @@ -39,7 +39,7 @@ bool CToxProto::InitToxCore() } } - debugLogA("CToxProto::InitToxCore: loading tox profile"); + debugLogA(__FUNCTION__": loading tox profile"); if (LoadToxProfile(options)) { @@ -47,17 +47,31 @@ bool CToxProto::InitToxCore() tox_callback_friend_message(tox, OnFriendMessage, this); tox_callback_friend_read_receipt(tox, OnReadReceipt, this); tox_callback_friend_typing(tox, OnTypingChanged, this); + // tox_callback_friend_name(tox, OnFriendNameChange, this); tox_callback_friend_status_message(tox, OnStatusMessageChanged, this); tox_callback_friend_status(tox, OnUserStatusChanged, this); tox_callback_friend_connection_status(tox, OnConnectionStatusChanged, this); - // file transfers + // transfers tox_callback_file_recv_control(tox, OnFileRequest, this); tox_callback_file_recv(tox, OnFriendFile, this); tox_callback_file_recv_chunk(tox, OnFileReceiveData, this); tox_callback_file_chunk_request(tox, OnFileSendData, this); // group chats //tox_callback_group_invite(tox, OnGroupChatInvite, this); + // a/v + toxAv = toxav_new(tox, TOX_MAX_CALLS); + toxav_register_audio_callback(toxAv, OnFriendAudio, this); + toxav_register_callstate_callback(toxAv, OnAvInvite, av_OnInvite, this); + toxav_register_callstate_callback(toxAv, OnAvStart, av_OnStart, this); + toxav_register_callstate_callback(toxAv, OnAvCancel, av_OnCancel, this); + toxav_register_callstate_callback(toxAv, OnAvReject, av_OnReject, this); + toxav_register_callstate_callback(toxAv, OnAvEnd, av_OnEnd, this); + toxav_register_callstate_callback(toxAv, OnAvRinging, av_OnRinging, this); + toxav_register_callstate_callback(toxAv, OnAvCsChange, av_OnPeerCSChange, this); + toxav_register_callstate_callback(toxAv, OnAvCsChange, av_OnSelfCSChange, this); + toxav_register_callstate_callback(toxAv, OnAvRequestTimeout, av_OnRequestTimeout, this); + toxav_register_callstate_callback(toxAv, OnAvPeerTimeout, av_OnPeerTimeout, this); uint8_t data[TOX_ADDRESS_SIZE]; tox_self_get_address(tox, data); @@ -82,7 +96,8 @@ bool CToxProto::InitToxCore() void CToxProto::UninitToxCore() { - if (tox) { + if (tox) + { for (size_t i = 0; i < transfers.Count(); i++) { FileTransferParam *transfer = transfers.GetAt(i); @@ -102,6 +117,9 @@ void CToxProto::UninitToxCore() // tox_set_status_message(tox, (uint8_t*)(char*)statusmes, mir_strlen(statusmes)); //} + if (toxAv) + toxav_kill(toxAv); + SaveToxProfile(); if (password != NULL) { diff --git a/protocols/Tox/src/tox_multimedia.cpp b/protocols/Tox/src/tox_multimedia.cpp new file mode 100644 index 0000000000..214f35f8d0 --- /dev/null +++ b/protocols/Tox/src/tox_multimedia.cpp @@ -0,0 +1,92 @@ +#include "common.h" + +void CToxProto::OnAvInvite(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvRinging(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvStart(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvEnd(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvReject(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvCancel(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvCsChange(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvRequestTimeout(void*, int32_t callId, void *arg) { } +void CToxProto::OnAvPeerTimeout(void*, int32_t callId, void *arg) { } + +void CToxProto::OnFriendAudio(void*, int32_t callId, const int16_t *PCM, uint16_t size, void *arg) +{ + CToxProto *proto = (CToxProto*)arg; + + ToxAvCSettings dest; + if (toxav_get_peer_csettings(proto->toxAv, callId, 0, &dest) != av_ErrorNone) + { + proto->debugLogA(__FUNCTION__": failed to get codec settings"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + if (dest.call_type != av_TypeAudio) + { + proto->debugLogA(__FUNCTION__": failed to play video"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + WAVEFORMATEX wfx = { 0 }; + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = dest.audio_channels; + wfx.wBitsPerSample = dest.audio_bitrate; + wfx.nSamplesPerSec = dest.audio_sample_rate; + wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample) / 8; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + + DWORD deviceId = proto->getDword("AudioOutputDeviceID", -1); + if (deviceId != av_ErrorNone) + { + proto->debugLogA(__FUNCTION__": failed to get device id"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + HWAVEOUT hDevice; + MMRESULT result = waveOutOpen(&hDevice, deviceId, &wfx, 0, 0, CALLBACK_NULL | WAVE_FORMAT_DIRECT); + if (result != MMSYSERR_NOERROR) + { + proto->debugLogA(__FUNCTION__": failed to open audio device"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + WAVEHDR header;// = { 0 }; + ZeroMemory(&header, sizeof(WAVEHDR)); + header.lpData = (LPSTR)PCM; + header.dwBufferLength = size; + + result = waveOutPrepareHeader(hDevice, &header, sizeof(WAVEHDR)); + if (result != MMSYSERR_NOERROR) + { + proto->debugLogA(__FUNCTION__": failed to prepare audio device header"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + result = waveOutWrite(hDevice, &header, sizeof(WAVEHDR)); + if (result != MMSYSERR_NOERROR) + { + proto->debugLogA(__FUNCTION__": failed to write to audio device"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + do + { + Sleep(100); + result = waveOutUnprepareHeader(hDevice, &header, sizeof(WAVEHDR)); + } while (result == WAVERR_STILLPLAYING); + + if (result != MMSYSERR_NOERROR) + { + proto->debugLogA(__FUNCTION__": failed to unprepare audio device header"); + toxav_stop_call(proto->toxAv, callId); + return; + } + + waveOutClose(hDevice); +} \ No newline at end of file diff --git a/protocols/Tox/src/tox_network.cpp b/protocols/Tox/src/tox_network.cpp index 29e261e0cd..c9d4a2b6c2 100644 --- a/protocols/Tox/src/tox_network.cpp +++ b/protocols/Tox/src/tox_network.cpp @@ -143,6 +143,7 @@ void CToxProto::DoTox() { mir_cslock lock(toxLock); tox_iterate(tox); + toxav_do(toxAv); } uint32_t interval = tox_iteration_interval(tox); Sleep(interval); diff --git a/protocols/Tox/src/tox_options.cpp b/protocols/Tox/src/tox_options.cpp index 49860ff5bd..1bdd3f9f1b 100644 --- a/protocols/Tox/src/tox_options.cpp +++ b/protocols/Tox/src/tox_options.cpp @@ -149,27 +149,36 @@ void CToxOptionsMain::OnApply() CToxOptionsMultimedia::CToxOptionsMultimedia(CToxProto *proto) : CToxDlgBase(proto, IDD_OPTIONS_AV, false), - m_audioInput(this, IDC_AUDIOINPUT), m_audioOutput(this, IDC_AUDIOOUTPUT) + m_audioInput(this, IDC_AUDIOINPUT), + m_audioOutput(this, IDC_AUDIOOUTPUT) { - m_audioInput.OnChange = Callback(this, &CToxOptionsMultimedia::AudioInput_OnClick); - m_audioOutput.OnChange = Callback(this, &CToxOptionsMultimedia::AudioOutput_OnClick); } void CToxOptionsMultimedia::OnInitDialog() { CToxDlgBase::OnInitDialog(); -} - -void CToxOptionsMultimedia::AudioInput_OnClick(CCtrlData*) -{ -} - -void CToxOptionsMultimedia::AudioOutput_OnClick(CCtrlData*) -{ + + DWORD count = 0; + + WAVEINCAPS wic; + count = waveInGetNumDevs(); + for (DWORD i = 0; i < count; i++) + if (!waveInGetDevCaps(i, &wic, sizeof(WAVEINCAPS))) + m_audioInput.InsertString(wic.szPname, i); + m_audioInput.SetCurSel(m_proto->getDword("AudioInputDeviceID", 0)); + + WAVEOUTCAPS woc; + count = waveOutGetNumDevs(); + for (DWORD i = 0; i < count; i++) + if (!waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))) + m_audioOutput.InsertString(woc.szPname, i); + m_audioOutput.SetCurSel(m_proto->getDword("AudioOutputDeviceID", 0)); } void CToxOptionsMultimedia::OnApply() { + m_proto->setDword("AudioInputDeviceID", m_audioInput.GetCurSel()); + m_proto->setDword("AudioOutputDeviceID", m_audioOutput.GetCurSel()); } ///////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Tox/src/tox_options.h b/protocols/Tox/src/tox_options.h index 6edc2688e6..44f4318d96 100644 --- a/protocols/Tox/src/tox_options.h +++ b/protocols/Tox/src/tox_options.h @@ -55,10 +55,6 @@ private: protected: void OnInitDialog(); - - void AudioInput_OnClick(CCtrlData*); - void AudioOutput_OnClick(CCtrlData*); - void OnApply(); public: diff --git a/protocols/Tox/src/tox_proto.cpp b/protocols/Tox/src/tox_proto.cpp index 98a048d6d7..03a1b1ad3a 100644 --- a/protocols/Tox/src/tox_proto.cpp +++ b/protocols/Tox/src/tox_proto.cpp @@ -1,7 +1,8 @@ #include "common.h" CToxProto::CToxProto(const char* protoName, const TCHAR* userName) : - PROTO(protoName, userName), password(NULL) + PROTO(protoName, userName), + tox(NULL), toxAv(NULL), password(NULL) { InitNetlib(); diff --git a/protocols/Tox/src/tox_proto.h b/protocols/Tox/src/tox_proto.h index 82bfe006f3..07d229c4d2 100644 --- a/protocols/Tox/src/tox_proto.h +++ b/protocols/Tox/src/tox_proto.h @@ -65,6 +65,7 @@ public: private: Tox *tox; + ToxAv *toxAv; char *password; mir_cs toxLock; TCHAR *accountName; @@ -235,7 +236,19 @@ private: void OnGotFriendAvatarInfo(FileTransferParam *transfer, const uint8_t *hash); - // folders + // multimedia + std::map calls; + static void OnFriendAudio(void *agent, int32_t callId, const int16_t *PCM, uint16_t size, void *arg); + + static void OnAvInvite(void*, int32_t callId, void *arg); + static void OnAvRinging(void*, int32_t callId, void *arg); + static void OnAvStart(void*, int32_t callId, void *arg); + static void OnAvEnd(void*, int32_t callId, void *arg); + static void OnAvReject(void*, int32_t callId, void *arg); + static void OnAvCancel(void*, int32_t callId, void *arg); + static void OnAvCsChange(void*, int32_t callId, void *arg); + static void OnAvRequestTimeout(void*, int32_t callId, void *arg); + static void OnAvPeerTimeout(void*, int32_t callId, void *arg); // utils TOX_USER_STATUS MirandaToToxStatus(int status); -- cgit v1.2.3