/*************************************************************************************** * * 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; }