上一篇实现了windows的音视频设备热插拔功能,这一篇集成到SDK中。我的对外接口类是HCMDesktopRecorder,该篇主要讲如何集成热插拔功能,其他代码忽略。
1、开启并注册热插拔
int HCMDesktopRecorder::init(/* 忽略 */)
{
/* 忽略 */
// Create thread for detect device callback
m_detectDeviceThread = std::thread(std::bind(&HCMDesktopRecorder::detectDeviceProcess, this));
// Start detecting device
DEVICE::DeviceDetector::GetInstance().startDetect();
m_deviceDetectCbId = DEVICE::DeviceDetector::GetInstance().registerCallback(std::bind(&HCMDesktopRecorder::deviceDetectCb,
this, std::placeholders::_1, std::placeholders::_2));
/* 忽略 */
}
向DeviceDetector注册的回调,一旦收到设备变更通知就触发自己的函数detectDeviceProcess
void HCMDesktopRecorder::deviceDetectCb(DEVICE::DeviceDetectType type, DEVICE::DeviceDetectAction action)
{
std::unique_lock<std::mutex> lock(m_detectDeviceMutex);
m_detectDeviceInfoList.push_back({
type, action });
m_detectDeviceFlag = true;
m_detectDeviceCond.notify_all();
}
detectDeviceProcess的线程函数实现如下:
void HCMDesktopRecorder::detectDeviceProcess()
{
while (m_inited) {
std::unique_lock<std::mutex> lock(m_detectDeviceMutex);
while (!m_detectDeviceFlag && m_inited) {
m_detectDeviceCond.wait_for(lock, std::chrono::microseconds(1000));
}
while (!m_detectDeviceInfoList.empty()) {
auto info = m_detectDeviceInfoList.front();
m_detectDeviceInfoList.pop_front();
handleAudioDevice(info.type, info.action);
handleVideoDevice(info.type, info.action);
}
m_detectDeviceFlag = false;
}
}
其中handleAudioDevice和handleVideoDevice实现有点长,如下。
如果发现当前使用的设备被拔掉了,那么先销毁内存,并找可用的新设备,如果找到了,则开启新设备并更新到muxer中,实现见replaceAudioCaptor和replaceVideoCaptor;如果监测到插入了新设备并且当前无相同类型设备在使用,那么同样创建新设备并更新到muxer,同样详见replaceAudioCaptor和replaceVideoCaptor
void HCMDesktopRecorder::handleAudioDevice(DEVICE::DeviceDetectType type, DEVICE::DeviceDetectAction action)
{
DEVICE::AUDIO_DEVICE defaultDevice = {
};
std::list<DEVICE::AUDIO_DEVICE> devices;
if (type == DEVICE::DeviceDetectType::DEVICE_DDETECT_TYPE_MIC) {
DEVICE::AudioDevice::getMicDevices(devices);
if (action == DEVICE::DeviceDetectAction::DEVICE_DDETECT_ACTION_REMOVE) {
bool removed = true;
for each (auto device in devices) {
if (device.id == m_setting.mic.id) {
removed = false;
break;
}
if (device.isDefault) {
defaultDevice = device;
}
}
if (removed) {
memset(m_setting.mic.id, 0, sizeof(m_setting.mic.id));
if (m_micCaptor != nullptr) {
m_fileMuxer->replaceAudioCaptor(m_micCaptor, true, false);
CAPTOR::destroyAudioCaptor(&m_micCaptor);
m_micCaptor = nullptr;
}
if (!devices.empty()) {
memcpy_s(m_setting.mic.id, sizeof(m_setting.mic.id), defaultDevice.id.c_str(), defaultDevice.id.size())