/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "sys_inc.h"
#include "audio_capture_mac.h"
#include "lock.h"


/***************************************************************************************/

static void avfAudioCallback(avf_audio_data * data, void * userdata)
{
    CMAudioCapture *capture = (CMAudioCapture *)userdata;

    capture->audioCallBack(data);
}

static void * audioCaptureThread(void * argv)
{
	CMAudioCapture *capture = (CMAudioCapture *)argv;

	capture->captureThread();

	return NULL;
}

/***************************************************************************************/

CMAudioCapture::CMAudioCapture() : CAudioCapture()
{
	m_pCapture = NULL;
}

CMAudioCapture::~CMAudioCapture()
{
    stopCapture();
}

CAudioCapture * CMAudioCapture::getInstance(int devid)
{
	if (devid < 0 || devid >= MAX_AUDIO_DEV_NUMS)
	{
		return NULL;
	}
	
	sys_os_mutex_enter(m_pInstMutex);

	if (NULL == m_pInstance[devid])
	{
		m_pInstance[devid] = new CMAudioCapture;
		if (m_pInstance[devid])
		{
			m_pInstance[devid]->m_nRefCnt++;
			m_pInstance[devid]->m_nDevIndex = devid;
		}
	}
	else
    {
        m_pInstance[devid]->m_nRefCnt++;
    }
	
	sys_os_mutex_leave(m_pInstMutex);

	return m_pInstance[devid];
}

int CMAudioCapture::getDeviceNums()
{
	int count = avf_audio_device_nums();
    
    return count > MAX_AUDIO_DEV_NUMS ? MAX_AUDIO_DEV_NUMS : count;
}

void CMAudioCapture::listDevice()
{
    avf_audio_device_list();
}

int CMAudioCapture::getDeviceIndex(const char * name)
{
    int index = avf_audio_device_get_index(name);

    return index > MAX_AUDIO_DEV_NUMS ? 0 : index;
}

BOOL CMAudioCapture::getDeviceName(int index, char * name, int namesize)
{
    return avf_audio_device_get_name(index, name, namesize);
}

BOOL CMAudioCapture::initCapture(int codec, int samplerate, int channels, int bitrate)
{
	CLock lock(m_pMutex);
	
	if (m_bInited)
	{
		return TRUE;
	}

	m_pCapture = avf_audio_init(m_nDevIndex, samplerate, 2);
    if (NULL == m_pCapture)
    {
        log_print(HT_LOG_ERR, "%s, avf_audio_init failed\r\n", __FUNCTION__);
        return FALSE;
    }

    avf_audio_set_callback(m_pCapture, avfAudioCallback, this);
	
	AudioEncoderParam params;
	memset(&params, 0, sizeof(params));
	
	params.SrcChannels = avf_audio_get_channels(m_pCapture);
	params.SrcSamplefmt = (AVSampleFormat)avf_audio_get_samplefmt(m_pCapture);
	params.SrcSamplerate = avf_audio_get_samplerate(m_pCapture);
	params.DstChannels = channels;
	params.DstSamplefmt = AV_SAMPLE_FMT_S16;
	params.DstSamplerate = samplerate;
	params.DstBitrate = bitrate;
	params.DstCodec = codec;

	if (m_encoder.init(&params) == FALSE)
	{
		return FALSE;
	}

    m_nChannels = params.SrcChannels;
	m_nSampleRate = params.SrcSamplerate;
	m_nBitrate = bitrate;
	m_bInited = TRUE;
	
	return TRUE;
}

void CMAudioCapture::audioCallBack(avf_audio_data * data)
{
    int i;
    AVFrame frame;
    
    memset(&frame, 0, sizeof(frame));

    for (i = 0; i < 4; i++)
    {
        frame.data[i] = data->data[i];
        frame.linesize[i] = data->linesize[i];
    }

    frame.extended_data = frame.data;
    frame.sample_rate = data->samplerate;
    frame.channels = data->channels;
    frame.format = data->format;
    frame.nb_samples = data->samples;
	frame.channel_layout = av_get_default_channel_layout(data->channels);
    frame.key_frame = 1;
    
    m_encoder.encode(&frame);
}

BOOL CMAudioCapture::capture(int *samples)
{
    if (!m_bInited)
	{
		return FALSE;
	}

    BOOL ret = avf_audio_read(m_pCapture, samples);

    return ret;	
}

void CMAudioCapture::captureThread()
{
	int samples = 0;
	int samplerate = m_nSampleRate;
	int64 cur_delay = 0;
	int64 pre_delay = 0;
	uint32 cur_time = 0;
	uint32 pre_time = 0;
	
	while (m_bCapture)
	{
		if (capture(&samples))
		{
			cur_time = sys_os_get_ms();
		    cur_delay = 1000000.0 / samplerate * samples;

		    if (pre_time > 0)
		    {
		        cur_delay += pre_delay - (cur_time - pre_time) * 1000;
		        if (cur_delay < 1000)
		        {
		            cur_delay = 0;
		        }
		    }

		    pre_time = cur_time;
		    pre_delay = cur_delay;
		    
		    if (cur_delay > 0)
		    {
			    usleep(cur_delay);
			}
		}
		else
		{
			usleep(10*1000);
		}
	}

	m_hCapture = 0;

	log_print(HT_LOG_INFO, "%s, exit\r\n", __FUNCTION__);
}

BOOL CMAudioCapture::startCapture()
{
    CLock lock(m_pMutex);

	if (!m_bInited)
	{
		return FALSE;
	}
	
	if (m_bCapture)
	{
		return TRUE;
	}
	
	// m_bCapture = TRUE;
	// m_hCapture = sys_os_create_thread((void *)audioCaptureThread, this);

	return TRUE;
}

void CMAudioCapture::stopCapture(void)
{
    CLock lock(m_pMutex);
    
	m_bCapture = FALSE;
	
	while (m_hCapture)
	{
		usleep(10*1000);
	}

	if (m_pCapture)
	{
	    avf_audio_uninit(m_pCapture);
	    m_pCapture = NULL;
	}

	m_bInited = FALSE;
}







