2019-10-25 19:51:40 -04:00
# include <cstring>
# include <string>
2020-02-09 08:53:39 -05:00
# include "./AudioInput.h"
# include "./AudioReframer.h"
# include "./AudioResampler.h"
2020-12-02 13:29:03 -05:00
# include "./AudioMerger.h"
2019-10-25 19:51:40 -04:00
# include "../logger.h"
2020-08-09 08:58:16 -04:00
# include "AudioGain.h"
2019-10-25 19:51:40 -04:00
using namespace std ;
using namespace tc ;
using namespace tc : : audio ;
AudioConsumer : : AudioConsumer ( tc : : audio : : AudioInput * handle , size_t channel_count , size_t sample_rate , size_t frame_size ) :
handle ( handle ) ,
channel_count ( channel_count ) ,
sample_rate ( sample_rate ) ,
frame_size ( frame_size ) {
if ( this - > frame_size > 0 ) {
2021-03-27 16:32:18 -04:00
this - > reframer = std : : make_unique < InputReframer > ( channel_count , frame_size ) ;
2019-10-25 19:51:40 -04:00
this - > reframer - > on_frame = [ & ] ( const void * buffer ) { this - > handle_framed_data ( buffer , this - > frame_size ) ; } ;
}
}
void AudioConsumer : : handle_framed_data ( const void * buffer , size_t samples ) {
2020-08-21 07:37:10 -04:00
std : : unique_lock read_callback_lock ( this - > on_read_lock ) ;
2019-10-25 19:51:40 -04:00
auto function = this - > on_read ; /* copy */
read_callback_lock . unlock ( ) ;
if ( ! function )
return ;
function ( buffer , samples ) ;
}
void AudioConsumer : : process_data ( const void * buffer , size_t samples ) {
2020-10-01 04:56:22 -04:00
if ( this - > reframer ) {
this - > reframer - > process ( buffer , samples ) ;
} else {
this - > handle_framed_data ( buffer , samples ) ;
}
2019-10-25 19:51:40 -04:00
}
AudioInput : : AudioInput ( size_t channels , size_t rate ) : _channel_count ( channels ) , _sample_rate ( rate ) { }
AudioInput : : ~ AudioInput ( ) {
this - > close_device ( ) ;
2020-02-09 08:53:39 -05:00
{
2020-08-21 07:37:10 -04:00
std : : lock_guard lock ( this - > consumers_lock ) ;
2020-02-09 08:53:39 -05:00
for ( const auto & consumer : this - > _consumers )
consumer - > handle = nullptr ;
}
free ( this - > resample_buffer ) ;
2019-10-25 19:51:40 -04:00
}
2020-02-08 10:50:48 -05:00
void AudioInput : : set_device ( const std : : shared_ptr < AudioDevice > & device ) {
2020-10-01 04:56:22 -04:00
std : : lock_guard lock { this - > input_source_lock } ;
2021-02-06 13:42:29 -05:00
if ( device = = this - > input_device ) {
return ;
}
2019-10-25 19:51:40 -04:00
2020-02-08 10:50:48 -05:00
this - > close_device ( ) ;
this - > input_device = device ;
2020-02-06 17:59:09 -05:00
}
2019-10-25 19:51:40 -04:00
2020-02-06 17:59:09 -05:00
void AudioInput : : close_device ( ) {
2020-10-01 04:56:22 -04:00
std : : lock_guard lock { this - > input_source_lock } ;
2020-02-08 10:50:48 -05:00
if ( this - > input_recorder ) {
this - > input_recorder - > remove_consumer ( this ) ;
this - > input_recorder - > stop_if_possible ( ) ;
this - > input_recorder . reset ( ) ;
2020-02-06 17:59:09 -05:00
}
2020-02-09 08:53:39 -05:00
this - > _resampler = nullptr ;
2020-02-08 10:50:48 -05:00
this - > input_device = nullptr ;
2019-10-25 19:51:40 -04:00
}
2020-02-08 10:50:48 -05:00
bool AudioInput : : record ( std : : string & error ) {
2020-10-01 04:56:22 -04:00
std : : lock_guard lock { this - > input_source_lock } ;
2020-02-08 10:50:48 -05:00
if ( ! this - > input_device ) {
error = " no device " ;
return false ;
}
2020-08-21 07:37:10 -04:00
if ( this - > input_recorder ) {
return true ;
}
2019-11-09 16:16:08 -05:00
2020-02-08 10:50:48 -05:00
this - > input_recorder = this - > input_device - > record ( ) ;
if ( ! this - > input_recorder ) {
error = " failed to get recorder " ;
return false ;
}
2020-02-09 08:53:39 -05:00
if ( this - > input_recorder - > sample_rate ( ) ! = this - > sample_rate ( ) ) {
this - > _resampler = std : : make_unique < AudioResampler > ( this - > input_recorder - > sample_rate ( ) , this - > sample_rate ( ) , this - > _channel_count ) ;
}
2020-02-08 10:50:48 -05:00
this - > input_recorder - > register_consumer ( this ) ;
if ( ! this - > input_recorder - > start ( error ) ) {
this - > input_recorder - > remove_consumer ( this ) ;
this - > input_recorder . reset ( ) ;
return false ;
}
2020-02-06 17:59:09 -05:00
return true ;
2019-10-25 19:51:40 -04:00
}
bool AudioInput : : recording ( ) {
2020-02-08 10:50:48 -05:00
return ! ! this - > input_recorder ;
2019-10-25 19:51:40 -04:00
}
void AudioInput : : stop ( ) {
2020-02-08 10:50:48 -05:00
if ( ! this - > input_recorder ) return ;
this - > input_recorder - > remove_consumer ( this ) ;
this - > input_recorder - > stop_if_possible ( ) ;
this - > input_recorder . reset ( ) ;
2019-10-25 19:51:40 -04:00
}
std : : shared_ptr < AudioConsumer > AudioInput : : create_consumer ( size_t frame_length ) {
2020-08-21 07:37:10 -04:00
auto result = std : : shared_ptr < AudioConsumer > ( new AudioConsumer ( this , this - > _channel_count , this - > _sample_rate , frame_length ) ) ;
2019-10-25 19:51:40 -04:00
{
2020-08-21 07:37:10 -04:00
std : : lock_guard lock ( this - > consumers_lock ) ;
2019-10-25 19:51:40 -04:00
this - > _consumers . push_back ( result ) ;
}
return result ;
}
void AudioInput : : delete_consumer ( const std : : shared_ptr < AudioConsumer > & source ) {
{
2020-08-21 07:37:10 -04:00
std : : lock_guard lock ( this - > consumers_lock ) ;
2019-10-25 19:51:40 -04:00
auto it = find ( this - > _consumers . begin ( ) , this - > _consumers . end ( ) , source ) ;
if ( it ! = this - > _consumers . end ( ) )
this - > _consumers . erase ( it ) ;
}
source - > handle = nullptr ;
}
2020-02-09 08:53:39 -05:00
void AudioInput : : consume ( const void * input , size_t frameCount , size_t channels ) {
if ( channels ! = this - > _channel_count ) {
2020-12-02 13:29:03 -05:00
if ( channels < 1 | | channels > 2 ) {
log_critical ( category : : audio , tr ( " Channel count miss match (Received: {})! " ) , channels ) ;
}
this - > ensure_resample_buffer_capacity ( frameCount * this - > _channel_count * sizeof ( float ) ) ;
audio : : merge : : merge_channels_interleaved ( this - > resample_buffer , this - > _channel_count , input , channels , frameCount ) ;
input = this - > resample_buffer ;
2020-02-09 08:53:39 -05:00
}
if ( this - > _resampler ) {
const auto expected_size = this - > _resampler - > estimated_output_size ( frameCount ) ;
const auto expected_byte_size = expected_size * this - > _channel_count * sizeof ( float ) ;
2020-12-02 13:29:03 -05:00
this - > ensure_resample_buffer_capacity ( expected_byte_size ) ;
2020-02-09 08:53:39 -05:00
2021-03-27 16:32:18 -04:00
size_t sample_count { expected_size } ;
if ( ! this - > _resampler - > process ( this - > resample_buffer , input , frameCount , sample_count ) ) {
log_error ( category : : audio , tr ( " Failed to resample input audio. " ) ) ;
2020-02-09 08:53:39 -05:00
return ;
}
2021-03-27 16:32:18 -04:00
frameCount = sample_count ;
2020-02-09 08:53:39 -05:00
input = this - > resample_buffer ;
2020-08-09 09:03:52 -04:00
audio : : apply_gain ( this - > resample_buffer , this - > _channel_count , frameCount , this - > _volume ) ;
2020-02-09 08:53:39 -05:00
} else if ( this - > _volume ! = 1 ) {
const auto byte_size = frameCount * this - > _channel_count * sizeof ( float ) ;
2020-12-02 13:29:03 -05:00
this - > ensure_resample_buffer_capacity ( byte_size ) ;
2020-02-09 08:53:39 -05:00
2020-12-02 13:29:03 -05:00
if ( this - > resample_buffer ! = input ) {
memcpy ( this - > resample_buffer , input , byte_size ) ;
input = this - > resample_buffer ;
}
2020-02-09 08:53:39 -05:00
2020-08-09 09:03:52 -04:00
audio : : apply_gain ( this - > resample_buffer , this - > _channel_count , frameCount , this - > _volume ) ;
2019-10-25 19:51:40 -04:00
}
2020-08-21 07:37:10 -04:00
auto begin = std : : chrono : : system_clock : : now ( ) ;
2020-12-02 13:29:03 -05:00
for ( const auto & consumer : this - > consumers ( ) ) {
consumer - > process_data ( input , frameCount ) ;
}
2020-02-09 08:53:39 -05:00
2020-08-21 07:37:10 -04:00
auto end = std : : chrono : : system_clock : : now ( ) ;
auto ms = std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( end - begin ) . count ( ) ;
2019-10-25 19:51:40 -04:00
if ( ms > 5 ) {
2020-08-21 07:37:10 -04:00
log_warn ( category : : audio , tr ( " Processing of audio input needed {}ms. This could be an issue! " ) , std : : chrono : : duration_cast < chrono : : milliseconds > ( end - begin ) . count ( ) ) ;
2019-10-25 19:51:40 -04:00
}
2020-12-02 13:29:03 -05:00
}
void AudioInput : : ensure_resample_buffer_capacity ( size_t size ) {
if ( this - > resample_buffer_size < size ) {
free ( this - > resample_buffer ) ;
this - > resample_buffer = malloc ( size ) ;
this - > resample_buffer_size = size ;
}
2019-10-25 19:51:40 -04:00
}