blob: 4bcb55eefc5a1bbf7d0673607e9d89c7f807530a [file] [log] [blame]
Heidi Miller54362a62014-10-24 16:00:04 -07001page.title=TV Audio
2@jd:body
3
4<!--
5 Copyright 2014 The Android Open Source Project
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18-->
19<div id="qv-wrapper">
20 <div id="qv">
21 <h2>In this document</h2>
22 <ol id="auto-toc">
23 </ol>
24 </div>
25</div>
26
27<p>The TV Input Framework (TIF) manager works with the audio routing API to support flexible audio
28path changes. When a System on Chip (SoC) implements the TV hardware abstraction layer (HAL), each
29TV input (HDMI IN, Tuner, etc.) provides <code>TvInputHardwareInfo</code> that specifies AudioPort information for audio type and address.</p>
30
31<ul>
32<li><b>Physical</b> audio input/output devices have a corresponding AudioPort.</li>
33<li><b>Software</b> audio output/input streams are represented as AudioMixPort (child class of
34AudioPort).</li>
35</ul>
36
37<p>The TIF then uses AudioPort information for the audio routing API.</p>
38
39<p><img src="audio/images/ape_audio_tv_tif.png" alt="Android TV Input Framework (TIF)" />
40<p class="img-caption"><strong>Figure 1.</strong> TV Input Framework (TIF)</p>
41
42<h2 id="Requirements">Requirements</h2>
43
44<p>A SoC must implement the audio HAL with the following audio routing API support:</p>
45
46<table>
47<tbody>
48<tr>
49<th>Audio Ports</th>
50<td>
51<ul>
52<li>TV Audio Input has a corresponding audio source port implementation.</li>
53<li>TV Audio Output has a corresponding audio sink port implementation.</li>
54<li>Can create audio patch between any TV input audio port and any TV output audio port.</li>
55</ul>
56</td>
57</tr>
58<tr>
59<th>Default Input</th>
60<td>AudioRecord (created with DEFAULT input source) must seize <i>virtual null input source</i> for
61AUDIO_DEVICE_IN_DEFAULT acquisition on Android TV.</td>
62</tr>
63<tr>
64<th>Device Loopback</th>
65<td>Requires supporting an AUDIO_DEVICE_IN_LOOPBACK input that is a complete mix of all audio output
66of all the TV output (11Khz, 16bit mono or 48Khz, 16bit mono). Used only for audio capture.
67</td>
68</tr>
69</tbody>
70</table>
71
72
73<h2 id="Audio Devices">TV audio devices</h2>
74
75<p>Android supports the following audio devices for TV audio input/output.</p>
76
77<h4>system/core/include/system/audio.h</h4>
78
79<pre>
80/* output devices */
81AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400,
82AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL,
83/* HDMI Audio Return Channel */
84AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000,
85/* S/PDIF out */
86AUDIO_DEVICE_OUT_SPDIF = 0x80000,
87/* input devices */
88AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20,
89AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL,
90/* TV tuner input */
91AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000,
92/* S/PDIF in */
93AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000,
94AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000,
95</pre>
96
97
98<h2 id="HAL extension">Audio HAL extension</h2>
99
100<p>The Audio HAL extension for the audio routing API is defined by following:</p>
101
102<h4>system/core/include/system/audio.h</h4>
103
104<pre>
105/* audio port configuration structure used to specify a particular configuration of an audio port */
106struct audio_port_config {
107 audio_port_handle_t id; /* port unique ID */
108 audio_port_role_t role; /* sink or source */
109 audio_port_type_t type; /* device, mix ... */
110 unsigned int config_mask; /* e.g AUDIO_PORT_CONFIG_ALL */
111 unsigned int sample_rate; /* sampling rate in Hz */
112 audio_channel_mask_t channel_mask; /* channel mask if applicable */
113 audio_format_t format; /* format if applicable */
114 struct audio_gain_config gain; /* gain to apply if applicable */
115 union {
116 struct audio_port_config_device_ext device; /* device specific info */
117 struct audio_port_config_mix_ext mix; /* mix specific info */
118 struct audio_port_config_session_ext session; /* session specific info */
119 } ext;
120};
121struct audio_port {
122 audio_port_handle_t id; /* port unique ID */
123 audio_port_role_t role; /* sink or source */
124 audio_port_type_t type; /* device, mix ... */
125 unsigned int num_sample_rates; /* number of sampling rates in following array */
126 unsigned int sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
127 unsigned int num_channel_masks; /* number of channel masks in following array */
128 audio_channel_mask_t channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
129 unsigned int num_formats; /* number of formats in following array */
130 audio_format_t formats[AUDIO_PORT_MAX_FORMATS];
131 unsigned int num_gains; /* number of gains in following array */
132 struct audio_gain gains[AUDIO_PORT_MAX_GAINS];
133 struct audio_port_config active_config; /* current audio port configuration */
134 union {
135 struct audio_port_device_ext device;
136 struct audio_port_mix_ext mix;
137 struct audio_port_session_ext session;
138 } ext;
139};
140</pre>
141
142<h4>hardware/libhardware/include/hardware/audio.h</h4>
143
144<pre>
145struct audio_hw_device {
146 :
147 /**
148 * Routing control
149 */
150
151 /* Creates an audio patch between several source and sink ports.
152 * The handle is allocated by the HAL and should be unique for this
153 * audio HAL module. */
154 int (*create_audio_patch)(struct audio_hw_device *dev,
155 unsigned int num_sources,
156 const struct audio_port_config *sources,
157 unsigned int num_sinks,
158 const struct audio_port_config *sinks,
159 audio_patch_handle_t *handle);
160
161 /* Release an audio patch */
162 int (*release_audio_patch)(struct audio_hw_device *dev,
163 audio_patch_handle_t handle);
164
165 /* Fills the list of supported attributes for a given audio port.
166 * As input, "port" contains the information (type, role, address etc...)
167 * needed by the HAL to identify the port.
168 * As output, "port" contains possible attributes (sampling rates, formats,
169 * channel masks, gain controllers...) for this port.
170 */
171 int (*get_audio_port)(struct audio_hw_device *dev,
172 struct audio_port *port);
173
174 /* Set audio port configuration */
175 int (*set_audio_port_config)(struct audio_hw_device *dev,
176 const struct audio_port_config *config);
177</pre>
178
179<h2 id="Testing">Testing DEVICE_IN_LOOPBACK</h2>
180
181<p>To test DEVICE_IN_LOOPBACK for TV monitoring, use the following testing code. After running the
182test, the captured audio saves to <code>/sdcard/record_loopback.raw</code>, where you can listen to
183it using <code>ffmeg</code>.</p>
184
185<pre>
186&lt;uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" /&gt;
187&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
188
189 AudioRecord mRecorder;
190 Handler mHandler = new Handler();
191 int mMinBufferSize = AudioRecord.getMinBufferSize(RECORD_SAMPLING_RATE,
192 AudioFormat.CHANNEL_IN_MONO,
193 AudioFormat.ENCODING_PCM_16BIT);;
194 static final int RECORD_SAMPLING_RATE = 48000;
195 public void doCapture() {
196 mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, RECORD_SAMPLING_RATE,
197 AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mMinBufferSize * 10);
198 AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
199 ArrayList&lt;AudioPort&gt; audioPorts = new ArrayList&lt;AudioPort&gt;();
200 am.listAudioPorts(audioPorts);
201 AudioPortConfig srcPortConfig = null;
202 AudioPortConfig sinkPortConfig = null;
203 for (AudioPort audioPort : audioPorts) {
204 if (srcPortConfig == null
205 && audioPort.role() == AudioPort.ROLE_SOURCE
206 && audioPort instanceof AudioDevicePort) {
207 AudioDevicePort audioDevicePort = (AudioDevicePort) audioPort;
208 if (audioDevicePort.type() == AudioManager.DEVICE_IN_LOOPBACK) {
209 srcPortConfig = audioPort.buildConfig(48000, AudioFormat.CHANNEL_IN_DEFAULT,
210 AudioFormat.ENCODING_DEFAULT, null);
211 Log.d(LOG_TAG, "Found loopback audio source port : " + audioPort);
212 }
213 }
214 else if (sinkPortConfig == null
215 && audioPort.role() == AudioPort.ROLE_SINK
216 && audioPort instanceof AudioMixPort) {
217 sinkPortConfig = audioPort.buildConfig(48000, AudioFormat.CHANNEL_OUT_DEFAULT,
218 AudioFormat.ENCODING_DEFAULT, null);
219 Log.d(LOG_TAG, "Found recorder audio mix port : " + audioPort);
220 }
221 }
222 if (srcPortConfig != null && sinkPortConfig != null) {
223 AudioPatch[] patches = new AudioPatch[] { null };
224 int status = am.createAudioPatch(
225 patches,
226 new AudioPortConfig[] { srcPortConfig },
227 new AudioPortConfig[] { sinkPortConfig });
228 Log.d(LOG_TAG, "Result of createAudioPatch(): " + status);
229 }
230 mRecorder.startRecording();
231 processAudioData();
232 mRecorder.stop();
233 mRecorder.release();
234 }
235 private void processAudioData() {
236 OutputStream rawFileStream = null;
237 byte data[] = new byte[mMinBufferSize];
238 try {
239 rawFileStream = new BufferedOutputStream(
240 new FileOutputStream(new File("/sdcard/record_loopback.raw")));
241 } catch (FileNotFoundException e) {
242 Log.d(LOG_TAG, "Can't open file.", e);
243 }
244 long startTimeMs = System.currentTimeMillis();
245 while (System.currentTimeMillis() - startTimeMs &lt; 5000) {
246 int nbytes = mRecorder.read(data, 0, mMinBufferSize);
247 if (nbytes &lt;= 0) {
248 continue;
249 }
250 try {
251 rawFileStream.write(data);
252 } catch (IOException e) {
253 Log.e(LOG_TAG, "Error on writing raw file.", e);
254 }
255 }
256 try {
257 rawFileStream.close();
258 } catch (IOException e) {
259 }
260 Log.d(LOG_TAG, "Exit audio recording.");
261 }
262</pre>
263
264<p>Locate the captured audio file in <code>/sdcard/record_loopback.raw</code> and listen to it using
265<code>ffmeg</code>:</p>
266
267<pre>
268adb pull /sdcard/record_loopback.raw
269ffmpeg -f s16le -ar 48k -ac 1 -i record_loopback.raw record_loopback.wav
270ffplay record_loopback.wav
271</pre>
272
273<h2 id="Use cases">Use cases</h2>
274
275<p>This section includes common use cases for TV audio.</p>
276
277<h3>TV tuner with speaker output</h3>
278
279<p>When a TV tuner becomes active, the audio routing API creates an audio patch between the tuner
280and the default output (e.g. the speaker). The tuner output does not require decoding, but final
281audio output is mixed with software output_stream.</p>
282
283<p><img src="audio/images/ape_audio_tv_tuner.png" alt="Android TV Tuner Audio Patch" />
284<p class="img-caption">
285<strong>Figure 2.</strong> Audio Patch for TV tuner with speaker output.</p>
286
287
288<h3>HDMI OUT during live TV</h3>
289
290<p>A user is watching live TV then switches to the HDMI audio output (Intent.ACTION_HDMI_AUDIO_PLUG)
291. The output device of all output_streams changes to the HDMI_OUT port, and the TIF manager changes
292the sink port of the existing tuner audio patch to the HDMI_OUT port.</p>
293
294<p><p><img src="audio/images/ape_audio_tv_hdmi_tuner.png" alt="Android TV HDMI-OUT Audio Patch" />
295<p class="img-caption">
296<strong>Figure 3.</strong> Audio Patch for HDMI OUT from live TV.</p>