~ubuntu-branches/ubuntu/trusty/alsa-utils/trusty

« back to all changes in this revision

Viewing changes to alsactl/alsactl.c

  • Committer: Package Import Robot
  • Author(s): Luke Yelavich
  • Date: 2013-07-26 10:56:44 UTC
  • mfrom: (1.2.17) (93.1.1 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130726105644-kim9enke2jnozg73
Tags: 1.0.27.1-1ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Move init script volume settings to new alsactl database:
    + Set sane level for 'Speaker' and 'Headphone', needed for Dell Mini 9
      and Dell E series
    + ute PC Beep on hda cards that support it during initial volume setup
    + Mute *Analog/Digital Control for Creative cards by default
    + Default Digital Input Source to be Digital Mic 1 so that users
      with digital mic will be able to use it out of the box
    + Mute "IEC958 Optical Raw" by default
    + Set sane level for headphone 1 for Dell Studio XPS with 2.6.30
    + Prefer built-in digital mics on newer Dells
    + Unmute 'Line HP Swap' for Dove boards
    + Set reasonable volume levels for VMWare guests using snd.ens1371
  - debian/README.init.cs4236: Include in /usr/share/doc/alsa-utils so that
    users of snd-cs4236 (e.g., ThinkPad 600) can have audible sound
  - debian/patches/unset_pulse_internal.patch: We don't want alsamixer to
    show the pulse mixer by default, since it can be controlled from
    pulseaudio itself
  - Use upstart jobs for storing/restoring card settings
  - Add udev rule to apply UCM profiles for panda and equivalent hardware
  - Add Vcs-Bzr field
* Create a new upstart job for the alsa state daemon, and adjust the
  other upstart jobs accordingly
* Put the daemon file in /var/lib/alsa

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <stdio.h>
28
28
#include <assert.h>
29
29
#include <errno.h>
 
30
#include <syslog.h>
 
31
#include <sched.h>
30
32
#include <alsa/asoundlib.h>
31
33
#include "alsactl.h"
32
34
 
33
35
#ifndef SYS_ASOUNDRC
34
36
#define SYS_ASOUNDRC "/var/lib/alsa/asound.state"
35
37
#endif
 
38
#ifndef SYS_PIDFILE
 
39
#define SYS_PIDFILE "/var/run/alsactl.pid"
 
40
#endif
36
41
 
37
42
int debugflag = 0;
38
43
int force_restore = 1;
39
44
int ignore_nocards = 0;
 
45
int do_lock = 0;
 
46
int use_syslog = 0;
40
47
char *command;
41
48
char *statefile = NULL;
42
49
 
 
50
#define TITLE   0x0100
 
51
#define HEADER  0x0200
 
52
#define FILEARG 0x0400
 
53
#define ENVARG  0x0800
 
54
#define INTARG  0x1000
 
55
#define EMPCMD  0x2000
 
56
#define CARDCMD 0x4000
 
57
#define KILLCMD 0x8000
 
58
 
 
59
struct arg {
 
60
        int sarg;
 
61
        char *larg;
 
62
        char *comment;
 
63
};
 
64
 
 
65
static struct arg args[] = {
 
66
{ TITLE, NULL, "Usage: alsactl <options> command" },
 
67
{ HEADER, NULL, "global options:" },
 
68
{ 'h', "help", "this help" },
 
69
{ 'd', "debug", "debug mode" },
 
70
{ 'v', "version", "print version of this program" },
 
71
{ HEADER, NULL, "Available state options:" },
 
72
{ FILEARG | 'f', "file", "configuration file (default " SYS_ASOUNDRC ")" },
 
73
{ 'l', "lock", "use file locking to serialize concurrent access" },
 
74
{ 'F', "force", "try to restore the matching controls as much as possible" },
 
75
{ 0, NULL, "  (default mode)" },
 
76
{ 'g', "ignore", "ignore 'No soundcards found' error" },
 
77
{ 'P', "pedantic", "do not restore mismatching controls (old default)" },
 
78
{ 'I', "no-init-fallback", "" },
 
79
{ 0, NULL, "don't initialize even if restore fails" },
 
80
{ FILEARG | 'r', "runstate", "save restore and init state to this file (only errors)" },
 
81
{ 0, NULL, "  default settings is 'no file set'" },
 
82
{ 'R', "remove", "remove runstate file at first, otherwise append errors" },
 
83
{ INTARG | 'p', "period", "store period in seconds for the daemon command" },
 
84
{ FILEARG | 'e', "pid-file", "pathname for the process id (daemon mode)" },
 
85
{ HEADER, NULL, "Available init options:" },
 
86
{ ENVARG | 'E', "env", "set environment variable for init phase (NAME=VALUE)" },
 
87
{ FILEARG | 'i', "initfile", "main configuation file for init phase" },
 
88
{ 0, NULL, "  (default " DATADIR "/init/00main)" },
 
89
{ 'b', "background", "run daemon in background" },
 
90
{ 's', "syslog", "use syslog for messages" },
 
91
{ INTARG | 'n', "nice", "set the process priority (see 'man nice')" },
 
92
{ 'c', "sched-idle", "set the process scheduling policy to idle (SCHED_IDLE)" },
 
93
{ HEADER, NULL, "Available commands:" },
 
94
{ CARDCMD, "store", "save current driver setup for one or each soundcards" },
 
95
{ EMPCMD, NULL, "  to configuration file" },
 
96
{ CARDCMD, "restore", "load current driver setup for one or each soundcards" },
 
97
{ EMPCMD, NULL, "  from configuration file" },
 
98
{ CARDCMD, "nrestore", "like restore, but notify the daemon to rescan soundcards" },
 
99
{ CARDCMD, "init", "initialize driver to a default state" },
 
100
{ CARDCMD, "daemon", "store state periodically for one or each soundcards" },
 
101
{ CARDCMD, "rdaemon", "like daemon but do the state restore at first" },
 
102
{ KILLCMD, "kill", "notify daemon to quit, rescan or save_and_quit" },
 
103
{ 0, NULL, NULL }
 
104
};
 
105
 
43
106
static void help(void)
44
107
{
45
 
        printf("Usage: alsactl <options> command\n");
46
 
        printf("\nAvailable global options:\n");
47
 
        printf("  -h,--help        this help\n");
48
 
        printf("  -d,--debug       debug mode\n");
49
 
        printf("  -v,--version     print version of this program\n");
50
 
        printf("\nAvailable state options:\n");
51
 
        printf("  -f,--file #      configuration file (default " SYS_ASOUNDRC ")\n");
52
 
        printf("  -F,--force       try to restore the matching controls as much as possible\n");
53
 
        printf("                   (default mode)\n");
54
 
        printf("  -g,--ignore      ignore 'No soundcards found' error\n");
55
 
        printf("  -P,--pedantic    do not restore mismatching controls (old default)\n");
56
 
        printf("  -I,--no-init-fallback\n"
57
 
               "                   don't initialize even if restore fails\n");
58
 
        printf("  -r,--runstate #  save restore and init state to this file (only errors)\n");
59
 
        printf("                   default settings is 'no file set'\n");
60
 
        printf("  -R,--remove      remove runstate file at first, otherwise append errors\n");
61
 
        printf("\nAvailable init options:\n");
62
 
        printf("  -E,--env #=#     set environment variable for init phase (NAME=VALUE)\n");
63
 
        printf("  -i,--initfile #  main configuation file for init phase (default " DATADIR "/init/00main)\n");
64
 
        printf("\n");
65
 
        printf("\nAvailable commands:\n");
66
 
        printf("  store   <card #> save current driver setup for one or each soundcards\n");
67
 
        printf("                   to configuration file\n");
68
 
        printf("  restore <card #> load current driver setup for one or each soundcards\n");
69
 
        printf("                   from configuration file\n");
70
 
        printf("  init    <card #> initialize driver to a default state\n");
 
108
        struct arg *n = args, *a;
 
109
        char *larg, sa[4], buf[32];
 
110
        int sarg;
 
111
 
 
112
        sa[0] = '-';
 
113
        sa[2] = ',';
 
114
        sa[3] = '\0';
 
115
        while (n->comment) {
 
116
                a = n;
 
117
                n++;
 
118
                sarg = a->sarg;
 
119
                if (sarg & (HEADER|TITLE)) {
 
120
                        printf("%s%s\n", (sarg & HEADER) != 0 ? "\n" : "",
 
121
                                                                a->comment);
 
122
                        continue;
 
123
                }
 
124
                buf[0] = '\0';
 
125
                larg = a->larg;
 
126
                if (sarg & (EMPCMD|CARDCMD|KILLCMD)) {
 
127
                        if (sarg & CARDCMD)
 
128
                                strcat(buf, "<card>");
 
129
                        else if (sarg & KILLCMD)
 
130
                                strcat(buf, "<cmd>");
 
131
                        printf("  %-8s  %-6s  %s\n", larg ? larg : "",
 
132
                                                        buf, a->comment);
 
133
                        continue;
 
134
                }
 
135
                sa[1] = a->sarg;
 
136
                sprintf(buf, "%s%s%s", sa[1] ? sa : "",
 
137
                                larg ? "--" : "", larg ? larg : "");
 
138
                if (sarg & ENVARG)
 
139
                        strcat(buf, " #=#");
 
140
                else if (sarg & (FILEARG|INTARG))
 
141
                        strcat(buf, " #");
 
142
                printf("  %-15s  %s\n", buf, a->comment);
 
143
        }
 
144
}
 
145
 
 
146
#define NO_NICE (-100000)
 
147
 
 
148
static void do_nice(int use_nice, int sched_idle)
 
149
{
 
150
        struct sched_param sched_param;
 
151
 
 
152
        if (use_nice != NO_NICE && nice(use_nice) < 0)
 
153
                error("nice(%i): %s", use_nice, strerror(errno));
 
154
        if (sched_idle) {
 
155
                if (sched_getparam(0, &sched_param) >= 0) {
 
156
                        sched_param.sched_priority = 0;
 
157
                        if (!sched_setscheduler(0, SCHED_RR, &sched_param))
 
158
                                error("sched_setparam failed: %s", strerror(errno));
 
159
                } else {
 
160
                        error("sched_getparam failed: %s", strerror(errno));
 
161
                }
 
162
        }
71
163
}
72
164
 
73
165
int main(int argc, char *argv[])
74
166
{
75
 
        static const struct option long_option[] =
76
 
        {
77
 
                {"help", 0, NULL, 'h'},
78
 
                {"file", 1, NULL, 'f'},
79
 
                {"env", 1, NULL, 'E'},
80
 
                {"initfile", 1, NULL, 'i'},
81
 
                {"no-init-fallback", 0, NULL, 'I'},
82
 
                {"force", 0, NULL, 'F'},
83
 
                {"ignore", 0, NULL, 'g'},
84
 
                {"pedantic", 0, NULL, 'P'},
85
 
                {"runstate", 0, NULL, 'r'},
86
 
                {"remove", 0, NULL, 'R'},
87
 
                {"debug", 0, NULL, 'd'},
88
 
                {"version", 0, NULL, 'v'},
89
 
                {NULL, 0, NULL, 0},
90
 
        };
91
167
        static const char *const devfiles[] = {
92
168
                "/dev/snd/controlC",
93
169
                "/dev/snd/pcmC",
97
173
        };
98
174
        char *cfgfile = SYS_ASOUNDRC;
99
175
        char *initfile = DATADIR "/init/00main";
 
176
        char *pidfile = SYS_PIDFILE;
100
177
        char *cardname, ncardname[16];
 
178
        char *cmd;
101
179
        const char *const *tmp;
102
180
        int removestate = 0;
103
181
        int init_fallback = 1; /* new default behavior */
104
 
        int res;
 
182
        int period = 5*60;
 
183
        int background = 0;
 
184
        int daemoncmd = 0;
 
185
        int use_nice = NO_NICE;
 
186
        int sched_idle = 0;
 
187
        struct arg *a;
 
188
        struct option *o;
 
189
        int i, j, k, res;
 
190
        struct option *long_option;
 
191
        char *short_option;
105
192
 
 
193
        long_option = calloc(ARRAY_SIZE(args), sizeof(struct option));
 
194
        if (long_option == NULL)
 
195
                exit(EXIT_FAILURE);
 
196
        short_option = malloc(128);
 
197
        if (short_option == NULL) {
 
198
                free(long_option);
 
199
                exit(EXIT_FAILURE);
 
200
        }
 
201
        for (i = j = k = 0; i < ARRAY_SIZE(args); i++) {
 
202
                a = &args[i];
 
203
                if ((a->sarg & 0xff) == 0)
 
204
                        continue;
 
205
                o = &long_option[j];
 
206
                o->name = a->larg;
 
207
                o->has_arg = (a->sarg & (ENVARG|FILEARG|INTARG)) != 0;
 
208
                o->flag = NULL;
 
209
                o->val = a->sarg & 0xff;
 
210
                j++;
 
211
                short_option[k++] = o->val;
 
212
                if (o->has_arg)
 
213
                        short_option[k++] = ':';
 
214
        }
 
215
        short_option[k] = '\0';
106
216
        command = argv[0];
107
217
        while (1) {
108
218
                int c;
109
219
 
110
 
                if ((c = getopt_long(argc, argv, "hdvf:FgE:i:IPr:R", long_option, NULL)) < 0)
 
220
                if ((c = getopt_long(argc, argv, short_option, long_option,
 
221
                                                                  NULL)) < 0)
111
222
                        break;
112
223
                switch (c) {
113
224
                case 'h':
114
225
                        help();
115
 
                        return EXIT_SUCCESS;
 
226
                        res = EXIT_SUCCESS;
 
227
                        goto out;
116
228
                case 'f':
117
229
                        cfgfile = optarg;
118
230
                        break;
 
231
                case 'l':
 
232
                        do_lock = 1;
 
233
                        break;
119
234
                case 'F':
120
235
                        force_restore = 1;
121
236
                        break;
125
240
                case 'E':
126
241
                        if (putenv(optarg)) {
127
242
                                fprintf(stderr, "environment string '%s' is wrong\n", optarg);
128
 
                                return EXIT_FAILURE;
 
243
                                res = EXIT_FAILURE;
 
244
                                goto out;
129
245
                        }
130
246
                        break;
131
247
                case 'i':
143
259
                case 'P':
144
260
                        force_restore = 0;
145
261
                        break;
 
262
                case 'p':
 
263
                        period = atoi(optarg);
 
264
                        if (period < 10)
 
265
                                period = 5*60;
 
266
                        else if (period > 24*60*60)
 
267
                                period = 24*60*60;
 
268
                        break;
 
269
                case 'e':
 
270
                        pidfile = optarg;
 
271
                        break;
 
272
                case 'b':
 
273
                        background = 1;
 
274
                        break;
 
275
                case 's':
 
276
                        use_syslog = 1;
 
277
                        break;
 
278
                case 'n':
 
279
                        use_nice = atoi(optarg);
 
280
                        if (use_nice < -20)
 
281
                                use_nice = -20;
 
282
                        else if (use_nice > 19)
 
283
                                use_nice = 19;
 
284
                        break;
 
285
                case 'c':
 
286
                        sched_idle = 1;
 
287
                        break;
146
288
                case 'd':
147
289
                        debugflag = 1;
148
290
                        break;
149
291
                case 'v':
150
292
                        printf("alsactl version " SND_UTIL_VERSION_STR "\n");
151
 
                        return EXIT_SUCCESS;
 
293
                        res = EXIT_SUCCESS;
 
294
                        goto out;
152
295
                case '?':               // error msg already printed
153
296
                        help();
154
 
                        return EXIT_FAILURE;
155
 
                        break;
 
297
                        res = EXIT_FAILURE;
 
298
                        goto out;
156
299
                default:                // should never happen
157
300
                        fprintf(stderr, 
158
301
                        "Invalid option '%c' (%d) not handled??\n", c, c);
159
302
                }
160
303
        }
 
304
        free(short_option);
 
305
        short_option = NULL;
 
306
        free(long_option);
 
307
        long_option = NULL;
161
308
        if (argc - optind <= 0) {
162
309
                fprintf(stderr, "alsactl: Specify command...\n");
163
 
                return 0;
 
310
                res = 0;
 
311
                goto out;
164
312
        }
165
313
 
166
314
        cardname = argc - optind > 1 ? argv[optind + 1] : NULL;
174
322
                }
175
323
        }
176
324
 
177
 
        if (!strcmp(argv[optind], "init")) {
 
325
        /* the global system file should be always locked */
 
326
        if (strcmp(cfgfile, SYS_ASOUNDRC) == 0)
 
327
                do_lock = 1;
 
328
 
 
329
        /* when running in background, use syslog for reports */
 
330
        if (background) {
 
331
                use_syslog = 1;
 
332
                daemon(0, 0);
 
333
        }
 
334
 
 
335
        cmd = argv[optind];
 
336
        daemoncmd = strcmp(cmd, "daemon") == 0 || strcmp(cmd, "rdaemon") == 0;
 
337
 
 
338
        if (use_syslog) {
 
339
                openlog("alsactl", LOG_CONS|LOG_PID, LOG_DAEMON);
 
340
                if (daemoncmd)
 
341
                        syslog(LOG_INFO, "alsactl " SND_UTIL_VERSION_STR " daemon started");
 
342
        }
 
343
 
 
344
        if (!strcmp(cmd, "init")) {
178
345
                res = init(initfile, cardname);
179
 
        } else if (!strcmp(argv[optind], "store")) {
 
346
                snd_config_update_free_global();
 
347
        } else if (!strcmp(cmd, "store")) {
180
348
                res = save_state(cfgfile, cardname);
181
 
        } else if (!strcmp(argv[optind], "restore")) {
 
349
        } else if (!strcmp(cmd, "restore") ||
 
350
                   !strcmp(cmd, "rdaemon") ||
 
351
                   !strcmp(cmd, "nrestore")) {
182
352
                if (removestate)
183
353
                        remove(statefile);
184
354
                res = load_state(cfgfile, initfile, cardname, init_fallback);
 
355
                if (!strcmp(cmd, "rdaemon")) {
 
356
                        do_nice(use_nice, sched_idle);
 
357
                        res = state_daemon(cfgfile, cardname, period, pidfile);
 
358
                }
 
359
                if (!strcmp(cmd, "nrestore"))
 
360
                        res = state_daemon_kill(pidfile, "rescan");
 
361
        } else if (!strcmp(cmd, "daemon")) {
 
362
                do_nice(use_nice, sched_idle);
 
363
                res = state_daemon(cfgfile, cardname, period, pidfile);
 
364
        } else if (!strcmp(cmd, "kill")) {
 
365
                res = state_daemon_kill(pidfile, cardname);
185
366
        } else {
186
 
                fprintf(stderr, "alsactl: Unknown command '%s'...\n", 
187
 
                        argv[optind]);
 
367
                fprintf(stderr, "alsactl: Unknown command '%s'...\n", cmd);
188
368
                res = -ENODEV;
189
369
        }
190
370
 
191
371
        snd_config_update_free_global();
 
372
        if (use_syslog) {
 
373
                if (daemoncmd)
 
374
                        syslog(LOG_INFO, "alsactl daemon stopped");
 
375
                closelog();
 
376
        }
192
377
        return res < 0 ? -res : 0;
 
378
 
 
379
out:
 
380
        free(short_option);
 
381
        free(long_option);
 
382
        return res;
193
383
}