Files
ANSCORE/MediaClient/media/audio_capture_linux.cpp

426 lines
8.5 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_linux.h"
#include "lock.h"
/***************************************************************************************/
static void * audioCaptureThread(void * argv)
{
CLAudioCapture *capture = (CLAudioCapture *)argv;
capture->captureThread();
return NULL;
}
/***************************************************************************************/
CLAudioCapture::CLAudioCapture() : CAudioCapture()
{
memset(&m_alsa, 0, sizeof(m_alsa));
m_alsa.period_size = 64;
m_alsa.framesize = 16 / 8 * 2;
m_pData = NULL;
}
CLAudioCapture::~CLAudioCapture()
{
stopCapture();
}
CAudioCapture * CLAudioCapture::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 CLAudioCapture();
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 CLAudioCapture::getDeviceNums()
{
int card = -1, count = 0, ret;
snd_ctl_card_info_t * info;
snd_ctl_card_info_alloca(&info);
ret = snd_card_next(&card);
while (ret == 0 && card != -1)
{
char name[16];
snd_ctl_t * ctl;
snprintf(name, sizeof(name), "hw:%d", card);
if (snd_ctl_open(&ctl, name, SND_CTL_NONBLOCK) < 0)
{
ret = snd_card_next(&card);
continue;
}
if (snd_ctl_card_info(ctl, info) < 0)
{
snd_ctl_close(ctl);
ret = snd_card_next(&card);
continue;
}
snd_ctl_close(ctl);
if (++count >= MAX_AUDIO_DEV_NUMS)
{
break;
}
ret = snd_card_next(&card);
}
return count > MAX_AUDIO_DEV_NUMS ? MAX_AUDIO_DEV_NUMS : count;
}
void CLAudioCapture::listDevice()
{
int card = -1, count = 0, ret;
snd_ctl_card_info_t * info;
printf("\r\nAvailable audio capture device : \r\n\r\n");
snd_ctl_card_info_alloca(&info);
ret = snd_card_next(&card);
while (ret == 0 && card != -1)
{
char name[16];
snd_ctl_t * ctl;
snprintf(name, sizeof(name), "hw:%d", card);
if (snd_ctl_open(&ctl, name, SND_CTL_NONBLOCK) < 0)
{
ret = snd_card_next(&card);
continue;
}
if (snd_ctl_card_info(ctl, info) < 0)
{
snd_ctl_close(ctl);
ret = snd_card_next(&card);
continue;
}
printf("index : %d, name : %s\r\n", count, snd_ctl_card_info_get_name(info));
snd_ctl_close(ctl);
if (++count >= MAX_AUDIO_DEV_NUMS)
{
break;
}
ret = snd_card_next(&card);
}
}
int CLAudioCapture::getDeviceIndex(const char * name)
{
int card = -1, count = 0, index = 0, ret;
snd_ctl_card_info_t * info;
snd_ctl_card_info_alloca(&info);
ret = snd_card_next(&card);
while (ret == 0 && card != -1)
{
char cname[16];
snd_ctl_t * ctl;
snprintf(cname, sizeof(cname), "hw:%d", card);
if (snd_ctl_open(&ctl, cname, SND_CTL_NONBLOCK) < 0)
{
ret = snd_card_next(&card);
continue;
}
if (snd_ctl_card_info(ctl, info) < 0)
{
snd_ctl_close(ctl);
ret = snd_card_next(&card);
continue;
}
if (strcasecmp(snd_ctl_card_info_get_name(info), name) == 0)
{
index = count;
snd_ctl_close(ctl);
break;
}
snd_ctl_close(ctl);
if (++count >= MAX_AUDIO_DEV_NUMS)
{
break;
}
ret = snd_card_next(&card);
}
return index;
}
BOOL CLAudioCapture::getDeviceName(int index, char * name, int namesize)
{
BOOL res = FALSE;
int card = -1, count = 0, ret;
snd_ctl_card_info_t * info;
snd_ctl_card_info_alloca(&info);
ret = snd_card_next(&card);
while (ret == 0 && card != -1)
{
char cname[16];
snd_ctl_t * ctl;
snprintf(cname, sizeof(cname), "hw:%d", card);
if (snd_ctl_open(&ctl, cname, SND_CTL_NONBLOCK) < 0)
{
ret = snd_card_next(&card);
continue;
}
if (snd_ctl_card_info(ctl, info) < 0)
{
snd_ctl_close(ctl);
ret = snd_card_next(&card);
continue;
}
if (index == count)
{
res = TRUE;
strncpy(name, snd_ctl_card_info_get_name(info), namesize);
snd_ctl_close(ctl);
break;
}
snd_ctl_close(ctl);
if (++count >= MAX_AUDIO_DEV_NUMS)
{
break;
}
ret = snd_card_next(&card);
}
return res;
}
BOOL CLAudioCapture::initCapture(int codec, int samplerate, int channels, int bitrate)
{
CLock lock(m_pMutex);
if (m_bInited)
{
return TRUE;
}
if (alsa_get_device_name(m_nDevIndex, m_alsa.devname, sizeof(m_alsa.devname)) == FALSE)
{
log_print(HT_LOG_ERR, "get device name failed. %d\r\n", m_nDevIndex);
return FALSE;
}
if (alsa_open_device(&m_alsa, SND_PCM_STREAM_CAPTURE, (uint32 *)&samplerate, 2) == FALSE)
{
log_print(HT_LOG_ERR, "open device (%s) failed\r\n", m_alsa.devname);
return FALSE;
}
m_pData = (uint8 *)malloc(ALSA_BUFFER_SIZE_MAX);
if (NULL == m_pData)
{
return FALSE;
}
memset(m_pData, 0, ALSA_BUFFER_SIZE_MAX);
AudioEncoderParam params;
memset(&params, 0, sizeof(params));
params.SrcChannels = 2;
params.SrcSamplefmt = AV_SAMPLE_FMT_S16;
params.SrcSamplerate = samplerate;
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 = channels;
m_nSampleRate = samplerate;
m_nBitrate = bitrate;
m_bInited = TRUE;
return TRUE;
}
BOOL CLAudioCapture::capture()
{
int res = 0;
if (NULL == m_alsa.handler)
{
return FALSE;
}
while (m_bCapture)
{
res = snd_pcm_wait(m_alsa.handler, 100);
if (res < 0)
{
if (alsa_xrun_recover(m_alsa.handler, res) < 0)
{
return FALSE;
}
}
res = snd_pcm_readi(m_alsa.handler, m_pData, m_alsa.period_size);
if (res == -EAGAIN)
{
continue;
}
else if (res < 0)
{
if (alsa_xrun_recover(m_alsa.handler, res) < 0)
{
return FALSE;
}
}
else if (res > 0)
{
break;
}
}
return m_encoder.encode(m_pData, res * m_alsa.framesize);
}
void CLAudioCapture::captureThread()
{
while (m_bCapture)
{
if (capture())
{
}
else
{
usleep(10*1000);
}
}
m_hCapture = 0;
log_print(HT_LOG_INFO, "%s, exit\r\n", __FUNCTION__);
}
BOOL CLAudioCapture::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 CLAudioCapture::stopCapture(void)
{
CLock lock(m_pMutex);
m_bCapture = FALSE;
while (m_hCapture)
{
usleep(10*1000);
}
alsa_close_device(&m_alsa);
if (m_pData)
{
free(m_pData);
m_pData = NULL;
}
m_bInited = FALSE;
}