aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Hung2014-03-26 20:29:07 -0500
committerAndy Hung2014-03-26 20:29:07 -0500
commit70530a69767a9a383c5bf546e6e803aac08a5a1e (patch)
tree71ae738911eb35f036d480145a96eb8ea411e4d6
parenta5b44d9bba0c5df52b37850bb929eb53817fb4a4 (diff)
downloadplatform-external-tinyalsa-70530a69767a9a383c5bf546e6e803aac08a5a1e.tar.gz
platform-external-tinyalsa-70530a69767a9a383c5bf546e6e803aac08a5a1e.tar.xz
platform-external-tinyalsa-70530a69767a9a383c5bf546e6e803aac08a5a1e.zip
Add pcm_params string conversion and format checking
Change-Id: I93415bd1a88ff0feaf14af3daf48e00dd1990176 Signed-off-by: Andy Hung <hunga@google.com>
-rw-r--r--include/tinyalsa/asoundlib.h17
-rw-r--r--pcm.c159
2 files changed, 175 insertions, 1 deletions
diff --git a/include/tinyalsa/asoundlib.h b/include/tinyalsa/asoundlib.h
index 03e3c13..1083dba 100644
--- a/include/tinyalsa/asoundlib.h
+++ b/include/tinyalsa/asoundlib.h
@@ -158,12 +158,27 @@ struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
158void pcm_params_free(struct pcm_params *pcm_params); 158void pcm_params_free(struct pcm_params *pcm_params);
159 159
160struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params, 160struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
161 enum pcm_param param); 161 enum pcm_param param);
162unsigned int pcm_params_get_min(struct pcm_params *pcm_params, 162unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
163 enum pcm_param param); 163 enum pcm_param param);
164unsigned int pcm_params_get_max(struct pcm_params *pcm_params, 164unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
165 enum pcm_param param); 165 enum pcm_param param);
166 166
167/* Converts the pcm parameters to a human readable string.
168 * The string parameter is a caller allocated buffer of size bytes,
169 * which is then filled up to size - 1 and null terminated,
170 * if size is greater than zero.
171 * The return value is the number of bytes copied to string
172 * (not including null termination) if less than size; otherwise,
173 * the number of bytes required for the buffer.
174 */
175int pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size);
176
177/* Returns 1 if the pcm_format is present (format bit set) in
178 * the pcm_params structure; 0 otherwise, or upon unrecognized format.
179 */
180int pcm_params_format_test(struct pcm_params *params, enum pcm_format format);
181
167/* Set and get config */ 182/* Set and get config */
168int pcm_get_config(struct pcm *pcm, struct pcm_config *config); 183int pcm_get_config(struct pcm *pcm, struct pcm_config *config);
169int pcm_set_config(struct pcm *pcm, struct pcm_config *config); 184int pcm_set_config(struct pcm *pcm, struct pcm_config *config);
diff --git a/pcm.c b/pcm.c
index 7c05a87..5ec68ec 100644
--- a/pcm.c
+++ b/pcm.c
@@ -51,6 +51,84 @@
51#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL 51#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
52#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) 52#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2)
53 53
54/* Logs information into a string; follows snprintf() in that
55 * offset may be greater than size, and though no characters are copied
56 * into string, characters are still counted into offset. */
57#define STRLOG(string, offset, size, ...) \
58 do { int temp, clipoffset = offset > size ? size : offset; \
59 temp = snprintf(string + clipoffset, size - clipoffset, __VA_ARGS__); \
60 if (temp > 0) offset += temp; } while (0)
61
62#ifndef ARRAY_SIZE
63#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
64#endif
65
66/* refer to SNDRV_PCM_ACCESS_##index in sound/asound.h. */
67static const char * const access_lookup[] = {
68 "MMAP_INTERLEAVED",
69 "MMAP_NONINTERLEAVED",
70 "MMAP_COMPLEX",
71 "RW_INTERLEAVED",
72 "RW_NONINTERLEAVED",
73};
74
75/* refer to SNDRV_PCM_FORMAT_##index in sound/asound.h. */
76static const char * const format_lookup[] = {
77 /*[0] =*/ "S8",
78 "U8",
79 "S16_LE",
80 "S16_BE",
81 "U16_LE",
82 "U16_BE",
83 "S24_LE",
84 "S24_BE",
85 "U24_LE",
86 "U24_BE",
87 "S32_LE",
88 "S32_BE",
89 "U32_LE",
90 "U32_BE",
91 "FLOAT_LE",
92 "FLOAT_BE",
93 "FLOAT64_LE",
94 "FLOAT64_BE",
95 "IEC958_SUBFRAME_LE",
96 "IEC958_SUBFRAME_BE",
97 "MU_LAW",
98 "A_LAW",
99 "IMA_ADPCM",
100 "MPEG",
101 /*[24] =*/ "GSM",
102 /* gap */
103 [31] = "SPECIAL",
104 "S24_3LE",
105 "S24_3BE",
106 "U24_3LE",
107 "U24_3BE",
108 "S20_3LE",
109 "S20_3BE",
110 "U20_3LE",
111 "U20_3BE",
112 "S18_3LE",
113 "S18_3BE",
114 "U18_3LE",
115 /*[43] =*/ "U18_3BE",
116#if 0
117 /* recent additions, may not be present on local asound.h */
118 "G723_24",
119 "G723_24_1B",
120 "G723_40",
121 "G723_40_1B",
122 "DSD_U8",
123 "DSD_U16_LE",
124#endif
125};
126
127/* refer to SNDRV_PCM_SUBFORMAT_##index in sound/asound.h. */
128static const char * const subformat_lookup[] = {
129 "STD",
130};
131
54static inline int param_is_mask(int p) 132static inline int param_is_mask(int p)
55{ 133{
56 return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && 134 return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@@ -611,6 +689,87 @@ unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
611 return param_get_max(params, p); 689 return param_get_max(params, p);
612} 690}
613 691
692static int pcm_mask_test(struct pcm_mask *m, unsigned int index)
693{
694 const unsigned int bitshift = 5; /* for 32 bit integer */
695 const unsigned int bitmask = (1 << bitshift) - 1;
696 unsigned int element;
697
698 element = index >> bitshift;
699 if (element >= ARRAY_SIZE(m->bits))
700 return 0; /* for safety, but should never occur */
701 return (m->bits[element] >> (index & bitmask)) & 1;
702}
703
704static int pcm_mask_to_string(struct pcm_mask *m, char *string, unsigned int size,
705 char *mask_name,
706 const char * const *bit_array_name, size_t bit_array_size)
707{
708 unsigned int i;
709 unsigned int offset = 0;
710
711 if (m == NULL)
712 return 0;
713 if (bit_array_size < 32) {
714 STRLOG(string, offset, size, "%12s:\t%#08x\n", mask_name, m->bits[0]);
715 } else { /* spans two or more bitfields, print with an array index */
716 for (i = 0; i < (bit_array_size + 31) >> 5; ++i) {
717 STRLOG(string, offset, size, "%9s[%d]:\t%#08x\n",
718 mask_name, i, m->bits[i]);
719 }
720 }
721 for (i = 0; i < bit_array_size; ++i) {
722 if (pcm_mask_test(m, i)) {
723 STRLOG(string, offset, size, "%12s \t%s\n", "", bit_array_name[i]);
724 }
725 }
726 return offset;
727}
728
729int pcm_params_to_string(struct pcm_params *params, char *string, unsigned int size)
730{
731 struct pcm_mask *m;
732 unsigned int min, max;
733 unsigned int clipoffset, offset;
734
735 m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
736 offset = pcm_mask_to_string(m, string, size,
737 "Access", access_lookup, ARRAY_SIZE(access_lookup));
738 m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
739 clipoffset = offset > size ? size : offset;
740 offset += pcm_mask_to_string(m, string + clipoffset, size - clipoffset,
741 "Format", format_lookup, ARRAY_SIZE(format_lookup));
742 m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
743 clipoffset = offset > size ? size : offset;
744 offset += pcm_mask_to_string(m, string + clipoffset, size - clipoffset,
745 "Subformat", subformat_lookup, ARRAY_SIZE(subformat_lookup));
746 min = pcm_params_get_min(params, PCM_PARAM_RATE);
747 max = pcm_params_get_max(params, PCM_PARAM_RATE);
748 STRLOG(string, offset, size, " Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
749 min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
750 max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
751 STRLOG(string, offset, size, " Channels:\tmin=%u\t\tmax=%u\n", min, max);
752 min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
753 max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
754 STRLOG(string, offset, size, " Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
755 min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
756 max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
757 STRLOG(string, offset, size, " Period size:\tmin=%u\t\tmax=%u\n", min, max);
758 min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
759 max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
760 STRLOG(string, offset, size, "Period count:\tmin=%u\t\tmax=%u\n", min, max);
761 return offset;
762}
763
764int pcm_params_format_test(struct pcm_params *params, enum pcm_format format)
765{
766 unsigned int alsa_format = pcm_format_to_alsa(format);
767
768 if (alsa_format == SNDRV_PCM_FORMAT_S16_LE && format != PCM_FORMAT_S16_LE)
769 return 0; /* caution: format not recognized is equivalent to S16_LE */
770 return pcm_mask_test(pcm_params_get_mask(params, PCM_PARAM_FORMAT), alsa_format);
771}
772
614int pcm_close(struct pcm *pcm) 773int pcm_close(struct pcm *pcm)
615{ 774{
616 if (pcm == &bad_pcm) 775 if (pcm == &bad_pcm)