Home | History | Annotate | Download | only in audio
      1 page.title=Audio Debugging
      2 @jd:body
      3 
      4 <!--
      5     Copyright 2013 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>
     28 This article describes some tips and tricks for debugging Android audio.
     29 </p>
     30 
     31 <h2 id="teeSink">Tee Sink</h2>
     32 
     33 <p>
     34 The "tee sink" is
     35 an AudioFlinger debugging feature, available in custom builds only,
     36 for retaining a short fragment of recent audio for later analysis.
     37 This permits comparison between what was actually played or recorded
     38 vs. what was expected.
     39 </p>
     40 
     41 <p>
     42 For privacy the tee sink is disabled by default, at both compile-time and
     43 run-time.  To use the tee sink, you will need to enable it by re-compiling,
     44 and also by setting a property.  Be sure to disable this feature after you are
     45 done debugging; the tee sink should not be left enabled in production builds.
     46 </p>
     47 
     48 <p>
     49 The instructions in the remainder of this section are for Android 5.0,
     50 and may require changes for other versions.
     51 </p>
     52 
     53 <h3 id="compile">Compile-time setup</h3>
     54 
     55 <ol>
     56 <li><code>cd frameworks/av/services/audioflinger</code></li>
     57 <li>Edit <code>Configuration.h</code>.</li>
     58 <li>Uncomment <code>#define TEE_SINK</code>.</li>
     59 <li>Re-build <code>libaudioflinger.so</code>.</li>
     60 <li><code>adb root</code></li>
     61 <li><code>adb remount</code></li>
     62 <li>Push or sync the new <code>libaudioflinger.so</code> to the device's <code>/system/lib</code>.</li>
     63 </ol>
     64 
     65 <h3 id="runtime">Run-time setup</h3>
     66 
     67 <ol>
     68 <li><code>adb shell getprop | grep ro.debuggable</code>
     69 <br />Confirm that the output is: <code>[ro.debuggable]: [1]</code>
     70 </li>
     71 <li><code>adb shell</code></li>
     72 <li><code>ls -ld /data/misc/media</code>
     73 <br />
     74 <p>
     75 Confirm that the output is:
     76 </p>
     77 <pre>
     78 drwx------ media media ... media
     79 </pre>
     80 <br />
     81 <p>
     82 If the directory does not exist, create it as follows:
     83 </p>
     84 <pre>
     85 mkdir /data/misc/media
     86 chown media:media /data/misc/media
     87 </pre>
     88 </li>
     89 <li><code>echo af.tee=# &gt; /data/local.prop</code>
     90 <br />Where the <code>af.tee</code> value is a number described below.
     91 </li>
     92 <li><code>chmod 644 /data/local.prop</code></li>
     93 <li><code>reboot</code></li>
     94 </ol>
     95 
     96 <h4>Values for <code>af.tee</code> property</h4>
     97 
     98 <p>
     99 The value of <code>af.tee</code> is a number between 0 and 7, expressing
    100 the sum of several bits, one per feature.
    101 See the code at <code>AudioFlinger::AudioFlinger()</code> in <code>AudioFlinger.cpp</code>
    102 for an explanation of each bit, but briefly:
    103 </p>
    104 <ul>
    105 <li>1 = input</li>
    106 <li>2 = FastMixer output</li>
    107 <li>4 = per-track AudioRecord and AudioTrack</li>
    108 </ul>
    109 
    110 <p>
    111 There is no bit for deep buffer or normal mixer yet,
    112 but you can get similar results using "4."
    113 </p>
    114 
    115 <h3 id="test">Test and acquire data</h3>
    116 
    117 <ol>
    118 <li>Run your audio test.</li>
    119 <li><code>adb shell dumpsys media.audio_flinger</code></li>
    120 <li>Look for a line in dumpsys output such as this:<br />
    121 <code>tee copied to /data/misc/media/20131010101147_2.wav</code>
    122 <br />This is a PCM .wav file.
    123 </li>
    124 <li><code>adb pull</code> any <code>/data/misc/media/*.wav</code> files of interest;
    125 note that track-specific dump filenames do not appear in the dumpsys output,
    126 but are still saved to <code>/data/misc/media</code> upon track closure.
    127 </li>
    128 <li>Review the dump files for privacy concerns before sharing with others.</li>
    129 </ol>
    130 
    131 <h4>Suggestions</h4>
    132 
    133 <p>Try these ideas for more useful results:</p>
    134 
    135 <ul>
    136 <li>Disable touch sounds and key clicks.</li>
    137 <li>Maximize all volumes.</li>
    138 <li>Disable apps that make sound or record from microphone,
    139 if they are not of interest to your test.
    140 </li>
    141 <li>Track-specific dumps are only saved when the track is closed;
    142 you may need to force close an app in order to dump its track-specific data
    143 </li>
    144 <li>Do the <code>dumpsys</code> immediately after test;
    145 there is a limited amount of recording space available.</li>
    146 <li>To make sure you don't lose your dump files,
    147 upload them to your host periodically.
    148 Only a limited number of dump files are preserved;
    149 older dumps are removed after that limit is reached.</li>
    150 </ul>
    151 
    152 <h3 id="restore">Restore</h3>
    153 
    154 <p>
    155 As noted above, the tee sink feature should not be left enabled.
    156 Restore your build and device as follows:
    157 </p>
    158 <ol>
    159 <li>Revert the source code changes to <code>Configuration.h</code>.</li>
    160 <li>Re-build <code>libaudioflinger.so</code>.</li>
    161 <li>Push or sync the restored <code>libaudioflinger.so</code>
    162 to the device's <code>/system/lib</code>.
    163 </li>
    164 <li><code>adb shell</code></li>
    165 <li><code>rm /data/local.prop</code></li>
    166 <li><code>rm /data/misc/media/*.wav</code></li>
    167 <li><code>reboot</code></li>
    168 </ol>
    169 
    170 <h2 id="mediaLog">media.log</h2>
    171 
    172 <h3 id="alogx">ALOGx macros</h3>
    173 
    174 <p>
    175 The standard Java language logging API in Android SDK is
    176 <a href="http://developer.android.com/reference/android/util/Log.html">android.util.Log</a>.
    177 </p>
    178 
    179 <p>
    180 The corresponding C language API in Android NDK is
    181 <code>__android_log_print</code>
    182 declared in <code>&lt;android/log.h&gt;</code>.
    183 </p>
    184 
    185 <p>
    186 Within the native portion of Android framework, we
    187 prefer macros named <code>ALOGE</code>, <code>ALOGW</code>,
    188 <code>ALOGI</code>, <code>ALOGV</code>, etc.  They are declared in
    189 <code>&lt;utils/Log.h&gt;</code>, and for the purposes of this article
    190 we'll collectively refer to them as <code>ALOGx</code>.
    191 </p>
    192 
    193 <p>
    194 All of these APIs are easy-to-use and well-understood, so they are pervasive
    195 throughout the Android platform.  In particular the <code>mediaserver</code>
    196 process, which includes the AudioFlinger sound server, uses
    197 <code>ALOGx</code> extensively.
    198 </p>
    199 
    200 <p>
    201 Nevertheless, there are some limitations to <code>ALOGx</code> and friends:
    202 </p>
    203 
    204 <ul>
    205 <li>
    206 They are susceptible to "log spam": the log buffer is a shared resource
    207 so it can easily overflow due to unrelated log entries, resulting in
    208 missed information.  The <code>ALOGV</code> variant is disabled at
    209 compile-time by default.  But of course even it can result in log spam
    210 if it is enabled.
    211 </li>
    212 <li>
    213 The underlying kernel system calls could block, possibly resulting in
    214 priority inversion and consequently measurement disturbances and
    215 inaccuracies.  This is of
    216 special concern to time-critical threads such as <code>FastMixer</code> and <code>FastCapture</code>.
    217 </li>
    218 <li>
    219 If a particular log is disabled to reduce log spam,
    220 then any information that would have been captured by that log is lost.
    221 It is not possible to enable a specific log retroactively,
    222 <i>after</i> it becomes clear that the log would have been interesting.
    223 </li>
    224 </ul>
    225 
    226 <h3 id="nblog">NBLOG, media.log, and MediaLogService</h3>
    227 
    228 <p>
    229 The <code>NBLOG</code> APIs and associated <code>media.log</code>
    230 process and <code>MediaLogService</code>
    231 service together form a newer logging system for media, and are specifically
    232 designed to address the issues above.  We will loosely use the term
    233 "media.log" to refer to all three, but strictly speaking <code>NBLOG</code> is the
    234 C++ logging API, <code>media.log</code> is a Linux process name, and <code>MediaLogService</code>
    235 is an Android binder service for examining the logs.
    236 </p>
    237 
    238 <p>
    239 A <code>media.log</code> "timeline" is a series
    240 of log entries whose relative ordering is preserved.
    241 By convention, each thread should use it's own timeline.
    242 </p>
    243 
    244 <h3 id="benefits">Benefits</h3>
    245 
    246 <p>
    247 The benefits of the <code>media.log</code> system are that it:
    248 </p>
    249 <ul>
    250 <li>Doesn't spam the main log unless and until it is needed.</li>
    251 <li>Can be examined even when <code>mediaserver</code> crashes or hangs.</li>
    252 <li>Is non-blocking per timeline.</li>
    253 <li>Offers less disturbance to performance.
    254 (Of course no form of logging is completely non-intrusive.)
    255 </li>
    256 </ul>
    257 
    258 <h3 id="architecture">Architecture</h3>
    259 
    260 <p>
    261 The diagram below shows the relationship of the <code>mediaserver</code> process
    262 and the <code>init</code> process, before <code>media.log</code> is introduced:
    263 </p>
    264 <img src="images/medialog_before.png" alt="Architecture before media.log" id="figure1" />
    265 <p class="img-caption">
    266   <strong>Figure 1.</strong> Architecture before media.log
    267 </p>
    268 
    269 <p>
    270 Notable points:
    271 </p>
    272 <ul>
    273 <li><code>init</code> forks and execs <code>mediaserver</code>.</li>
    274 <li><code>init</code> detects the death of <code>mediaserver</code>, and re-forks as necessary.</li>
    275 <li><code>ALOGx</code> logging is not shown.</li>
    276 </ul>
    277 
    278 <p>
    279 The diagram below shows the new relationship of the components,
    280 after <code>media.log</code> is added to the architecture:
    281 </p>
    282 <img src="images/medialog_after.png" alt="Architecture after media.log" id="figure2" />
    283 <p class="img-caption">
    284   <strong>Figure 2.</strong> Architecture after media.log
    285 </p>
    286 
    287 <p>
    288 Important changes:
    289 </p>
    290 
    291 <ul>
    292 
    293 <li>
    294 Clients use <code>NBLOG</code> API to construct log entries and append them to
    295 a circular buffer in shared memory.
    296 </li>
    297 
    298 <li>
    299 <code>MediaLogService</code> can dump the contents of the circular buffer at any time.
    300 </li>
    301 
    302 <li>
    303 The circular buffer is designed in such a way that any corruption of the
    304 shared memory will not crash <code>MediaLogService</code>, and it will still be able
    305 to dump as much of the buffer that is not affected by the corruption.
    306 </li>
    307 
    308 <li>
    309 The circular buffer is non-blocking and lock-free for both writing
    310 new entries and reading existing entries.
    311 </li>
    312 
    313 <li>
    314 No kernel system calls are required to write to or read from the circular buffer
    315 (other than optional timestamps).
    316 </li>
    317 
    318 </ul>
    319 
    320 <h4>Where to use</h4>
    321 
    322 <p>
    323 As of Android 4.4, there are only a few log points in AudioFlinger
    324 that use the <code>media.log</code> system.  Though the new APIs are not as
    325 easy to use as <code>ALOGx</code>, they are not extremely difficult either.
    326 We encourage you to learn the new logging system for those
    327 occasions when it is indispensable.
    328 In particular, it is recommended for AudioFlinger threads that must
    329 run frequently, periodically, and without blocking such as the
    330 <code>FastMixer</code> and <code>FastCapture</code> threads.
    331 </p>
    332 
    333 <h3 id="how">How to use</h3>
    334 
    335 <h4>Add logs</h4>
    336 
    337 <p>
    338 First, you need to add logs to your code.
    339 </p>
    340 
    341 <p>
    342 In <code>FastMixer</code> and <code>FastCapture</code> threads, use code such as this:
    343 </p>
    344 <pre>
    345 logWriter-&gt;log("string");
    346 logWriter-&gt;logf("format", parameters);
    347 logWriter-&gt;logTimestamp();
    348 </pre>
    349 <p>
    350 As this <code>NBLog</code> timeline is used only by the <code>FastMixer</code> and
    351 <code>FastCapture</code> threads,
    352 there is no need for mutual exclusion.
    353 </p>
    354 
    355 <p>
    356 In other AudioFlinger threads, use <code>mNBLogWriter</code>:
    357 </p>
    358 <pre>
    359 mNBLogWriter-&gt;log("string");
    360 mNBLogWriter-&gt;logf("format", parameters);
    361 mNBLogWriter-&gt;logTimestamp();
    362 </pre>
    363 <p>
    364 For threads other than <code>FastMixer</code> and <code>FastCapture</code>,
    365 the thread's <code>NBLog</code> timeline can be used by both the thread itself, and
    366 by binder operations.  <code>NBLog::Writer</code> does not provide any
    367 implicit mutual exclusion per timeline, so be sure that all logs occur
    368 within a context where the thread's mutex <code>mLock</code> is held.
    369 </p>
    370 
    371 <p>
    372 After you have added the logs, re-build AudioFlinger.
    373 </p>
    374 
    375 <p class="caution"><strong>Caution:</strong>
    376 A separate <code>NBLog::Writer</code> timeline is required per thread,
    377 to ensure thread safety, since timelines omit mutexes by design.  If you
    378 want more than one thread to use the same timeline, you can protect with an
    379 existing mutex (as described above for <code>mLock</code>).  Or you can
    380 use the <code>NBLog::LockedWriter</code> wrapper instead of <code>NBLog::Writer</code>.
    381 However, this negates a prime benefit of this API: its non-blocking
    382 behavior.
    383 </p>
    384 
    385 <p>
    386 The full <code>NBLog</code> API is at <code>frameworks/av/include/media/nbaio/NBLog.h</code>.
    387 </p>
    388 
    389 <h4>Enable media.log</h4>
    390 
    391 <p>
    392 <code>media.log</code> is disabled by default. It is active only when property
    393 <code>ro.test_harness</code> is <code>1</code>.  You can enable it by:
    394 </p>
    395 
    396 <pre>
    397 adb root
    398 adb shell
    399 echo ro.test_harness=1 > /data/local.prop
    400 chmod 644 /data/local.prop
    401 reboot
    402 </pre>
    403 
    404 <p>
    405 The connection is lost during reboot, so:
    406 </p>
    407 <pre>
    408 adb shell
    409 </pre>
    410 
    411 The command <code>ps media</code> will now show two processes:
    412 <ul>
    413 <li>media.log</li>
    414 <li>mediaserver</li>
    415 </ul>
    416 <p>
    417 Note the process ID of <code>mediaserver</code> for later.
    418 </p>
    419 
    420 <h4>Displaying the timelines</h4>
    421 
    422 <p>
    423 You can manually request a log dump at any time.
    424 This command shows logs from all the active and recent timelines, and then clears them:
    425 </p>
    426 <pre>
    427 dumpsys media.log
    428 </pre>
    429 
    430 <p>
    431 Note that by design timelines are independent,
    432 and there is no facility for merging timelines.
    433 </p>
    434 
    435 <h4>Recovering logs after mediaserver death</h4>
    436 
    437 <p>
    438 Now try killing <code>mediaserver</code> process: <code>kill -9 #</code>, where # is
    439 the process ID you noted earlier.  You should see a dump from <code>media.log</code>
    440 in the main <code>logcat</code>, showing all the logs leading up to the crash.
    441 </p>
    442 <pre>
    443 dumpsys media.log
    444 </pre>
    445