Compare commits

...

2 Commits

10 changed files with 151 additions and 8 deletions

View File

@ -79,7 +79,7 @@ device_manager {
id: "ethercat_motors"
type: DEVICE_TYPE_MOTOR_SYSTEM
config_file: "devices/motor/ethercat_motors.pb.txt"
enable: true
enable: false
}
devices {
@ -93,14 +93,14 @@ device_manager {
id: "eyou_arm"
type: DEVICE_TYPE_ROBOT_ARM
config_file: "devices/arm/arm.pb.txt"
enable: true
enable: false
}
devices {
id: "eyou_left_arm"
type: DEVICE_TYPE_ROBOT_ARM
config_file: "devices/arm/arm_eyou_left.pb.txt"
enable: true
enable: false
}
devices {
@ -168,13 +168,13 @@ device_manager {
type: DEVICE_TYPE_CAMERA
config_file: "devices/camera/camera.pb.txt"
# Host-development default: keep physical cameras disabled.
enable: true
enable: false
}
devices {
id: "usb_cam1"
type: DEVICE_TYPE_CAMERA
config_file: "devices/camera/camera.pb.txt"
# Host-development default: keep physical cameras disabled.
enable: true
enable: false
}
}

View File

@ -27,7 +27,6 @@ task_manager {
type: TASK_TYPE_QUIC_EDGE
run_mode: TASK_RUN_MODE_BLOCKING_SERVICE
config_file: "tasks/quic_edge_task/quic_edge_task.pb.txt"
# Host-development default: no QUIC Gateway or physical media devices.
enable: false
enable: true
}
}

View File

@ -1,4 +1,7 @@
add_library(ffmpeg_microphone SHARED src/ffmpeg_microphone.cpp)
add_library(ffmpeg_microphone SHARED
src/ffmpeg_microphone.cpp
src/microphone_device_discovery.cpp
)
target_include_directories(ffmpeg_microphone PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -0,0 +1,74 @@
#include "devices/microphone/microphone_device_discovery.h"
#include <memory>
#include <stdexcept>
#include <utility>
extern "C" {
#include <libavdevice/avdevice.h>
#include <libavutil/error.h>
}
namespace cmvr::device {
namespace {
std::string avErrorToString(int error)
{
char buffer[AV_ERROR_MAX_STRING_SIZE] = {0};
av_strerror(error, buffer, sizeof(buffer));
return buffer;
}
struct DeviceListDeleter {
void operator()(AVDeviceInfoList* list) const
{
avdevice_free_list_devices(&list);
}
};
} // namespace
std::vector<MicrophoneInputDeviceInfo> listAvailableMicrophoneInputDevices()
{
constexpr const char* kBackend = "alsa";
avdevice_register_all();
const AVInputFormat* input_format = av_find_input_format(kBackend);
if (!input_format) {
throw std::runtime_error("FFmpeg ALSA input backend is unavailable");
}
AVDeviceInfoList* raw_device_list = nullptr;
const int result = avdevice_list_input_sources(
input_format, nullptr, nullptr, &raw_device_list);
std::unique_ptr<AVDeviceInfoList, DeviceListDeleter> device_list(raw_device_list);
if (result < 0) {
throw std::runtime_error(
"Failed to list ALSA microphone devices: " + avErrorToString(result));
}
std::vector<MicrophoneInputDeviceInfo> devices;
if (!device_list) {
return devices;
}
devices.reserve(static_cast<std::size_t>(device_list->nb_devices));
for (int index = 0; index < device_list->nb_devices; ++index) {
const AVDeviceInfo* source = device_list->devices[index];
if (!source || !source->device_name || source->device_name[0] == '\0') {
continue;
}
MicrophoneInputDeviceInfo device;
device.input_device = source->device_name;
device.display_name = source->device_description && source->device_description[0] != '\0'
? source->device_description
: source->device_name;
device.backend = kBackend;
device.is_default = index == device_list->default_device;
devices.push_back(std::move(device));
}
return devices;
}
} // namespace cmvr::device

View File

@ -0,0 +1,19 @@
#pragma once
#include <string>
#include <vector>
namespace cmvr::device {
struct MicrophoneInputDeviceInfo {
std::string input_device;
std::string display_name;
std::string backend;
bool is_default{false};
};
// Returns the capture devices that can be used as microphone inputs.
// Throws std::runtime_error when the platform backend cannot enumerate devices.
std::vector<MicrophoneInputDeviceInfo> listAvailableMicrophoneInputDevices();
} // namespace cmvr::device

View File

@ -18,6 +18,7 @@ target_link_libraries(service PRIVATE
cmvr_es::proto
osqp
cmvr_es::device_manager
cmvr_es::device::microphone
cmvr_es::task_manager
cmvr_es::algorithms::controller
cmvr_es::task

View File

@ -17,6 +17,10 @@ namespace cmvr::service
public:
gRPCMicroPhoneServiceImpl();
~gRPCMicroPhoneServiceImpl() override = default;
grpc::Status ListDevices(
grpc::ServerContext* context,
const api::ListMicrophoneDevicesCommand_Request* request,
api::ListMicrophoneDevicesCommand_Feedback* response) override;
grpc::Status GetStatus(grpc::ServerContext* context, const api::GetMicStateCommand_Request* request,api::GetMicStateCommand_Feedback* response) override;
grpc::Status StartRecord(grpc::ServerContext* context, const api::StartMicRecordingCommand_Request* request,api::StartMicRecordingCommand_Feedback* response) override;
grpc::Status StopRecord(grpc::ServerContext* context, const api::StopMicRecordingCommand_Request* request,api::StopMicRecordingCommand_Feedback* response) override;

View File

@ -1,4 +1,5 @@
#include "common/base/logging/logger.h"
#include "devices/microphone/microphone_device_discovery.h"
#include "manager/media_source_hub/include/device_media_source_adapter.h"
#include <algorithm>
#include <chrono>
@ -28,6 +29,31 @@ grpc::Status failResponse(ResponseT* response, const std::string& message) {
gRPCMicroPhoneServiceImpl::gRPCMicroPhoneServiceImpl(): dmgr_(DeviceManager::getInstance()) {}
grpc::Status gRPCMicroPhoneServiceImpl::ListDevices(
grpc::ServerContext* context,
const api::ListMicrophoneDevicesCommand_Request* request,
api::ListMicrophoneDevicesCommand_Feedback* response) {
(void)context;
(void)request;
try {
const auto devices = listAvailableMicrophoneInputDevices();
for (const auto& device : devices) {
auto* item = response->add_devices();
item->set_input_device(device.input_device);
item->set_display_name(device.display_name);
item->set_backend(device.backend);
item->set_is_default(device.is_default);
}
response->mutable_header()->set_success(true);
setCurrentTimestamp(response->mutable_header()->mutable_timestamp());
CMVR_LOG(INFO) << "[gRPCMicroPhoneServiceImpl] (ListDevices): found "
<< devices.size() << " microphone input device(s)";
return grpc::Status::OK;
} catch (const std::exception& e) {
return failResponse(response, e.what());
}
}
grpc::Status gRPCMicroPhoneServiceImpl::GetStatus(grpc::ServerContext* context,
const api::GetMicStateCommand_Request* request, api::GetMicStateCommand_Feedback* response) {
try {

View File

@ -12,6 +12,22 @@ message MicState {
string error_message = 5;
}
message MicrophoneInputDevice {
string input_device = 1;
string display_name = 2;
string backend = 3;
bool is_default = 4;
}
message ListMicrophoneDevicesCommand {
message Request {}
message Feedback {
CommandHeader.Feedback header = 1;
repeated MicrophoneInputDevice devices = 2;
}
}
message GetMicStateCommand {
message Request {
CommandHeader.Request header = 1;

View File

@ -5,6 +5,7 @@ import "cmvr/api/microphone_command.proto";
package cmvr.api;
service MicPhoneService {
rpc ListDevices(ListMicrophoneDevicesCommand.Request) returns (ListMicrophoneDevicesCommand.Feedback);
rpc GetStatus(GetMicStateCommand.Request) returns (GetMicStateCommand.Feedback);
rpc StartRecord(StartMicRecordingCommand.Request) returns (StartMicRecordingCommand.Feedback);
rpc StopRecord(StopMicRecordingCommand.Request) returns (StopMicRecordingCommand.Feedback);