blob: 7490683512c38803651ac34b818e271b114ffb3f [file] [log] [blame]
Earl Ouedb71582016-11-29 15:59:57 +08001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
En-Shuo Hsuaa0a03d2021-04-12 20:06:24 +08005// Simple playback test drivers. Plays test tones using the Alsa defined
Earl Ouedb71582016-11-29 15:59:57 +08006// API allowing for configuration of volume, frequency, channels of output,
7// etc. See the output of PrintUsage() for instructions on how to use.
8
9#include <getopt.h>
Earl Ouedb71582016-11-29 15:59:57 +080010#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <set>
15#include <string>
16
Earl Ou7ae955b2016-11-30 16:41:22 +080017#include "include/alsa_client.h"
18#include "include/common.h"
Earl Ou06c1ad62016-12-01 17:21:50 +080019#include "include/sample_format.h"
Earl Ou7ae955b2016-11-30 16:41:22 +080020#include "include/tone_generators.h"
Earl Ouedb71582016-11-29 15:59:57 +080021
22static struct option long_options[] = {
23 {"test-type", 1, NULL, 't'},
24 {"alsa-device", 1, NULL, 'd'},
25 {"tone-length", 1, NULL, 'l'},
26 {"frequency", 1, NULL, 'h'},
27 {"format", 1, NULL, 'f'},
28 {"sample-rate", 1, NULL, 'r'},
29 {"start-volume", 1, NULL, 's'},
30 {"end-volume", 1, NULL, 'e'},
31 {"channels", 1, NULL, 'c'},
32 {"active-channels", 1, NULL, 'a'},
33};
34
Earl Ou7ae955b2016-11-30 16:41:22 +080035TestConfig::TestType ParseTestType(const char *option) {
Earl Ouedb71582016-11-29 15:59:57 +080036 if (strcmp(option, "scale") == 0) {
37 return TestConfig::kASharpMinorScale;
38 } else if (strcmp(option, "tone") == 0) {
39 return TestConfig::kSingleTone;
40 }
41 return TestConfig::kInvalid;
42}
43
Earl Ou7ae955b2016-11-30 16:41:22 +080044SampleFormat ParseFormat(const char *arg) {
Earl Ouedb71582016-11-29 15:59:57 +080045 if (strcmp(arg, "u8") == 0) {
46 return SampleFormat(SampleFormat::kPcmU8);
47 } else if (strcmp(arg, "s16") == 0) {
48 return SampleFormat(SampleFormat::kPcmS16);
49 } else if (strcmp(arg, "s24") == 0) {
50 return SampleFormat(SampleFormat::kPcmS24);
51 } else if (strcmp(arg, "s32") == 0) {
52 return SampleFormat(SampleFormat::kPcmS32);
53 } else {
54 return SampleFormat(SampleFormat::kPcmInvalid);
55 }
56}
57
Earl Ou7ae955b2016-11-30 16:41:22 +080058bool ParseOptions(int argc, char *argv[], TestConfig *config) {
Earl Ouedb71582016-11-29 15:59:57 +080059 int opt = 0;
60 int optindex = -1;
61 while ((opt = getopt_long(argc, argv, "t:d:l:f:h:r:s:e:c:a:",
62 long_options,
63 &optindex)) != -1) {
64 switch (opt) {
65 case 't':
66 config->type = ParseTestType(optarg);
67 break;
68
69 case 'd':
70 config->alsa_device = std::string(optarg);
71 break;
72
73 case 'l':
74 config->tone_length_sec = atof(optarg);
75 break;
76
77 case 'f':
78 config->format = ParseFormat(optarg);
79 break;
80
81 case 'h':
82 config->frequency = atof(optarg);
83 break;
84
85 case 'r':
86 config->sample_rate = atoi(optarg);
87 break;
88
89 case 's':
90 config->start_volume = atof(optarg);
91 break;
92
93 case 'e':
94 config->end_volume = atof(optarg);
95 break;
96
97 case 'c':
98 config->channels = atoi(optarg);
99 break;
100
101 case 'a':
102 ParseActiveChannels(optarg, &config->active_channels);
103 break;
104
105 default:
106 assert(false);
Earl Ou7ae955b2016-11-30 16:41:22 +0800107 }
Earl Ouedb71582016-11-29 15:59:57 +0800108 }
109
110 if (config->type == TestConfig::kInvalid) {
111 fprintf(stderr, "Test type must be \"scale\" or \"tone\"\n");
112 return false;
113 }
114
115 // Avoid overly short tones.
116 if (config->tone_length_sec < 0.01) {
117 fprintf(stderr, "Tone length too short. Must be 0.01s or greater.\n");
118 return false;
119 }
120
121 // Normalize the active channel set to explicitly list all channels.
122 if (config->active_channels.empty()) {
123 for (int i = 0; i < config->channels; ++i) {
124 config->active_channels.insert(i);
125 }
126 }
127
128 return true;
129}
130
Earl Ou7ae955b2016-11-30 16:41:22 +0800131void PrintUsage(FILE *out, const char *name) {
Earl Ouedb71582016-11-29 15:59:57 +0800132 TestConfig default_config;
133
134 fprintf(out, "Usage: %s [options]\n", name);
135 fprintf(out, "\t-t, --test-type: \"scale\" or \"tone\"\n");
136 fprintf(out, "\t-d, --alsa-device: "
137 "Name of alsa device to use (def %s).\n",
138 default_config.alsa_device.c_str());
139 fprintf(out,
140 "\t-l, --tone-length: "
141 "Decimal value of tone length in secs (def %0.2lf).\n",
142 default_config.tone_length_sec);
143 fprintf(out,
144 "\t-h, --frequency: "
145 "Tone frequency in HZ (def %0.2lf). Used if -T tone.\n",
146 default_config.frequency);
147 fprintf(out,
148 "\t-f, --format: "
149 "Sample format to use when talking to PA (def %s).\n",
150 default_config.format.to_string());
151 fprintf(out,
152 "\t-r, --sample-rate: "
153 "Sample rate of generated wave in HZ (def %d).\n",
154 default_config.sample_rate);
155 fprintf(out,
156 "\t-s, --start-volume: "
157 "Decimal value of start volume (def %0.2lf).\n",
158 default_config.start_volume);
159 fprintf(out,
160 "\t-e, --end-volume: "
161 "Decimal value of end volume (def %0.2lf).\n",
162 default_config.end_volume);
163 fprintf(out,
164 "\t-c, --channels: "
165 "The number of channels (def %d).\n",
166 default_config.channels);
167 fprintf(out,
168 "\t-a, --active-channels: "
169 "Comma-separated list of channels to play on. (def all channels)\n");
170 fprintf(out, "\nThe volume of the sample will be a linear ramp over the "
171 "duration of playback. The tone length, in scale mode, is the "
172 "length of each individual tone in the scale.\n\n");
173}
174
Earl Ou7ae955b2016-11-30 16:41:22 +0800175void PrintConfig(FILE *out, const TestConfig &config) {
Earl Ouedb71582016-11-29 15:59:57 +0800176 fprintf(out, "Config Values:\n");
177 if (config.type == TestConfig::kASharpMinorScale) {
178 fprintf(out, "\tType: A#Minor Scale\n");
179 } else if (config.type == TestConfig::kSingleTone) {
180 fprintf(out, "\tType: Single Tone\n");
181 fprintf(out, "\tFrequency: %0.2lf\n", config.frequency);
182 }
183
184 fprintf(out, "\tAlsa Device: %s\n", config.alsa_device.c_str());
185 fprintf(out, "\tFormat: %s\n", config.format.to_string());
186 fprintf(out, "\tTone Length (sec): %0.2lf\n", config.tone_length_sec);
187 fprintf(out, "\tSample Rate (HZ): %d\n", config.sample_rate);
188 fprintf(out, "\tStart Volume (0-1.0): %0.2lf\n", config.start_volume);
189 fprintf(out, "\tEnd Volume (0-1.0): %0.2lf\n", config.end_volume);
190 fprintf(out, "\tChannels: %d\n", config.channels);
191
192 fprintf(out, "\tActive Channels: ");
193 for (std::set<int>::const_iterator it = config.active_channels.begin();
194 it != config.active_channels.end();
195 ++it) {
196 fprintf(out, "%d ", *it);
197 }
198 fprintf(out, "\n");
199}
200
Earl Ou7ae955b2016-11-30 16:41:22 +0800201int main(int argc, char *argv[]) {
Earl Ouedb71582016-11-29 15:59:57 +0800202 TestConfig config;
203
204 if (!ParseOptions(argc, argv, &config)) {
205 fprintf(stderr, "\n"); // Newline before usage.
206 PrintUsage(stderr, argv[0]);
207 return 1;
208 }
209
210 PrintConfig(stdout, config);
211
212 AlsaPlaybackClient client(config.alsa_device);
213 if (!client.Init(config.sample_rate,
214 config.format,
215 config.channels,
216 &config.active_channels)) {
217 fprintf(stderr, "Unable to initialize Alsa: %d\n",
218 client.last_error());
219 return 1;
220 }
221
222 if (config.type == TestConfig::kASharpMinorScale) {
223 ASharpMinorGenerator scale_generator(config.sample_rate,
224 config.tone_length_sec);
225 scale_generator.SetVolumes(config.start_volume, config.end_volume);
226 client.SetPlayObj(&scale_generator);
227 client.PlayTones();
228 } else {
229 MultiToneGenerator tone_generator(config.sample_rate,
230 config.tone_length_sec);
231 tone_generator.SetVolumes(config.start_volume, config.end_volume);
232 tone_generator.Reset(config.frequency);
233 client.SetPlayObj(&tone_generator);
234 client.PlayTones();
235 }
236
237 return 0;
238}