Usage¶
Common¶
- You should have a protocol object:
phoneCallProtocol(min_layer=65, max_layer=VoIPController.CONNECTION_MAX_LAYER, udp_p2p=True, udp_reflector=True) - All VoIP-related updates have type of
updatePhoneCallwithphone_callfield of typesphoneCallEmpty,phoneCallWaiting,phoneCallRequested,phoneCallAccepted,phoneCallorphoneCallDiscarded - Use
tgvoip.utils.generate_visualization()withauth_keyandg_afor outgoing org_a_or_bfor incoming calls to get emojis if you need them
Starting conversation¶
- Create a
VoIPControllerinstance - Call
tgvoip.VoIPController.set_send_audio_frame_callback()(see docs for arguments) if needed, otherwise silence will be sent - Call
tgvoip.VoIPController.set_recv_audio_frame_callback()(see docs for arguments) if needed, otherwise nothing will be done to incoming audio stream - Add state change handlers to
tgvoip.VoIPController.call_state_changed_handlers(see docs for handler format) list if needed - Add signal bars change handlers to
tgvoip.VoIPController.signal_bars_changed_handlers(see docs for handler format) list if needed - Invoke
help.getConfig()(result is later referred asconfig) - Call
tgvoip.VoIPController.set_config()(arguments are:config.call_packet_timeout_ms / 1000., config.call_connect_timeout_ms / 1000., DataSaving.NEVER, call.id) - Call
tgvoip.VoIPController.set_encryption_key()(arguments are:i2b(auth_key), is_outgoingwhereis_outgoingis a corresponding boolean value) - Build a
listoftgvoip.Endpointobjects fromcall.connection(single) andcall.alternative_connections(another list) - Call
tgvoip.VoIPController.set_remote_endpoints()(arguments are:endpoints, call.p2p_allowed, False, call.protocol.max_layer) - Call
tgvoip.VoIPController.start() - Call
tgvoip.VoIPController.connect()
Discarding call¶
- Build
peer:inputPhoneCall(id=call.id, access_hash=call.access_hash) - Get call duration using
tgvoip.VoIPController.call_duration - Get connection ID using
tgvoip.VoIPController.get_preferred_relay_id() - Build a suitable
reasonobject (types are:phoneCallDiscardReasonBusy,phoneCallDiscardReasonDisconnect,phoneCallDiscardReasonHangup,phoneCallDiscardReasonMissed) - Invoke
phone.discardCall(peer, duration, connection_id, reason). You might getCALL_ALREADY_DECLINEDerror, this is fine - Destroy the
tgvoip.VoIPControllerobject
Ending conversation¶
- Send call rating and debug log if call ended normally (not failed): TBD
- Destroy the
tgvoip.VoIPControllerobject, everything will be done automatically
Making outgoing calls¶
- Get a
user_idobject for user you want to call (of typeinputPeerUser) - Request a Diffie-Hellman config using
messages.getDhConfig(version=0, random_length=256) - Check received config using
tgvoip.utils.check_dhc(). If check is not passed, do not make the call. You might want to cache received config because check is expensive - Choose a random value
a,1 < a < dhc.p-1 - Calculate
g_a:pow(dhc.g, a, dhc.p) - Calculate
g_a_hash:sha256(g_a) - Choose a random value
random_id,0 <= random_id <= 0x7fffffff-1 - Invoke
phone.requestCall(user_id, random_id, g_a_hash, protocol) - Wait for an update with
phoneCallAcceptedobject, it means that other party has accepted the call. You also might get aphoneCallDiscardedobject, it means that other party has declined the call - If you have got a
phoneCallDiscardedobject, stop thetgvoip.VoIPController. Otherwise, continue - Check a
g_bvalue from receivedphoneCallAccepted(later referred ascall) object usingtgvoip.utils.check_g(). If check is not passed, stop the call - Calculate
auth_key:pow(call.g_b, a, dhc.p) - Calculate
key_fingerprintusingtgvoip.utils.calc_fingerprint() - Build
peer:inputPhoneCall(id=call.id, access_hash=call.access_hash) - Invoke
phone.confirmCall(key_fingerprint, peer, g_a, protocol) - Start the conversation
Receiving calls¶
- You will receive an update containing
phoneCallRequestedobject (later referred ascall). You might discard it right away (use0for duration and connection_id) - Request a Diffie-Hellman config using
messages.getDhConfig(version=0, random_length=256) - Check received config using
tgvoip.utils.check_dhc(). If check is not passed, do not make the call. You might want to cache received config because check is expensive - Choose a random value
b,1 < b < dhc.p-1 - Calculate
g_b:pow(dhc.g, b, dhc.p) - Save
call.g_a_hash - Build
peer:inputPhoneCall(id=call.id, access_hash=call.access_hash) - Invoke
phone.acceptCall(peer, g_b, protocol). You might getCALL_ALREADY_DISCARDEDorCALL_ALREADY_ACCEPTEDerrors, then you should stop current conversation. Also, if response containsphoneCallDiscardedobject you should stop the call - Wait for an update with
phoneCallobject (later referred ascall) - Check that
call.g_a_or_bis not empty andsha256(call.g_a_or_b)equals tog_a_hashyou saved before. If it doesn’t match, stop the call - Check a
call.g_a_or_bvalue object usingtgvoip.utils.check_g()(second argument isdhc.p). If check is not passed, stop the call - Calculate
auth_key:pow(call.g_a_or_b, b, dhc.p) - Calculate
key_fingerprintusingtgvoip.utils.calc_fingerprint() - Check that
key_fingerprintyou have just calculated matchescall.key_fingerprint. If it doesn’t match, stop the call - Start the conversation