276 lines
5.6 KiB
C++
276 lines
5.6 KiB
C++
|
|
/***************************************************************************************
|
||
|
|
*
|
||
|
|
* 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(¶ms, 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(¶ms) == 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|