|
Packit |
3ae693 |
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/***
|
|
Packit |
3ae693 |
This file is part of libcanberra.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
Copyright 2008 Lennart Poettering
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is free software; you can redistribute it and/or modify
|
|
Packit |
3ae693 |
it under the terms of the GNU Lesser General Public License as
|
|
Packit |
3ae693 |
published by the Free Software Foundation, either version 2.1 of the
|
|
Packit |
3ae693 |
License, or (at your option) any later version.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is distributed in the hope that it will be useful, but
|
|
Packit |
3ae693 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
3ae693 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
3ae693 |
Lesser General Public License for more details.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
3ae693 |
License along with libcanberra. If not, see
|
|
Packit |
3ae693 |
<http://www.gnu.org/licenses/>.
|
|
Packit |
3ae693 |
***/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3ae693 |
#include <config.h>
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include <stdio.h>
|
|
Packit |
3ae693 |
#include <sys/types.h>
|
|
Packit |
3ae693 |
#include <sys/eventfd.h>
|
|
Packit |
3ae693 |
#include <unistd.h>
|
|
Packit |
3ae693 |
#include <string.h>
|
|
Packit |
3ae693 |
#include <errno.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include <canberra.h>
|
|
Packit |
3ae693 |
#include <libudev.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include "macro.h"
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static char *find_device(void) {
|
|
Packit |
3ae693 |
struct udev *udev = NULL;
|
|
Packit |
3ae693 |
struct udev_enumerate *udev_enum = NULL;
|
|
Packit |
3ae693 |
struct udev_list_entry *i, *first;
|
|
Packit |
3ae693 |
int internal_device = -1, pci_device = -1, other_device = -1;
|
|
Packit |
3ae693 |
char *s = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(udev = udev_new())) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to allocate udev context.\n");
|
|
Packit |
3ae693 |
return NULL;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(udev_enum = udev_enumerate_new(udev))) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to allocate enumeration object.\n");
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (udev_enumerate_add_match_subsystem(udev_enum, "sound") < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to install subsystem match.\n");
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (udev_enumerate_scan_devices(udev_enum) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to enumerate devices.\n");
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
first = udev_enumerate_get_list_entry(udev_enum);
|
|
Packit |
3ae693 |
udev_list_entry_foreach(i, first) {
|
|
Packit |
3ae693 |
const char *sysfs, *p;
|
|
Packit |
3ae693 |
long l;
|
|
Packit |
3ae693 |
char d[64];
|
|
Packit |
3ae693 |
char *e = NULL;
|
|
Packit |
3ae693 |
struct udev_device *dev;
|
|
Packit |
3ae693 |
const char *ff, *class, *bus;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
sysfs = udev_list_entry_get_name(i);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(p = strrchr(sysfs, '/')))
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
p++;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (strncmp(p, "card", 4) != 0)
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
errno = 0;
|
|
Packit |
3ae693 |
l = strtol(p + 4, &e, 10);
|
|
Packit |
3ae693 |
if (!e || *e != 0 || errno != 0)
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Check whether this sound card has a playback device
|
|
Packit |
3ae693 |
* #0 (i.e. something that is not HDMI, SPDIF or
|
|
Packit |
3ae693 |
* something other weird.) */
|
|
Packit |
3ae693 |
snprintf(d, sizeof(d), "/sys/class/sound/card%i/pcmC%iD0p", (int) l, (int) l);
|
|
Packit |
3ae693 |
if (access(d, F_OK) < 0)
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(dev = udev_device_new_from_syspath(udev, sysfs)))
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
class = udev_device_get_property_value(dev, "SOUND_CLASS");
|
|
Packit |
3ae693 |
ff = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR");
|
|
Packit |
3ae693 |
bus = udev_device_get_property_value(dev, "ID_BUS");
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Ignore modems and other non-audio sound device */
|
|
Packit |
3ae693 |
if (class && !ca_streq(class, "sound")) {
|
|
Packit |
3ae693 |
udev_device_unref(dev);
|
|
Packit |
3ae693 |
continue;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Prefer "internal" devices */
|
|
Packit |
3ae693 |
if (internal_device < 0 && ff && ca_streq(ff, "internal"))
|
|
Packit |
3ae693 |
internal_device = (int) l;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* If no "internal" device is available, prefer PCI devices */
|
|
Packit |
3ae693 |
if (pci_device < 0 && bus && ca_streq(bus, "pci"))
|
|
Packit |
3ae693 |
pci_device = (int) l;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* If neither "internal" nor PCI devices are
|
|
Packit |
3ae693 |
* available, pick whatever we can find */
|
|
Packit |
3ae693 |
if (other_device < 0)
|
|
Packit |
3ae693 |
other_device = (int) l;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
udev_device_unref(dev);
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (internal_device >= 0)
|
|
Packit |
3ae693 |
asprintf(&s, "front:%i", internal_device);
|
|
Packit |
3ae693 |
else if (pci_device >= 0)
|
|
Packit |
3ae693 |
asprintf(&s, "front:%i", pci_device);
|
|
Packit |
3ae693 |
else if (other_device >= 0)
|
|
Packit |
3ae693 |
asprintf(&s, "front:%i", other_device);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
if (udev_enum)
|
|
Packit |
3ae693 |
udev_enumerate_unref(udev_enum);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (udev)
|
|
Packit |
3ae693 |
udev_unref(udev);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return s;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static void finish_cb(ca_context *c, uint32_t id, int error_code, void *userdata) {
|
|
Packit |
3ae693 |
uint64_t u = 1;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
for (;;) {
|
|
Packit |
3ae693 |
if (write(CA_PTR_TO_INT(userdata), &u, sizeof(u)) > 0)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (errno != EINTR) {
|
|
Packit |
3ae693 |
fprintf(stderr, "write() failed: %s\n", strerror(errno));
|
|
Packit |
3ae693 |
exit(EXIT_FAILURE);
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int main(int argc, char *argv[]) {
|
|
Packit |
3ae693 |
ca_context *c = NULL;
|
|
Packit |
3ae693 |
ca_proplist *p = NULL;
|
|
Packit |
3ae693 |
int ret = EXIT_FAILURE, r;
|
|
Packit |
3ae693 |
int fd = -1;
|
|
Packit |
3ae693 |
char *device = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (argc > 2) {
|
|
Packit |
3ae693 |
fprintf(stderr, "This program expects no more than one parameter.\n");
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((fd = eventfd(0, EFD_CLOEXEC)) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to create event file descriptor: %s\n", strerror(errno));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_context_create(&c)) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to create context: %s\n", ca_strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_context_set_driver(c, "alsa")) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to set driver: %s\n", ca_strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(device = find_device())) {
|
|
Packit |
3ae693 |
ret = EXIT_SUCCESS;
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_context_change_device(c, device)) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to set device: %s\n", ca_strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_proplist_create(&p)) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to create property list: %s\n", ca_strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_proplist_sets(p, CA_PROP_EVENT_ID, argc >= 2 ? argv[1] : "system-bootup")) < 0 ||
|
|
Packit |
3ae693 |
(r = ca_proplist_sets(p, CA_PROP_CANBERRA_CACHE_CONTROL, "never")) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to set event id: %s\n", strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((r = ca_context_play_full(c, 0, p, finish_cb, CA_INT_TO_PTR(fd))) < 0) {
|
|
Packit |
3ae693 |
fprintf(stderr, "Failed to play event sound: %s\n", ca_strerror(r));
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
for (;;) {
|
|
Packit |
3ae693 |
uint64_t u;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (read(fd, &u, sizeof(u)) < 0) {
|
|
Packit |
3ae693 |
if (errno == EINTR)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
fprintf(stderr, "read() failed: %s\n", strerror(errno));
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
} else
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = EXIT_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
if (c)
|
|
Packit |
3ae693 |
ca_context_destroy(c);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (p)
|
|
Packit |
3ae693 |
ca_proplist_destroy(p);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (fd >= 0)
|
|
Packit |
3ae693 |
close(fd);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
free(device);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|