static void inotify_cb( pa_mainloop_api *a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { struct { struct inotify_event event; char name[NAME_MAX+1]; } buf; pa_inotify *i = userdata; int pid_fd; pa_assert(i); if (pa_read(fd, &buf, sizeof(buf), NULL) < (int) sizeof(buf.event)) pa_log_warn("inotify did not read a full event."); else pa_log_debug("inotify callback, event mask: 0x%x", (int) buf.event.mask); pid_fd = pa_open_cloexec(i->filename, O_RDONLY #ifdef O_NOFOLLOW |O_NOFOLLOW #endif , S_IRUSR); if (pid_fd < 0) { if (i->callback) i->callback(i->callback_data); } else pa_close(pid_fd); }
static int open_pid_file(const char *fn, int mode) { int fd; pa_assert(fn); for (;;) { struct stat st; if ((fd = pa_open_cloexec(fn, mode #ifdef O_NOFOLLOW |O_NOFOLLOW #endif , S_IRUSR|S_IWUSR )) < 0) { if (mode != O_RDONLY || errno != ENOENT) pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } /* Try to lock the file. If that fails, go without */ if (pa_lock_fd(fd, 1) < 0) goto fail; if (fstat(fd, &st) < 0) { pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } /* Does the file still exist in the file system? When yes, we're done, otherwise restart */ if (st.st_nlink >= 1) break; if (pa_lock_fd(fd, 0) < 0) goto fail; if (pa_close(fd) < 0) { pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno)); fd = -1; goto fail; } } return fd; fail: if (fd >= 0) { int saved_errno = errno; pa_lock_fd(fd, 0); pa_close(fd); errno = saved_errno; } return -1; }
/* Load an authorization cookie from file fn and store it in data. If * the cookie file doesn't exist, create it */ static int load(const char *fn, void *data, size_t length) { int fd = -1; int writable = 1; int unlock = 0, ret = -1; ssize_t r; pa_assert(fn); pa_assert(data); pa_assert(length > 0); if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_read(fd, data, length, NULL)) < 0) { pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } if ((size_t) r != length) { pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length); if (!writable) { pa_log_warn("Unable to write cookie to read-only file"); goto finish; } if (generate(fd, data, length) < 0) goto finish; } ret = 0; finish: if (fd >= 0) { if (unlock) pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); ret = -1; } } return ret; }
/* Store the specified cookie in the specified cookie file */ int pa_authkey_save(const char *fn, const void *data, size_t length) { int fd = -1; int unlock = 0, ret = -1; ssize_t r; char *p; pa_assert(fn); pa_assert(data); pa_assert(length > 0); if (!(p = normalize_path(fn))) return -2; if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } unlock = pa_lock_fd(fd, 1) >= 0; if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) { pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } ret = 0; finish: if (fd >= 0) { if (unlock) pa_lock_fd(fd, 0); if (pa_close(fd) < 0) { pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno)); ret = -1; } } pa_xfree(p); return ret; }
static char *get_cpuinfo(void) { char *cpuinfo; int n, fd; cpuinfo = pa_xmalloc(MAX_BUFFER); if ((fd = pa_open_cloexec("/proc/cpuinfo", O_RDONLY, 0)) < 0) { pa_xfree(cpuinfo); return NULL; } if ((n = pa_read(fd, cpuinfo, MAX_BUFFER-1, NULL)) < 0) { pa_xfree(cpuinfo); pa_close(fd); return NULL; } cpuinfo[n] = 0; pa_close(fd); return cpuinfo; }
static int open_audio_device(struct userdata *u, pa_sample_spec *ss) { pa_assert(u); pa_assert(ss); if ((u->fd = pa_open_cloexec(u->device_name, u->mode | O_NONBLOCK, 0)) < 0) { pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno)); return -1; } pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (auto_format(u->fd, u->mode, ss) < 0) return -1; if (set_buffer(u->fd, u->buffer_size) < 0) return -1; u->written_bytes = u->read_bytes = 0; u->play_samples_msw = u->record_samples_msw = 0; u->prev_playback_samples = u->prev_record_samples = 0; return u->fd; }
int pa__init(pa_module *m) { struct userdata *u; struct stat st; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma; struct pollfd *pollfd; pa_source_new_data data; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); goto fail; } ss = m->core->default_sample_spec; map = m->core->default_channel_map; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("Invalid sample format specification or channel map"); goto fail; } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; pa_memchunk_reset(&u->memchunk); u->rtpoll = pa_rtpoll_new(); if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { pa_log("pa_thread_mq_init() failed."); goto fail; } u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); if (mkfifo(u->filename, 0666) < 0) { pa_log("mkfifo('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) { pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } pa_make_fd_nonblock(u->fd); if (fstat(u->fd, &st) < 0) { pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } if (!S_ISFIFO(st.st_mode)) { pa_log("'%s' is not a FIFO.", u->filename); goto fail; } pa_source_new_data_init(&data); data.driver = __FILE__; data.module = m; pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->filename); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Unix FIFO source %s", u->filename); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_source_new_data_done(&data); goto fail; } u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY); pa_source_new_data_done(&data); if (!u->source) { pa_log("Failed to create source."); goto fail; } u->source->parent.process_msg = source_process_msg; u->source->userdata = u; pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(pa_pipe_buf(u->fd), &u->source->sample_spec)); u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->fd = u->fd; pollfd->events = pollfd->revents = 0; if (!(u->thread = pa_thread_new("pipe-source", thread_func, u))) { pa_log("Failed to create thread."); goto fail; } pa_source_put(u->source); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
int pa_oss_open(const char *device, int *mode, int* pcaps) { int fd = -1; int caps; char *t; pa_assert(device); pa_assert(mode); pa_assert(*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY); if(!pcaps) pcaps = ∩︀ if (*mode == O_RDWR) { if ((fd = pa_open_cloexec(device, O_RDWR|O_NDELAY, 0)) >= 0) { ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } if (*pcaps & DSP_CAP_DUPLEX) goto success; pa_log_warn("'%s' doesn't support full duplex", device); pa_close(fd); } if ((fd = pa_open_cloexec(device, (*mode = O_WRONLY)|O_NDELAY, 0)) < 0) { if ((fd = pa_open_cloexec(device, (*mode = O_RDONLY)|O_NDELAY, 0)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } } else { if ((fd = pa_open_cloexec(device, *mode|O_NDELAY, 0)) < 0) { pa_log("open('%s'): %s", device, pa_cstrerror(errno)); goto fail; } } *pcaps = 0; if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) { pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno)); goto fail; } success: t = pa_sprintf_malloc( "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", *pcaps & DSP_CAP_BATCH ? " BATCH" : "", #ifdef DSP_CAP_BIND *pcaps & DSP_CAP_BIND ? " BIND" : "", #else "", #endif *pcaps & DSP_CAP_COPROC ? " COPROC" : "", *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "", #ifdef DSP_CAP_FREERATE *pcaps & DSP_CAP_FREERATE ? " FREERATE" : "", #else "", #endif #ifdef DSP_CAP_INPUT *pcaps & DSP_CAP_INPUT ? " INPUT" : "", #else "", #endif *pcaps & DSP_CAP_MMAP ? " MMAP" : "", #ifdef DSP_CAP_MODEM *pcaps & DSP_CAP_MODEM ? " MODEM" : "", #else "", #endif #ifdef DSP_CAP_MULTI *pcaps & DSP_CAP_MULTI ? " MULTI" : "", #else "", #endif #ifdef DSP_CAP_OUTPUT *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "", #else "", #endif *pcaps & DSP_CAP_REALTIME ? " REALTIME" : "", #ifdef DSP_CAP_SHADOW *pcaps & DSP_CAP_SHADOW ? " SHADOW" : "", #else "", #endif #ifdef DSP_CAP_VIRTUAL *pcaps & DSP_CAP_VIRTUAL ? " VIRTUAL" : "", #else "", #endif *pcaps & DSP_CAP_TRIGGER ? " TRIGGER" : ""); pa_log_debug("capabilities:%s", t); pa_xfree(t); return fd; fail: if (fd >= 0) pa_close(fd); return -1; }
int pa_log_set_target(pa_log_target *t) { int fd = -1; int old_fd; pa_assert(t); switch (t->type) { case PA_LOG_STDERR: case PA_LOG_SYSLOG: #ifdef HAVE_JOURNAL case PA_LOG_JOURNAL: #endif case PA_LOG_NULL: break; case PA_LOG_FILE: if ((fd = pa_open_cloexec(t->file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { pa_log(_("Failed to open target file '%s'."), t->file); return -1; } break; case PA_LOG_NEWFILE: { char *file_path; char *p; unsigned version; file_path = pa_sprintf_malloc("%s.xx", t->file); p = file_path + strlen(t->file); for (version = 0; version <= LOG_MAX_SUFFIX_NUMBER; version++) { memset(p, 0, 3); /* Overwrite the ".xx" part in file_path with zero bytes. */ if (version > 0) pa_snprintf(p, 4, ".%u", version); /* Why 4? ".xx" + termitating zero byte. */ if ((fd = pa_open_cloexec(file_path, O_WRONLY | O_TRUNC | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) >= 0) break; } if (version > LOG_MAX_SUFFIX_NUMBER) { pa_log(_("Tried to open target file '%s', '%s.1', '%s.2' ... '%s.%d', but all failed."), t->file, t->file, t->file, t->file, LOG_MAX_SUFFIX_NUMBER); pa_xfree(file_path); return -1; } else pa_log_debug("Opened target file %s\n", file_path); pa_xfree(file_path); break; } } target.type = t->type; pa_xfree(target.file); target.file = pa_xstrdup(t->file); old_fd = log_fd; log_fd = fd; if (old_fd >= 0) pa_close(old_fd); return 0; }
int pa_sound_file_load( pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk, pa_proplist *p) { SNDFILE *sf = NULL; SF_INFO sfi; int ret = -1; size_t l; sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL; void *ptr = NULL; int fd; pa_assert(fname); pa_assert(ss); pa_assert(chunk); pa_memchunk_reset(chunk); if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) { pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); goto finish; } #ifdef HAVE_POSIX_FADVISE if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) { pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno)); goto finish; } else pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded."); #endif pa_zero(sfi); if (!(sf = sf_open_fd(fd, SFM_READ, &sfi, 1))) { pa_log("Failed to open file %s", fname); goto finish; } fd = -1; if (pa_sndfile_read_sample_spec(sf, ss) < 0) { pa_log("Failed to determine file sample format."); goto finish; } if ((map && pa_sndfile_read_channel_map(sf, map) < 0)) { if (ss->channels > 2) pa_log("Failed to determine file channel map, synthesizing one."); pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); } if (p) pa_sndfile_init_proplist(sf, p); if ((l = pa_frame_size(ss) * (size_t) sfi.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log("File too large"); goto finish; } chunk->memblock = pa_memblock_new(pool, l); chunk->index = 0; chunk->length = l; readf_function = pa_sndfile_readf_function(ss); ptr = pa_memblock_acquire(chunk->memblock); if ((readf_function && readf_function(sf, ptr, sfi.frames) != sfi.frames) || (!readf_function && sf_read_raw(sf, ptr, (sf_count_t) l) != (sf_count_t) l)) { pa_log("Premature file end"); goto finish; } ret = 0; finish: if (sf) sf_close(sf); if (ptr) pa_memblock_release(chunk->memblock); if (ret != 0 && chunk->memblock) pa_memblock_unref(chunk->memblock); if (fd >= 0) pa_close(fd); return ret; }
int main(int argc, char *argv[]) { pa_mainloop* m = NULL; int ret = 1, c; char *bn, *server = NULL; pa_time_event *time_event = NULL; const char *filename = NULL; /* type for pa_read/_write. passed as userdata to the callbacks */ unsigned long type = 0; static const struct option long_options[] = { {"record", 0, NULL, 'r'}, {"playback", 0, NULL, 'p'}, {"device", 1, NULL, 'd'}, {"server", 1, NULL, 's'}, {"client-name", 1, NULL, 'n'}, {"stream-name", 1, NULL, ARG_STREAM_NAME}, {"version", 0, NULL, ARG_VERSION}, {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"volume", 1, NULL, ARG_VOLUME}, {"rate", 1, NULL, ARG_SAMPLERATE}, {"format", 1, NULL, ARG_SAMPLEFORMAT}, {"channels", 1, NULL, ARG_CHANNELS}, {"channel-map", 1, NULL, ARG_CHANNELMAP}, {"fix-format", 0, NULL, ARG_FIX_FORMAT}, {"fix-rate", 0, NULL, ARG_FIX_RATE}, {"fix-channels", 0, NULL, ARG_FIX_CHANNELS}, {"no-remap", 0, NULL, ARG_NO_REMAP}, {"no-remix", 0, NULL, ARG_NO_REMIX}, {"latency", 1, NULL, ARG_LATENCY}, {"process-time", 1, NULL, ARG_PROCESS_TIME}, {"property", 1, NULL, ARG_PROPERTY}, {"raw", 0, NULL, ARG_RAW}, {"passthrough", 0, NULL, ARG_PASSTHROUGH}, {"file-format", 2, NULL, ARG_FILE_FORMAT}, {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS}, {"latency-msec", 1, NULL, ARG_LATENCY_MSEC}, {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC}, {"monitor-stream", 1, NULL, ARG_MONITOR_STREAM}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif bn = pa_path_get_filename(argv[0]); if (strstr(bn, "play")) { mode = PLAYBACK; raw = false; } else if (strstr(bn, "record")) { mode = RECORD; raw = false; } else if (strstr(bn, "cat")) { mode = PLAYBACK; raw = true; } else if (strstr(bn, "rec") || strstr(bn, "mon")) { mode = RECORD; raw = true; } proplist = pa_proplist_new(); while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) { switch (c) { case 'h' : help(bn); ret = 0; goto quit; case ARG_VERSION: printf(_("pacat %s\n" "Compiled with libpulse %s\n" "Linked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; case 'r': mode = RECORD; break; case 'p': mode = PLAYBACK; break; case 'd': pa_xfree(device); device = pa_xstrdup(optarg); break; case 's': pa_xfree(server); server = pa_xstrdup(optarg); break; case 'n': { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) { pa_log(_("Invalid client name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } pa_xfree(t); break; } case ARG_STREAM_NAME: { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) { pa_log(_("Invalid stream name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } pa_xfree(t); break; } case 'v': verbose = 1; break; case ARG_VOLUME: { int v = atoi(optarg); volume = v < 0 ? 0U : (pa_volume_t) v; volume_is_set = true; break; } case ARG_CHANNELS: sample_spec.channels = (uint8_t) atoi(optarg); sample_spec_set = true; break; case ARG_SAMPLEFORMAT: sample_spec.format = pa_parse_sample_format(optarg); sample_spec_set = true; break; case ARG_SAMPLERATE: sample_spec.rate = (uint32_t) atoi(optarg); sample_spec_set = true; break; case ARG_CHANNELMAP: if (!pa_channel_map_parse(&channel_map, optarg)) { pa_log(_("Invalid channel map '%s'"), optarg); goto quit; } channel_map_set = true; break; case ARG_FIX_CHANNELS: flags |= PA_STREAM_FIX_CHANNELS; break; case ARG_FIX_RATE: flags |= PA_STREAM_FIX_RATE; break; case ARG_FIX_FORMAT: flags |= PA_STREAM_FIX_FORMAT; break; case ARG_NO_REMIX: flags |= PA_STREAM_NO_REMIX_CHANNELS; break; case ARG_NO_REMAP: flags |= PA_STREAM_NO_REMAP_CHANNELS; break; case ARG_LATENCY: if (((latency = (size_t) atoi(optarg))) <= 0) { pa_log(_("Invalid latency specification '%s'"), optarg); goto quit; } break; case ARG_PROCESS_TIME: if (((process_time = (size_t) atoi(optarg))) <= 0) { pa_log(_("Invalid process time specification '%s'"), optarg); goto quit; } break; case ARG_LATENCY_MSEC: if (((latency_msec = (int32_t) atoi(optarg))) <= 0) { pa_log(_("Invalid latency specification '%s'"), optarg); goto quit; } break; case ARG_PROCESS_TIME_MSEC: if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) { pa_log(_("Invalid process time specification '%s'"), optarg); goto quit; } break; case ARG_PROPERTY: { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_setp(proplist, t) < 0) { pa_xfree(t); pa_log(_("Invalid property '%s'"), optarg); goto quit; } pa_xfree(t); break; } case ARG_RAW: raw = true; break; case ARG_PASSTHROUGH: flags |= PA_STREAM_PASSTHROUGH; break; case ARG_FILE_FORMAT: if (optarg) { if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) { pa_log(_("Unknown file format %s."), optarg); goto quit; } } raw = false; break; case ARG_LIST_FILE_FORMATS: pa_sndfile_dump_formats(); ret = 0; goto quit; case ARG_MONITOR_STREAM: if (pa_atou(optarg, &monitor_stream) < 0) { pa_log(_("Failed to parse the argument for --monitor-stream")); goto quit; } break; default: goto quit; } } if (!pa_sample_spec_valid(&sample_spec)) { pa_log(_("Invalid sample specification")); goto quit; } if (optind+1 == argc) { int fd; filename = argv[optind]; if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { pa_log(_("open(): %s"), strerror(errno)); goto quit; } if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) { pa_log(_("dup2(): %s"), strerror(errno)); goto quit; } pa_close(fd); } else if (optind+1 <= argc) { pa_log(_("Too many arguments.")); goto quit; } if (!raw) { SF_INFO sfi; pa_zero(sfi); if (mode == RECORD) { /* This might patch up the sample spec */ if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) { pa_log(_("Failed to generate sample specification for file.")); goto quit; } if (file_format <= 0) { char *extension; if (filename && (extension = strrchr(filename, '.'))) file_format = pa_sndfile_format_from_string(extension+1); if (file_format <= 0) file_format = SF_FORMAT_WAV; /* Transparently upgrade classic .wav to wavex for multichannel audio */ if (file_format == SF_FORMAT_WAV && (sample_spec.channels > 2 || (channel_map_set && !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) && !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT)))) file_format = SF_FORMAT_WAVEX; } sfi.format |= file_format; } if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO, mode == RECORD ? SFM_WRITE : SFM_READ, &sfi, 0))) { pa_log(_("Failed to open audio file.")); goto quit; } if (mode == PLAYBACK) { if (sample_spec_set) pa_log(_("Warning: specified sample specification will be overwritten with specification from file.")); if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) { pa_log(_("Failed to determine sample specification from file.")); goto quit; } sample_spec_set = true; if (!channel_map_set) { /* Allow the user to overwrite the channel map on the command line */ if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) { if (sample_spec.channels > 2) pa_log(_("Warning: Failed to determine channel map from file.")); } else channel_map_set = true; } } } if (!channel_map_set) pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); if (!pa_channel_map_compatible(&channel_map, &sample_spec)) { pa_log(_("Channel map doesn't match sample specification")); goto quit; } if (!raw) { pa_proplist *sfp; if (mode == PLAYBACK) readf_function = pa_sndfile_readf_function(&sample_spec); else { if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0) pa_log(_("Warning: failed to write channel map to file.")); writef_function = pa_sndfile_writef_function(&sample_spec); } /* Fill in libsndfile prop list data */ sfp = pa_proplist_new(); pa_sndfile_init_proplist(sndfile, sfp); pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp); pa_proplist_free(sfp); } if (verbose) { char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."), mode == RECORD ? _("recording") : _("playback"), pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec), pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map)); } /* Fill in client name if none was set */ if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) { char *t; if ((t = pa_locale_to_utf8(bn))) { pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t); pa_xfree(t); } } /* Fill in media name if none was set */ if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) { const char *t; if ((t = filename) || (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME))) pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t); if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) { pa_log(_("Failed to set media name.")); goto quit; } } /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { pa_log(_("pa_mainloop_new() failed.")); goto quit; } mainloop_api = pa_mainloop_get_api(m); pa_assert_se(pa_signal_init(mainloop_api) == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); pa_signal_new(SIGTERM, exit_signal_callback, NULL); #ifdef SIGUSR1 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); #endif pa_disable_sigpipe(); if (raw) { #ifdef OS_IS_WIN32 /* need to turn on binary mode for stdio io. Windows, meh */ setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY); #endif if (!(stdio_event = mainloop_api->io_new(mainloop_api, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, mode == PLAYBACK ? stdin_callback : stdout_callback, &type))) { pa_log(_("io_new() failed.")); goto quit; } } /* Create a new connection context */ if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) { pa_log(_("pa_context_new() failed.")); goto quit; } pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ if (pa_context_connect(context, server, 0, NULL) < 0) { pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); goto quit; } if (verbose) { if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) { pa_log(_("pa_context_rttime_new() failed.")); goto quit; } } /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { pa_log(_("pa_mainloop_run() failed.")); goto quit; } quit: if (stream) pa_stream_unref(stream); if (context) pa_context_unref(context); if (stdio_event) { pa_assert(mainloop_api); mainloop_api->io_free(stdio_event); } if (time_event) { pa_assert(mainloop_api); mainloop_api->time_free(time_event); } if (m) { pa_signal_done(); pa_mainloop_free(m); } pa_xfree(silence_buffer); pa_xfree(buffer); pa_xfree(server); pa_xfree(device); if (sndfile) sf_close(sndfile); if (proplist) pa_proplist_free(proplist); return ret; }
int pa__init(pa_module*m) { pa_iochannel *io; pa_modargs *ma; bool exit_on_eof = false; #ifndef OS_IS_WIN32 int fd; #endif pa_assert(m); if (m->core->running_as_daemon) { pa_log_info("Running as daemon, refusing to load this module."); return 0; } if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "exit_on_eof", &exit_on_eof) < 0) { pa_log("exit_on_eof= expects boolean argument."); goto fail; } if (pa_stdio_acquire() < 0) { pa_log("STDIN/STDOUT already in use."); goto fail; } /* We try to open the controlling tty anew here. This has the * benefit of giving us a new fd that doesn't share the O_NDELAY * flag with fds 0, 1, or 2. Since pa_iochannel_xxx needs O_NDELAY * on its fd using those fds directly could set O_NDELAY which * fprintf() doesn't really like, resulting in truncated output * of log messages, particularly because if stdout and stderr are * dup'ed they share the same O_NDELAY, too. */ #ifndef OS_IS_WIN32 if ((fd = pa_open_cloexec("/dev/tty", O_RDWR|O_NONBLOCK, 0)) >= 0) { io = pa_iochannel_new(m->core->mainloop, fd, fd); pa_log_debug("Managed to open /dev/tty."); } else #endif { io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO); pa_iochannel_set_noclose(io, true); pa_log_debug("Failed to open /dev/tty, using stdin/stdout fds instead."); } m->userdata = pa_cli_new(m->core, io, m); pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); return -1; }
int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; int version; struct input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; pa_volume_t volume_limit = PA_VOLUME_NORM*3/2; pa_volume_t volume_step = PA_VOLUME_NORM/20; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } if (pa_modargs_get_value_u32(ma, "volume_limit", &volume_limit) < 0) { pa_log("Failed to parse volume limit"); goto fail; } if (pa_modargs_get_value_u32(ma, "volume_step", &volume_step) < 0) { pa_log("Failed to parse volume step"); goto fail; } m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; u->fd_type = 0; u->volume_limit = PA_CLAMP_VOLUME(volume_limit); u->volume_step = PA_CLAMP_VOLUME(volume_step); if ((u->fd = pa_open_cloexec(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY, 0)) < 0) { pa_log("Failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { pa_log("EVIOCGVERSION failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); if (ioctl(u->fd, EVIOCGID, &input_id)) { pa_log("EVIOCGID failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", input_id.vendor, input_id.product, input_id.version, input_id.bustype); memset(name, 0, sizeof(name)); if (ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev device name: %s", name); memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { pa_log("EVIOCGBIT failed: %s", pa_cstrerror(errno)); goto fail; } if (!test_bit(EV_KEY, evtype_bitmask)) { pa_log("Device has no keys."); goto fail; } u->io = m->core->mainloop->io_new(m->core->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
int pa_play_file( pa_sink *sink, const char *fname, const pa_cvolume *volume) { file_stream *u = NULL; pa_sample_spec ss; pa_channel_map cm; pa_sink_input_new_data data; int fd; SF_INFO sfi; pa_memchunk silence; pa_assert(sink); pa_assert(fname); u = pa_msgobject_new(file_stream); u->parent.parent.free = file_stream_free; u->parent.process_msg = file_stream_process_msg; u->core = sink->core; u->sink_input = NULL; u->sndfile = NULL; u->readf_function = NULL; u->memblockq = NULL; if ((fd = pa_open_cloexec(fname, O_RDONLY, 0)) < 0) { pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno)); goto fail; } /* FIXME: For now we just use posix_fadvise to avoid page faults * when accessing the file data. Eventually we should move the * file reader into the main event loop and pass the data over the * asyncmsgq. */ #ifdef HAVE_POSIX_FADVISE if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) { pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno)); goto fail; } else pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded."); if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) { pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno)); goto fail; } else pa_log_debug("POSIX_FADV_WILLNEED succeeded."); #endif pa_zero(sfi); if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfi, 1))) { pa_log("Failed to open file %s", fname); goto fail; } fd = -1; if (pa_sndfile_read_sample_spec(u->sndfile, &ss) < 0) { pa_log("Failed to determine file sample format."); goto fail; } if (pa_sndfile_read_channel_map(u->sndfile, &cm) < 0) { if (ss.channels > 2) pa_log_info("Failed to determine file channel map, synthesizing one."); pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT); } u->readf_function = pa_sndfile_readf_function(&ss); pa_sink_input_new_data_init(&data); pa_sink_input_new_data_set_sink(&data, sink, FALSE); data.driver = __FILE__; pa_sink_input_new_data_set_sample_spec(&data, &ss); pa_sink_input_new_data_set_channel_map(&data, &cm); pa_sink_input_new_data_set_volume(&data, volume); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, pa_path_get_filename(fname)); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_FILENAME, fname); pa_sndfile_init_proplist(u->sndfile, data.proplist); pa_sink_input_new(&u->sink_input, sink->core, &data); pa_sink_input_new_data_done(&data); if (!u->sink_input) goto fail; u->sink_input->pop = sink_input_pop_cb; u->sink_input->process_rewind = sink_input_process_rewind_cb; u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->userdata = u; pa_sink_input_get_silence(u->sink_input, &silence); u->memblockq = pa_memblockq_new("sound-file-stream memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &silence); pa_memblock_unref(silence.memblock); pa_sink_input_put(u->sink_input); /* The reference to u is dangling here, because we want to keep * this stream around until it is fully played. */ return 0; fail: file_stream_unref(u); if (fd >= 0) pa_close(fd); return -1; }