mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-06 07:15:35 -04:00
Add wireless status detection and monitoring functions
This commit is contained in:
parent
4564f76627
commit
9bde703969
1 changed files with 179 additions and 0 deletions
|
|
@ -276,6 +276,168 @@ static void unescape(const char *src, char *dst)
|
||||||
*d = 0;
|
*d = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum wireless_status read_wireless_status(const char *sysfs_path)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
ssize_t sz;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(sysfs_path, O_RDONLY | O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return WIRELESS_STATUS_UNKNOWN;
|
||||||
|
|
||||||
|
sz = read(fd, buf, sizeof(buf) - 1);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (sz <= 0)
|
||||||
|
return WIRELESS_STATUS_UNKNOWN;
|
||||||
|
|
||||||
|
buf[sz] = '\0';
|
||||||
|
if (buf[sz - 1] == '\n')
|
||||||
|
buf[sz - 1] = '\0';
|
||||||
|
|
||||||
|
if (spa_streq(buf, "connected"))
|
||||||
|
return WIRELESS_STATUS_CONNECTED;
|
||||||
|
if (spa_streq(buf, "disconnected"))
|
||||||
|
return WIRELESS_STATUS_DISCONNECTED;
|
||||||
|
|
||||||
|
return WIRELESS_STATUS_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_usb_interface_dir(const char *name)
|
||||||
|
{
|
||||||
|
const char *colon = strchr(name, ':');
|
||||||
|
if (!colon || !strchr(name, '-'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const char *p = colon + 1; *p; p++)
|
||||||
|
if (*p != '.' && !(*p >= '0' && *p <= '9'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *check_wireless_status_at_path(struct impl *this, const char *path)
|
||||||
|
{
|
||||||
|
char wireless_path[PATH_MAX];
|
||||||
|
char *result;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = spa_scnprintf(wireless_path, sizeof(wireless_path),
|
||||||
|
"%s/wireless_status", path);
|
||||||
|
if (res < 0 || (size_t)res >= sizeof(wireless_path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (access(wireless_path, R_OK) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result = strdup(wireless_path);
|
||||||
|
if (!result)
|
||||||
|
spa_log_error(this->log, "failed to allocate wireless_status path");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *search_siblings_for_wireless_status(struct impl *this, const char *parent_path)
|
||||||
|
{
|
||||||
|
struct dirent *entry;
|
||||||
|
char *result = NULL;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
spa_autoptr(DIR) parent_dir = opendir(parent_path);
|
||||||
|
if (!parent_dir)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while ((entry = readdir(parent_dir)) != NULL) {
|
||||||
|
char sibling_path[PATH_MAX];
|
||||||
|
char *path;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (entry->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!is_usb_interface_dir(entry->d_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
res = spa_scnprintf(sibling_path, sizeof(sibling_path),
|
||||||
|
"%s/%s", parent_path, entry->d_name);
|
||||||
|
if (res < 0 || (size_t)res >= sizeof(sibling_path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
path = check_wireless_status_at_path(this, sibling_path);
|
||||||
|
if (path) {
|
||||||
|
count++;
|
||||||
|
if (!result)
|
||||||
|
result = path;
|
||||||
|
else
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
spa_log_info(this->log, "found %d wireless_status files, using first one", count);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *find_wireless_status_path(struct impl *this, const char *card_syspath)
|
||||||
|
{
|
||||||
|
char usb_device_path[PATH_MAX];
|
||||||
|
char *last_slash, *result;
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
res = spa_scnprintf(usb_device_path, sizeof(usb_device_path), "%s", card_syspath);
|
||||||
|
if (res < 0 || (size_t)res >= sizeof(usb_device_path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result = check_wireless_status_at_path(this, usb_device_path);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_PARENT_TRAVERSAL_DEPTH; i++) {
|
||||||
|
last_slash = strrchr(usb_device_path, '/');
|
||||||
|
if (!last_slash || last_slash == usb_device_path)
|
||||||
|
break;
|
||||||
|
|
||||||
|
*last_slash = '\0';
|
||||||
|
|
||||||
|
result = search_siblings_for_wireless_status(this, usb_device_path);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_wireless_status(struct impl *this, struct card *card)
|
||||||
|
{
|
||||||
|
enum wireless_status status;
|
||||||
|
bool disconnected;
|
||||||
|
|
||||||
|
if (!card->wireless_status_path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
status = read_wireless_status(card->wireless_status_path);
|
||||||
|
|
||||||
|
if (status == WIRELESS_STATUS_UNKNOWN) {
|
||||||
|
spa_log_info(this->log, "card %u wireless_status unreadable, removing monitor",
|
||||||
|
card->card_nr);
|
||||||
|
free(card->wireless_status_path);
|
||||||
|
card->wireless_status_path = NULL;
|
||||||
|
card->wireless_disconnected = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnected = (status == WIRELESS_STATUS_DISCONNECTED);
|
||||||
|
if (disconnected != card->wireless_disconnected) {
|
||||||
|
spa_log_info(this->log, "card %u wireless device %s",
|
||||||
|
card->card_nr, disconnected ? "disconnected" : "connected");
|
||||||
|
card->wireless_disconnected = disconnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int check_device_pcm_class(const char *devname)
|
static int check_device_pcm_class(const char *devname)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
|
@ -906,6 +1068,23 @@ static int start_inotify(struct impl *this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct card *find_card_by_wireless_status_path(struct impl *this, const char *syspath)
|
||||||
|
{
|
||||||
|
char wireless_path[PATH_MAX];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = spa_scnprintf(wireless_path, sizeof(wireless_path), "%s/wireless_status", syspath);
|
||||||
|
if (res < 0 || (size_t)res >= sizeof(wireless_path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < this->n_cards; i++) {
|
||||||
|
if (this->cards[i].wireless_status_path &&
|
||||||
|
spa_streq(this->cards[i].wireless_status_path, wireless_path))
|
||||||
|
return &this->cards[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void impl_on_fd_events(struct spa_source *source)
|
static void impl_on_fd_events(struct spa_source *source)
|
||||||
{
|
{
|
||||||
struct impl *this = source->data;
|
struct impl *this = source->data;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue