2019-10-26 01:51:40 +02:00
# include "AudioSender.h"
# include "VoiceConnection.h"
# include "../ServerConnection.h"
# include "../../logger.h"
# include "AudioEventLoop.h"
# include "../../audio/AudioMerger.h"
using namespace std ;
using namespace tc ;
using namespace tc : : audio ;
using namespace tc : : audio : : codec ;
using namespace tc : : connection ;
VoiceSender : : VoiceSender ( tc : : connection : : VoiceConnection * handle ) : handle ( handle ) { }
VoiceSender : : ~ VoiceSender ( ) {
2019-12-07 22:27:20 +01:00
audio : : encode_event_loop - > cancel ( dynamic_pointer_cast < event : : EventEntry > ( this - > _ref . lock ( ) ) ) ;
2019-10-26 01:51:40 +02:00
this - > clear_buffer ( ) ; /* buffer might be accessed within encode_raw_frame, but this could not be trigered while this will be deallocated! */
}
bool VoiceSender : : initialize_codec ( std : : string & error , connection : : codec : : value codec , size_t channels , size_t rate , bool reset_encoder ) {
auto & data = this - > codec [ codec ] ;
bool new_allocated = ! data ;
if ( new_allocated ) {
data = make_unique < AudioCodec > ( ) ;
data - > packet_counter = 0 ;
data - > last_packet = chrono : : system_clock : : now ( ) ;
}
auto info = codec : : get_info ( codec ) ;
if ( ! info | | ! info - > supported ) {
if ( new_allocated )
log_error ( category : : voice_connection , tr ( " Tried to send voice packet but we dont support the current codec ({}) " ) , codec ) ;
return false ;
}
if ( ! data - > converter ) {
data - > converter = info - > new_converter ( error ) ;
if ( ! data - > converter )
return false ;
} else if ( reset_encoder ) {
data - > converter - > reset_encoder ( ) ;
}
if ( ! data - > resampler | | data - > resampler - > input_rate ( ) ! = rate )
data - > resampler = make_shared < AudioResampler > ( rate , data - > converter - > sample_rate ( ) , data - > converter - > channels ( ) ) ;
if ( ! data - > resampler - > valid ( ) ) {
error = " resampler is invalid " ;
return false ;
}
return true ;
}
void VoiceSender : : set_voice_send_enabled ( bool flag ) {
this - > voice_send_enabled = flag ;
}
void VoiceSender : : send_data ( const void * data , size_t samples , size_t rate , size_t channels ) {
unique_lock lock ( this - > _execute_lock ) ;
if ( ! this - > handle ) {
log_warn ( category : : voice_connection , tr ( " Dropping raw audio frame because of an invalid handle. " ) ) ;
return ;
}
lock . unlock ( ) ;
if ( ! this - > voice_send_enabled ) {
log_warn ( category : : voice_connection , tr ( " Dropping raw audio frame because voice sending has been disabled! " ) ) ;
return ;
}
auto frame = make_unique < AudioFrame > ( ) ;
frame - > sample_rate = rate ;
frame - > channels = channels ;
frame - > buffer = pipes : : buffer { ( void * ) data , samples * channels * 4 } ;
frame - > timestamp = chrono : : system_clock : : now ( ) ;
{
lock_guard buffer_lock ( this - > raw_audio_buffer_lock ) ;
this - > raw_audio_buffers . push_back ( move ( frame ) ) ;
}
2019-12-07 22:27:20 +01:00
audio : : encode_event_loop - > schedule ( dynamic_pointer_cast < event : : EventEntry > ( this - > _ref . lock ( ) ) ) ;
2019-10-26 01:51:40 +02:00
}
void VoiceSender : : send_stop ( ) {
unique_lock lock ( this - > _execute_lock ) ;
if ( ! this - > handle ) {
log_warn ( category : : voice_connection , tr ( " Dropping audio end frame because of an invalid handle. " ) ) ;
return ;
}
lock . unlock ( ) ;
auto frame = make_unique < AudioFrame > ( ) ;
frame - > sample_rate = 0 ;
frame - > channels = 0 ;
frame - > buffer = pipes : : buffer { nullptr , 0 } ;
frame - > timestamp = chrono : : system_clock : : now ( ) ;
{
lock_guard buffer_lock ( this - > raw_audio_buffer_lock ) ;
this - > raw_audio_buffers . push_back ( move ( frame ) ) ;
}
2019-12-07 22:27:20 +01:00
audio : : encode_event_loop - > schedule ( dynamic_pointer_cast < event : : EventEntry > ( this - > _ref . lock ( ) ) ) ;
2019-10-26 01:51:40 +02:00
}
void VoiceSender : : finalize ( ) {
lock_guard lock ( this - > _execute_lock ) ;
this - > handle = nullptr ;
}
void VoiceSender : : event_execute ( const std : : chrono : : system_clock : : time_point & point ) {
static auto max_time = chrono : : milliseconds ( 10 ) ;
bool reschedule = false ;
auto now = chrono : : system_clock : : now ( ) ;
while ( true ) {
unique_lock buffer_lock ( this - > raw_audio_buffer_lock ) ;
if ( this - > raw_audio_buffers . empty ( ) )
break ;
if ( chrono : : system_clock : : now ( ) - now > max_time ) {
reschedule = true ;
break ;
}
auto entry = move ( this - > raw_audio_buffers . front ( ) ) ;
this - > raw_audio_buffers . pop_front ( ) ;
buffer_lock . unlock ( ) ;
//TODO: Drop too old buffers!
this - > encode_raw_frame ( entry ) ;
}
if ( reschedule ) {
log_warn ( category : : voice_connection , tr ( " Audio data decode will take longer than {} us. Enqueueing for later " ) , chrono : : duration_cast < chrono : : microseconds > ( max_time ) . count ( ) ) ;
2019-12-07 22:27:20 +01:00
audio : : decode_event_loop - > schedule ( dynamic_pointer_cast < event : : EventEntry > ( this - > _ref . lock ( ) ) ) ;
2019-10-26 01:51:40 +02:00
}
}
void VoiceSender : : encode_raw_frame ( const std : : unique_ptr < AudioFrame > & frame ) {
auto codec = this - > _current_codec ;
auto & codec_data = this - > codec [ codec ] ;
bool flag_head = true , flag_reset = true ;
if ( codec_data ) {
if ( codec_data - > last_packet + chrono : : seconds ( 1 ) < frame - > timestamp )
codec_data - > packet_counter = 0 ;
flag_head = codec_data - > packet_counter < 5 ;
flag_reset = codec_data - > packet_counter = = 0 ;
codec_data - > packet_counter + + ;
codec_data - > last_packet = frame - > timestamp ;
}
if ( frame - > channels = = 0 | | frame - > sample_rate = = 0 | | frame - > buffer . empty ( ) ) {
lock_guard lock ( this - > _execute_lock ) ;
if ( ! this - > handle ) {
log_warn ( category : : voice_connection , tr ( " Dropping audio end because of an invalid handle. " ) ) ;
return ;
}
if ( codec_data )
codec_data - > packet_counter = 0 ;
auto server = this - > handle - > handle ( ) ;
server - > send_voice_data ( this - > _buffer , 0 , codec , flag_head ) ;
return ;
}
string error ;
if ( flag_reset ) {
log_trace ( category : : voice_connection , tr ( " Resetting encoder for voice sender " ) ) ;
}
if ( ! this - > initialize_codec ( error , codec , frame - > channels , frame - > sample_rate , flag_reset ) ) {
log_error ( category : : voice_connection , tr ( " Failed to initialize codec: {} " ) , error ) ;
return ;
}
auto merged_channel_byte_size = codec_data - > converter - > channels ( ) * ( frame - > buffer . length ( ) / frame - > channels ) ;
auto estimated_resampled_byte_size = codec_data - > resampler - > estimated_output_size ( merged_channel_byte_size ) ;
this - > ensure_buffer ( max ( estimated_resampled_byte_size , merged_channel_byte_size ) ) ;
auto codec_channels = codec_data - > converter - > channels ( ) ;
if ( ! audio : : merge : : merge_channels_interleaved ( this - > _buffer , codec_channels , frame - > buffer . data_ptr ( ) , frame - > channels , frame - > buffer . length ( ) / frame - > channels / 4 ) ) {
log_warn ( category : : voice_connection , tr ( " Failed to merge channels to output stream channel count! Dropping local voice packet " ) ) ;
return ;
}
auto resampled_samples = codec_data - > resampler - > process ( this - > _buffer , this - > _buffer , merged_channel_byte_size / codec_channels / 4 ) ;
if ( resampled_samples < = 0 ) {
log_error ( category : : voice_connection , tr ( " Resampler returned {} " ) , resampled_samples ) ;
return ;
}
if ( resampled_samples * codec_channels * 4 ! = codec_data - > converter - > bytes_per_frame ( ) ) {
log_error ( category : : voice_connection ,
tr ( " Could not encode audio frame. Frame length is not equal to code frame length! Codec: {}, Packet: {} " ) ,
codec_data - > converter - > bytes_per_frame ( ) , resampled_samples * codec_channels * 4
) ;
return ;
}
char _packet_buffer [ 512 ] ;
auto encoded_bytes = codec_data - > converter - > encode ( error , this - > _buffer , _packet_buffer , 512 ) ;
if ( encoded_bytes < = 0 ) {
log_error ( category : : voice_connection , tr ( " Failed to encode voice: {} " ) , error ) ;
return ;
}
{
lock_guard lock ( this - > _execute_lock ) ;
if ( ! this - > handle ) {
log_warn ( category : : voice_connection , tr ( " Dropping audio frame because of an invalid handle. " ) ) ;
return ;
}
auto server = this - > handle - > handle ( ) ;
server - > send_voice_data ( _packet_buffer , encoded_bytes , codec , flag_head ) ;
}
}