static int parse_sample_format(pa_config_parser_state *state) { pa_daemon_conf *c; pa_sample_format_t f; pa_assert(state); c = state->data; if ((f = pa_parse_sample_format(state->rvalue)) < 0) { pa_log(_("[%s:%u] Invalid sample format '%s'."), state->filename, state->lineno, state->rvalue); return -1; } c->default_sample_spec.format = f; return 0; }
static int parse_sample_format(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; pa_sample_format_t f; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(data); if ((f = pa_parse_sample_format(rvalue)) < 0) { pa_log(_("[%s:%u] Invalid sample format '%s'."), filename, line, rvalue); return -1; } c->default_sample_spec.format = f; return 0; }
static int read_backend_default_spec(pa_sample_spec *sample_spec) { /* Read spec from backend */ char *out; out = read_param("default-format"); sample_spec->format = pa_parse_sample_format(out); free(out); out = read_param("default-rate"); sample_spec->rate = atoi(out); free(out); out = read_param("default-channels"); sample_spec->channels = atoi(out); free(out); return 0; }
/* For PCM streams */ int pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { char *sf = NULL, *m = NULL; int rate, channels; int ret = -PA_ERR_INVALID; pa_assert(f); pa_assert(ss); if (!pa_format_info_is_pcm(f)) return pa_format_info_to_sample_spec_fake(f, ss); if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf)) goto out; if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate)) goto out; if (pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels)) goto out; if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID) goto out; ss->rate = (uint32_t) rate; ss->channels = (uint8_t) channels; if (map) { pa_channel_map_init(map); if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m) == 0) if (pa_channel_map_parse(map, m) == NULL) goto out; } ret = 0; out: if (sf) pa_xfree(sf); if (m) pa_xfree(m); return ret; }
/* For PCM streams */ pa_bool_t pa_format_info_to_sample_spec(pa_format_info *f, pa_sample_spec *ss, pa_channel_map *map) { char *sf = NULL, *m = NULL; int rate, channels; pa_bool_t ret = FALSE; pa_assert(f); pa_assert(ss); pa_return_val_if_fail(f->encoding == PA_ENCODING_PCM, FALSE); if (!pa_format_info_get_prop_string(f, PA_PROP_FORMAT_SAMPLE_FORMAT, &sf)) goto out; if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_RATE, &rate)) goto out; if (!pa_format_info_get_prop_int(f, PA_PROP_FORMAT_CHANNELS, &channels)) goto out; if ((ss->format = pa_parse_sample_format(sf)) == PA_SAMPLE_INVALID) goto out; ss->rate = (uint32_t) rate; ss->channels = (uint8_t) channels; if (map) { pa_channel_map_init(map); if (pa_format_info_get_prop_string(f, PA_PROP_FORMAT_CHANNEL_MAP, &m)) if (pa_channel_map_parse(map, m) == NULL) goto out; } ret = TRUE; out: if (sf) pa_xfree(sf); if (m) pa_xfree(m); 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; 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; }
static void resolver_cb( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { struct userdata *u = userdata; struct tunnel *tnl; pa_assert(u); tnl = tunnel_new(interface, protocol, name, type, domain); if (event != AVAHI_RESOLVER_FOUND) pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client))); else { char *device = NULL, *dname, *module_name, *args; const char *t; char at[AVAHI_ADDRESS_STR_MAX], cmt[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_sample_spec ss; pa_channel_map cm; AvahiStringList *l; pa_bool_t channel_map_set = FALSE; pa_module *m; ss = u->core->default_sample_spec; cm = u->core->default_channel_map; for (l = txt; l; l = l->next) { char *key, *value; pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0); if (pa_streq(key, "device")) { pa_xfree(device); device = value; value = NULL; } else if (pa_streq(key, "rate")) ss.rate = (uint32_t) atoi(value); else if (pa_streq(key, "channels")) ss.channels = (uint8_t) atoi(value); else if (pa_streq(key, "format")) ss.format = pa_parse_sample_format(value); else if (pa_streq(key, "channel_map")) { pa_channel_map_parse(&cm, value); channel_map_set = TRUE; } avahi_free(key); avahi_free(value); } if (!channel_map_set && cm.channels != ss.channels) pa_channel_map_init_extend(&cm, ss.channels, PA_CHANNEL_MAP_DEFAULT); if (!pa_sample_spec_valid(&ss)) { pa_log("Service '%s' contains an invalid sample specification.", name); avahi_free(device); goto finish; } if (!pa_channel_map_valid(&cm) || cm.channels != ss.channels) { pa_log("Service '%s' contains an invalid channel map.", name); avahi_free(device); goto finish; } if (device) dname = pa_sprintf_malloc("tunnel.%s.%s", host_name, device); else dname = pa_sprintf_malloc("tunnel.%s", host_name); if (!pa_namereg_is_valid_name(dname)) { pa_log("Cannot construct valid device name from credentials of service '%s'.", dname); avahi_free(device); pa_xfree(dname); goto finish; } t = strstr(type, "sink") ? "sink" : "source"; module_name = pa_sprintf_malloc("module-tunnel-%s", t); args = pa_sprintf_malloc("server=[%s]:%u " "%s=%s " "format=%s " "channels=%u " "rate=%u " "%s_name=%s " "channel_map=%s", avahi_address_snprint(at, sizeof(at), a), port, t, device, pa_sample_format_to_string(ss.format), ss.channels, ss.rate, t, dname, pa_channel_map_snprint(cmt, sizeof(cmt), &cm)); pa_log_debug("Loading %s with arguments '%s'", module_name, args); if ((m = pa_module_load(u->core, module_name, args))) { tnl->module_index = m->index; pa_hashmap_put(u->tunnels, tnl, tnl); tnl = NULL; } pa_xfree(module_name); pa_xfree(dname); pa_xfree(args); avahi_free(device); } finish: avahi_service_resolver_free(r); if (tnl) tunnel_free(tnl); }
int main(int argc, char *argv[]) { pa_mempool *pool = NULL; pa_sample_spec a, b; int ret = 1, c; bool all_formats = true; pa_resample_method_t method; int seconds; unsigned crossover_freq = 120; static const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"version", 0, NULL, ARG_VERSION}, {"from-rate", 1, NULL, ARG_FROM_SAMPLERATE}, {"from-format", 1, NULL, ARG_FROM_SAMPLEFORMAT}, {"from-channels", 1, NULL, ARG_FROM_CHANNELS}, {"to-rate", 1, NULL, ARG_TO_SAMPLERATE}, {"to-format", 1, NULL, ARG_TO_SAMPLEFORMAT}, {"to-channels", 1, NULL, ARG_TO_CHANNELS}, {"seconds", 1, NULL, ARG_SECONDS}, {"resample-method", 1, NULL, ARG_RESAMPLE_METHOD}, {"dump-resample-methods", 0, NULL, ARG_DUMP_RESAMPLE_METHODS}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif pa_log_set_level(PA_LOG_WARN); if (!getenv("MAKE_CHECK")) pa_log_set_level(PA_LOG_INFO); pa_assert_se(pool = pa_mempool_new(false, 0)); a.channels = b.channels = 1; a.rate = b.rate = 44100; a.format = b.format = PA_SAMPLE_S16LE; method = PA_RESAMPLER_AUTO; seconds = 60; while ((c = getopt_long(argc, argv, "hv", long_options, NULL)) != -1) { switch (c) { case 'h' : help(argv[0]); ret = 0; goto quit; case 'v': pa_log_set_level(PA_LOG_DEBUG); break; case ARG_VERSION: printf(_("%s %s\n"), argv[0], PACKAGE_VERSION); ret = 0; goto quit; case ARG_DUMP_RESAMPLE_METHODS: dump_resample_methods(); ret = 0; goto quit; case ARG_FROM_CHANNELS: a.channels = (uint8_t) atoi(optarg); break; case ARG_FROM_SAMPLEFORMAT: a.format = pa_parse_sample_format(optarg); all_formats = false; break; case ARG_FROM_SAMPLERATE: a.rate = (uint32_t) atoi(optarg); break; case ARG_TO_CHANNELS: b.channels = (uint8_t) atoi(optarg); break; case ARG_TO_SAMPLEFORMAT: b.format = pa_parse_sample_format(optarg); all_formats = false; break; case ARG_TO_SAMPLERATE: b.rate = (uint32_t) atoi(optarg); break; case ARG_SECONDS: seconds = atoi(optarg); break; case ARG_RESAMPLE_METHOD: if (*optarg == '\0' || pa_streq(optarg, "help")) { dump_resample_methods(); ret = 0; goto quit; } method = pa_parse_resample_method(optarg); break; default: goto quit; } } ret = 0; pa_assert_se(pool = pa_mempool_new(false, 0)); if (!all_formats) { pa_resampler *resampler; pa_memchunk i, j; pa_usec_t ts; pa_log_debug("Compilation CFLAGS: %s", PA_CFLAGS); pa_log_debug("=== %d seconds: %d Hz %d ch (%s) -> %d Hz %d ch (%s)", seconds, a.rate, a.channels, pa_sample_format_to_string(a.format), b.rate, b.channels, pa_sample_format_to_string(b.format)); ts = pa_rtclock_now(); pa_assert_se(resampler = pa_resampler_new(pool, &a, NULL, &b, NULL, crossover_freq, method, 0)); pa_log_info("init: %llu", (long long unsigned)(pa_rtclock_now() - ts)); i.memblock = pa_memblock_new(pool, pa_usec_to_bytes(1*PA_USEC_PER_SEC, &a)); ts = pa_rtclock_now(); i.length = pa_memblock_get_length(i.memblock); i.index = 0; while (seconds--) { pa_resampler_run(resampler, &i, &j); if (j.memblock) pa_memblock_unref(j.memblock); } pa_log_info("resampling: %llu", (long long unsigned)(pa_rtclock_now() - ts)); pa_memblock_unref(i.memblock); pa_resampler_free(resampler); goto quit; } for (a.format = 0; a.format < PA_SAMPLE_MAX; a.format ++) { for (b.format = 0; b.format < PA_SAMPLE_MAX; b.format ++) { pa_resampler *forth, *back; pa_memchunk i, j, k; pa_log_debug("=== %s -> %s -> %s -> /2", pa_sample_format_to_string(a.format), pa_sample_format_to_string(b.format), pa_sample_format_to_string(a.format)); pa_assert_se(forth = pa_resampler_new(pool, &a, NULL, &b, NULL, crossover_freq, method, 0)); pa_assert_se(back = pa_resampler_new(pool, &b, NULL, &a, NULL, crossover_freq, method, 0)); i.memblock = generate_block(pool, &a); i.length = pa_memblock_get_length(i.memblock); i.index = 0; pa_resampler_run(forth, &i, &j); pa_resampler_run(back, &j, &k); dump_block("before", &a, &i); dump_block("after", &b, &j); dump_block("reverse", &a, &k); pa_memblock_unref(i.memblock); pa_memblock_unref(j.memblock); pa_memblock_unref(k.memblock); pa_resampler_free(forth); pa_resampler_free(back); } } quit: if (pool) pa_mempool_free(pool); return ret; }
int pa__init(pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; pa_sink_new_data data; size_t nbytes; pa_assert(m); pa_web_debug_func_t func = pa_get_user_data(PA_USER_WEB_FUNC); if (!func) { pa_log_error("Failed to get user web func from user data"); goto fail; } ma = pa_modargs_new(m->argument, valid_modargs); if (!ma) { 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; } pa_modargs_get_value_u32(ma, "fixed_rate", &ss.rate); uint32_t c = 0; pa_modargs_get_value_u32(ma, "fixed_channels", &c); if (c) ss.channels = c; const char* fixed_fmt = pa_modargs_get_value(ma, "fixed_format", NULL); if (fixed_fmt) ss.format = pa_parse_sample_format(fixed_fmt); if (ss.channels != map.channels) { pa_log_error("sample_spec channels[%d] != channel_map channels[%d]", ss.channels, map.channels); pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT); pa_log_debug("after init extend mmap.channels=%d", map.channels); } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; u->rtpoll = pa_rtpoll_new(); u->data_func = web_data_func; pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); pa_sink_new_data_init(&data); data.driver = __FILE__; data.module = m; pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Remote Output")); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_sink_new_data_done(&data); goto fail; } u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY); pa_sink_new_data_done(&data); if (!u->sink) { pa_log("Failed to create sink object."); goto fail; } u->sink->parent.process_msg = sink_process_msg; u->sink->update_requested_latency = sink_update_requested_latency_cb; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); u->block_usec = BLOCK_USEC; nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec); pa_sink_set_max_rewind(u->sink, nbytes); pa_sink_set_max_request(u->sink, nbytes); // call websocket to start func(1, NULL, ss.rate, ss.format); u->thread = pa_thread_new("remote-sink", thread_func, u); if (!u->thread) { pa_log("Failed to create thread."); goto fail; } pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC); pa_sink_put(u->sink); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }