From: Jaechul Lee Date: Fri, 3 Dec 2021 02:15:30 +0000 (+0900) Subject: Support external device playback and capture on sink2/source2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fref%2Ffor%2Ftizen;p=platform%2Fcore%2Fmultimedia%2Fpulseaudio-modules-tizen.git Support external device playback and capture on sink2/source2 module-alsa-card try to use 'device_id' that is from udev but tizenaudio-sink2/source2 can't load device with device_id. This patch makes devices load with device_id and device_string both. [Version] 13.0.78 [Issue Type] New feature Change-Id: I26645fc7b43b6289a3da9017b5643a0e65b8e026 Signed-off-by: Jaechul Lee --- diff --git a/Makefile.am b/Makefile.am index 300d9a3..7fa049b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ pulsemodlibexec_LTLIBRARIES = \ libhal-interface.la \ libprocessor.la \ libcommunicator.la \ - libtizenaudio-utils.la \ + libtizenaudio-util.la \ module-tizenaudio-sink.la \ module-tizenaudio-source.la \ module-tizenaudio-sink2.la \ @@ -79,19 +79,26 @@ module_tizenaudio_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_source_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la module_tizenaudio_source_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source -libtizenaudio_utils_la_SOURCES = src/tizenaudio-sink2.c src/tizenaudio-sink2.h src/tizenaudio-source2.c src/tizenaudio-source2.h src/echo-cancel/echo-cancel-def.h -libtizenaudio_utils_la_LDFLAGS = $(MODULE_LDFLAGS) -libtizenaudio_utils_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la -libtizenaudio_utils_la_CFLAGS = $(MODULE_CFLAGS) +libtizenaudio_util_la_SOURCES = \ + src/tizenaudio-sink2.c \ + src/tizenaudio-sink2.h \ + src/tizenaudio-source2.c \ + src/tizenaudio-source2.h \ + src/tizenaudio-util.c \ + src/tizenaudio-util.h \ + src/echo-cancel/echo-cancel-def.h +libtizenaudio_util_la_LDFLAGS = $(MODULE_LDFLAGS) +libtizenaudio_util_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la +libtizenaudio_util_la_CFLAGS = $(MODULE_CFLAGS) module_tizenaudio_sink2_la_SOURCES = src/module-tizenaudio-sink2.c module_tizenaudio_sink2_la_LDFLAGS = $(MODULE_LDFLAGS) -module_tizenaudio_sink2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-utils.la +module_tizenaudio_sink2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-util.la module_tizenaudio_sink2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_sink2 module_tizenaudio_source2_la_SOURCES = src/module-tizenaudio-source2.c src/echo-cancel/echo-cancel-def.h module_tizenaudio_source2_la_LDFLAGS = $(MODULE_LDFLAGS) -module_tizenaudio_source2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-utils.la +module_tizenaudio_source2_la_LIBADD = $(MODULE_LIBADD) libtizenaudio-util.la module_tizenaudio_source2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source2 libprocessor_la_SOURCES = \ diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 896f569..762292c 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -91,7 +91,7 @@ install -m 0644 %SOURCE1 %{buildroot}%{_tmpfilesdir}/pulseaudio.conf %{_libdir}/pulse-%{module_ver}/modules/module-tizenaudio-publish.so %{_libdir}/pulse-%{module_ver}/modules/module-tizenaudio-echo-cancel.so %{_libdir}/pulse-%{module_ver}/modules/libprocessor.so -%{_libdir}/pulse-%{module_ver}/modules/libtizenaudio-utils.so +%{_libdir}/pulse-%{module_ver}/modules/libtizenaudio-util.so %{_libdir}/pulse-%{module_ver}/modules/libhal-interface.so %{_libdir}/pulse-%{module_ver}/modules/libcommunicator.so %{_tmpfilesdir}/pulseaudio.conf diff --git a/src/module-tizenaudio-sink2.c b/src/module-tizenaudio-sink2.c index 9a22a63..0b10724 100644 --- a/src/module-tizenaudio-sink2.c +++ b/src/module-tizenaudio-sink2.c @@ -65,7 +65,7 @@ int pa__init(pa_module *m) { goto fail; } - if (!(m->userdata = pa_tizenaudio_sink2_new(m, ma, __FILE__, NULL))) + if (!(m->userdata = pa_tizenaudio_sink2_new(m, ma, __FILE__, NULL, NULL, NULL, NULL))) goto fail; pa_modargs_free(ma); diff --git a/src/module-tizenaudio-source2.c b/src/module-tizenaudio-source2.c index 381362a..c916b58 100644 --- a/src/module-tizenaudio-source2.c +++ b/src/module-tizenaudio-source2.c @@ -65,7 +65,7 @@ int pa__init(pa_module*m) { goto fail; } - if (!(m->userdata = pa_tizenaudio_source2_new(m, ma, __FILE__, NULL))) + if (!(m->userdata = pa_tizenaudio_source2_new(m, ma, __FILE__, NULL, NULL, NULL, NULL))) goto fail; pa_modargs_free(ma); diff --git a/src/tizenaudio-sink2.c b/src/tizenaudio-sink2.c index 530f01a..9e4c970 100644 --- a/src/tizenaudio-sink2.c +++ b/src/tizenaudio-sink2.c @@ -46,6 +46,7 @@ #include #include "hal-interface.h" +#include "tizenaudio-util.h" #include "echo-cancel/echo-cancel-def.h" #define DEFAULT_SINK_NAME "tizenaudio-sink2" @@ -377,59 +378,39 @@ finish: pa_log_debug("Thread shutting down"); } -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *c/*mapping somthing */) { +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_sink_new_data data; uint32_t alternate_sample_rate; const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; + const char *modarg_device_id; size_t frame_size, buffer_size, period_frames, buffer_frames; + pa_pcm_params param; pa_assert(m); pa_assert(ma); + /* + * TODO: It doesn't need to handle sample_spec, channels_map yet. + * Because it comes from UCM + */ 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) { + + if (channel_map && channel_map->channels != ss.channels) + ss.channels = channel_map->channels; + + pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log_error("Invalid sample format specification or channel map"); goto fail; } @@ -449,22 +430,13 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - if ((modarg_device = pa_modargs_get_value(ma, "device_id", NULL))) { - strcpy(card, modarg_device); - strcpy(device, "0"); - } else if ((modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - } else { - pa_log_error("Unknown device"); + modarg_device_id = pa_modargs_get_value(ma, "device_id", NULL); + modarg_device = pa_modargs_get_value(ma, "device", NULL); + if (!modarg_device_id && !modarg_device) { + pa_log_error("Failed to get device id or device string"); goto fail; } - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); u->nfrags = DEFAULT_FRAGMENTS; if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || @@ -472,10 +444,44 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive pa_log_error("fragment_size or fragments are invalid."); goto fail; } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + frame_size = pa_frame_size(&ss); + buffer_size = u->frag_size * u->nfrags; + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + param.direction = DIRECTION_OUT; + param.ss = &ss; + param.period_size = u->frag_size / pa_frame_size(&ss); + param.periods = u->nfrags; + + if (modarg_device_id && device_string) { + if (pa_hal_interface_pcm_open_by_dev_id( + u->hal_interface, + modarg_device_id, + device_string, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else { + if (pa_hal_interface_pcm_open_by_device( + u->hal_interface, + modarg_device, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } pa_sink_new_data_init(&data); - data.driver = __FILE__; + data.driver = driver; data.module = m; data.card = c; pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); @@ -487,19 +493,15 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, "tizen.version", "2"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - // TODO: Need to check usb. - if (pa_modargs_get_value(ma, "device_id", NULL)) { - pa_proplist_sets(data.proplist, "device.bus", "usb"); - } - - frame_size = pa_frame_size(&ss); - buffer_size = u->frag_size * u->nfrags; - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + /* + * TODO: tricky code for tizen + */ + if (modarg_device_id) + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "usb"); + if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_sink_new_data_done(&data); @@ -518,17 +520,7 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; u->sink->userdata = u; - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_OUT, - &u->sink->sample_spec, - u->frag_size / pa_frame_size(&u->sink->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); @@ -546,7 +538,9 @@ pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *drive return u->sink; fail: - userdata_free(u); + if (u) + userdata_free(u); + return NULL; } @@ -586,5 +580,7 @@ void pa_tizenaudio_sink2_free(pa_sink *s) { pa_sink_assert_ref(s); pa_assert_se((u = s->userdata)); + pa_hal_interface_unref(u->hal_interface); + userdata_free(u); } diff --git a/src/tizenaudio-sink2.h b/src/tizenaudio-sink2.h index 4891f39..f74777e 100644 --- a/src/tizenaudio-sink2.h +++ b/src/tizenaudio-sink2.h @@ -29,8 +29,16 @@ #include #include #include - -pa_sink *pa_tizenaudio_sink2_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *card/*mapping somthing */); +#include +#include + +pa_sink *pa_tizenaudio_sink2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map); void pa_tizenaudio_sink2_free(pa_sink *s); diff --git a/src/tizenaudio-source2.c b/src/tizenaudio-source2.c index dd5f8a3..c856d01 100644 --- a/src/tizenaudio-source2.c +++ b/src/tizenaudio-source2.c @@ -46,6 +46,7 @@ #include #include "hal-interface.h" +#include "tizenaudio-util.h" #include "echo-cancel/echo-cancel-def.h" #define DEFAULT_SOURCE_NAME "tizenaudio-source2" @@ -395,58 +396,39 @@ finish: pa_log_debug("Thread shutting down"); } -static int parse_to_get_card(const char *modarg_device, char *card) { - const char *name_p; - char *card_p; - - if (!strchr(modarg_device, ',')) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - name_p = modarg_device; - card_p = card; - while (*name_p != ',') - *(card_p++) = *(name_p++); - *card_p = '\0'; - - return 0; -} - -static int parse_to_get_device(const char *modarg_device, char *device) { - const char *comma_p; - char *device_p; - - if (!(comma_p = strchr(modarg_device, ','))) { - pa_log_error("Failed to parse device argument : no comma"); - return -1; - } - - comma_p++; - device_p = device; - while (*comma_p != '\0') - *(device_p++) = *(comma_p++); - *device_p = '\0'; - - return 0; -} - -pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *c/*mapping somthing */) { +pa_source *pa_tizenaudio_source2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_source_new_data data; uint32_t alternate_sample_rate; const char *modarg_device; - char card[DEVICE_NAME_MAX]; - char device[DEVICE_NAME_MAX]; + const char *modarg_device_id; size_t frame_size, buffer_size, period_frames, buffer_frames; + pa_pcm_params param; pa_assert(m); + pa_assert(ma); + /* + * TODO: It doesn't need to handle sample_spec, channels_map yet. + * Because it comes from UCM + */ 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) { + + if (channel_map && channel_map->channels != ss.channels) + ss.channels = channel_map->channels; + + pa_channel_map_init_extend(&map, ss.channels, PA_CHANNEL_MAP_ALSA); + + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log_error("Invalid sample format specification or channel map"); goto fail; } @@ -465,22 +447,13 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); - if ((modarg_device = pa_modargs_get_value(ma, "device_id", NULL))) { - strcpy(card, modarg_device); - strcpy(device, "0"); //TODO temp - } else if ((modarg_device = pa_modargs_get_value(ma, "device", NULL))) { - if (parse_to_get_card(modarg_device, card) || parse_to_get_device(modarg_device, device)) { - pa_log_error("failed to parse device module argument, %s", modarg_device); - goto fail; - } - } else { - pa_log_error("Unknown device"); + modarg_device_id = pa_modargs_get_value(ma, "device_id", NULL); + modarg_device = pa_modargs_get_value(ma, "device", NULL); + if (!modarg_device_id && !modarg_device) { + pa_log_error("Failed to get device id or device string"); goto fail; } - u->card = pa_xstrdup(card); - u->device = pa_xstrdup(device); - u->frag_size = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGMENT_MSEC * PA_USEC_PER_MSEC, &ss); u->nfrags = DEFAULT_FRAGMENTS; if (pa_modargs_get_value_u32(ma, "fragment_size", &u->frag_size) < 0 || @@ -488,7 +461,41 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d pa_log_error("fragment_size or fragments are invalid."); goto fail; } - pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", u->card, u->device, u->frag_size, u->nfrags); + + frame_size = pa_frame_size(&ss); + buffer_size = u->frag_size * u->nfrags; + buffer_frames = buffer_size / frame_size; + period_frames = u->frag_size / frame_size; + + param.direction = DIRECTION_IN; + param.ss = &ss; + param.period_size = u->frag_size / pa_frame_size(&ss); + param.periods = u->nfrags; + + if (modarg_device_id && device_string) { + if (pa_hal_interface_pcm_open_by_dev_id( + u->hal_interface, + modarg_device_id, + device_string, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } else { + if (pa_hal_interface_pcm_open_by_device( + u->hal_interface, + modarg_device, + ¶m, + (void **)&u->pcm_handle, + &u->card, + &u->device)) { + pa_log_error("Error opening PCM device"); + goto fail; + } + } pa_source_new_data_init(&data); data.driver = __FILE__; @@ -503,19 +510,15 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d pa_proplist_sets(data.proplist, "tizen.device", u->device); pa_proplist_sets(data.proplist, "tizen.version", "2"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "tizen"); - - // TODO: Need to check usb. - if (pa_modargs_get_value(ma, "device_id", NULL)) { - pa_proplist_sets(data.proplist, "device.bus", "usb"); - } - - frame_size = pa_frame_size(&ss); - buffer_size = u->frag_size * u->nfrags; - buffer_frames = buffer_size / frame_size; - period_frames = u->frag_size / frame_size; pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%zu", buffer_frames * frame_size); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%zu", period_frames * frame_size); + /* + * TODO: tricky code for tizen + */ + if (pa_modargs_get_value(ma, "device_id", NULL)) + pa_proplist_sets(data.proplist, "device.bus", "usb"); + if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log_error("Invalid properties."); pa_source_new_data_done(&data); @@ -534,17 +537,8 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb; u->source->userdata = u; - if (pa_hal_interface_pcm_open(u->hal_interface, - u->card, - u->device, - DIRECTION_IN, - &u->source->sample_spec, - u->frag_size / pa_frame_size(&u->source->sample_spec), - u->nfrags, - (void **)&u->pcm_handle)) { - pa_log_error("Error opening PCM device"); - goto fail; - } + pa_log_info("card(%s) device(%s) fragment_size(%u), fragments(%u)", + u->card, u->device, u->frag_size, u->nfrags); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); @@ -555,13 +549,16 @@ pa_source *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *d pa_log_error("Failed to create thread."); goto fail; } + pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(buffer_size, &ss)); pa_source_put(u->source); return u->source; fail: - userdata_free(u); + if (u) + userdata_free(u); + return NULL; } @@ -601,5 +598,7 @@ void pa_tizenaudio_source2_free(pa_source *s) { pa_source_assert_ref(s); pa_assert_se((u = s->userdata)); + pa_hal_interface_unref(u->hal_interface); + userdata_free(u); } diff --git a/src/tizenaudio-source2.h b/src/tizenaudio-source2.h index 53c0523..fa3406a 100644 --- a/src/tizenaudio-source2.h +++ b/src/tizenaudio-source2.h @@ -28,9 +28,17 @@ #include #include -#include - -pa_sink *pa_tizenaudio_source2_new(pa_module *m, pa_modargs *ma, const char *driver, pa_card *card/*mapping somthing */); +#include +#include +#include + +pa_source *pa_tizenaudio_source2_new(pa_module *m, + pa_modargs *ma, + const char *driver, + pa_card *c, + char **device_string, + pa_sample_spec *sample_spec, + pa_channel_map *channel_map); void pa_tizenaudio_source2_free(pa_source *s); diff --git a/src/tizenaudio-util.c b/src/tizenaudio-util.c new file mode 100644 index 0000000..3446c44 --- /dev/null +++ b/src/tizenaudio-util.c @@ -0,0 +1,199 @@ +/*** + This file is part of PulseAudio. + + Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "hal-interface.h" +#include "tizenaudio-util.h" + +#define DEVICE_NAME_MAX 32 + +static int parse_to_get_card(const char *device_string, char *card, const char *def) { + const char *name_p; + char *card_p; + + if (!strchr(device_string, ',')) { + int n; + + if (!def) + return -1; + + n = snprintf(card, DEVICE_NAME_MAX, "%s", (!strncmp(def, "hw:", 3)) ? def+3 : def); + card[n] = '\0'; + + return 0; + } + + name_p = device_string; + card_p = card; + + if (!strncmp(name_p, "hw:", 3)) + name_p += 3; + + while (*name_p != ',') + *(card_p++) = *(name_p++); + *card_p = '\0'; + + return 0; +} + +static int parse_to_get_device(const char *device_string, char *device, const char *def) { + const char *comma_p; + char *device_p; + + if (!(comma_p = strchr(device_string, ','))) { + int n; + + if (!def) + return -1; + + n = snprintf(device, DEVICE_NAME_MAX, "%s", def); + device[n] = '\0'; + + return 0; + } + + comma_p++; + device_p = device; + while (*comma_p != '\0') + *(device_p++) = *(comma_p++); + *device_p = '\0'; + + return 0; +} + +int32_t pa_hal_interface_pcm_open_by_dev_id(pa_hal_interface *h, + const char *dev_id, + char **device_string, + pa_pcm_params *param, + pcm_handle *pcm_h, + char **rcard, + char **rdevice) { + char **i; + char card[DEVICE_NAME_MAX]; + char device[DEVICE_NAME_MAX]; + + pa_assert(dev_id); + pa_assert(device_string); + pa_assert(device_string[0]); + + pa_assert(rcard); + pa_assert(rdevice); + + for (i=device_string; *i; i++) { + char *d; + + pa_log_debug("Try to open device(%s), id(%s)", *i, dev_id); + + if (!(d = pa_replace(*i, "%f", dev_id))) { + pa_log_error("Error parsing i(%s) dev_id(%s)", *i, dev_id); + continue; + } + + if (parse_to_get_device(d, device, "0") < 0) { + pa_log_error("Failed to parse device_string. It doesn't contain device"); + pa_xfree(d); + continue; + } + + if (parse_to_get_card(d, card, (const char *)d) < 0) { + pa_log_error("Failed to parse card"); + pa_xfree(d); + continue; + } + + if (pa_hal_interface_pcm_open(h, + card, + device, + param->direction, + param->ss, + param->period_size, + param->periods, + (void **)pcm_h)) { + pa_log_error("Failed to open PCM device (%s)", d); + pa_xfree(d); + continue; + } + + *rcard = pa_xstrdup(card); + *rdevice = pa_xstrdup(device); + + pa_log_debug("card(%s) device(%s) opened successfully", *rcard, *rdevice); + + pa_xfree(d); + + return 0; + } + + pa_log_error("Error opening PCM device"); + + return -1; +} + +int32_t pa_hal_interface_pcm_open_by_device(pa_hal_interface *h, + const char* dev, + pa_pcm_params *param, + pcm_handle *pcm_h, + char **rcard, + char **rdevice) { + char card[DEVICE_NAME_MAX]; + char device[DEVICE_NAME_MAX]; + + pa_assert(dev); + + pa_log_debug("Try to open device(%s)", dev); + + if (parse_to_get_device(dev, device, NULL) < 0) { + pa_log_error("Failed to parse device. dev(%s)", dev); + return -1; + } + + if (parse_to_get_card(dev, card, NULL) < 0) { + pa_log_error("Failed to parse card. dev(%s)", dev); + return -1; + } + + if (pa_hal_interface_pcm_open(h, + card, + device, + param->direction, + param->ss, + param->period_size, + param->periods, + (void **)pcm_h)) { + pa_log_error("Failed to open PCM device (%s) card(%s), device(%s)", dev, card, device); + return -1; + } + + *rcard = pa_xstrdup(card); + *rdevice = pa_xstrdup(device); + + pa_log_debug("card(%s) device(%s) opened successfully", *rcard, *rdevice); + + return 0; +} diff --git a/src/tizenaudio-util.h b/src/tizenaudio-util.h new file mode 100644 index 0000000..aa6d29e --- /dev/null +++ b/src/tizenaudio-util.h @@ -0,0 +1,55 @@ +#ifndef footizenaudioutilhfoo +#define footizenaudioutilhfoo + +/*** + This file is part of PulseAudio. + + Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +typedef struct pa_pcm_params pa_pcm_params; +struct pa_pcm_params { + io_direction_t direction; + pa_sample_spec *ss; + uint32_t period_size; + uint32_t periods; +}; + + +int32_t pa_hal_interface_pcm_open_by_dev_id(pa_hal_interface *h, + const char *dev_id, + char **device_string, + pa_pcm_params *param, + pcm_handle *pcm_h, + char **rcard, + char **rdevice); + +int32_t pa_hal_interface_pcm_open_by_device(pa_hal_interface *h, + const char* dev, + pa_pcm_params *param, + pcm_handle *pcm_h, + char **rcard, + char **rdevice); +#endif +