1/*
2**
3** Copyright 2016, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18package com.android.commands.media;
19
20import android.content.Context;
21import android.media.AudioManager;
22import android.media.AudioSystem;
23import android.media.IAudioService;
24import android.os.ServiceManager;
25import android.util.AndroidException;
26
27import com.android.internal.os.BaseCommand;
28
29import java.io.BufferedReader;
30import java.io.IOException;
31import java.io.InputStreamReader;
32import java.io.PrintStream;
33import java.lang.ArrayIndexOutOfBoundsException;
34
35/**
36 * Command line tool to exercise AudioService.setStreamVolume()
37 *                           and AudioService.adjustStreamVolume()
38 */
39public class VolumeCtrl {
40
41    private final static String TAG = "VolumeCtrl";
42
43    // --stream affects --set, --adj or --get options.
44    // --show affects --set and --adj options.
45    // --get can be used with --set, --adj or by itself.
46    public final static String USAGE = new String(
47            "the options are as follows: \n" +
48            "\t\t--stream STREAM selects the stream to control, see AudioManager.STREAM_*\n" +
49            "\t\t                controls AudioManager.STREAM_MUSIC if no stream is specified\n"+
50            "\t\t--set INDEX     sets the volume index value\n" +
51            "\t\t--adj DIRECTION adjusts the volume, use raise|same|lower for the direction\n" +
52            "\t\t--get           outputs the current volume\n" +
53            "\t\t--show          shows the UI during the volume change\n" +
54            "\texamples:\n" +
55            "\t\tadb shell media volume --show --stream 3 --set 11\n" +
56            "\t\tadb shell media volume --stream 0 --adj lower\n" +
57            "\t\tadb shell media volume --stream 3 --get\n"
58            );
59
60    private final static int VOLUME_CONTROL_MODE_SET = 1;
61    private final static int VOLUME_CONTROL_MODE_ADJUST = 2;
62
63    private final static String ADJUST_LOWER = "lower";
64    private final static String ADJUST_SAME = "same";
65    private final static String ADJUST_RAISE = "raise";
66
67    public static void run(BaseCommand cmd) throws Exception {
68        //----------------------------------------
69        // Default parameters
70        int stream = AudioManager.STREAM_MUSIC;
71        int volIndex = 5;
72        int mode = 0;
73        int adjDir = AudioManager.ADJUST_RAISE;
74        boolean showUi = false;
75        boolean doGet = false;
76
77        //----------------------------------------
78        // read options
79        String option;
80        String adjustment = null;
81        while ((option = cmd.nextOption()) != null) {
82            switch (option) {
83                case "--show":
84                    showUi = true;
85                    break;
86                case "--get":
87                    doGet = true;
88                    log(LOG_V, "will get volume");
89                    break;
90                case "--stream":
91                    stream = Integer.decode(cmd.nextArgRequired()).intValue();
92                    log(LOG_V, "will control stream=" + stream + " (" + streamName(stream) + ")");
93                    break;
94                case "--set":
95                    volIndex = Integer.decode(cmd.nextArgRequired()).intValue();
96                    mode = VOLUME_CONTROL_MODE_SET;
97                    log(LOG_V, "will set volume to index=" + volIndex);
98                    break;
99                case "--adj":
100                    mode = VOLUME_CONTROL_MODE_ADJUST;
101                    adjustment = cmd.nextArgRequired();
102                    log(LOG_V, "will adjust volume");
103                    break;
104                default:
105                    throw new IllegalArgumentException("Unknown argument " + option);
106            }
107        }
108
109        //------------------------------
110        // Read options: validation
111        if (mode == VOLUME_CONTROL_MODE_ADJUST) {
112            if (adjustment == null) {
113                cmd.showError("Error: no valid volume adjustment (null)");
114                return;
115            }
116            switch (adjustment) {
117                case ADJUST_RAISE: adjDir = AudioManager.ADJUST_RAISE; break;
118                case ADJUST_SAME: adjDir = AudioManager.ADJUST_SAME; break;
119                case ADJUST_LOWER: adjDir = AudioManager.ADJUST_LOWER; break;
120                default:
121                    cmd.showError("Error: no valid volume adjustment, was " + adjustment
122                            + ", expected " + ADJUST_LOWER + "|" + ADJUST_SAME + "|"
123                            + ADJUST_RAISE);
124                    return;
125            }
126        }
127
128        //----------------------------------------
129        // Test initialization
130        log(LOG_V, "Connecting to AudioService");
131        IAudioService audioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
132                Context.AUDIO_SERVICE));
133        if (audioService == null) {
134            System.err.println(BaseCommand.NO_SYSTEM_ERROR_CODE);
135            throw new AndroidException(
136                    "Can't connect to audio service; is the system running?");
137        }
138
139        if (mode == VOLUME_CONTROL_MODE_SET) {
140            if ((volIndex > audioService.getStreamMaxVolume(stream))
141                    || (volIndex < audioService.getStreamMinVolume(stream))) {
142                cmd.showError(String.format("Error: invalid volume index %d for stream %d "
143                        + "(should be in [%d..%d])", volIndex, stream,
144                        audioService.getStreamMinVolume(stream),
145                        audioService.getStreamMaxVolume(stream)));
146                return;
147            }
148        }
149
150        //----------------------------------------
151        // Non-interactive test
152        final int flag = showUi? AudioManager.FLAG_SHOW_UI : 0;
153        final String pack = cmd.getClass().getPackage().getName();
154        if (mode == VOLUME_CONTROL_MODE_SET) {
155            audioService.setStreamVolume(stream, volIndex, flag, pack/*callingPackage*/);
156        } else if (mode == VOLUME_CONTROL_MODE_ADJUST) {
157            audioService.adjustStreamVolume(stream, adjDir, flag, pack);
158        }
159        if (doGet) {
160            log(LOG_V, "volume is " + audioService.getStreamVolume(stream) +
161                       " in range [" + audioService.getStreamMinVolume(stream) +
162                       ".." + audioService.getStreamMaxVolume(stream) + "]");
163        }
164    }
165
166    //--------------------------------------------
167    // Utilities
168
169    static final String LOG_V = "[v]";
170    static final String LOG_W = "[w]";
171    static final String LOG_OK = "[ok]";
172
173    static void log(String code, String msg) {
174        System.out.println(code + " " + msg);
175    }
176
177    static String streamName(int stream) {
178        try {
179            return AudioSystem.STREAM_NAMES[stream];
180        } catch (ArrayIndexOutOfBoundsException e) {
181            return "invalid stream";
182        }
183    }
184
185}
186