153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <stdio.h> 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2753a5a1b3Sopenharmony_ci 2853a5a1b3Sopenharmony_ci#include <pulsecore/sink-input.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/module.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/modargs.h> 3153a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h> 3253a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ciPA_MODULE_AUTHOR("Lennart Poettering"); 3553a5a1b3Sopenharmony_ciPA_MODULE_DESCRIPTION("Sine wave generator"); 3653a5a1b3Sopenharmony_ciPA_MODULE_VERSION(PACKAGE_VERSION); 3753a5a1b3Sopenharmony_ciPA_MODULE_LOAD_ONCE(false); 3853a5a1b3Sopenharmony_ciPA_MODULE_USAGE( 3953a5a1b3Sopenharmony_ci "sink=<sink to connect to> " 4053a5a1b3Sopenharmony_ci "rate=<sample rate> " 4153a5a1b3Sopenharmony_ci "frequency=<frequency in Hz>"); 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_cistruct userdata { 4453a5a1b3Sopenharmony_ci pa_core *core; 4553a5a1b3Sopenharmony_ci pa_module *module; 4653a5a1b3Sopenharmony_ci pa_sink_input *sink_input; 4753a5a1b3Sopenharmony_ci pa_memchunk memchunk; 4853a5a1b3Sopenharmony_ci size_t peek_index; 4953a5a1b3Sopenharmony_ci}; 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_cistatic const char* const valid_modargs[] = { 5253a5a1b3Sopenharmony_ci "sink", 5353a5a1b3Sopenharmony_ci "rate", 5453a5a1b3Sopenharmony_ci "frequency", 5553a5a1b3Sopenharmony_ci NULL, 5653a5a1b3Sopenharmony_ci}; 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_cistatic int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { 5953a5a1b3Sopenharmony_ci struct userdata *u; 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 6253a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 6353a5a1b3Sopenharmony_ci pa_assert(chunk); 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci *chunk = u->memchunk; 6653a5a1b3Sopenharmony_ci pa_memblock_ref(chunk->memblock); 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci chunk->index += u->peek_index; 6953a5a1b3Sopenharmony_ci chunk->length -= u->peek_index; 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci u->peek_index = 0; 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci return 0; 7453a5a1b3Sopenharmony_ci} 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_cistatic void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { 7753a5a1b3Sopenharmony_ci struct userdata *u; 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 8053a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci nbytes %= u->memchunk.length; 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci if (u->peek_index >= nbytes) 8553a5a1b3Sopenharmony_ci u->peek_index -= nbytes; 8653a5a1b3Sopenharmony_ci else 8753a5a1b3Sopenharmony_ci u->peek_index = u->memchunk.length + u->peek_index - nbytes; 8853a5a1b3Sopenharmony_ci} 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_cistatic void sink_input_kill_cb(pa_sink_input *i) { 9153a5a1b3Sopenharmony_ci struct userdata *u; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 9453a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_ci pa_sink_input_unlink(u->sink_input); 9753a5a1b3Sopenharmony_ci pa_sink_input_unref(u->sink_input); 9853a5a1b3Sopenharmony_ci u->sink_input = NULL; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 10153a5a1b3Sopenharmony_ci} 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci/* Called from IO thread context */ 10453a5a1b3Sopenharmony_cistatic void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) { 10553a5a1b3Sopenharmony_ci struct userdata *u; 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 10853a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci /* If we are added for the first time, ask for a rewinding so that 11153a5a1b3Sopenharmony_ci * we are heard right-away. */ 11253a5a1b3Sopenharmony_ci if (PA_SINK_INPUT_IS_LINKED(state) && 11353a5a1b3Sopenharmony_ci i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) 11453a5a1b3Sopenharmony_ci pa_sink_input_request_rewind(i, 0, false, true, true); 11553a5a1b3Sopenharmony_ci} 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ciint pa__init(pa_module*m) { 11853a5a1b3Sopenharmony_ci pa_modargs *ma = NULL; 11953a5a1b3Sopenharmony_ci struct userdata *u; 12053a5a1b3Sopenharmony_ci pa_sink *sink; 12153a5a1b3Sopenharmony_ci pa_sample_spec ss; 12253a5a1b3Sopenharmony_ci uint32_t frequency; 12353a5a1b3Sopenharmony_ci pa_sink_input_new_data data; 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 12653a5a1b3Sopenharmony_ci pa_log("Failed to parse module arguments"); 12753a5a1b3Sopenharmony_ci goto fail; 12853a5a1b3Sopenharmony_ci } 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK))) { 13153a5a1b3Sopenharmony_ci pa_log("No such sink."); 13253a5a1b3Sopenharmony_ci goto fail; 13353a5a1b3Sopenharmony_ci } 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ci ss.format = PA_SAMPLE_FLOAT32; 13653a5a1b3Sopenharmony_ci ss.rate = sink->sample_spec.rate; 13753a5a1b3Sopenharmony_ci ss.channels = 1; 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci if (pa_modargs_get_sample_rate(ma, &ss.rate) < 0) { 14053a5a1b3Sopenharmony_ci pa_log("Invalid rate specification"); 14153a5a1b3Sopenharmony_ci goto fail; 14253a5a1b3Sopenharmony_ci } 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci frequency = 440; 14553a5a1b3Sopenharmony_ci if (pa_modargs_get_value_u32(ma, "frequency", &frequency) < 0 || frequency < 1 || frequency > ss.rate/2) { 14653a5a1b3Sopenharmony_ci pa_log("Invalid frequency specification"); 14753a5a1b3Sopenharmony_ci goto fail; 14853a5a1b3Sopenharmony_ci } 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci m->userdata = u = pa_xnew0(struct userdata, 1); 15153a5a1b3Sopenharmony_ci u->core = m->core; 15253a5a1b3Sopenharmony_ci u->module = m; 15353a5a1b3Sopenharmony_ci u->sink_input = NULL; 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci u->peek_index = 0; 15653a5a1b3Sopenharmony_ci pa_memchunk_sine(&u->memchunk, m->core->mempool, ss.rate, frequency); 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci pa_sink_input_new_data_init(&data); 15953a5a1b3Sopenharmony_ci data.driver = __FILE__; 16053a5a1b3Sopenharmony_ci data.module = m; 16153a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sink(&data, sink, false, true); 16253a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME, "%u Hz Sine", frequency); 16353a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "abstract"); 16453a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, "sine.hz", "%u", frequency); 16553a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sample_spec(&data, &ss); 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ci pa_sink_input_new(&u->sink_input, m->core, &data); 16853a5a1b3Sopenharmony_ci pa_sink_input_new_data_done(&data); 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci if (!u->sink_input) 17153a5a1b3Sopenharmony_ci goto fail; 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci u->sink_input->pop = sink_input_pop_cb; 17453a5a1b3Sopenharmony_ci u->sink_input->process_rewind = sink_input_process_rewind_cb; 17553a5a1b3Sopenharmony_ci u->sink_input->kill = sink_input_kill_cb; 17653a5a1b3Sopenharmony_ci u->sink_input->state_change = sink_input_state_change_cb; 17753a5a1b3Sopenharmony_ci u->sink_input->userdata = u; 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci pa_sink_input_put(u->sink_input); 18053a5a1b3Sopenharmony_ci 18153a5a1b3Sopenharmony_ci pa_modargs_free(ma); 18253a5a1b3Sopenharmony_ci return 0; 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_cifail: 18553a5a1b3Sopenharmony_ci if (ma) 18653a5a1b3Sopenharmony_ci pa_modargs_free(ma); 18753a5a1b3Sopenharmony_ci 18853a5a1b3Sopenharmony_ci pa__done(m); 18953a5a1b3Sopenharmony_ci return -1; 19053a5a1b3Sopenharmony_ci} 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_civoid pa__done(pa_module*m) { 19353a5a1b3Sopenharmony_ci struct userdata *u; 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci pa_assert(m); 19653a5a1b3Sopenharmony_ci 19753a5a1b3Sopenharmony_ci if (!(u = m->userdata)) 19853a5a1b3Sopenharmony_ci return; 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci if (u->sink_input) { 20153a5a1b3Sopenharmony_ci pa_sink_input_unlink(u->sink_input); 20253a5a1b3Sopenharmony_ci pa_sink_input_unref(u->sink_input); 20353a5a1b3Sopenharmony_ci } 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci if (u->memchunk.memblock) 20653a5a1b3Sopenharmony_ci pa_memblock_unref(u->memchunk.memblock); 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci pa_xfree(u); 20953a5a1b3Sopenharmony_ci} 210