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 
18 package com.android.commands.media;
19 
20 import android.content.Context;
21 import android.media.AudioManager;
22 import android.media.AudioSystem;
23 import android.media.IAudioService;
24 import android.os.ServiceManager;
25 import android.util.AndroidException;
26 
27 import com.android.internal.os.BaseCommand;
28 
29 import java.io.BufferedReader;
30 import java.io.IOException;
31 import java.io.InputStreamReader;
32 import java.io.PrintStream;
33 import java.lang.ArrayIndexOutOfBoundsException;
34 
35 /**
36  * Command line tool to exercise AudioService.setStreamVolume()
37  *                           and AudioService.adjustStreamVolume()
38  */
39 public 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 
run(BaseCommand cmd)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 
log(String code, String msg)173     static void log(String code, String msg) {
174         System.out.println(code + " " + msg);
175     }
176 
streamName(int stream)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