static char* get_backtrace(unsigned show_nframes) { void* trace[32]; int n_frames; char **symbols, *e, *r; unsigned j, n, s; size_t a; pa_assert(show_nframes > 0); n_frames = backtrace(trace, PA_ELEMENTSOF(trace)); if (n_frames <= 0) return NULL; symbols = backtrace_symbols(trace, n_frames); if (!symbols) return NULL; s = skip_backtrace; n = PA_MIN((unsigned) n_frames, s + show_nframes); a = 4; for (j = s; j < n; j++) { if (j > s) a += 2; a += strlen(pa_path_get_filename(symbols[j])); } r = pa_xnew(char, a); strcpy(r, " ("); e = r + 2; for (j = s; j < n; j++) { const char *sym; if (j > s) { strcpy(e, "<<"); e += 2; } sym = pa_path_get_filename(symbols[j]); strcpy(e, sym); e += strlen(sym); } strcpy(e, ")"); free(symbols); return r; }
void pa_cmdline_help(const char *argv0) { pa_assert(argv0); printf(_("%s [options]\n\n" "COMMANDS:\n" " -h, --help Show this help\n" " --version Show version\n" " --dump-conf Dump default configuration\n" " --dump-modules Dump list of available modules\n" " --dump-resample-methods Dump available resample methods\n" " --cleanup-shm Cleanup stale shared memory segments\n" " --start Start the daemon if it is not running\n" " -k --kill Kill a running daemon\n" " --check Check for a running daemon (only returns exit code)\n\n" "OPTIONS:\n" " --system[=BOOL] Run as system-wide instance\n" " -D, --daemonize[=BOOL] Daemonize after startup\n" " --fail[=BOOL] Quit when startup fails\n" " --high-priority[=BOOL] Try to set high nice level\n" " (only available as root, when SUID or\n" " with elevated RLIMIT_NICE)\n" " --realtime[=BOOL] Try to enable realtime scheduling\n" " (only available as root, when SUID or\n" " with elevated RLIMIT_RTPRIO)\n" " --disallow-module-loading[=BOOL] Disallow module user requested module\n" " loading/unloading after startup\n" " --disallow-exit[=BOOL] Disallow user requested exit\n" " --exit-idle-time=SECS Terminate the daemon when idle and this\n" " time passed\n" " --scache-idle-time=SECS Unload autoloaded samples when idle and\n" " this time passed\n" " --log-level[=LEVEL] Increase or set verbosity level\n" " -v --verbose Increase the verbosity level\n" " --log-target={auto,syslog,stderr,file:PATH,newfile:PATH}\n" " Specify the log target\n" " --log-meta[=BOOL] Include code location in log messages\n" " --log-time[=BOOL] Include timestamps in log messages\n" " --log-backtrace=FRAMES Include a backtrace in log messages\n" " -p, --dl-search-path=PATH Set the search path for dynamic shared\n" " objects (plugins)\n" " --resample-method=METHOD Use the specified resampling method\n" " (See --dump-resample-methods for\n" " possible values)\n" " --use-pid-file[=BOOL] Create a PID file\n" " --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n" " platforms that support it.\n" " --disable-shm[=BOOL] Disable shared memory support.\n" " --enable-memfd[=BOOL] Enable memfd shared memory support.\n\n" "STARTUP SCRIPT:\n" " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n" " the specified argument\n" " -F, --file=FILENAME Run the specified script\n" " -C Open a command line on the running TTY\n" " after startup\n\n" " -n Don't load default script file\n"), pa_path_get_filename(argv0)); }
pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) { pa_client *c; pa_core_assert_ref(core); pa_assert(data); if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0) return NULL; c = pa_xnew(pa_client, 1); c->core = core; c->proplist = pa_proplist_copy(data->proplist); c->driver = pa_xstrdup(pa_path_get_filename(data->driver)); c->module = data->module; c->sink_inputs = pa_idxset_new(NULL, NULL); c->source_outputs = pa_idxset_new(NULL, NULL); c->userdata = NULL; c->kill = NULL; c->send_event = NULL; pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0); pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME))); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index); pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_PUT], c); pa_core_check_idle(core); return c; }
/* Return a newly allocated sting containing the parent directory of the specified file */ char *pa_parent_dir(const char *fn) { char *slash, *dir = pa_xstrdup(fn); if ((slash = (char*) pa_path_get_filename(dir)) == dir) { pa_xfree(dir); return NULL; } *(slash-1) = 0; return dir; }
static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) { const char *name = "OpenAL Soft"; char path_name[PATH_MAX]; pa_context_state_t state; pa_context *context; int err; if(pa_get_binary_name(path_name, sizeof(path_name))) name = pa_path_get_filename(path_name); context = pa_context_new(pa_threaded_mainloop_get_api(loop), name); if(!context) { ERR("pa_context_new() failed\n"); return NULL; } pa_context_set_state_callback(context, context_state_callback, loop); if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0) { while((state=pa_context_get_state(context)) != PA_CONTEXT_READY) { if(!PA_CONTEXT_IS_GOOD(state)) { err = pa_context_errno(context); if(err > 0) err = -err; break; } pa_threaded_mainloop_wait(loop); } } pa_context_set_state_callback(context, NULL, NULL); if(err < 0) { if(!silent) ERR("Context did not connect: %s\n", pa_strerror(err)); pa_context_unref(context); return NULL; } return context; }
static void add_file(pa_core *c, const char *pathname) { struct stat st; const char *e; pa_core_assert_ref(c); pa_assert(pathname); e = pa_path_get_filename(pathname); if (stat(pathname, &st) < 0) { pa_log("stat('%s'): %s", pathname, pa_cstrerror(errno)); return; } #if defined(S_ISREG) && defined(S_ISLNK) if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) #endif pa_scache_add_file_lazy(c, e, pathname, NULL); }
int ao_plugin_open(ao_device *device, ao_sample_format *format) { char *p=NULL, t[256], t2[256]; const char *fn = NULL; ao_pulse_internal *internal; struct pa_sample_spec ss; struct pa_channel_map map; struct pa_buffer_attr battr; size_t allocated = 128; assert(device && device->internal && format); internal = (ao_pulse_internal *) device->internal; if (format->bits == 8) ss.format = PA_SAMPLE_U8; else if (format->bits == 16) ss.format = PA_SAMPLE_S16NE; #ifdef PA_SAMPLE_S24NE else if (format->bits == 24) ss.format = PA_SAMPLE_S24NE; #endif else return 0; if (device->output_channels <= 0 || device->output_channels > PA_CHANNELS_MAX) return 0; ss.channels = device->output_channels; ss.rate = format->rate; disable_sigpipe(); if (internal->client_name) { snprintf(t, sizeof(t), "libao[%s]", internal->client_name); snprintf(t2, sizeof(t2), "libao[%s] playback stream", internal->client_name); } else { while (1) { p = pa_xmalloc(allocated); if (!(fn = pa_get_binary_name(p, allocated))) { break; } if (fn != p || strlen(p) < allocated - 1) { fn = pa_path_get_filename(fn); snprintf(t, sizeof(t), "libao[%s]", fn); snprintf(t2, sizeof(t2), "libao[%s] playback stream", fn); break; } pa_xfree(p); allocated *= 2; } pa_xfree(p); p = NULL; if (!fn) { strcpy(t, "libao"); strcpy(t2, "libao playback stream"); } } if(device->input_map){ int i; pa_channel_map_init(&map); map.channels=device->output_channels; for(i=0;i<device->output_channels;i++){ if(device->input_map[i]==-1){ map.map[i] = PA_CHANNEL_POSITION_INVALID; }else{ map.map[i] = device->input_map[i]; } } } /* buffering attributes */ battr.prebuf = battr.minreq = battr.fragsize = -1; battr.tlength = (int)(internal->buffer_time * format->rate) / 1000000 * ((format->bits+7)/8) + device->output_channels; battr.minreq = battr.tlength/4; battr.maxlength = battr.tlength+battr.minreq; internal->simple = pa_simple_new(internal->server, t, PA_STREAM_PLAYBACK, internal->sink, t2, &ss, (device->input_map ? &map : NULL), &battr, NULL); if (!internal->simple) return 0; device->driver_byte_format = AO_FMT_NATIVE; internal->static_delay = pa_simple_get_latency(internal->simple, NULL); if(internal->static_delay<0) internal->static_delay = 0; return 1; }
char *pa_get_home_dir(char *s, size_t l) { char *e; #ifdef HAVE_PWD_H char buf[1024]; struct passwd pw, *r; #endif pa_assert(s); pa_assert(l > 0); if ((e = getenv("HOME"))) return pa_strlcpy(s, e, l); if ((e = getenv("USERPROFILE"))) return pa_strlcpy(s, e, l); #ifdef HAVE_PWD_H #ifdef HAVE_GETPWUID_R if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { pa_log("getpwuid_r() failed"); #else /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) * that do not support getpwuid_r. */ if ((r = getpwuid(getuid())) == NULL) { pa_log("getpwuid_r() failed"); #endif return NULL; } return pa_strlcpy(s, r->pw_dir, l); #else /* HAVE_PWD_H */ return NULL; #endif } char *pa_get_binary_name(char *s, size_t l) { pa_assert(s); pa_assert(l > 0); #if defined(OS_IS_WIN32) { char path[PATH_MAX]; if (GetModuleFileName(NULL, path, PATH_MAX)) return pa_strlcpy(s, pa_path_get_filename(path), l); } #endif #ifdef __linux__ { char *rp; /* This works on Linux only */ if ((rp = pa_readlink("/proc/self/exe"))) { pa_strlcpy(s, pa_path_get_filename(rp), l); pa_xfree(rp); return s; } } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) { #ifndef TASK_COMM_LEN /* Actually defined in linux/sched.h */ #define TASK_COMM_LEN 16 #endif char tcomm[TASK_COMM_LEN+1]; memset(tcomm, 0, sizeof(tcomm)); /* This works on Linux only */ if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0) return pa_strlcpy(s, tcomm, l); } #endif return NULL; }
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; 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}, {"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}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); 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; } 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_FILE_FORMAT: raw = FALSE; 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; 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 = open(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; } /* Transparently upgrade classic .wav to wavex for multichannel audio */ if (file_format <= 0) { if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) || (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO)))) file_format = SF_FORMAT_WAV; else 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); } /* 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) { 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, NULL))) { 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(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) { struct userdata *u = NULL; bool record = true, playback = true; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; uint32_t buffer_length_msec; int fd = -1; pa_sink_new_data sink_new_data; pa_source_new_data source_new_data; char const *name; char *name_buf; bool namereg_fail; 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_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect a boolean argument."); goto fail; } if (!playback && !record) { pa_log("neither playback nor record enabled for device."); goto fail; } u = pa_xnew0(struct userdata, 1); if (!(u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC * 2, true, true, 10, pa_rtclock_now(), true))) goto fail; /* * For a process (or several processes) to use the same audio device for both * record and playback at the same time, the device's mixer must be enabled. * See mixerctl(1). It may be turned off for playback only or record only. */ u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("failed to parse sample specification"); goto fail; } u->frame_size = pa_frame_size(&ss); u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss); buffer_length_msec = 100; if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) { pa_log("failed to parse buffer_length argument"); goto fail; } u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss); if (u->buffer_size < 2 * u->minimum_request) { pa_log("buffer_length argument cannot be smaller than %u", (unsigned)(pa_bytes_to_usec(2 * u->minimum_request, &ss) / 1000)); goto fail; } if (u->buffer_size > MAX_BUFFER_SIZE) { pa_log("buffer_length argument cannot be greater than %u", (unsigned)(pa_bytes_to_usec(MAX_BUFFER_SIZE, &ss) / 1000)); goto fail; } u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE)); if ((fd = open_audio_device(u, &ss)) < 0) goto fail; u->core = m->core; u->module = m; m->userdata = u; pa_memchunk_reset(&u->memchunk); u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); u->rtpoll_item = NULL; build_pollfd(u); if (u->mode != O_WRONLY) { name_buf = NULL; namereg_fail = true; if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) { name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name)); namereg_fail = false; } pa_source_new_data_init(&source_new_data); source_new_data.driver = __FILE__; source_new_data.module = m; pa_source_new_data_set_name(&source_new_data, name); source_new_data.namereg_fail = namereg_fail; pa_source_new_data_set_sample_spec(&source_new_data, &ss); pa_source_new_data_set_channel_map(&source_new_data, &map); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris"); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source"); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial"); pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size); if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_source_new_data_done(&source_new_data); goto fail; } u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); pa_source_new_data_done(&source_new_data); pa_xfree(name_buf); if (!u->source) { pa_log("Failed to create source object"); goto fail; } u->source->userdata = u; u->source->parent.process_msg = source_process_msg; 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(u->buffer_size, &u->source->sample_spec)); pa_source_set_get_volume_callback(u->source, source_get_volume); pa_source_set_set_volume_callback(u->source, source_set_volume); u->source->refresh_volume = true; } else u->source = NULL; if (u->mode != O_RDONLY) { name_buf = NULL; namereg_fail = true; if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) { name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name)); namereg_fail = false; } pa_sink_new_data_init(&sink_new_data); sink_new_data.driver = __FILE__; sink_new_data.module = m; pa_sink_new_data_set_name(&sink_new_data, name); sink_new_data.namereg_fail = namereg_fail; pa_sink_new_data_set_sample_spec(&sink_new_data, &ss); pa_sink_new_data_set_channel_map(&sink_new_data, &map); pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name); pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris"); pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink"); pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial"); if (pa_modargs_get_proplist(ma, "sink_properties", sink_new_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_sink_new_data_done(&sink_new_data); goto fail; } u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY); pa_sink_new_data_done(&sink_new_data); pa_assert(u->sink); u->sink->userdata = u; u->sink->parent.process_msg = sink_process_msg; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec)); pa_sink_set_max_request(u->sink, u->buffer_size); pa_sink_set_max_rewind(u->sink, u->buffer_size); pa_sink_set_get_volume_callback(u->sink, sink_get_volume); pa_sink_set_set_volume_callback(u->sink, sink_set_volume); pa_sink_set_get_mute_callback(u->sink, sink_get_mute); pa_sink_set_set_mute_callback(u->sink, sink_set_mute); u->sink->refresh_volume = u->sink->refresh_muted = true; } else u->sink = NULL; pa_assert(u->source || u->sink); u->sig = pa_signal_new(SIGPOLL, sig_callback, u); if (u->sig) ioctl(u->fd, I_SETSIG, S_MSG); else pa_log_warn("Could not register SIGPOLL handler"); if (!(u->thread = pa_thread_new("solaris", thread_func, u))) { pa_log("Failed to create thread."); goto fail; } /* Read mixer settings */ if (u->sink) { if (sink_new_data.volume_is_set) u->sink->set_volume(u->sink); else u->sink->get_volume(u->sink); if (sink_new_data.muted_is_set) u->sink->set_mute(u->sink); else u->sink->get_mute(u->sink); pa_sink_put(u->sink); } if (u->source) { if (source_new_data.volume_is_set) u->source->set_volume(u->source); else u->source->get_volume(u->source); pa_source_put(u->source); } pa_modargs_free(ma); return 0; fail: if (u) pa__done(m); else if (fd >= 0) close(fd); if (ma) pa_modargs_free(ma); return -1; }
int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; int c, ret = 1, screen = 0; xcb_connection_t *xcb = NULL; enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { switch (c) { case 'D' : dname = optarg; break; case 'h': printf(_("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" " -d Show current PulseAudio data attached to X11 display (default)\n" " -e Export local PulseAudio data to X11 display\n" " -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n" " -r Remove PulseAudio data from X11 display\n"), pa_path_get_filename(argv[0])); ret = 0; goto finish; case 'd': mode = DUMP; break; case 'e': mode = EXPORT; break; case 'i': mode = IMPORT; break; case 'r': mode = REMOVE; break; case 'c': cookie_file = optarg; break; case 'I': source = optarg; break; case 'O': sink = optarg; break; case 'S': server = optarg; break; default: fprintf(stderr, _("Failed to parse command line.\n")); goto finish; } } if (!(xcb = xcb_connect(dname, &screen))) { pa_log(_("xcb_connect() failed")); goto finish; } if (xcb_connection_has_error(xcb)) { pa_log(_("xcb_connection_has_error() returned true")); goto finish; } switch (mode) { case DUMP: { char t[1024]; if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t))) printf(_("Server: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t))) printf(_("Source: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t))) printf(_("Sink: %s\n"), t); if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t))) printf(_("Cookie: %s\n"), t); break; } case IMPORT: { char t[1024]; if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t))) printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t))) printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t))) printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t); if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { fprintf(stderr, _("Failed to parse cookie data\n")); goto finish; } if (pa_authkey_save(cookie_file, cookie, l) < 0) { fprintf(stderr, _("Failed to save cookie data\n")); goto finish; } } break; } case EXPORT: { pa_client_conf *conf = pa_client_conf_new(); uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; assert(conf); pa_client_conf_load(conf, false, true); pa_x11_del_prop(xcb, screen, "PULSE_SERVER"); pa_x11_del_prop(xcb, screen, "PULSE_SINK"); pa_x11_del_prop(xcb, screen, "PULSE_SOURCE"); pa_x11_del_prop(xcb, screen, "PULSE_ID"); pa_x11_del_prop(xcb, screen, "PULSE_COOKIE"); if (server) pa_x11_set_prop(xcb, screen, "PULSE_SERVER", server); else if (conf->default_server) pa_x11_set_prop(xcb, screen, "PULSE_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { fprintf(stderr, _("Failed to get FQDN.\n")); goto finish; } pa_x11_set_prop(xcb, screen, "PULSE_SERVER", hn); } if (sink) pa_x11_set_prop(xcb, screen, "PULSE_SINK", sink); else if (conf->default_sink) pa_x11_set_prop(xcb, screen, "PULSE_SINK", conf->default_sink); if (source) pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", source); if (conf->default_source) pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); if (pa_authkey_load(cookie_file, true, cookie, sizeof(cookie)) < 0) { fprintf(stderr, _("Failed to load cookie data\n")); goto finish; } pa_x11_set_prop(xcb, screen, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: pa_x11_del_prop(xcb, screen, "PULSE_SERVER"); pa_x11_del_prop(xcb, screen, "PULSE_SINK"); pa_x11_del_prop(xcb, screen, "PULSE_SOURCE"); pa_x11_del_prop(xcb, screen, "PULSE_ID"); pa_x11_del_prop(xcb, screen, "PULSE_COOKIE"); pa_x11_del_prop(xcb, screen, "PULSE_SESSION_ID"); break; default: fprintf(stderr, _("Not yet implemented.\n")); goto finish; } ret = 0; finish: if (xcb) { xcb_flush(xcb); xcb_disconnect(xcb); } return ret; }
void pa_log_levelv_meta( pa_log_level_t level, const char*file, int line, const char *func, const char *format, va_list ap) { char *t, *n; int saved_errno = errno; char *bt = NULL; pa_log_target_t _target; pa_log_level_t _maximum_level; unsigned _show_backtrace; pa_log_flags_t _flags; /* We don't use dynamic memory allocation here to minimize the hit * in RT threads */ char text[16*1024], location[128], timestamp[32]; pa_assert(level < PA_LOG_LEVEL_MAX); pa_assert(format); PA_ONCE_BEGIN { init_defaults(); } PA_ONCE_END; _target = target_override_set ? target_override : target; _maximum_level = PA_MAX(maximum_level, maximum_level_override); _show_backtrace = PA_MAX(show_backtrace, show_backtrace_override); _flags = flags | flags_override; if (PA_LIKELY(level > _maximum_level)) { errno = saved_errno; return; } pa_vsnprintf(text, sizeof(text), format, ap); if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func) pa_snprintf(location, sizeof(location), "[%s:%i %s()] ", file, line, func); else if ((_flags & (PA_LOG_PRINT_META|PA_LOG_PRINT_FILE)) && file) pa_snprintf(location, sizeof(location), "%s: ", pa_path_get_filename(file)); else location[0] = 0; if (_flags & PA_LOG_PRINT_TIME) { static pa_usec_t start, last; pa_usec_t u, a, r; u = pa_rtclock_now(); PA_ONCE_BEGIN { start = u; last = u; } PA_ONCE_END; r = u - last; a = u - start; /* This is not thread safe, but this is a debugging tool only * anyway. */ last = u; pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ", (unsigned long long) (a / PA_USEC_PER_SEC), (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000), (unsigned long long) (r / PA_USEC_PER_SEC), (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000)); } else
void pa_log_levelv_meta( pa_log_level_t level, const char*file, int line, const char *func, const char *format, va_list ap) { const char *e; char *text, *t, *n, *location; pa_assert(level < PA_LOG_LEVEL_MAX); pa_assert(format); if ((e = getenv(ENV_LOGLEVEL))) maximal_level = atoi(e); if (level > maximal_level) return; text = pa_vsprintf_malloc(format, ap); if (getenv(ENV_LOGMETA) && file && line > 0 && func) location = pa_sprintf_malloc("[%s:%i %s()] ", file, line, func); else if (file) location = pa_sprintf_malloc("%s: ", pa_path_get_filename(file)); else location = pa_xstrdup(""); if (!pa_utf8_valid(text)) pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); for (t = text; t; t = n) { if ((n = strchr(t, '\n'))) { *n = 0; n++; } if (!*t) continue; switch (log_target) { case PA_LOG_STDERR: { const char *prefix = "", *suffix = ""; char *local_t; #ifndef OS_IS_WIN32 /* Yes indeed. Useless, but fun! */ if (isatty(STDERR_FILENO)) { if (level <= PA_LOG_ERROR) { prefix = "\x1B[1;31m"; suffix = "\x1B[0m"; } else if (level <= PA_LOG_WARN) { prefix = "\x1B[1m"; suffix = "\x1B[0m"; } } #endif local_t = pa_utf8_to_locale(t); if (!local_t) fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, t, suffix); else { fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, local_t, suffix); pa_xfree(local_t); } break; } #ifdef HAVE_SYSLOG_H case PA_LOG_SYSLOG: { char *local_t; openlog(log_ident_local ? log_ident_local : "???", LOG_PID, LOG_USER); local_t = pa_utf8_to_locale(t); if (!local_t) syslog(level_to_syslog[level], "%s%s", location, t); else { syslog(level_to_syslog[level], "%s%s", location, local_t); pa_xfree(local_t); } closelog(); break; } #endif case PA_LOG_USER: { char *x; x = pa_sprintf_malloc("%s%s", location, t); user_log_func(level, x); pa_xfree(x); break; } case PA_LOG_NULL: default: break; } } pa_xfree(text); pa_xfree(location); }
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; }
/* Called from main context */ int pa_source_output_new( pa_source_output**_o, pa_core *core, pa_source_output_new_data *data) { pa_source_output *o; pa_resampler *resampler = NULL; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; int r; char *pt; pa_assert(_o); pa_assert(core); pa_assert(data); pa_assert_ctl_context(); if (data->client) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist); if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data)) < 0) return r; pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID); if (!data->source) { data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE); data->save_source = FALSE; } pa_return_val_if_fail(data->source, -PA_ERR_NOENTITY); pa_return_val_if_fail(PA_SOURCE_IS_LINKED(pa_source_get_state(data->source)), -PA_ERR_BADSTATE); pa_return_val_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of, -PA_ERR_INVALID); if (!data->sample_spec_is_set) data->sample_spec = data->source->sample_spec; pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID); if (!data->channel_map_is_set) { if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec)) data->channel_map = data->source->channel_map; else pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID); pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID); if (data->flags & PA_SOURCE_OUTPUT_FIX_FORMAT) data->sample_spec.format = data->source->sample_spec.format; if (data->flags & PA_SOURCE_OUTPUT_FIX_RATE) data->sample_spec.rate = data->source->sample_spec.rate; if (data->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) { data->sample_spec.channels = data->source->sample_spec.channels; data->channel_map = data->source->channel_map; } pa_assert(pa_sample_spec_valid(&data->sample_spec)); pa_assert(pa_channel_map_valid(&data->channel_map)); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID); if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0) return r; if ((data->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) && pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) { pa_log("Failed to create source output: source is suspended."); return -PA_ERR_BADSTATE; } if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log("Failed to create source output: too many outputs per source."); return -PA_ERR_TOOLARGE; } if ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) || !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) { if (!(resampler = pa_resampler_new( core->mempool, &data->source->sample_spec, &data->source->channel_map, &data->sample_spec, &data->channel_map, data->resample_method, ((data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((data->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | (core->disable_remixing || (data->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return -PA_ERR_NOTSUPPORTED; } } o = pa_msgobject_new(pa_source_output); o->parent.parent.free = source_output_free; o->parent.process_msg = pa_source_output_process_msg; o->core = core; o->state = PA_SOURCE_OUTPUT_INIT; o->flags = data->flags; o->proplist = pa_proplist_copy(data->proplist); o->driver = pa_xstrdup(pa_path_get_filename(data->driver)); o->module = data->module; o->source = data->source; o->destination_source = data->destination_source; o->client = data->client; o->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID; o->requested_resample_method = data->resample_method; o->sample_spec = data->sample_spec; o->channel_map = data->channel_map; o->direct_on_input = data->direct_on_input; o->save_source = data->save_source; reset_callbacks(o); o->userdata = NULL; o->thread_info.state = o->state; o->thread_info.attached = FALSE; o->thread_info.sample_spec = o->sample_spec; o->thread_info.resampler = resampler; o->thread_info.requested_source_latency = (pa_usec_t) -1; o->thread_info.direct_on_input = o->direct_on_input; o->thread_info.delay_memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&o->source->sample_spec), 0, 1, 0, &o->source->silence); pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0); pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0); if (o->client) pa_assert_se(pa_idxset_put(o->client->source_outputs, o, NULL) >= 0); if (o->direct_on_input) pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0); pt = pa_proplist_to_string_sep(o->proplist, "\n "); pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s\n %s", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)), o->source->name, pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), pt); pa_xfree(pt); /* Don't forget to call pa_source_output_put! */ *_o = o; return 0; }
char *pa_get_binary_name(char *s, size_t l) { pa_assert(s); pa_assert(l > 0); #if defined(OS_IS_WIN32) { char path[PATH_MAX]; if (GetModuleFileName(NULL, path, PATH_MAX)) return pa_strlcpy(s, pa_path_get_filename(path), l); } #endif #ifdef __linux__ { char *rp; /* This works on Linux only */ if ((rp = pa_readlink("/proc/self/exe"))) { pa_strlcpy(s, pa_path_get_filename(rp), l); pa_xfree(rp); return s; } } #endif #ifdef __FreeBSD__ { char *rp; if ((rp = pa_readlink("/proc/curproc/file"))) { pa_strlcpy(s, pa_path_get_filename(rp), l); pa_xfree(rp); return s; } } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME) { #ifndef TASK_COMM_LEN /* Actually defined in linux/sched.h */ #define TASK_COMM_LEN 16 #endif char tcomm[TASK_COMM_LEN+1]; memset(tcomm, 0, sizeof(tcomm)); /* This works on Linux only */ if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0) return pa_strlcpy(s, tcomm, l); } #endif #ifdef OS_IS_DARWIN { int mib[] = { CTL_KERN, KERN_PROCARGS, getpid(), 0 }; size_t len, nmib = (sizeof(mib) / sizeof(mib[0])) - 1; char *buf; sysctl(mib, nmib, NULL, &len, NULL, 0); buf = (char *) pa_xmalloc(len); if (sysctl(mib, nmib, buf, &len, NULL, 0) == 0) { pa_strlcpy(s, basename(buf), l); pa_xfree(buf); return s; } pa_xfree(buf); /* fall thru */ } #endif /* OS_IS_DARWIN */ errno = ENOENT; return NULL; }
int main(int argc, char *argv[]) { const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE; int c, ret = 1; Display *d = NULL; enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP; while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) { switch (c) { case 'D' : dname = optarg; break; case 'h': printf("%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n\n" " -d Show current PulseAudio data attached to X11 display (default)\n" " -e Export local PulseAudio data to X11 display\n" " -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n" " -r Remove PulseAudio data from X11 display\n", pa_path_get_filename(argv[0])); ret = 0; goto finish; case 'd': mode = DUMP; break; case 'e': mode = EXPORT; break; case 'i': mode = IMPORT; break; case 'r': mode = REMOVE; break; case 'c': cookie_file = optarg; break; case 'I': source = optarg; break; case 'O': sink = optarg; break; case 'S': server = optarg; break; default: fprintf(stderr, "Failed to parse command line.\n"); goto finish; } } if (!(d = XOpenDisplay(dname))) { pa_log("XOpenDisplay() failed"); goto finish; } switch (mode) { case DUMP: { char t[1024]; if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("Server: %s\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("Source: %s\n", t); if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) printf("Sink: %s\n", t); if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) printf("Cookie: %s\n", t); break; } case IMPORT: { char t[1024]; if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t); if (pa_x11_get_prop(d, "PULSE_SOURCE", t, sizeof(t))) printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t); if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t); if (pa_x11_get_prop(d, "PULSE_COOKIE", t, sizeof(t))) { uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; size_t l; if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) { fprintf(stderr, "Failed to parse cookie data\n"); goto finish; } if (pa_authkey_save(cookie_file, cookie, l) < 0) { fprintf(stderr, "Failed to save cookie data\n"); goto finish; } } break; } case EXPORT: { pa_client_conf *conf = pa_client_conf_new(); uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; assert(conf); if (pa_client_conf_load(conf, NULL) < 0) { fprintf(stderr, "Failed to load client configuration file.\n"); goto finish; } if (pa_client_conf_env(conf) < 0) { fprintf(stderr, "Failed to read environment configuration data.\n"); goto finish; } pa_x11_del_prop(d, "PULSE_SERVER"); pa_x11_del_prop(d, "PULSE_SINK"); pa_x11_del_prop(d, "PULSE_SOURCE"); pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); if (server) pa_x11_set_prop(d, "PULSE_SERVER", server); else if (conf->default_server) pa_x11_set_prop(d, "PULSE_SERVER", conf->default_server); else { char hn[256]; if (!pa_get_fqdn(hn, sizeof(hn))) { fprintf(stderr, "Failed to get FQDN.\n"); goto finish; } pa_x11_set_prop(d, "PULSE_SERVER", hn); } if (sink) pa_x11_set_prop(d, "PULSE_SINK", sink); else if (conf->default_sink) pa_x11_set_prop(d, "PULSE_SINK", conf->default_sink); if (source) pa_x11_set_prop(d, "PULSE_SOURCE", source); if (conf->default_source) pa_x11_set_prop(d, "PULSE_SOURCE", conf->default_source); pa_client_conf_free(conf); if (pa_authkey_load_auto(cookie_file, cookie, sizeof(cookie)) < 0) { fprintf(stderr, "Failed to load cookie data\n"); goto finish; } pa_x11_set_prop(d, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx))); break; } case REMOVE: pa_x11_del_prop(d, "PULSE_SERVER"); pa_x11_del_prop(d, "PULSE_SINK"); pa_x11_del_prop(d, "PULSE_SOURCE"); pa_x11_del_prop(d, "PULSE_ID"); pa_x11_del_prop(d, "PULSE_COOKIE"); break; default: fprintf(stderr, "No yet implemented.\n"); goto finish; } ret = 0; finish: if (d) { XSync(d, False); XCloseDisplay(d); } return ret; }
/* Called from main context */ pa_source* pa_source_new( pa_core *core, pa_source_new_data *data, pa_source_flags_t flags) { pa_source *s; const char *name; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; char *pt; pa_assert(core); pa_assert(data); pa_assert(data->name); pa_assert_ctl_context(); s = pa_msgobject_new(pa_source); if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) { pa_log_debug("Failed to register name %s.", data->name); pa_xfree(s); return NULL; } pa_source_new_data_set_name(data, name); if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); return NULL; } /* FIXME, need to free s here on failure */ pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver)); pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]); pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); if (!data->volume_is_set) pa_cvolume_reset(&data->volume, data->sample_spec.channels); pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; if (data->card) pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist); pa_device_init_description(data->proplist); pa_device_init_icon(data->proplist, FALSE); pa_device_init_intended_roles(data->proplist); if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) { pa_xfree(s); pa_namereg_unregister(core, name); return NULL; } s->parent.parent.free = source_free; s->parent.process_msg = pa_source_process_msg; s->core = core; s->state = PA_SOURCE_INIT; s->flags = flags; s->priority = 0; s->suspend_cause = 0; s->name = pa_xstrdup(name); s->proplist = pa_proplist_copy(data->proplist); s->driver = pa_xstrdup(pa_path_get_filename(data->driver)); s->module = data->module; s->card = data->card; s->priority = pa_device_init_priority(s->proplist); s->sample_spec = data->sample_spec; s->channel_map = data->channel_map; s->outputs = pa_idxset_new(NULL, NULL); s->n_corked = 0; s->monitor_of = NULL; s->output_from_master = NULL; s->volume = data->volume; pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels); s->base_volume = PA_VOLUME_NORM; s->n_volume_steps = PA_VOLUME_NORM+1; s->muted = data->muted; s->refresh_volume = s->refresh_muted = FALSE; reset_callbacks(s); s->userdata = NULL; s->asyncmsgq = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ s->ports = data->ports; data->ports = NULL; s->active_port = NULL; s->save_port = FALSE; if (data->active_port && s->ports) if ((s->active_port = pa_hashmap_get(s->ports, data->active_port))) s->save_port = data->save_port; if (!s->active_port && s->ports) { void *state; pa_device_port *p; PA_HASHMAP_FOREACH(p, s->ports, state) if (!s->active_port || p->priority > s->active_port->priority) s->active_port = p; }
int pa__init(pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; const char *dev; int fd = -1; int nfrags, orig_frag_size, frag_size; int mode, caps; pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64]; const char *name; pa_bool_t namereg_fail; pa_sink_new_data sink_new_data; pa_source_new_data source_new_data; 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_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect boolean argument."); goto fail; } if (!playback && !record) { pa_log("Neither playback nor record enabled for device."); goto fail; } mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); 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_OSS) < 0) { pa_log("Failed to parse sample specification or channel map"); goto fail; } nfrags = (int) m->core->default_n_fragments; frag_size = (int) pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); if (frag_size <= 0) frag_size = (int) pa_frame_size(&ss); if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log("Failed to parse fragments arguments"); goto fail; } if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { pa_log("Failed to parse mmap argument."); goto fail; } if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) { pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode."); use_mmap = FALSE; } if (use_mmap && mode == O_WRONLY) { pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode."); use_mmap = FALSE; } if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0) pa_log_info("Hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); orig_frag_size = frag_size; if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) goto fail; if (pa_oss_auto_format(fd, &ss) < 0) goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } pa_assert(frag_size > 0); u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; m->userdata = u; u->fd = fd; u->mixer_fd = -1; u->mixer_devmask = 0; u->use_getospace = u->use_getispace = TRUE; u->use_getodelay = TRUE; u->mode = mode; u->frame_size = pa_frame_size(&ss); u->device_name = pa_xstrdup(dev); u->in_nfrags = u->out_nfrags = (uint32_t) (u->nfrags = nfrags); u->out_fragment_size = u->in_fragment_size = (uint32_t) (u->frag_size = frag_size); u->orig_frag_size = orig_frag_size; u->use_mmap = use_mmap; u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); u->rtpoll_item = NULL; build_pollfd(u); if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->in_fragment_size = (uint32_t) info.fragsize; u->in_nfrags = (uint32_t) info.fragstotal; u->use_getispace = TRUE; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize); u->out_fragment_size = (uint32_t) info.fragsize; u->out_nfrags = (uint32_t) info.fragstotal; u->use_getospace = TRUE; } u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size; u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size; if (mode != O_WRONLY) { char *name_buf = NULL; if (use_mmap) { if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno)); use_mmap = u->use_mmap = FALSE; u->in_mmap = NULL; } else pa_log_debug("Successfully mmap()ed input buffer."); } if ((name = pa_modargs_get_value(ma, "source_name", NULL))) namereg_fail = TRUE; else { name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev)); namereg_fail = FALSE; } pa_source_new_data_init(&source_new_data); source_new_data.driver = __FILE__; source_new_data.module = m; pa_source_new_data_set_name(&source_new_data, name); source_new_data.namereg_fail = namereg_fail; pa_source_new_data_set_sample_spec(&source_new_data, &ss); pa_source_new_data_set_channel_map(&source_new_data, &map); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, dev); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "oss"); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev); pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial"); pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->in_hwbuf_size)); pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->in_fragment_size)); if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_source_new_data_done(&source_new_data); goto fail; } u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); pa_source_new_data_done(&source_new_data); pa_xfree(name_buf); if (!u->source) { pa_log("Failed to create source object"); 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(u->in_hwbuf_size, &u->source->sample_spec)); u->source->refresh_volume = TRUE; if (use_mmap) u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags); }
int main(int argc, char*argv[]) { pid_t pid; int fd = -1; int ret = 1, i; struct sockaddr_un sa; char *ibuf = NULL; char *obuf = NULL; size_t buf_size, ibuf_size, ibuf_index, ibuf_length, obuf_size, obuf_index, obuf_length; char *cli; bool ibuf_eof, obuf_eof, ibuf_closed, obuf_closed; struct pollfd pollfd[3]; struct pollfd *watch_socket, *watch_stdin, *watch_stdout; int stdin_type = 0, stdout_type = 0, fd_type = 0; char *bn = NULL; int c; static const struct option long_options[] = { {"version", 0, NULL, ARG_VERSION}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif bn = pa_path_get_filename(argv[0]); while ((c = getopt_long(argc, argv, "h", long_options, NULL)) != -1) { switch (c) { case 'h' : help(bn); ret = 0; goto quit; case ARG_VERSION: printf(_("pacmd %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; default: goto quit; } } if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) { pa_log(_("No PulseAudio daemon running, or not running as session daemon.")); goto quit; } if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) { pa_log(_("socket(PF_UNIX, SOCK_STREAM, 0): %s"), strerror(errno)); goto quit; } pa_zero(sa); sa.sun_family = AF_UNIX; if (!(cli = pa_runtime_path("cli"))) goto quit; pa_strlcpy(sa.sun_path, cli, sizeof(sa.sun_path)); pa_xfree(cli); for (i = 0; i < 5; i++) { int r; if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { pa_log(_("connect(): %s"), strerror(errno)); goto quit; } if (r >= 0) break; if (pa_pid_file_kill(SIGUSR2, NULL, "pulseaudio") < 0) { pa_log(_("Failed to kill PulseAudio daemon.")); goto quit; } pa_msleep(300); } if (i >= 5) { pa_log(_("Daemon not responding.")); goto quit; } buf_size = pa_pipe_buf(fd); ibuf_size = PA_MIN(buf_size, pa_pipe_buf(STDIN_FILENO)); ibuf = pa_xmalloc(ibuf_size); obuf_size = PA_MIN(buf_size, pa_pipe_buf(STDOUT_FILENO)); obuf = pa_xmalloc(obuf_size); ibuf_index = ibuf_length = obuf_index = obuf_length = 0; ibuf_eof = obuf_eof = ibuf_closed = obuf_closed = false; if (argc > 1) { for (i = 1; i < argc; i++) { size_t k; k = PA_MIN(ibuf_size - ibuf_length, strlen(argv[i])); memcpy(ibuf + ibuf_length, argv[i], k); ibuf_length += k; if (ibuf_length < ibuf_size) { ibuf[ibuf_length] = i < argc-1 ? ' ' : '\n'; ibuf_length++; } } ibuf_eof = true; } if (!ibuf_eof && isatty(STDIN_FILENO)) { /* send hello to enable interactive mode (welcome message, prompt) */ if (pa_write(fd, "hello\n", 6, &fd_type) < 0) { pa_log(_("write(): %s"), strerror(errno)); goto quit; } } for (;;) { struct pollfd *p; if (ibuf_eof && obuf_eof && ibuf_length <= 0 && obuf_length <= 0) break; if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) { shutdown(fd, SHUT_WR); ibuf_closed = true; } if (obuf_length <= 0 && obuf_eof && !obuf_closed) { shutdown(fd, SHUT_RD); obuf_closed = true; } pa_zero(pollfd); p = pollfd; if (ibuf_length > 0 || (!obuf_eof && obuf_length <= 0)) { watch_socket = p++; watch_socket->fd = fd; watch_socket->events = (ibuf_length > 0 ? POLLOUT : 0) | (!obuf_eof && obuf_length <= 0 ? POLLIN : 0); } else watch_socket = NULL; if (!ibuf_eof && ibuf_length <= 0) { watch_stdin = p++; watch_stdin->fd = STDIN_FILENO; watch_stdin->events = POLLIN; } else watch_stdin = NULL; if (obuf_length > 0) { watch_stdout = p++; watch_stdout->fd = STDOUT_FILENO; watch_stdout->events = POLLOUT; } else watch_stdout = NULL; if (pa_poll(pollfd, p-pollfd, -1) < 0) { if (errno == EINTR) continue; pa_log(_("poll(): %s"), strerror(errno)); goto quit; } if (watch_stdin) { if (watch_stdin->revents & POLLIN) { ssize_t r; pa_assert(ibuf_length <= 0); if ((r = pa_read(STDIN_FILENO, ibuf, ibuf_size, &stdin_type)) <= 0) { if (r < 0) { pa_log(_("read(): %s"), strerror(errno)); goto quit; } ibuf_eof = true; } else { ibuf_length = (size_t) r; ibuf_index = 0; } } else if (watch_stdin->revents & POLLHUP) ibuf_eof = true; } if (watch_socket) { if (watch_socket->revents & POLLIN) { ssize_t r; pa_assert(obuf_length <= 0); if ((r = pa_read(fd, obuf, obuf_size, &fd_type)) <= 0) { if (r < 0) { pa_log(_("read(): %s"), strerror(errno)); goto quit; } obuf_eof = true; } else { obuf_length = (size_t) r; obuf_index = 0; } } else if (watch_socket->revents & POLLHUP) obuf_eof = true; } if (watch_stdout) { if (watch_stdout->revents & POLLHUP) { obuf_eof = true; obuf_length = 0; } else if (watch_stdout->revents & POLLOUT) { ssize_t r; pa_assert(obuf_length > 0); if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, &stdout_type)) < 0) { pa_log(_("write(): %s"), strerror(errno)); goto quit; } obuf_length -= (size_t) r; obuf_index += obuf_index; } } if (watch_socket) { if (watch_socket->revents & POLLHUP) { ibuf_eof = true; ibuf_length = 0; } if (watch_socket->revents & POLLOUT) { ssize_t r; pa_assert(ibuf_length > 0); if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, &fd_type)) < 0) { pa_log(_("write(): %s"), strerror(errno)); goto quit; } ibuf_length -= (size_t) r; ibuf_index += obuf_index; } } } ret = 0; quit: if (fd >= 0) pa_close(fd); pa_xfree(obuf); pa_xfree(ibuf); return ret; }