回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

安全 USB 麦克风 简单

头像 zoologist 2025.12.09 17 0

基于 ESP32-S3 开发的 USB 安全麦克风。让使用者完全避免开会中声音泄露的尴尬。

1.主控是 ESP32-S3,内置USB Device 支持,将自身模拟为一个 USB麦克风

2.使用MSM261S4030H0麦克风,这是一个高灵敏度的单麦克,通过I2S接口直接输出音频信息。

 

通过国产的 Cherry USB 架构实现了一个简单的 UAC.

关键代码如下:

代码
1.初始化麦克风的 I2S ,特别注意是单声道
// 标准模式配置
i2s_std_config_t std_cfg =
{
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(
    I2S_DATA_BIT_WIDTH_32BIT,
    I2S_SLOT_MODE_MONO
),
//.slot_cfg.slot_mask = I2S_STD_SLOT_LEFT,
.gpio_cfg = {
.bclk = I2S_BCK_GPIO,
.ws = I2S_WS_GPIO,
.din = I2S_DATA_GPIO,
.invert_flags = {
.bclk_inv = false, //时钟空闲时为 High
.ws_inv = false
}
}
};
std_cfg.slot_cfg.slot_mode=I2S_SLOT_MODE_MONO;
std_cfg.slot_cfg.slot_mask=I2S_STD_SLOT_LEFT;
代码
2.Cherry USB架构下,下面的函数中完成 UAC 的初始化,同时创建一个队列用于接收音频数据
void audio_v1_init(uint8_t busid, uintptr_t reg_base)
{
    //  创建同步信号
    sign_tx = xSemaphoreCreateBinary();
    //  数据队列
s_receive_queue = xQueueCreate(10, sizeof(i2c_mic_rx_data_t));
//创建接收任务
xTaskCreatePinnedToCore(task_func, "task", 4096, NULL, 10, NULL, tskNO_AFFINITY);
 
 
    ESP_ERROR_CHECK(esp_task_wdt_add_user("usb", &twdt_usb));
 
    usbd_desc_register(busid, audio_v1_descriptor);
    usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0100, audio_entity_table, 1));
    usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0100, audio_entity_table, 1));
    usbd_add_endpoint(busid, &audio_in_ep);
 
    usbd_initialize(busid, reg_base, usbd_event_handler);
}
代码
3.收到的音频数据在如下回调函数中
 
void usbd_audio_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
    //USB_LOG_RAW("actual in len:%d\r\n", nbytes);
    ep_tx_busy_flag = false;
    if (0 == tx_flag)
    {
        printf("usbd_audio_iso_callback tx_flag = 0\n");
    }
    
    //  释放信号,让Main那边可以发送了
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(sign_tx, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
代码
4. 最终,在将音频数据发送给PC时,做一个简单的判断,只有指定的 GPIO 拉低才会将数据发送出去,否则送出空数据包
 
// 如果当前没有发送
if (ep_tx_busy_flag != true)
{
ep_tx_busy_flag = true;
 
                xSemaphoreTake(sign_tx, 0);
 
if(gpio_get_level(GPIO_NUM_9) == 0) {  // 低电平触发
// 发送数据到 USB 
usbd_ep_start_write(0, AUDIO_IN_EP, rx_data.buffer, rx_data.size);
} else {
usbd_ep_start_write(0, AUDIO_IN_EP, NullBuffer, AUDIO_IN_PACKET);
}
 
 
                
                xSemaphoreTake(sign_tx, 10);
                
while (ep_tx_busy_flag)
{
if (tx_flag == false)
{
break;
}
}
//发送完成,释放缓冲区
rx_data.size = 0;
free(rx_data.buffer);

image.png
image.png

 

附件

评论

user-avatar