Merge "aaudio: fix race condition in timestamp path"
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..575603f
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+    name: "com.android.media",
+    manifest: "manifest.json",
+    native_shared_libs: [
+        // Extractor plugins
+        "libaacextractor",
+        "libamrextractor",
+        "libflacextractor",
+        "libmidiextractor",
+        "libmkvextractor",
+        "libmp3extractor",
+        "libmp4extractor",
+        "libmpeg2extractor",
+        "liboggextractor",
+        "libwavextractor",
+        // MediaPlayer2
+        "libmedia2_jni",
+    ],
+    key: "com.android.media.key",
+}
+
+apex_key {
+    name: "com.android.media.key",
+    public_key: "com.android.media.avbpubkey",
+    private_key: "com.android.media.pem",
+}
diff --git a/apex/OWNERS b/apex/OWNERS
new file mode 100644
index 0000000..5587f5f
--- /dev/null
+++ b/apex/OWNERS
@@ -0,0 +1,6 @@
+chz@google.com
+dwkang@google.com
+jiyong@google.com
+lajos@google.com
+marcone@google.com
+wjia@google.com
diff --git a/apex/com.android.media.avbpubkey b/apex/com.android.media.avbpubkey
new file mode 100644
index 0000000..c0c8fd3
--- /dev/null
+++ b/apex/com.android.media.avbpubkey
Binary files differ
diff --git a/apex/com.android.media.pem b/apex/com.android.media.pem
new file mode 100644
index 0000000..8daa50e
--- /dev/null
+++ b/apex/com.android.media.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEA06dKiF+xQp36Xcosmac+DzJTXC9nbHy0Yqfy+zEC5hlwXbHZ
+1gAZZu8zL9p7kbBkmtSCulU0M+cTHr74gkG9UDkM/S7Z+957FzHMqWXY03gupFP7
+lcCnKtpkzsyQrABavynoxyY6dfmKZNtEFQrikK1zs80CppRoMwZS2dLogX8qO5LU
+gLe7/0PZBdbQSVA5AARE+AO6pR5Px/8QAere9TCLcm1aK9BUVOJvaAZAf7bD2f8s
+3J/lANQ1tvXXZrFL1i26H6sNja11u5/M0odg3SfqKI0x/317nLkYx8QSSHVKEjBs
+nzsyoFry4INEh/q7zSEX5+S1VA6ORjyof3u7CrGavrYwI2k6x3t+Dkc2dfNDaNY9
+9vGYD1nMyRqUzSIqaOz8q78tc1A391Lua8SB1E0Tx/FnsPjxPee0wZ1taGddkZxD
+cvMdQJhLyE6EloimFiOhkVjnAnlPYiiPEQkwJomE9kCsP9aMmyhwBOpbbRISj1ua
+edESrpTC5DHpt1owjtAfHvD8TfmPWT1KSN1iCQAuh5hnEM5LLDljc/AYvJV4L5uR
+l/6t5dE8deg9ksY6lVRrUwHsXxUtBPhM82PWSrpAPNJCHLuBBVx+zDD//kOmt5oe
+OyYJ2RcDsnLmDfFLHbPcAwuyfmxQ+pbFBfiL4NaKoUWRy0viR4/3zulysCsCAwEA
+AQKCAgAphaNIl8VVtVpdtgED79xr7MqPxjj6/ogA5sPzZY0VCR6TMwXyRri1Ce43
+0Bv32+wQt+ohlf+UwxtsJ7jnDPCP4XFb5iobkG0DguCMxw8/hU9ZK6Sqn03sSUYH
+j/g91h/3ashg8W38oQT2flGf8y+5hF2zg1+mwGykvfPZCdhVN1ZYs5h+3AzEqlHU
+JG1eRJ+6EhxZr5mZNRYfvTkttx8gaPKiczOCbu9sa7PBa6CRrZBEnxv0+GVbwUX8
+a8RjQBsJnJTsC4mwJrx3H4V2M9rb6C224ORTJBHxEBr9bcjMcD4kzV0x69IlxVHq
+m7YBGz5morxm4OZ15BkjTFkeEW8C8bdpRrYoY8ocmybWUf6g5IxpE33M699lWzdn
++xwPloJOA5sqsDIXGXt4+KPb2hjHLpqS4V9Rw1JQErBgB9/0EHqK4u1kwI1/djea
+Ny26esGgjmupq+M+G3vQysKEX8m/KhYZKw8yqG4LrzUKp1uosEXEeE+FBnPW1fwU
+OapJTAKLDAeItz2YsZ+82oTMREKR6gNoAw3yF3dxo/E4sk3IDG4y3w7A8D5dlBBM
+hx2fDqnieS/OffGndbbbIIGH0Sb1MBURNlZlXwXz1hbACc8FMYmn4iyQUJfKlCfU
+Rp1jOR4silFxEGYhSi0Jw7+AJe1prZRyZYp2ZQQ+trGvqQNhwQKCAQEA7CsaDxvP
+L9GI8yFVznAG5SZvIut3/lLA7hd4F0LKJ277hW8YMENLjvmrtEQW1dyQqQXV+CpL
+QErvgRuVj9DyV6qOKDimmpqhT+YZlbxp98N9Ba8RJ4ckw07vPNvglTjAeIZyUbRP
+VX5Onr/OFw66GLzOIhsOnRlqviOKg2wm1kfBF3OBAwVczqh4PJ4gc3rbW9jPN3pn
+eaouV4CdGIooXckV6XtQCGjWFNNzxmuknn1GbLbHslGuDUX89rQsRsk9qZGpi1M1
+Cf2yaQY0d+AjDdPslXKZ92EbDAmo3KGtoxy2hWWytZHbUhtWgguEwxDMkJhJ0yCM
+ZSLQZ2TXlC/iCwKCAQEA5W0xuNTozb2UrwqEaDCkogxgdv5NdQvlvBM7+fD4RpOY
+ItDFcudhuapnpxdbPrdl3F5bgTXZJ4jKMIKePVveugI7wNCQX7aSET3U0Qj47RzA
+vVVHb0K3SZsicpK7K067Ejk1esxrPreaTnUj14jUle20Cq+3iysJnwMFs2DkmE1B
+UK6MiBJ1+MbFuBATw7TWxu8yPyfa3JzUAEsfP8NqqIlXrK26DdGefd8C0hysiq4X
+3matZ3SDck1mCk4LS9PCZZlDqdxLM6/UIoy4cj0qbSPdFMop8zjB8lF/1OABowkT
+e/9L0dpG08G35aEJJ6vKSGnFLbstgly165PlGapeYQKCAQEAwoShuw4BsXYZIYA0
+Z4sX8secRBvDwoKwi6pi7G3DiYU8v2OIfb//zOxRg3GNiWpY8A5xdSyIvJS7/hAV
+ONY1tQUyf2hhuPdhpCh2rED62up14CeYroD+Q6uRGwRTTzTmOp8qK6eirF0TLmf2
+vEESAGwKMEcu2zBjHeayIJsExftlzAYDndRd440ZM3xeaB8p69WAn0Y/UhNchg/V
+1K9+nfiRBrTdb3/BzHd5ZVWlyjCOv94wTuw9uosJ1r0Btu/rzO2/wpSvG+KMfzpw
+HshKtwn1VAaHUBz4JQsTvV2hYba1ktv3vNs81LzVnNkV6YC9rN7x92ZYnLh3BKIn
+edOSjwKCAQAP51zeAixNLsoixCjfjBetgAwj04cNCREY04CB1/lt8wdFypEVYQK+
+OxjKVW0m0NHHz+ap81ClU+8oI7XSbQ7oeAUqXYrUh7Ria5XYE7Ylwat+tG2qQcaw
+3IcryA4fd2qyXbLeW1NH2rRgofAlHcAW0I59eybPB+G32x7HC31tLVXMwPzO5fC1
+mRnVo4+rLlsBGU2zYRDj4B82Ef8NjX9URYkFWFmgYZqKAS6R4Bj52A2hhh6ZIFOI
+VeMv7a8Mx5YfMtuk57dy0spyxqx2htTtEeJecZEs4g9Xu9yPpiOW6KcoHk9kMaxd
+O32C9oHK9TalhGd9vw7tjX2y4eKsv8mhAoIBABEtJSjQ571YUbELvJgnVILWKExj
+nURnbQ8C2j2lLdb20fi8UGJDei9g2b2oCs3SfCaMcRqoOs4uy8ZJzofPelwWY1B7
+SZezn/2d1Q/cXpaXew++krhFvJFVxya6eLD7pvEVQAsGtkp9BTi2CFIhcGo5UQdc
+pym7XjFsW0LCI8mOAleuYe7DEpEU79RdsfxgQpeh1NgFJRpupHT6I2BkVijD/TI4
+kbwz11SuznkUTB4QePIwnEzV+gqDtlny4M1Qvsk8hqcU6JUOu+MOT1qnI6ZGSsdS
+D6RhPukordC9y/cbiV6qqKBVZ39O8ydWvpto/g7G7fSL5SddFuVRnwAV7Vg=
+-----END RSA PRIVATE KEY-----
diff --git a/apex/manifest.json b/apex/manifest.json
new file mode 100644
index 0000000..e2df3a3
--- /dev/null
+++ b/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.media",
+  "version": 1
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index f5ff69d..53addf1 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -39,6 +39,8 @@
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
+LOCAL_LDFLAGS += -Wl,--version-script=$(LOCAL_PATH)/libcamera2ndk.map.txt
+
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     liblog \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 61fc897..0311677 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -640,7 +640,7 @@
         MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
         MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
         MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
-        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
+        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_VIDEO_HEVC
     };
 
     const char *codecType = queryDecoders? "decoder" : "encoder";
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 73ecda1..a2594aa 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -225,8 +225,13 @@
 
 void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
     uint32_t size = data.readInt32();
-    vector.insertAt((size_t)0, size);
-    data.read(vector.editArray(), size);
+    if (vector.insertAt((size_t)0, size) < 0) {
+        vector.clear();
+    }
+    if (data.read(vector.editArray(), size) != NO_ERROR) {
+        vector.clear();
+        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+    }
 }
 
 void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/include/mediadrm/Crypto.h b/include/mediadrm/Crypto.h
deleted file mode 120000
index 9af6495..0000000
--- a/include/mediadrm/Crypto.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Crypto.h
\ No newline at end of file
diff --git a/include/mediadrm/Drm.h b/include/mediadrm/Drm.h
deleted file mode 120000
index ac60003..0000000
--- a/include/mediadrm/Drm.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Drm.h
\ No newline at end of file
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index a721b65..ccf80d0 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -618,6 +618,7 @@
             mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
             mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
             mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
+            mTrackMetadata->setInt32(kKeyBitsPerSample, getBitsPerSample());
             mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
             // sample rate is non-zero, so division by zero not possible
             mTrackMetadata->setInt64(kKeyDuration,
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 5331ba8..21ccf44 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -55,6 +55,8 @@
 #define UINT32_MAX       (4294967295U)
 #endif
 
+#define ALAC_SPECIFIC_INFO_SIZE (36)
+
 namespace android {
 
 enum {
@@ -331,6 +333,8 @@
         case FOURCC('t', 'w', 'o', 's'):
         case FOURCC('s', 'o', 'w', 't'):
             return MEDIA_MIMETYPE_AUDIO_RAW;
+        case FOURCC('a', 'l', 'a', 'c'):
+            return MEDIA_MIMETYPE_AUDIO_ALAC;
 
         default:
             ALOGW("Unknown fourcc: %c%c%c%c",
@@ -455,6 +459,7 @@
                 track->meta.findInt64(kKeyDuration, &duration) &&
                 track->meta.findInt32(kKeySampleRate, &samplerate)) {
 
+            // elst has to be processed only the first time this function is called
             track->has_elst = false;
 
             if (track->elst_segment_duration > INT64_MAX) {
@@ -462,16 +467,19 @@
             }
             int64_t segment_duration = track->elst_segment_duration;
             int64_t media_time = track->elst_media_time;
-            int64_t halfscale = mHeaderTimescale / 2;
+            int64_t halfscale = track->timescale / 2;
+
             ALOGV("segment_duration = %" PRId64 ", media_time = %" PRId64
-                  ", halfscale = %" PRId64 ", timescale = %d",
-                  segment_duration,
-                  media_time,
-                  halfscale,
-                  mHeaderTimescale);
+                  ", halfscale = %" PRId64 ", mdhd_timescale = %d, track_timescale = %u",
+                  segment_duration, media_time,
+                  halfscale, mHeaderTimescale, track->timescale);
+
+            if ((uint32_t)samplerate != track->timescale){
+                ALOGV("samplerate:%" PRId32 ", track->timescale and samplerate are different!", samplerate);
+            }
 
             int64_t delay;
-            // delay = ((media_time * samplerate) + halfscale) / mHeaderTimescale;
+            // delay = ((media_time * samplerate) + halfscale) / track->timescale;
             if (__builtin_mul_overflow(media_time, samplerate, &delay) ||
                     __builtin_add_overflow(delay, halfscale, &delay) ||
                     (delay /= mHeaderTimescale, false) ||
@@ -498,33 +506,43 @@
 
             int64_t segment_end;
             int64_t padding;
-            // padding = scaled_duration - ((segment_duration + media_time) * 1000000);
-            if (__builtin_add_overflow(segment_duration, media_time, &segment_end) ||
-                    __builtin_mul_overflow(segment_end, 1000000, &segment_end) ||
-                    __builtin_sub_overflow(scaled_duration, segment_end, &padding)) {
+            int64_t segment_duration_e6;
+            int64_t media_time_scaled_e6;
+            int64_t media_time_scaled;
+            // padding = scaled_duration - ((segment_duration * 1000000) +
+            //                  ((media_time * mHeaderTimeScale * 1000000)/track->timescale) )
+            // segment_duration is based on timescale in movie header box(mdhd)
+            // media_time is based on timescale track header/media timescale
+            if (__builtin_mul_overflow(segment_duration, 1000000, &segment_duration_e6) ||
+                __builtin_mul_overflow(media_time, mHeaderTimescale, &media_time_scaled) ||
+                __builtin_mul_overflow(media_time_scaled, 1000000, &media_time_scaled_e6)) {
+                return;
+            }
+            media_time_scaled_e6 /= track->timescale;
+            if(__builtin_add_overflow(segment_duration_e6, media_time_scaled_e6, &segment_end) ||
+                __builtin_sub_overflow(scaled_duration, segment_end, &padding)) {
                 return;
             }
             ALOGV("segment_end = %" PRId64 ", padding = %" PRId64, segment_end, padding);
-
+            int64_t paddingsamples = 0;
             if (padding < 0) {
                 // track duration from media header (which is what kKeyDuration is) might
                 // be slightly shorter than the segment duration, which would make the
                 // padding negative. Clamp to zero.
                 padding = 0;
-            }
-
-            int64_t paddingsamples;
-            int64_t halfscale_e6;
-            int64_t timescale_e6;
-            // paddingsamples = ((padding * samplerate) + (halfscale * 1000000))
-            //                / (mHeaderTimescale * 1000000);
-            if (__builtin_mul_overflow(padding, samplerate, &paddingsamples) ||
-                    __builtin_mul_overflow(halfscale, 1000000, &halfscale_e6) ||
-                    __builtin_mul_overflow(mHeaderTimescale, 1000000, &timescale_e6) ||
-                    __builtin_add_overflow(paddingsamples, halfscale_e6, &paddingsamples) ||
-                    (paddingsamples /= timescale_e6, false) ||
-                    paddingsamples > INT32_MAX) {
-                return;
+            } else {
+                int64_t halfscale_e6;
+                int64_t timescale_e6;
+                // paddingsamples = ((padding * samplerate) + (halfscale * 1000000))
+                //                / (mHeaderTimescale * 1000000);
+                if (__builtin_mul_overflow(padding, samplerate, &paddingsamples) ||
+                        __builtin_mul_overflow(halfscale, 1000000, &halfscale_e6) ||
+                        __builtin_mul_overflow(mHeaderTimescale, 1000000, &timescale_e6) ||
+                        __builtin_add_overflow(paddingsamples, halfscale_e6, &paddingsamples) ||
+                        (paddingsamples /= timescale_e6, false) ||
+                        paddingsamples > INT32_MAX) {
+                    return;
+                }
             }
             ALOGV("paddingsamples = %" PRId64, paddingsamples);
             track->meta.setInt32(kKeyEncoderPadding, paddingsamples);
@@ -1122,6 +1140,43 @@
                 mLastTrack->meta.setInt32(kKeyChannelCount, num_channels);
                 mLastTrack->meta.setInt32(kKeySampleRate, sample_rate);
             }
+
+            // If format type is 'alac', it is necessary to get the parameters
+            // from a alac atom spreading behind the frma atom.
+            // See 'external/alac/ALACMagicCookieDescription.txt'.
+            if (original_fourcc == FOURCC('a', 'l', 'a', 'c')) {
+                // Store ALAC magic cookie (decoder needs it).
+                uint8_t alacInfo[12];
+                data_offset = *offset;
+                if (mDataSource->readAt(
+                        data_offset, alacInfo, sizeof(alacInfo)) < (ssize_t)sizeof(alacInfo)) {
+                    return ERROR_IO;
+                }
+                uint32_t size = U32_AT(&alacInfo[0]);
+                if ((size != ALAC_SPECIFIC_INFO_SIZE) ||
+                        (U32_AT(&alacInfo[4]) != FOURCC('a', 'l', 'a', 'c')) ||
+                        (U32_AT(&alacInfo[8]) != 0)) {
+                    return ERROR_MALFORMED;
+                }
+
+                data_offset += sizeof(alacInfo);
+                uint8_t cookie[size - sizeof(alacInfo)];
+                if (mDataSource->readAt(
+                        data_offset, cookie, sizeof(cookie)) < (ssize_t)sizeof(cookie)) {
+                    return ERROR_IO;
+                }
+
+                uint8_t bitsPerSample = cookie[5];
+                mLastTrack->meta.setInt32(kKeyBitsPerSample, bitsPerSample);
+                mLastTrack->meta.setInt32(kKeyChannelCount, cookie[9]);
+                mLastTrack->meta.setInt32(kKeySampleRate, U32_AT(&cookie[20]));
+                mLastTrack->meta.setData(
+                    kKeyAlacMagicCookie, MetaData::TYPE_NONE, cookie, sizeof(cookie));
+
+                // Add the size of ALAC Specific Info (36 bytes) and terminator
+                // atom (8 bytes).
+                *offset += (size + 8);
+            }
             break;
         }
 
@@ -1490,6 +1545,7 @@
         case FOURCC('s', 'a', 'w', 'b'):
         case FOURCC('t', 'w', 'o', 's'):
         case FOURCC('s', 'o', 'w', 't'):
+        case FOURCC('a', 'l', 'a', 'c'):
         {
             if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')
                     && depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) {
@@ -1572,6 +1628,40 @@
             mLastTrack->meta.setInt32(kKeyChannelCount, num_channels);
             mLastTrack->meta.setInt32(kKeySampleRate, sample_rate);
 
+            if (chunk_type == FOURCC('a', 'l', 'a', 'c')) {
+
+                // See 'external/alac/ALACMagicCookieDescription.txt for the detail'.
+                // Store ALAC magic cookie (decoder needs it).
+                uint8_t alacInfo[12];
+                data_offset += sizeof(buffer);
+                if (mDataSource->readAt(
+                        data_offset, alacInfo, sizeof(alacInfo)) < (ssize_t)sizeof(alacInfo)) {
+                    return ERROR_IO;
+                }
+                uint32_t size = U32_AT(&alacInfo[0]);
+                if ((size != ALAC_SPECIFIC_INFO_SIZE) ||
+                        (U32_AT(&alacInfo[4]) != FOURCC('a', 'l', 'a', 'c')) ||
+                        (U32_AT(&alacInfo[8]) != 0)) {
+                    return ERROR_MALFORMED;
+                }
+                data_offset += sizeof(alacInfo);
+                uint8_t cookie[size - sizeof(alacInfo)];
+                if (mDataSource->readAt(
+                        data_offset, cookie, sizeof(cookie)) < (ssize_t)sizeof(cookie)) {
+                    return ERROR_IO;
+                }
+
+                uint8_t bitsPerSample = cookie[5];
+                mLastTrack->meta.setInt32(kKeyBitsPerSample, bitsPerSample);
+                mLastTrack->meta.setInt32(kKeyChannelCount, cookie[9]);
+                mLastTrack->meta.setInt32(kKeySampleRate, U32_AT(&cookie[20]));
+                mLastTrack->meta.setData(
+                        kKeyAlacMagicCookie, MetaData::TYPE_NONE, cookie, sizeof(cookie));
+                data_offset += sizeof(cookie);
+                *offset = data_offset;
+                CHECK_EQ(*offset, stop_offset);
+            }
+
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset, depth + 1);
                 if (err != OK) {
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 9191386..24e623b 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -269,9 +269,6 @@
 
     off64_t size;
     if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
-        sp<AnotherPacketSource> impl = haveVideo
-                ? mParser->getSource(ATSParser::VIDEO)
-                : mParser->getSource(ATSParser::AUDIO);
         size_t prevSyncSize = 1;
         int64_t durationUs = -1;
         List<int64_t> durations;
@@ -305,17 +302,32 @@
                 }
             }
         }
-        status_t err;
-        int64_t bufferedDurationUs;
-        bufferedDurationUs = impl->getBufferedDurationUs(&err);
-        if (err == ERROR_END_OF_STREAM) {
-            durationUs = bufferedDurationUs;
+
+        bool found = false;
+        for (int i = 0; i < ATSParser::NUM_SOURCE_TYPES; ++i) {
+            ATSParser::SourceType type = static_cast<ATSParser::SourceType>(i);
+            sp<AnotherPacketSource> impl = mParser->getSource(type);
+            if (impl == NULL) {
+                continue;
+            }
+
+            int64_t trackDurationUs = durationUs;
+
+            status_t err;
+            int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err);
+            if (err == ERROR_END_OF_STREAM) {
+                trackDurationUs = bufferedDurationUs;
+            }
+            if (trackDurationUs > 0) {
+                ALOGV("[SourceType%d] durationUs=%" PRId64 "", type, trackDurationUs);
+                const sp<MetaData> meta = impl->getFormat();
+                meta->setInt64(kKeyDuration, trackDurationUs);
+                impl->setFormat(meta);
+
+                found = true;
+            }
         }
-        if (durationUs > 0) {
-            const sp<MetaData> meta = impl->getFormat();
-            meta->setInt64(kKeyDuration, durationUs);
-            impl->setFormat(meta);
-        } else {
+        if (!found) {
             estimateDurationsFromTimesUsAtEnd();
         }
     }
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index f5a1b01..fe509bf 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -310,6 +310,7 @@
                 mTrackMeta.setInt32(kKeyChannelCount, mNumChannels);
                 mTrackMeta.setInt32(kKeyChannelMask, mChannelMask);
                 mTrackMeta.setInt32(kKeySampleRate, mSampleRate);
+                mTrackMeta.setInt32(kKeyBitsPerSample, mBitsPerSample);
                 mTrackMeta.setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
 
                 int64_t durationUs = 0;
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index f00f7a8..4857008 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -32,6 +32,7 @@
 cc_library_headers {
     name: "libaaudio_headers",
     export_include_dirs: ["include"],
+    version_script: "libaaudio.map.txt",
 }
 
 subdirs = ["*"]
diff --git a/media/libaaudio/examples/input_monitor/Android.bp b/media/libaaudio/examples/input_monitor/Android.bp
index d8c5843..5d399b5 100644
--- a/media/libaaudio/examples/input_monitor/Android.bp
+++ b/media/libaaudio/examples/input_monitor/Android.bp
@@ -5,6 +5,7 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
 
 cc_test {
@@ -14,4 +15,5 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/loopback/Android.bp b/media/libaaudio/examples/loopback/Android.bp
index 5b7d956..53e5020 100644
--- a/media/libaaudio/examples/loopback/Android.bp
+++ b/media/libaaudio/examples/loopback/Android.bp
@@ -9,4 +9,5 @@
         "libaudioutils",
         ],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index ef9a753..9711b86 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -34,12 +34,123 @@
 
 // Tag for machine readable results as property = value pairs
 #define LOOPBACK_RESULT_TAG      "RESULT: "
-#define LOOPBACK_SAMPLE_RATE     48000
 
-#define MILLIS_PER_SECOND        1000
+constexpr int32_t kDefaultSampleRate = 48000;
+constexpr int32_t kMillisPerSecond   = 1000;
+constexpr int32_t kMinLatencyMillis  = 4;    // arbitrary and very low
+constexpr int32_t kMaxLatencyMillis  = 400;  // arbitrary and generous
+constexpr double  kMaxEchoGain       = 10.0; // based on experiments, otherwise too noisy
+constexpr double  kMinimumConfidence = 0.5;
 
-#define MAX_ZEROTH_PARTIAL_BINS  40
-constexpr double MAX_ECHO_GAIN = 10.0; // based on experiments, otherwise autocorrelation too noisy
+static void printAudioScope(float sample) {
+    const int maxStars = 80; // arbitrary, fits on one line
+    char c = '*';
+    if (sample < -1.0) {
+        sample = -1.0;
+        c = '$';
+    } else if (sample > 1.0) {
+        sample = 1.0;
+        c = '$';
+    }
+    int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars);
+    for (int i = 0; i < numSpaces; i++) {
+        putchar(' ');
+    }
+    printf("%c\n", c);
+}
+
+/*
+
+FIR filter designed with
+http://t-filter.appspot.com
+
+sampling frequency: 48000 Hz
+
+* 0 Hz - 8000 Hz
+  gain = 1.2
+  desired ripple = 5 dB
+  actual ripple = 5.595266169703693 dB
+
+* 12000 Hz - 20000 Hz
+  gain = 0
+  desired attenuation = -40 dB
+  actual attenuation = -37.58691566571914 dB
+
+*/
+
+#define FILTER_TAP_NUM 11
+
+static const float sFilterTaps8000[FILTER_TAP_NUM] = {
+        -0.05944219353343189f,
+        -0.07303434839503208f,
+        -0.037690487672689066f,
+        0.1870480506596512f,
+        0.3910337357836833f,
+        0.5333672385425637f,
+        0.3910337357836833f,
+        0.1870480506596512f,
+        -0.037690487672689066f,
+        -0.07303434839503208f,
+        -0.05944219353343189f
+};
+
+class LowPassFilter {
+public:
+
+    /*
+     * Filter one input sample.
+     * @return filtered output
+     */
+    float filter(float input) {
+        float output = 0.0f;
+        mX[mCursor] = input;
+        // Index backwards over x.
+        int xIndex = mCursor + FILTER_TAP_NUM;
+        // Write twice so we avoid having to wrap in the middle of the convolution.
+        mX[xIndex] = input;
+        for (int i = 0; i < FILTER_TAP_NUM; i++) {
+            output += sFilterTaps8000[i] * mX[xIndex--];
+        }
+        if (++mCursor >= FILTER_TAP_NUM) {
+            mCursor = 0;
+        }
+        return output;
+    }
+
+    /**
+     * @return true if PASSED
+     */
+    bool test() {
+        // Measure the impulse of the filter at different phases so we exercise
+        // all the wraparound cases in the FIR.
+        for (int offset = 0; offset < (FILTER_TAP_NUM * 2); offset++ ) {
+            // printf("LowPassFilter: cursor = %d\n", mCursor);
+            // Offset by one each time.
+            if (filter(0.0f) != 0.0f) {
+                printf("ERROR: filter should return 0.0 before impulse response\n");
+                return false;
+            }
+            for (int i = 0; i < FILTER_TAP_NUM; i++) {
+                float output = filter((i == 0) ? 1.0f : 0.0f); // impulse
+                if (output != sFilterTaps8000[i]) {
+                    printf("ERROR: filter should return impulse response\n");
+                    return false;
+                }
+            }
+            for (int i = 0; i < FILTER_TAP_NUM; i++) {
+                if (filter(0.0f) != 0.0f) {
+                    printf("ERROR: filter should return 0.0 after impulse response\n");
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+private:
+    float   mX[FILTER_TAP_NUM * 2]{}; // twice as big as needed to avoid wrapping
+    int32_t mCursor = 0;
+};
 
 // A narrow impulse seems to have better immunity against over estimating the
 // latency due to detecting subharmonics by the auto-correlator.
@@ -78,6 +189,12 @@
     int64_t mSeed = 99887766;
 };
 
+
+typedef struct LatencyReport_s {
+    double latencyInFrames;
+    double confidence;
+} LatencyReport;
+
 static double calculateCorrelation(const float *a,
                                    const float *b,
                                    int windowSize)
@@ -101,130 +218,75 @@
     return correlation;
 }
 
-static int calculateCorrelations(const float *haystack, int haystackSize,
-                                 const float *needle, int needleSize,
-                                 float *results, int resultSize)
-{
-    int maxCorrelations = haystackSize - needleSize;
-    int numCorrelations = std::min(maxCorrelations, resultSize);
-
-    for (int ic = 0; ic < numCorrelations; ic++) {
-        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
-        results[ic] = correlation;
-    }
-
-    return numCorrelations;
-}
-
-/*==========================================================================================*/
-/**
- * Scan until we get a correlation of a single scan that goes over the tolerance level,
- * peaks then drops back down.
- */
-static double findFirstMatch(const float *haystack, int haystackSize,
-                             const float *needle, int needleSize, double threshold  )
-{
-    int ic;
-    // How many correlations can we calculate?
-    int numCorrelations = haystackSize - needleSize;
-    double maxCorrelation = 0.0;
-    int peakIndex = -1;
-    double location = -1.0;
-    const double backThresholdScaler = 0.5;
-
-    for (ic = 0; ic < numCorrelations; ic++) {
-        double correlation = calculateCorrelation(&haystack[ic], needle, needleSize);
-
-        if( (correlation > maxCorrelation) ) {
-            maxCorrelation = correlation;
-            peakIndex = ic;
-        }
-
-        //printf("PaQa_FindFirstMatch: ic = %4d, correlation = %8f, maxSum = %8f\n",
-        //    ic, correlation, maxSum );
-        // Are we past what we were looking for?
-        if((maxCorrelation > threshold) && (correlation < backThresholdScaler * maxCorrelation)) {
-            location = peakIndex;
-            break;
-        }
-    }
-
-    return location;
-}
-
-typedef struct LatencyReport_s {
-    double latencyInFrames;
-    double confidence;
-} LatencyReport;
-
-// Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental.
-// Using first echo instead of the original impulse for a better match.
-static int measureLatencyFromEchos(const float *haystack, int haystackSize,
-                            const float *needle, int needleSize,
-                            LatencyReport *report) {
-    const double threshold = 0.1;
-    printf("measureLatencyFromEchos: haystackSize = %d, needleSize = %d\n",
-           haystackSize, needleSize);
-
-    // Find first peak
-    int first = (int) (findFirstMatch(haystack,
-                                      haystackSize,
-                                      needle,
-                                      needleSize,
-                                      threshold) + 0.5);
-
-    // Use first echo as the needle for the other echos because
-    // it will be more similar.
-    needle = &haystack[first];
-    int again = (int) (findFirstMatch(haystack,
-                                      haystackSize,
-                                      needle,
-                                      needleSize,
-                                      threshold) + 0.5);
-
-    printf("measureLatencyFromEchos: first = %d, again at %d\n", first, again);
-    first = again;
-
+static int measureLatencyFromEchos(const float *data,
+                                   int32_t numFloats,
+                                   int32_t sampleRate,
+                                   LatencyReport *report) {
     // Allocate results array
-    int remaining = haystackSize - first;
-    const int maxReasonableLatencyFrames = 48000 * 2; // arbitrary but generous value
-    int numCorrelations = std::min(remaining, maxReasonableLatencyFrames);
-    float *correlations = new float[numCorrelations];
-    float *harmonicSums = new float[numCorrelations](); // set to zero
+    const int minReasonableLatencyFrames = sampleRate * kMinLatencyMillis / kMillisPerSecond;
+    const int maxReasonableLatencyFrames = sampleRate * kMaxLatencyMillis / kMillisPerSecond;
+    int32_t maxCorrelationSize = maxReasonableLatencyFrames * 3;
+    int numCorrelations = std::min(numFloats, maxCorrelationSize);
+    float *correlations = new float[numCorrelations]{};
+    float *harmonicSums = new float[numCorrelations]{};
 
-    // Generate correlation for every position.
-    numCorrelations = calculateCorrelations(&haystack[first], remaining,
-                                            needle, needleSize,
-                                            correlations, numCorrelations);
+    // Perform sliding auto-correlation.
+    // Skip first frames to avoid huge peak at zero offset.
+    for (int i = minReasonableLatencyFrames; i < numCorrelations; i++) {
+        int32_t remaining = numFloats - i;
+        float correlation = (float) calculateCorrelation(&data[i], data, remaining);
+        correlations[i] = correlation;
+        // printf("correlation[%d] = %f\n", ic, correlation);
+    }
 
-    // Add higher harmonics mapped onto lower harmonics.
-    // This reinforces the "fundamental" echo.
-    const int numEchoes = 10;
+    // Apply a technique similar to Harmonic Product Spectrum Analysis to find echo fundamental.
+    // Add higher harmonics mapped onto lower harmonics. This reinforces the "fundamental" echo.
+    const int numEchoes = 8;
     for (int partial = 1; partial < numEchoes; partial++) {
-        for (int i = 0; i < numCorrelations; i++) {
+        for (int i = minReasonableLatencyFrames; i < numCorrelations; i++) {
             harmonicSums[i / partial] += correlations[i] / partial;
         }
     }
 
     // Find highest peak in correlation array.
     float maxCorrelation = 0.0;
-    float sumOfPeaks = 0.0;
     int peakIndex = 0;
-    const int skip = MAX_ZEROTH_PARTIAL_BINS; // skip low bins
-    for (int i = skip; i < numCorrelations; i++) {
+    for (int i = 0; i < numCorrelations; i++) {
         if (harmonicSums[i] > maxCorrelation) {
             maxCorrelation = harmonicSums[i];
-            sumOfPeaks += maxCorrelation;
             peakIndex = i;
-            printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
+            // printf("maxCorrelation = %f at %d\n", maxCorrelation, peakIndex);
         }
     }
-
     report->latencyInFrames = peakIndex;
-    if (sumOfPeaks < 0.0001) {
+/*
+    {
+        int32_t topPeak = peakIndex * 7 / 2;
+        for (int i = 0; i < topPeak; i++) {
+            float sample = harmonicSums[i];
+            printf("%4d: %7.5f ", i, sample);
+            printAudioScope(sample);
+        }
+    }
+*/
+
+    // Calculate confidence.
+    if (maxCorrelation < 0.001) {
         report->confidence = 0.0;
     } else {
-        report->confidence = maxCorrelation / sumOfPeaks;
+        // Compare peak to average value around peak.
+        int32_t numSamples = std::min(numCorrelations, peakIndex * 2);
+        if (numSamples <= 0) {
+            report->confidence = 0.0;
+        } else {
+            double sum = 0.0;
+            for (int i = 0; i < numSamples; i++) {
+                sum += harmonicSums[i];
+            }
+            const double average = sum / numSamples;
+            const double ratio = average / maxCorrelation; // will be < 1.0
+            report->confidence = 1.0 - sqrt(ratio);
+        }
     }
 
     delete[] correlations;
@@ -320,7 +382,9 @@
         }
 
         assert(info.channels == 1);
+        assert(info.format == SF_FORMAT_FLOAT);
 
+        setSampleRate(info.samplerate);
         allocate(info.frames);
         mFrameCounter = sf_readf_float(sndFile, mData, info.frames);
 
@@ -328,11 +392,49 @@
         return mFrameCounter;
     }
 
+    /**
+     * Square the samples so they are all positive and so the peaks are emphasized.
+     */
+    void square() {
+        for (int i = 0; i < mFrameCounter; i++) {
+            const float sample = mData[i];
+            mData[i] = sample * sample;
+        }
+    }
+
+    /**
+     * Low pass filter the recording using a simple FIR filter.
+     * Note that the lowpass filter cutoff tracks the sample rate.
+     * That is OK because the impulse width is a fixed number of samples.
+     */
+    void lowPassFilter() {
+        for (int i = 0; i < mFrameCounter; i++) {
+            mData[i] = mLowPassFilter.filter(mData[i]);
+        }
+    }
+
+    /**
+     * Remove DC offset using a one-pole one-zero IIR filter.
+     */
+    void dcBlocker() {
+        const float R = 0.996; // narrow notch at zero Hz
+        float x1 = 0.0;
+        float y1 = 0.0;
+        for (int i = 0; i < mFrameCounter; i++) {
+            const float x = mData[i];
+            const float y = x - x1 + (R * y1);
+            mData[i] = y;
+            y1 = y;
+            x1 = x;
+        }
+    }
+
 private:
-    float  *mData = nullptr;
-    int32_t mFrameCounter = 0;
-    int32_t mMaxFrames = 0;
-    int32_t mSampleRate = 48000; // common default
+    float        *mData = nullptr;
+    int32_t       mFrameCounter = 0;
+    int32_t       mMaxFrames = 0;
+    int32_t       mSampleRate = kDefaultSampleRate; // common default
+    LowPassFilter mLowPassFilter;
 };
 
 // ====================================================================================
@@ -352,8 +454,12 @@
 
     virtual void printStatus() {};
 
-    virtual int getResult() {
-        return -1;
+    int32_t getResult() {
+        return mResult;
+    }
+
+    void setResult(int32_t result) {
+        mResult = result;
     }
 
     virtual bool isDone() {
@@ -382,7 +488,7 @@
     static float measurePeakAmplitude(float *inputData, int inputChannelCount, int numFrames) {
         float peak = 0.0f;
         for (int i = 0; i < numFrames; i++) {
-            float pos = fabs(*inputData);
+            const float pos = fabs(*inputData);
             if (pos > peak) {
                 peak = pos;
             }
@@ -393,7 +499,8 @@
 
 
 private:
-    int32_t mSampleRate = LOOPBACK_SAMPLE_RATE;
+    int32_t mSampleRate = kDefaultSampleRate;
+    int32_t mResult = 0;
 };
 
 class PeakDetector {
@@ -412,24 +519,6 @@
     float  mPrevious = 0.0f;
 };
 
-
-static void printAudioScope(float sample) {
-    const int maxStars = 80; // arbitrary, fits on one line
-    char c = '*';
-    if (sample < -1.0) {
-        sample = -1.0;
-        c = '$';
-    } else if (sample > 1.0) {
-        sample = 1.0;
-        c = '$';
-    }
-    int numSpaces = (int) (((sample + 1.0) * 0.5) * maxStars);
-    for (int i = 0; i < numSpaces; i++) {
-        putchar(' ');
-    }
-    printf("%c\n", c);
-}
-
 // ====================================================================================
 /**
  * Measure latency given a loopback stream data.
@@ -450,17 +539,13 @@
     }
 
     void reset() override {
-        mDownCounter = 200;
+        mDownCounter = getSampleRate() / 2;
         mLoopCounter = 0;
         mMeasuredLoopGain = 0.0f;
         mEchoGain = 1.0f;
         mState = STATE_INITIAL_SILENCE;
     }
 
-    virtual int getResult() {
-        return mState == STATE_DONE ? 0 : -1;
-    }
-
     virtual bool isDone() {
         return mState == STATE_DONE || mState == STATE_FAILED;
     }
@@ -473,27 +558,57 @@
         return mEchoGain;
     }
 
-    void report() override {
+    bool testLowPassFilter() {
+        LowPassFilter filter;
+        return filter.test();
+    }
 
+    void report() override {
         printf("EchoAnalyzer ---------------\n");
-        printf(LOOPBACK_RESULT_TAG "measured.gain          = %f\n", mMeasuredLoopGain);
-        printf(LOOPBACK_RESULT_TAG "echo.gain              = %f\n", mEchoGain);
-        printf(LOOPBACK_RESULT_TAG "test.state             = %d\n", mState);
-        if (mMeasuredLoopGain >= 0.9999) {
+        if (getResult() != 0) {
+            printf(LOOPBACK_RESULT_TAG "result          = %d\n", getResult());
+            return;
+        }
+
+        // printf("LowPassFilter test %s\n", testLowPassFilter() ? "PASSED" : "FAILED");
+
+        printf(LOOPBACK_RESULT_TAG "measured.gain          = %8f\n", mMeasuredLoopGain);
+        printf(LOOPBACK_RESULT_TAG "echo.gain              = %8f\n", mEchoGain);
+        printf(LOOPBACK_RESULT_TAG "test.state             = %8d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "test.state.name        = %8s\n", convertStateToText(mState));
+
+        if (mState == STATE_WAITING_FOR_SILENCE) {
+            printf("WARNING - Stuck waiting for silence. Input may be too noisy!\n");
+            setResult(ERROR_NOISY);
+        } else if (mMeasuredLoopGain >= 0.9999) {
             printf("   ERROR - clipping, turn down volume slightly\n");
+            setResult(ERROR_CLIPPING);
+        } else if (mState != STATE_DONE && mState != STATE_GATHERING_ECHOS) {
+            printf("WARNING - Bad state. Check volume on device.\n");
+            setResult(ERROR_INVALID_STATE);
         } else {
-            const float *needle = s_Impulse;
-            int needleSize = (int) (sizeof(s_Impulse) / sizeof(float));
-            float *haystack = mAudioRecording.getData();
-            int haystackSize = mAudioRecording.size();
-            measureLatencyFromEchos(haystack, haystackSize, needle, needleSize, &mLatencyReport);
-            if (mLatencyReport.confidence < 0.01) {
-                printf("   ERROR - confidence too low = %f\n", mLatencyReport.confidence);
-            } else {
-                double latencyMillis = 1000.0 * mLatencyReport.latencyInFrames / getSampleRate();
-                printf(LOOPBACK_RESULT_TAG "latency.frames        = %8.2f\n", mLatencyReport.latencyInFrames);
-                printf(LOOPBACK_RESULT_TAG "latency.msec          = %8.2f\n", latencyMillis);
-                printf(LOOPBACK_RESULT_TAG "latency.confidence    = %8.6f\n", mLatencyReport.confidence);
+            // Cleanup the signal to improve the auto-correlation.
+            mAudioRecording.dcBlocker();
+            mAudioRecording.square();
+            mAudioRecording.lowPassFilter();
+
+            printf("Please wait several seconds for auto-correlation to complete.\n");
+            measureLatencyFromEchos(mAudioRecording.getData(),
+                                    mAudioRecording.size(),
+                                    getSampleRate(),
+                                    &mLatencyReport);
+
+            double latencyMillis = kMillisPerSecond * (double) mLatencyReport.latencyInFrames
+                                   / getSampleRate();
+            printf(LOOPBACK_RESULT_TAG "latency.frames         = %8.2f\n",
+                   mLatencyReport.latencyInFrames);
+            printf(LOOPBACK_RESULT_TAG "latency.msec           = %8.2f\n",
+                   latencyMillis);
+            printf(LOOPBACK_RESULT_TAG "latency.confidence     = %8.6f\n",
+                   mLatencyReport.confidence);
+            if (mLatencyReport.confidence < kMinimumConfidence) {
+                printf("   ERROR - confidence too low!\n");
+                setResult(ERROR_CONFIDENCE);
             }
         }
     }
@@ -519,6 +634,11 @@
         sendImpulses(outputData, outputChannelCount, kImpulseSizeInFrames);
     }
 
+    // @return number of frames for a typical block of processing
+    int32_t getBlockFrames() {
+        return getSampleRate() / 8;
+    }
+
     void process(float *inputData, int inputChannelCount,
                  float *outputData, int outputChannelCount,
                  int numFrames) override {
@@ -527,7 +647,7 @@
         int numWritten;
         int numSamples;
 
-        echo_state_t nextState = mState;
+        echo_state nextState = mState;
 
         switch (mState) {
             case STATE_INITIAL_SILENCE:
@@ -536,10 +656,11 @@
                 for (int i = 0; i < numSamples; i++) {
                     outputData[i] = 0;
                 }
-                if (mDownCounter-- <= 0) {
+                mDownCounter -= numFrames;
+                if (mDownCounter <= 0) {
                     nextState = STATE_MEASURING_GAIN;
                     //printf("%5d: switch to STATE_MEASURING_GAIN\n", mLoopCounter);
-                    mDownCounter = 8;
+                    mDownCounter = getBlockFrames() * 2;
                 }
                 break;
 
@@ -548,14 +669,16 @@
                 peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
                 // If we get several in a row then go to next state.
                 if (peak > mPulseThreshold) {
-                    if (mDownCounter-- <= 0) {
+                    mDownCounter -= numFrames;
+                    if (mDownCounter <= 0) {
                         //printf("%5d: switch to STATE_WAITING_FOR_SILENCE, measured peak = %f\n",
                         //       mLoopCounter, peak);
-                        mDownCounter = 8;
+                        mDownCounter = getBlockFrames();
                         mMeasuredLoopGain = peak;  // assumes original pulse amplitude is one
+                        mSilenceThreshold = peak * 0.1; // scale silence to measured pulse
                         // Calculate gain that will give us a nice decaying echo.
                         mEchoGain = mDesiredEchoGain / mMeasuredLoopGain;
-                        if (mEchoGain > MAX_ECHO_GAIN) {
+                        if (mEchoGain > kMaxEchoGain) {
                             printf("ERROR - loop gain too low. Increase the volume.\n");
                             nextState = STATE_FAILED;
                         } else {
@@ -563,7 +686,7 @@
                         }
                     }
                 } else if (numFrames > kImpulseSizeInFrames){ // ignore short callbacks
-                    mDownCounter = 8;
+                    mDownCounter = getBlockFrames();
                 }
                 break;
 
@@ -576,13 +699,14 @@
                 peak = measurePeakAmplitude(inputData, inputChannelCount, numFrames);
                 // If we get several in a row then go to next state.
                 if (peak < mSilenceThreshold) {
-                    if (mDownCounter-- <= 0) {
+                    mDownCounter -= numFrames;
+                    if (mDownCounter <= 0) {
                         nextState = STATE_SENDING_PULSE;
                         //printf("%5d: switch to STATE_SENDING_PULSE\n", mLoopCounter);
-                        mDownCounter = 8;
+                        mDownCounter = getBlockFrames();
                     }
                 } else {
-                    mDownCounter = 8;
+                    mDownCounter = getBlockFrames();
                 }
                 break;
 
@@ -615,11 +739,11 @@
                 }
                 if (numWritten  < numFrames) {
                     nextState = STATE_DONE;
-                    //printf("%5d: switch to STATE_DONE\n", mLoopCounter);
                 }
                 break;
 
             case STATE_DONE:
+            case STATE_FAILED:
             default:
                 break;
         }
@@ -633,12 +757,23 @@
     }
 
     int load(const char *fileName) override {
-        return mAudioRecording.load(fileName);
+        int result = mAudioRecording.load(fileName);
+        setSampleRate(mAudioRecording.getSampleRate());
+        mState = STATE_DONE;
+        return result;
     }
 
 private:
 
-    enum echo_state_t {
+    enum error_code {
+        ERROR_OK = 0,
+        ERROR_NOISY = -99,
+        ERROR_CLIPPING,
+        ERROR_CONFIDENCE,
+        ERROR_INVALID_STATE
+    };
+
+    enum echo_state {
         STATE_INITIAL_SILENCE,
         STATE_MEASURING_GAIN,
         STATE_WAITING_FOR_SILENCE,
@@ -648,6 +783,35 @@
         STATE_FAILED
     };
 
+    const char *convertStateToText(echo_state state) {
+        const char *result = "Unknown";
+        switch(state) {
+            case STATE_INITIAL_SILENCE:
+                result = "INIT";
+                break;
+            case STATE_MEASURING_GAIN:
+                result = "GAIN";
+                break;
+            case STATE_WAITING_FOR_SILENCE:
+                result = "SILENCE";
+                break;
+            case STATE_SENDING_PULSE:
+                result = "PULSE";
+                break;
+            case STATE_GATHERING_ECHOS:
+                result = "ECHOS";
+                break;
+            case STATE_DONE:
+                result = "DONE";
+                break;
+            case STATE_FAILED:
+                result = "FAILED";
+                break;
+        }
+        return result;
+    }
+
+
     int32_t         mDownCounter = 500;
     int32_t         mLoopCounter = 0;
     int32_t         mSampleIndex = 0;
@@ -656,7 +820,7 @@
     float           mMeasuredLoopGain = 0.0f;
     float           mDesiredEchoGain = 0.95f;
     float           mEchoGain = 1.0f;
-    echo_state_t    mState = STATE_INITIAL_SILENCE;
+    echo_state      mState = STATE_INITIAL_SILENCE;
 
     AudioRecording  mAudioRecording; // contains only the input after the gain detection burst
     LatencyReport   mLatencyReport;
@@ -674,27 +838,38 @@
 class SineAnalyzer : public LoopbackProcessor {
 public:
 
-    virtual int getResult() {
-        return mState == STATE_LOCKED ? 0 : -1;
-    }
-
     void report() override {
         printf("SineAnalyzer ------------------\n");
-        printf(LOOPBACK_RESULT_TAG "peak.amplitude     = %7.5f\n", mPeakAmplitude);
-        printf(LOOPBACK_RESULT_TAG "sine.magnitude     = %7.5f\n", mMagnitude);
-        printf(LOOPBACK_RESULT_TAG "phase.offset       = %7.5f\n", mPhaseOffset);
-        printf(LOOPBACK_RESULT_TAG "ref.phase          = %7.5f\n", mPhase);
-        printf(LOOPBACK_RESULT_TAG "frames.accumulated = %6d\n", mFramesAccumulated);
-        printf(LOOPBACK_RESULT_TAG "sine.period        = %6d\n", mSinePeriod);
-        printf(LOOPBACK_RESULT_TAG "test.state         = %6d\n", mState);
-        printf(LOOPBACK_RESULT_TAG "frame.count        = %6d\n", mFrameCounter);
+        printf(LOOPBACK_RESULT_TAG "peak.amplitude     = %8f\n", mPeakAmplitude);
+        printf(LOOPBACK_RESULT_TAG "sine.magnitude     = %8f\n", mMagnitude);
+        printf(LOOPBACK_RESULT_TAG "peak.noise         = %8f\n", mPeakNoise);
+        printf(LOOPBACK_RESULT_TAG "rms.noise          = %8f\n", mRootMeanSquareNoise);
+        float amplitudeRatio = mMagnitude / mPeakNoise;
+        float signalToNoise = amplitudeRatio * amplitudeRatio;
+        printf(LOOPBACK_RESULT_TAG "signal.to.noise    = %8.2f\n", signalToNoise);
+        float signalToNoiseDB = 10.0 * log(signalToNoise);
+        printf(LOOPBACK_RESULT_TAG "signal.to.noise.db = %8.2f\n", signalToNoiseDB);
+        if (signalToNoiseDB < MIN_SNRATIO_DB) {
+            printf("ERROR - signal to noise ratio is too low! < %d dB. Adjust volume.\n", MIN_SNRATIO_DB);
+            setResult(ERROR_NOISY);
+        }
+        printf(LOOPBACK_RESULT_TAG "frames.accumulated = %8d\n", mFramesAccumulated);
+        printf(LOOPBACK_RESULT_TAG "sine.period        = %8d\n", mSinePeriod);
+        printf(LOOPBACK_RESULT_TAG "test.state         = %8d\n", mState);
+        printf(LOOPBACK_RESULT_TAG "frame.count        = %8d\n", mFrameCounter);
         // Did we ever get a lock?
         bool gotLock = (mState == STATE_LOCKED) || (mGlitchCount > 0);
         if (!gotLock) {
             printf("ERROR - failed to lock on reference sine tone\n");
+            setResult(ERROR_NO_LOCK);
         } else {
             // Only print if meaningful.
-            printf(LOOPBACK_RESULT_TAG "glitch.count       = %6d\n", mGlitchCount);
+            printf(LOOPBACK_RESULT_TAG "glitch.count       = %8d\n", mGlitchCount);
+            printf(LOOPBACK_RESULT_TAG "max.glitch         = %8f\n", mMaxGlitchDelta);
+            if (mGlitchCount > 0) {
+                printf("ERROR - number of glitches > 0\n");
+                setResult(ERROR_GLITCHES);
+            }
         }
     }
 
@@ -732,15 +907,48 @@
         }
 
         for (int i = 0; i < numFrames; i++) {
+            bool sineEnabled = true;
             float sample = inputData[i * inputChannelCount];
 
             float sinOut = sinf(mPhase);
 
             switch (mState) {
                 case STATE_IDLE:
-                case STATE_IMMUNE:
-                case STATE_WAITING_FOR_SIGNAL:
+                    sineEnabled = false;
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_MEASURE_NOISE;
+                        mDownCounter = NOISE_FRAME_COUNT;
+                    }
                     break;
+                case STATE_MEASURE_NOISE:
+                    sineEnabled = false;
+                    mPeakNoise = std::max(abs(sample), mPeakNoise);
+                    mNoiseSumSquared += sample * sample;
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_WAITING_FOR_SIGNAL;
+                        mRootMeanSquareNoise = sqrt(mNoiseSumSquared / NOISE_FRAME_COUNT);
+                        mTolerance = std::max(MIN_TOLERANCE, mPeakNoise * 2.0f);
+                        mPhase = 0.0; // prevent spike at start
+                    }
+                    break;
+
+                case STATE_IMMUNE:
+                    mDownCounter--;
+                    if (mDownCounter <= 0) {
+                        mState = STATE_WAITING_FOR_SIGNAL;
+                    }
+                    break;
+
+                case STATE_WAITING_FOR_SIGNAL:
+                    if (peak > mThreshold) {
+                        mState = STATE_WAITING_FOR_LOCK;
+                        //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
+                        resetAccumulator();
+                    }
+                    break;
+
                 case STATE_WAITING_FOR_LOCK:
                     mSinAccumulator += sample * sinOut;
                     mCosAccumulator += sample * cosf(mPhase);
@@ -766,13 +974,14 @@
                     // printf("    predicted = %f, actual = %f\n", predicted, sample);
 
                     float diff = predicted - sample;
-                    if (fabs(diff) > mTolerance) {
+                    float absDiff = fabs(diff);
+                    mMaxGlitchDelta = std::max(mMaxGlitchDelta, absDiff);
+                    if (absDiff > mTolerance) {
                         mGlitchCount++;
                         //printf("%5d: Got a glitch # %d, predicted = %f, actual = %f\n",
                         //       mFrameCounter, mGlitchCount, predicted, sample);
                         mState = STATE_IMMUNE;
-                        //printf("%5d: switch to STATE_IMMUNE\n", mFrameCounter);
-                        mDownCounter = mSinePeriod;  // Set duration of IMMUNE state.
+                        mDownCounter = mSinePeriod * PERIODS_IMMUNE;
                     }
 
                     // Track incoming signal and slowly adjust magnitude to account
@@ -792,44 +1001,23 @@
                 } break;
             }
 
+            float output = 0.0f;
             // Output sine wave so we can measure it.
-            outputData[i * outputChannelCount] = (sinOut * mOutputAmplitude)
-                    + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
-            // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut,  mPhaseIncrement);
-
-            // advance and wrap phase
-            mPhase += mPhaseIncrement;
-            if (mPhase > M_PI) {
-                mPhase -= (2.0 * M_PI);
+            if (sineEnabled) {
+                output = (sinOut * mOutputAmplitude)
+                         + (mWhiteNoise.nextRandomDouble() * mNoiseAmplitude);
+                // printf("%5d: sin(%f) = %f, %f\n", i, mPhase, sinOut,  mPhaseIncrement);
+                // advance and wrap phase
+                mPhase += mPhaseIncrement;
+                if (mPhase > M_PI) {
+                    mPhase -= (2.0 * M_PI);
+                }
             }
+            outputData[i * outputChannelCount] = output;
+
 
             mFrameCounter++;
         }
-
-        // Do these once per buffer.
-        switch (mState) {
-            case STATE_IDLE:
-                mState = STATE_IMMUNE; // so we can tell when
-                break;
-            case STATE_IMMUNE:
-                mDownCounter -= numFrames;
-                if (mDownCounter <= 0) {
-                    mState = STATE_WAITING_FOR_SIGNAL;
-                    //printf("%5d: switch to STATE_WAITING_FOR_SIGNAL\n", mFrameCounter);
-                }
-                break;
-            case STATE_WAITING_FOR_SIGNAL:
-                if (peak > mThreshold) {
-                    mState = STATE_WAITING_FOR_LOCK;
-                    //printf("%5d: switch to STATE_WAITING_FOR_LOCK\n", mFrameCounter);
-                    resetAccumulator();
-                }
-                break;
-            case STATE_WAITING_FOR_LOCK:
-            case STATE_LOCKED:
-                break;
-        }
-
     }
 
     void resetAccumulator() {
@@ -840,18 +1028,31 @@
 
     void reset() override {
         mGlitchCount = 0;
-        mState = STATE_IMMUNE;
-        mDownCounter = IMMUNE_FRAME_COUNT;
+        mState = STATE_IDLE;
+        mDownCounter = IDLE_FRAME_COUNT;
         mPhaseIncrement = 2.0 * M_PI / mSinePeriod;
         printf("phaseInc = %f for period %d\n", mPhaseIncrement, mSinePeriod);
         resetAccumulator();
         mProcessCount = 0;
+        mPeakNoise = 0.0f;
+        mNoiseSumSquared = 0.0;
+        mRootMeanSquareNoise = 0.0;
+        mPhase = 0.0f;
+        mMaxGlitchDelta = 0.0;
     }
 
 private:
 
+    enum error_code {
+        OK,
+        ERROR_NO_LOCK = -80,
+        ERROR_GLITCHES,
+        ERROR_NOISY
+    };
+
     enum sine_state_t {
         STATE_IDLE,
+        STATE_MEASURE_NOISE,
         STATE_IMMUNE,
         STATE_WAITING_FOR_SIGNAL,
         STATE_WAITING_FOR_LOCK,
@@ -859,10 +1060,16 @@
     };
 
     enum constants {
-        IMMUNE_FRAME_COUNT = 48 * 500,
-        PERIODS_NEEDED_FOR_LOCK = 8
+        // Arbitrary durations, assuming 48000 Hz
+        IDLE_FRAME_COUNT = 48 * 100,
+        NOISE_FRAME_COUNT = 48 * 600,
+        PERIODS_NEEDED_FOR_LOCK = 8,
+        PERIODS_IMMUNE = 2,
+        MIN_SNRATIO_DB = 65
     };
 
+    static constexpr float MIN_TOLERANCE = 0.01;
+
     int     mSinePeriod = 79;
     double  mPhaseIncrement = 0.0;
     double  mPhase = 0.0;
@@ -870,25 +1077,29 @@
     double  mPreviousPhaseOffset = 0.0;
     double  mMagnitude = 0.0;
     double  mThreshold = 0.005;
-    double  mTolerance = 0.01;
+    double  mTolerance = MIN_TOLERANCE;
     int32_t mFramesAccumulated = 0;
     int32_t mProcessCount = 0;
     double  mSinAccumulator = 0.0;
     double  mCosAccumulator = 0.0;
+    float   mMaxGlitchDelta = 0.0f;
     int32_t mGlitchCount = 0;
     double  mPeakAmplitude = 0.0;
-    int     mDownCounter = IMMUNE_FRAME_COUNT;
+    int     mDownCounter = IDLE_FRAME_COUNT;
     int32_t mFrameCounter = 0;
     float   mOutputAmplitude = 0.75;
 
+    // measure background noise
+    float   mPeakNoise = 0.0f;
+    double  mNoiseSumSquared = 0.0;
+    double  mRootMeanSquareNoise = 0.0;
+
     PseudoRandom  mWhiteNoise;
     float   mNoiseAmplitude = 0.00; // Used to experiment with warbling caused by DRC.
 
     sine_state_t  mState = STATE_IDLE;
 };
 
-
-#undef LOOPBACK_SAMPLE_RATE
 #undef LOOPBACK_RESULT_TAG
 
 #endif /* AAUDIO_EXAMPLES_LOOPBACK_ANALYSER_H */
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 91ebf73..2a02b20 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -35,15 +35,17 @@
 #include "AAudioExampleUtils.h"
 #include "LoopbackAnalyzer.h"
 
+// V0.4.00 = rectify and low-pass filter the echos, use auto-correlation on entire echo
+#define APP_VERSION             "0.4.00"
+
 // Tag for machine readable results as property = value pairs
 #define RESULT_TAG              "RESULT: "
-#define NUM_SECONDS             5
-#define PERIOD_MILLIS           1000
-#define NUM_INPUT_CHANNELS      1
 #define FILENAME_ALL            "/data/loopback_all.wav"
 #define FILENAME_ECHOS          "/data/loopback_echos.wav"
-#define APP_VERSION             "0.2.04"
+#define FILENAME_PROCESSED      "/data/loopback_processed.wav"
 
+constexpr int kLogPeriodMillis       = 1000;
+constexpr int kNumInputChannels      = 1;
 constexpr int kNumCallbacksToDrain   = 20;
 constexpr int kNumCallbacksToDiscard = 20;
 
@@ -174,7 +176,8 @@
         int64_t inputFramesWritten = AAudioStream_getFramesWritten(myData->inputStream);
         int64_t inputFramesRead = AAudioStream_getFramesRead(myData->inputStream);
         int64_t framesAvailable = inputFramesWritten - inputFramesRead;
-        actualFramesRead = readFormattedData(myData, numFrames);
+
+        actualFramesRead = readFormattedData(myData, numFrames); // READ
         if (actualFramesRead < 0) {
             result = AAUDIO_CALLBACK_RESULT_STOP;
         } else {
@@ -194,6 +197,7 @@
                 }
                 myData->insufficientReadCount++;
                 myData->insufficientReadFrames += numFrames - actualFramesRead; // deficit
+                // printf("Error insufficientReadCount = %d\n",(int)myData->insufficientReadCount);
             }
 
             int32_t numSamples = actualFramesRead * myData->actualInputChannelCount;
@@ -336,9 +340,9 @@
 
     aaudio_result_t       result = AAUDIO_OK;
     aaudio_sharing_mode_t requestedInputSharingMode  = AAUDIO_SHARING_MODE_SHARED;
-    int                   requestedInputChannelCount = NUM_INPUT_CHANNELS;
+    int                   requestedInputChannelCount = kNumInputChannels;
     aaudio_format_t       requestedInputFormat       = AAUDIO_FORMAT_UNSPECIFIED;
-    int32_t               requestedInputCapacity     = -1;
+    int32_t               requestedInputCapacity     = AAUDIO_UNSPECIFIED;
     aaudio_performance_mode_t inputPerformanceLevel  = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
 
     int32_t               outputFramesPerBurst = 0;
@@ -356,6 +360,9 @@
 
     printf("%s - Audio loopback using AAudio V" APP_VERSION "\n", argv[0]);
 
+    // Use LOW_LATENCY as the default to match input default.
+    argParser.setPerformanceMode(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+
     for (int i = 1; i < argc; i++) {
         const char *arg = argv[i];
         if (argParser.parseArg(arg)) {
@@ -404,7 +411,7 @@
     }
 
     int32_t requestedDuration = argParser.getDurationSeconds();
-    int32_t requestedDurationMillis = requestedDuration * MILLIS_PER_SECOND;
+    int32_t requestedDurationMillis = requestedDuration * kMillisPerSecond;
     int32_t timeMillis = 0;
     int32_t recordingDuration = std::min(60 * 5, requestedDuration);
 
@@ -421,9 +428,11 @@
 
             loopbackData.loopbackProcessor = &loopbackData.echoAnalyzer;
             int read = loopbackData.loopbackProcessor->load(FILENAME_ECHOS);
-            printf("main() read %d mono samples from %s on Android device\n", read, FILENAME_ECHOS);
+            printf("main() read %d mono samples from %s on Android device, rate = %d\n",
+                   read, FILENAME_ECHOS,
+                   loopbackData.loopbackProcessor->getSampleRate());
             loopbackData.loopbackProcessor->report();
-            return 0;
+            goto report_result;
         }
             break;
         default:
@@ -459,15 +468,10 @@
     argParser.setPerformanceMode(inputPerformanceLevel);
     argParser.setChannelCount(requestedInputChannelCount);
     argParser.setSharingMode(requestedInputSharingMode);
-
-    // Make sure the input buffer has plenty of capacity.
-    // Extra capacity on input should not increase latency if we keep it drained.
-    int32_t inputBufferCapacity = requestedInputCapacity;
-    if (inputBufferCapacity < 0) {
-        int32_t outputBufferCapacity = AAudioStream_getBufferCapacityInFrames(outputStream);
-        inputBufferCapacity = 2 * outputBufferCapacity;
+    if (requestedInputCapacity != AAUDIO_UNSPECIFIED) {
+        printf("Warning! If you set input capacity then maybe no FAST track on Legacy path!\n");
     }
-    argParser.setBufferCapacity(inputBufferCapacity);
+    argParser.setBufferCapacity(requestedInputCapacity);
 
     result = recorder.open(argParser);
     if (result != AAUDIO_OK) {
@@ -517,15 +521,11 @@
     // Start OUTPUT first so INPUT does not overflow.
     result = player.start();
     if (result != AAUDIO_OK) {
-        printf("ERROR - AAudioStream_requestStart(output) returned %d = %s\n",
-               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
     result = recorder.start();
     if (result != AAUDIO_OK) {
-        printf("ERROR - AAudioStream_requestStart(input) returned %d = %s\n",
-               result, AAudio_convertResultToText(result));
         goto finish;
     }
 
@@ -568,7 +568,7 @@
                    AAudioStream_getXRunCount(outputStream)
             );
         }
-        int32_t periodMillis = (timeMillis < 2000) ? PERIOD_MILLIS / 4 : PERIOD_MILLIS;
+        int32_t periodMillis = (timeMillis < 2000) ? kLogPeriodMillis / 4 : kLogPeriodMillis;
         usleep(periodMillis * 1000);
         timeMillis += periodMillis;
     }
@@ -590,45 +590,6 @@
     printf("input error = %d = %s\n",
            loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
 
-    if (loopbackData.inputError == AAUDIO_OK) {
-        if (testMode == TEST_SINE_MAGNITUDE) {
-            printAudioGraph(loopbackData.audioRecording, 200);
-        }
-        // Print again so we don't have to scroll past waveform.
-        printf("OUTPUT Stream ----------------------------------------\n");
-        argParser.compareWithStream(outputStream);
-        printf("INPUT  Stream ----------------------------------------\n");
-        argParser.compareWithStream(inputStream);
-
-        loopbackData.loopbackProcessor->report();
-    }
-
-    {
-        int32_t framesRead = AAudioStream_getFramesRead(inputStream);
-        int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
-        printf("Callback Results ---------------------------------------- INPUT\n");
-        printf("  input overruns   = %d\n", AAudioStream_getXRunCount(inputStream));
-        printf("  framesWritten    = %8d\n", framesWritten);
-        printf("  framesRead       = %8d\n", framesRead);
-        printf("  myFramesRead     = %8d\n", (int) loopbackData.framesReadTotal);
-        printf("  written - read   = %8d\n", (int) (framesWritten - framesRead));
-        printf("  insufficient #   = %8d\n", (int) loopbackData.insufficientReadCount);
-        if (loopbackData.insufficientReadCount > 0) {
-            printf("  insufficient frames = %8d\n", (int) loopbackData.insufficientReadFrames);
-        }
-    }
-    {
-        int32_t framesRead = AAudioStream_getFramesRead(outputStream);
-        int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
-        printf("Callback Results ---------------------------------------- OUTPUT\n");
-        printf("  output underruns = %d\n", AAudioStream_getXRunCount(outputStream));
-        printf("  myFramesWritten  = %8d\n", (int) loopbackData.framesWrittenTotal);
-        printf("  framesWritten    = %8d\n", framesWritten);
-        printf("  framesRead       = %8d\n", framesRead);
-        printf("  min numFrames    = %8d\n", (int) loopbackData.minNumFrames);
-        printf("  max numFrames    = %8d\n", (int) loopbackData.maxNumFrames);
-    }
-
     written = loopbackData.loopbackProcessor->save(FILENAME_ECHOS);
     if (written > 0) {
         printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
@@ -641,10 +602,46 @@
                written, FILENAME_ALL);
     }
 
-    if (loopbackData.loopbackProcessor->getResult() < 0) {
-        printf("ERROR: LOOPBACK PROCESSING FAILED. Maybe because the volume was too low.\n");
-        result = loopbackData.loopbackProcessor->getResult();
+    if (loopbackData.inputError == AAUDIO_OK) {
+        if (testMode == TEST_SINE_MAGNITUDE) {
+            printAudioGraph(loopbackData.audioRecording, 200);
+        }
+
+        loopbackData.loopbackProcessor->report();
     }
+
+    {
+        int32_t framesRead = AAudioStream_getFramesRead(inputStream);
+        int32_t framesWritten = AAudioStream_getFramesWritten(inputStream);
+        const int64_t framesAvailable = framesWritten - framesRead;
+        printf("Callback Results ---------------------------------------- INPUT\n");
+        printf("  input overruns   = %8d\n", AAudioStream_getXRunCount(inputStream));
+        printf("  framesWritten    = %8d\n", framesWritten);
+        printf("  framesRead       = %8d\n", framesRead);
+        printf("  myFramesRead     = %8d\n", (int) loopbackData.framesReadTotal);
+        printf("  written - read   = %8d\n", (int) framesAvailable);
+        printf("  insufficient #   = %8d\n", (int) loopbackData.insufficientReadCount);
+        if (loopbackData.insufficientReadCount > 0) {
+            printf("  insuffic. frames = %8d\n", (int) loopbackData.insufficientReadFrames);
+        }
+        int32_t actualInputCapacity = AAudioStream_getBufferCapacityInFrames(inputStream);
+        if (framesAvailable > 2 * actualInputCapacity) {
+            printf("  WARNING: written - read > 2*capacity !\n");
+        }
+    }
+
+    {
+        int32_t framesRead = AAudioStream_getFramesRead(outputStream);
+        int32_t framesWritten = AAudioStream_getFramesWritten(outputStream);
+        printf("Callback Results ---------------------------------------- OUTPUT\n");
+        printf("  output underruns = %8d\n", AAudioStream_getXRunCount(outputStream));
+        printf("  myFramesWritten  = %8d\n", (int) loopbackData.framesWrittenTotal);
+        printf("  framesWritten    = %8d\n", framesWritten);
+        printf("  framesRead       = %8d\n", framesRead);
+        printf("  min numFrames    = %8d\n", (int) loopbackData.minNumFrames);
+        printf("  max numFrames    = %8d\n", (int) loopbackData.maxNumFrames);
+    }
+
     if (loopbackData.insufficientReadCount > 3) {
         printf("ERROR: LOOPBACK PROCESSING FAILED. insufficientReadCount too high\n");
         result = AAUDIO_ERROR_UNAVAILABLE;
@@ -656,14 +653,23 @@
     delete[] loopbackData.inputFloatData;
     delete[] loopbackData.inputShortData;
 
+report_result:
+    written = loopbackData.loopbackProcessor->save(FILENAME_PROCESSED);
+    if (written > 0) {
+        printf("main() wrote %8d processed samples to \"%s\" on Android device\n",
+               written, FILENAME_PROCESSED);
+    }
+
+    if (loopbackData.loopbackProcessor->getResult() < 0) {
+        result = loopbackData.loopbackProcessor->getResult();
+    }
     printf(RESULT_TAG "result = %d \n", result); // machine readable
     printf("result is %s\n", AAudio_convertResultToText(result)); // human readable
     if (result != AAUDIO_OK) {
-        printf("FAILURE\n");
+        printf("TEST FAILED\n");
         return EXIT_FAILURE;
     } else {
-        printf("SUCCESS\n");
+        printf("TEST PASSED\n");
         return EXIT_SUCCESS;
     }
 }
-
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 88d7401..a2b9177 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -130,10 +130,12 @@
     }
 
     int32_t getBufferCapacity() const {
+        printf("%s() returns %d\n", __func__, mBufferCapacity);
         return mBufferCapacity;
     }
 
     void setBufferCapacity(int32_t frames) {
+        printf("%s(%d)\n", __func__, frames);
         mBufferCapacity = frames;
     }
 
@@ -185,18 +187,26 @@
         mNumberOfBursts = numBursts;
     }
 
+    int32_t getFramesPerCallback() const {
+        return mFramesPerCallback;
+    }
+    void setFramesPerCallback(int32_t size) {
+        mFramesPerCallback = size;
+    }
+
     /**
      * Apply these parameters to a stream builder.
      * @param builder
      */
     void applyParameters(AAudioStreamBuilder *builder) const {
+        AAudioStreamBuilder_setBufferCapacityInFrames(builder, getBufferCapacity());
         AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
-        AAudioStreamBuilder_setFormat(builder, mFormat);
-        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
-        AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
         AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
-        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+        AAudioStreamBuilder_setFormat(builder, mFormat);
+        AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
         AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+        AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+        AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
 
         // Call P functions if supported.
         loadFutureFunctions();
@@ -232,6 +242,7 @@
     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
 
     int32_t                    mNumberOfBursts  = AAUDIO_UNSPECIFIED;
+    int32_t                    mFramesPerCallback = AAUDIO_UNSPECIFIED;
 };
 
 class AAudioArgsParser : public AAudioParameters {
@@ -272,7 +283,9 @@
                     if (strlen(arg) > 2) {
                         policy = atoi(&arg[2]);
                     }
-                    AAudio_setMMapPolicy(policy);
+                    if (!AAudio_setMMapPolicy(policy)) {
+                        printf("ERROR: invalid MMAP policy mode %i\n", policy);
+                    }
                 } break;
                 case 'n':
                     setNumberOfBursts(atoi(&arg[2]));
@@ -295,6 +308,9 @@
                 case 'y':
                     setContentType(atoi(&arg[2]));
                     break;
+                case 'z':
+                    setFramesPerCallback(atoi(&arg[2]));
+                    break;
                 default:
                     unrecognized = true;
                     break;
@@ -348,6 +364,7 @@
         printf("      -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
         printf("      -x to use EXCLUSIVE mode\n");
         printf("      -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
+        printf("      -z{callbackSize} or block size, in frames, default = 0\n");
     }
 
     static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -363,7 +380,7 @@
                 mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
                 break;
             default:
-                printf("ERROR invalid performance mode %c\n", c);
+                printf("ERROR: invalid performance mode %c\n", c);
                 break;
         }
         return mode;
@@ -404,6 +421,9 @@
         printf("  Capacity:     requested = %d, actual = %d\n", getBufferCapacity(),
                AAudioStream_getBufferCapacityInFrames(stream));
 
+        printf("  CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
+               AAudioStream_getFramesPerDataCallback(stream));
+
         printf("  SharingMode:  requested = %s, actual = %s\n",
                getSharingModeText(getSharingMode()),
                getSharingModeText(AAudioStream_getSharingMode(stream)));
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 54b77ba..1645986 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -193,7 +193,7 @@
      aaudio_result_t start() {
         aaudio_result_t result = AAudioStream_requestStart(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestStart() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStart(output) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         return result;
@@ -203,7 +203,7 @@
     aaudio_result_t stop() {
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestStop() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestStop(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -215,7 +215,7 @@
     aaudio_result_t pause() {
         aaudio_result_t result = AAudioStream_requestPause(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestPause() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestPause(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         int32_t xRunCount = AAudioStream_getXRunCount(mStream);
@@ -223,11 +223,27 @@
         return result;
     }
 
+    aaudio_result_t waitUntilPaused() {
+        aaudio_result_t result = AAUDIO_OK;
+        aaudio_stream_state_t currentState = AAudioStream_getState(mStream);
+        aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
+        while (result == AAUDIO_OK && currentState == AAUDIO_STREAM_STATE_PAUSING) {
+            result = AAudioStream_waitForStateChange(mStream, inputState,
+                                                     &currentState, NANOS_PER_SECOND);
+            inputState = currentState;
+        }
+        if (result != AAUDIO_OK) {
+            return result;
+        }
+        return (currentState == AAUDIO_STREAM_STATE_PAUSED)
+               ? AAUDIO_OK : AAUDIO_ERROR_INVALID_STATE;
+    }
+
     // Flush the stream. AAudio will stop calling your callback function.
     aaudio_result_t flush() {
         aaudio_result_t result = AAudioStream_requestFlush(mStream);
         if (result != AAUDIO_OK) {
-            printf("ERROR - AAudioStream_requestFlush() returned %d %s\n",
+            printf("ERROR - AAudioStream_requestFlush(output) returned %d %s\n",
                    result, AAudio_convertResultToText(result));
         }
         return result;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index 869fad0..246e2d7 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -201,8 +201,10 @@
      aaudio_result_t start() {
         aaudio_result_t result = AAudioStream_requestStart(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestStart(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
+            fprintf(stderr, "        Did you remember to enter:   adb root    ????\n");
+
         }
         return result;
     }
@@ -211,8 +213,9 @@
     aaudio_result_t stop() {
         aaudio_result_t result = AAudioStream_requestStop(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestStop() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestStop(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
+
         }
         return result;
     }
@@ -221,7 +224,7 @@
     aaudio_result_t pause() {
         aaudio_result_t result = AAudioStream_requestPause(mStream);
         if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_requestPause() returned %d %s\n",
+            fprintf(stderr, "ERROR - AAudioStream_requestPause(input) returned %d %s\n",
                     result, AAudio_convertResultToText(result));
         }
         return result;
diff --git a/media/libaaudio/examples/write_sine/Android.bp b/media/libaaudio/examples/write_sine/Android.bp
index aa25e67..cc80861 100644
--- a/media/libaaudio/examples/write_sine/Android.bp
+++ b/media/libaaudio/examples/write_sine/Android.bp
@@ -4,6 +4,7 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
 
 cc_test {
@@ -12,4 +13,5 @@
     cflags: ["-Wall", "-Werror"],
     shared_libs: ["libaaudio"],
     header_libs: ["libaaudio_example_utils"],
+    pack_relocations: false,
 }
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index e33e9f8..7a48153 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -30,6 +30,8 @@
 #include "AAudioSimplePlayer.h"
 #include "AAudioArgsParser.h"
 
+#define APP_VERSION  "0.1.5"
+
 /**
  * Open stream, play some sine waves, then close the stream.
  *
@@ -109,13 +111,13 @@
         startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
         for (int second = 0; second < durationSeconds; second++) {
             // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
-            long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+            myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
             int64_t millis =
                     (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
             result = myData.waker.get();
-            printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+            printf(" waker result = %d, at %6d millis"
                            ", second = %3d, framesWritten = %8d, underruns = %d\n",
-                   ret, result, (int) millis,
+                   result, (int) millis,
                    second,
                    (int) AAudioStream_getFramesWritten(player.getStream()),
                    (int) AAudioStream_getXRunCount(player.getStream()));
@@ -138,6 +140,10 @@
             if (result != AAUDIO_OK) {
                 goto error;
             }
+            result = player.waitUntilPaused();
+            if (result != AAUDIO_OK) {
+                goto error;
+            }
             result = player.flush();
         }
         if (result != AAUDIO_OK) {
@@ -219,7 +225,7 @@
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine sweep using an AAudio callback V0.1.4\n", argv[0]);
+    printf("%s - Play a sine sweep using an AAudio callback V%s\n", argv[0], APP_VERSION);
 
     for (int i = 1; i < argc; i++) {
         const char *arg = argv[i];
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 3a7a578..4ef765d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -150,6 +150,11 @@
         allowMMap = false;
     }
 
+    if (!allowMMap && !allowLegacy) {
+        ALOGE("%s() no backend available: neither MMAP nor legacy path are allowed", __func__);
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    }
+
     result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
     if (result == AAUDIO_OK) {
         // Open the stream using the parameters from the builder.
diff --git a/media/libeffects/Android.bp b/media/libeffects/Android.bp
deleted file mode 100644
index 0dd3f17..0000000
--- a/media/libeffects/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["factory", "config"]
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
new file mode 100644
index 0000000..227f2a1
--- /dev/null
+++ b/media/libeffects/downmix/Android.bp
@@ -0,0 +1,27 @@
+// Multichannel downmix effect library
+cc_library_shared {
+    name: "libdownmix",
+
+    vendor: true,
+    srcs: ["EffectDownmix.c"],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+
+    relative_install_path: "soundfx",
+
+    cflags: [
+        //"-DBUILD_FLOAT",
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    header_libs: [
+        "libaudioeffects",
+        "libhardware_headers",
+    ],
+    static_libs: ["libaudioutils" ],
+}
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
deleted file mode 100644
index a5fbf14..0000000
--- a/media/libeffects/downmix/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Multichannel downmix effect library
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-	EffectDownmix.c
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils liblog
-
-LOCAL_MODULE:= libdownmix
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-
-LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-effects) \
-	$(call include-path-for, audio-utils)
-
-#-DBUILD_FLOAT
-LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_HEADER_LIBRARIES += libhardware_headers
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
new file mode 100644
index 0000000..eafc483
--- /dev/null
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// DynamicsProcessing library
+cc_library_shared {
+    name: "libdynproc",
+
+    vendor: true,
+
+    srcs: [
+        "EffectDynamicsProcessing.cpp",
+        "dsp/DPBase.cpp",
+        "dsp/DPFrequency.cpp",
+    ],
+
+    cflags: [
+        "-O2",
+        "-fvisibility=hidden",
+
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+
+    relative_install_path: "soundfx",
+
+    header_libs: [
+        "libaudioeffects",
+        "libeigen",
+    ],
+}
diff --git a/media/libeffects/dynamicsproc/Android.mk b/media/libeffects/dynamicsproc/Android.mk
deleted file mode 100644
index 7be0c49..0000000
--- a/media/libeffects/dynamicsproc/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# DynamicsProcessing library
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-
-EIGEN_PATH := external/eigen
-LOCAL_C_INCLUDES += $(EIGEN_PATH)
-
-LOCAL_SRC_FILES:= \
-    EffectDynamicsProcessing.cpp \
-    dsp/DPBase.cpp \
-    dsp/DPFrequency.cpp
-
-LOCAL_CFLAGS+= -O2 -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE:= libdynproc
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudioeffects
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
new file mode 100644
index 0000000..5a13af6
--- /dev/null
+++ b/media/libeffects/loudness/Android.bp
@@ -0,0 +1,27 @@
+// LoudnessEnhancer library
+cc_library_shared {
+    name: "libldnhncr",
+
+    vendor: true,
+    srcs: [
+        "EffectLoudnessEnhancer.cpp",
+        "dsp/core/dynamic_range_compression.cpp",
+    ],
+
+    cflags: [
+        "-O2",
+        "-fvisibility=hidden",
+
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+
+    relative_install_path: "soundfx",
+
+    header_libs: ["libaudioeffects"],
+}
diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk
deleted file mode 100644
index 712cbd5..0000000
--- a/media/libeffects/loudness/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# LoudnessEnhancer library
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-    EffectLoudnessEnhancer.cpp \
-    dsp/core/dynamic_range_compression.cpp
-
-LOCAL_CFLAGS+= -O2 -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog \
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE:= libldnhncr
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudioeffects
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
new file mode 100644
index 0000000..5c57c43
--- /dev/null
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -0,0 +1,211 @@
+// Music bundle
+cc_library_static {
+    name: "libmusicbundle",
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    vendor: true,
+    srcs: [
+        "StereoWidening/src/LVCS_BypassMix.c",
+        "StereoWidening/src/LVCS_Control.c",
+        "StereoWidening/src/LVCS_Equaliser.c",
+        "StereoWidening/src/LVCS_Init.c",
+        "StereoWidening/src/LVCS_Process.c",
+        "StereoWidening/src/LVCS_ReverbGenerator.c",
+        "StereoWidening/src/LVCS_StereoEnhancer.c",
+        "StereoWidening/src/LVCS_Tables.c",
+        "Bass/src/LVDBE_Control.c",
+        "Bass/src/LVDBE_Init.c",
+        "Bass/src/LVDBE_Process.c",
+        "Bass/src/LVDBE_Tables.c",
+        "Bundle/src/LVM_API_Specials.c",
+        "Bundle/src/LVM_Buffers.c",
+        "Bundle/src/LVM_Init.c",
+        "Bundle/src/LVM_Process.c",
+        "Bundle/src/LVM_Tables.c",
+        "Bundle/src/LVM_Control.c",
+        "SpectrumAnalyzer/src/LVPSA_Control.c",
+        "SpectrumAnalyzer/src/LVPSA_Init.c",
+        "SpectrumAnalyzer/src/LVPSA_Memory.c",
+        "SpectrumAnalyzer/src/LVPSA_Process.c",
+        "SpectrumAnalyzer/src/LVPSA_QPD_Init.c",
+        "SpectrumAnalyzer/src/LVPSA_QPD_Process.c",
+        "SpectrumAnalyzer/src/LVPSA_Tables.c",
+        "Eq/src/LVEQNB_CalcCoef.c",
+        "Eq/src/LVEQNB_Control.c",
+        "Eq/src/LVEQNB_Init.c",
+        "Eq/src/LVEQNB_Process.c",
+        "Eq/src/LVEQNB_Tables.c",
+        "Common/src/InstAlloc.c",
+        "Common/src/DC_2I_D16_TRC_WRA_01.c",
+        "Common/src/DC_2I_D16_TRC_WRA_01_Init.c",
+        "Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c",
+        "Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c",
+        "Common/src/FO_1I_D16F16C15_TRC_WRA_01.c",
+        "Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c",
+        "Common/src/BP_1I_D16F32C30_TRC_WRA_01.c",
+        "Common/src/BP_1I_D16F16C14_TRC_WRA_01.c",
+        "Common/src/BP_1I_D32F32C30_TRC_WRA_02.c",
+        "Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c",
+        "Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c",
+        "Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c",
+        "Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c",
+        "Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c",
+        "Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c",
+        "Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c",
+        "Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c",
+        "Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c",
+        "Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c",
+        "Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c",
+        "Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c",
+        "Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c",
+        "Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c",
+        "Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c",
+        "Common/src/Int16LShiftToInt32_16x32.c",
+        "Common/src/From2iToMono_16.c",
+        "Common/src/Copy_16.c",
+        "Common/src/MonoTo2I_16.c",
+        "Common/src/MonoTo2I_32.c",
+        "Common/src/LoadConst_16.c",
+        "Common/src/LoadConst_32.c",
+        "Common/src/dB_to_Lin32.c",
+        "Common/src/Shift_Sat_v16xv16.c",
+        "Common/src/Shift_Sat_v32xv32.c",
+        "Common/src/Abs_32.c",
+        "Common/src/Int32RShiftToInt16_Sat_32x16.c",
+        "Common/src/From2iToMono_32.c",
+        "Common/src/mult3s_16x16.c",
+        "Common/src/Mult3s_32x16.c",
+        "Common/src/NonLinComp_D16.c",
+        "Common/src/DelayMix_16x16.c",
+        "Common/src/MSTo2i_Sat_16x16.c",
+        "Common/src/From2iToMS_16x16.c",
+        "Common/src/Mac3s_Sat_16x16.c",
+        "Common/src/Mac3s_Sat_32x16.c",
+        "Common/src/Add2_Sat_16x16.c",
+        "Common/src/Add2_Sat_32x32.c",
+        "Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c",
+        "Common/src/LVC_MixSoft_1St_D16C31_SAT.c",
+        "Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c",
+        "Common/src/LVC_Mixer_SetTimeConstant.c",
+        "Common/src/LVC_Mixer_SetTarget.c",
+        "Common/src/LVC_Mixer_GetTarget.c",
+        "Common/src/LVC_Mixer_Init.c",
+        "Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c",
+        "Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c",
+        "Common/src/LVC_Core_MixInSoft_D16C31_SAT.c",
+        "Common/src/LVC_Mixer_GetCurrent.c",
+        "Common/src/LVC_MixSoft_2St_D16C31_SAT.c",
+        "Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c",
+        "Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c",
+        "Common/src/LVC_MixInSoft_D16C31_SAT.c",
+        "Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c",
+        "Common/src/LVM_Timer.c",
+        "Common/src/LVM_Timer_Init.c",
+    ],
+
+    local_include_dirs: [
+        "Eq/lib",
+        "Eq/src",
+        "Bass/lib",
+        "Bass/src",
+        "Common/src",
+        "Bundle/src",
+        "SpectrumAnalyzer/lib",
+        "SpectrumAnalyzer/src",
+        "StereoWidening/src",
+        "StereoWidening/lib",
+    ],
+    export_include_dirs: [
+        "Common/lib",
+        "Bundle/lib",
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DBUILD_FLOAT",
+        "-DHIGHER_FS",
+
+        "-Wall",
+        "-Werror",
+    ],
+
+}
+
+// Reverb library
+cc_library_static {
+    name: "libreverb",
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    vendor: true,
+    srcs: [
+        "Reverb/src/LVREV_ApplyNewSettings.c",
+        "Reverb/src/LVREV_ClearAudioBuffers.c",
+        "Reverb/src/LVREV_GetControlParameters.c",
+        "Reverb/src/LVREV_GetInstanceHandle.c",
+        "Reverb/src/LVREV_GetMemoryTable.c",
+        "Reverb/src/LVREV_Process.c",
+        "Reverb/src/LVREV_SetControlParameters.c",
+        "Reverb/src/LVREV_Tables.c",
+        "Common/src/Abs_32.c",
+        "Common/src/InstAlloc.c",
+        "Common/src/LoadConst_16.c",
+        "Common/src/LoadConst_32.c",
+        "Common/src/From2iToMono_32.c",
+        "Common/src/Mult3s_32x16.c",
+        "Common/src/FO_1I_D32F32C31_TRC_WRA_01.c",
+        "Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c",
+        "Common/src/DelayAllPass_Sat_32x16To32.c",
+        "Common/src/Copy_16.c",
+        "Common/src/Mac3s_Sat_32x16.c",
+        "Common/src/DelayWrite_32.c",
+        "Common/src/Shift_Sat_v32xv32.c",
+        "Common/src/Add2_Sat_32x32.c",
+        "Common/src/JoinTo2i_32x32.c",
+        "Common/src/MonoTo2I_32.c",
+        "Common/src/LVM_FO_HPF.c",
+        "Common/src/LVM_FO_LPF.c",
+        "Common/src/LVM_Polynomial.c",
+        "Common/src/LVM_Power10.c",
+        "Common/src/LVM_GetOmega.c",
+        "Common/src/MixSoft_2St_D32C31_SAT.c",
+        "Common/src/MixSoft_1St_D32C31_WRA.c",
+        "Common/src/MixInSoft_D32C31_SAT.c",
+        "Common/src/LVM_Mixer_TimeConstant.c",
+        "Common/src/Core_MixHard_2St_D32C31_SAT.c",
+        "Common/src/Core_MixSoft_1St_D32C31_WRA.c",
+        "Common/src/Core_MixInSoft_D32C31_SAT.c",
+    ],
+
+    local_include_dirs: [
+        "Reverb/src",
+        "Common/src",
+    ],
+    export_include_dirs: [
+        "Reverb/lib",
+        "Common/lib",
+    ],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DBUILD_FLOAT",
+        "-DHIGHER_FS",
+
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/media/libeffects/lvm/lib/Android.mk b/media/libeffects/lvm/lib/Android.mk
deleted file mode 100644
index 941eb3e..0000000
--- a/media/libeffects/lvm/lib/Android.mk
+++ /dev/null
@@ -1,191 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Music bundle
-
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-    StereoWidening/src/LVCS_BypassMix.c \
-    StereoWidening/src/LVCS_Control.c \
-    StereoWidening/src/LVCS_Equaliser.c \
-    StereoWidening/src/LVCS_Init.c \
-    StereoWidening/src/LVCS_Process.c \
-    StereoWidening/src/LVCS_ReverbGenerator.c \
-    StereoWidening/src/LVCS_StereoEnhancer.c \
-    StereoWidening/src/LVCS_Tables.c \
-    Bass/src/LVDBE_Control.c \
-    Bass/src/LVDBE_Init.c \
-    Bass/src/LVDBE_Process.c \
-    Bass/src/LVDBE_Tables.c \
-    Bundle/src/LVM_API_Specials.c \
-    Bundle/src/LVM_Buffers.c \
-    Bundle/src/LVM_Init.c \
-    Bundle/src/LVM_Process.c \
-    Bundle/src/LVM_Tables.c \
-    Bundle/src/LVM_Control.c \
-    SpectrumAnalyzer/src/LVPSA_Control.c \
-    SpectrumAnalyzer/src/LVPSA_Init.c \
-    SpectrumAnalyzer/src/LVPSA_Memory.c \
-    SpectrumAnalyzer/src/LVPSA_Process.c \
-    SpectrumAnalyzer/src/LVPSA_QPD_Init.c \
-    SpectrumAnalyzer/src/LVPSA_QPD_Process.c \
-    SpectrumAnalyzer/src/LVPSA_Tables.c \
-    Eq/src/LVEQNB_CalcCoef.c \
-    Eq/src/LVEQNB_Control.c \
-    Eq/src/LVEQNB_Init.c \
-    Eq/src/LVEQNB_Process.c \
-    Eq/src/LVEQNB_Tables.c \
-    Common/src/InstAlloc.c \
-    Common/src/DC_2I_D16_TRC_WRA_01.c \
-    Common/src/DC_2I_D16_TRC_WRA_01_Init.c \
-    Common/src/FO_2I_D16F32C15_LShx_TRC_WRA_01.c \
-    Common/src/FO_2I_D16F32Css_LShx_TRC_WRA_01_Init.c \
-    Common/src/FO_1I_D16F16C15_TRC_WRA_01.c \
-    Common/src/FO_1I_D16F16Css_TRC_WRA_01_Init.c \
-    Common/src/BP_1I_D16F32C30_TRC_WRA_01.c \
-    Common/src/BP_1I_D16F16C14_TRC_WRA_01.c \
-    Common/src/BP_1I_D32F32C30_TRC_WRA_02.c \
-    Common/src/BP_1I_D16F16Css_TRC_WRA_01_Init.c \
-    Common/src/BP_1I_D16F32Cll_TRC_WRA_01_Init.c \
-    Common/src/BP_1I_D32F32Cll_TRC_WRA_02_Init.c \
-    Common/src/BQ_2I_D32F32Cll_TRC_WRA_01_Init.c \
-    Common/src/BQ_2I_D32F32C30_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F32C15_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F32C14_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F32C13_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F32Css_TRC_WRA_01_init.c \
-    Common/src/BQ_2I_D16F16C15_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F16C14_TRC_WRA_01.c \
-    Common/src/BQ_2I_D16F16Css_TRC_WRA_01_Init.c \
-    Common/src/BQ_1I_D16F16C15_TRC_WRA_01.c \
-    Common/src/BQ_1I_D16F16Css_TRC_WRA_01_Init.c \
-    Common/src/BQ_1I_D16F32C14_TRC_WRA_01.c \
-    Common/src/BQ_1I_D16F32Css_TRC_WRA_01_init.c \
-    Common/src/PK_2I_D32F32C30G11_TRC_WRA_01.c \
-    Common/src/PK_2I_D32F32C14G11_TRC_WRA_01.c \
-    Common/src/PK_2I_D32F32CssGss_TRC_WRA_01_Init.c \
-    Common/src/PK_2I_D32F32CllGss_TRC_WRA_01_Init.c \
-    Common/src/Int16LShiftToInt32_16x32.c \
-    Common/src/From2iToMono_16.c \
-    Common/src/Copy_16.c \
-    Common/src/MonoTo2I_16.c \
-    Common/src/MonoTo2I_32.c \
-    Common/src/LoadConst_16.c \
-    Common/src/LoadConst_32.c \
-    Common/src/dB_to_Lin32.c \
-    Common/src/Shift_Sat_v16xv16.c \
-    Common/src/Shift_Sat_v32xv32.c \
-    Common/src/Abs_32.c \
-    Common/src/Int32RShiftToInt16_Sat_32x16.c \
-    Common/src/From2iToMono_32.c \
-    Common/src/mult3s_16x16.c \
-    Common/src/Mult3s_32x16.c \
-    Common/src/NonLinComp_D16.c \
-    Common/src/DelayMix_16x16.c \
-    Common/src/MSTo2i_Sat_16x16.c \
-    Common/src/From2iToMS_16x16.c \
-    Common/src/Mac3s_Sat_16x16.c \
-    Common/src/Mac3s_Sat_32x16.c \
-    Common/src/Add2_Sat_16x16.c \
-    Common/src/Add2_Sat_32x32.c \
-    Common/src/LVC_MixSoft_1St_2i_D16C31_SAT.c \
-    Common/src/LVC_MixSoft_1St_D16C31_SAT.c \
-    Common/src/LVC_Mixer_VarSlope_SetTimeConstant.c \
-    Common/src/LVC_Mixer_SetTimeConstant.c \
-    Common/src/LVC_Mixer_SetTarget.c \
-    Common/src/LVC_Mixer_GetTarget.c \
-    Common/src/LVC_Mixer_Init.c \
-    Common/src/LVC_Core_MixHard_1St_2i_D16C31_SAT.c \
-    Common/src/LVC_Core_MixSoft_1St_2i_D16C31_WRA.c \
-    Common/src/LVC_Core_MixInSoft_D16C31_SAT.c \
-    Common/src/LVC_Mixer_GetCurrent.c \
-    Common/src/LVC_MixSoft_2St_D16C31_SAT.c \
-    Common/src/LVC_Core_MixSoft_1St_D16C31_WRA.c \
-    Common/src/LVC_Core_MixHard_2St_D16C31_SAT.c \
-    Common/src/LVC_MixInSoft_D16C31_SAT.c \
-    Common/src/AGC_MIX_VOL_2St1Mon_D32_WRA.c \
-    Common/src/LVM_Timer.c \
-    Common/src/LVM_Timer_Init.c
-
-LOCAL_MODULE:= libmusicbundle
-
-LOCAL_C_INCLUDES += \
-    $(LOCAL_PATH)/Eq/lib \
-    $(LOCAL_PATH)/Eq/src \
-    $(LOCAL_PATH)/Bass/lib \
-    $(LOCAL_PATH)/Bass/src \
-    $(LOCAL_PATH)/Common/lib \
-    $(LOCAL_PATH)/Common/src \
-    $(LOCAL_PATH)/Bundle/lib \
-    $(LOCAL_PATH)/Bundle/src \
-    $(LOCAL_PATH)/SpectrumAnalyzer/lib \
-    $(LOCAL_PATH)/SpectrumAnalyzer/src \
-    $(LOCAL_PATH)/StereoWidening/src \
-    $(LOCAL_PATH)/StereoWidening/lib
-
-LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_STATIC_LIBRARY)
-
-
-
-# Reverb library
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-    Reverb/src/LVREV_ApplyNewSettings.c \
-    Reverb/src/LVREV_ClearAudioBuffers.c \
-    Reverb/src/LVREV_GetControlParameters.c \
-    Reverb/src/LVREV_GetInstanceHandle.c \
-    Reverb/src/LVREV_GetMemoryTable.c \
-    Reverb/src/LVREV_Process.c \
-    Reverb/src/LVREV_SetControlParameters.c \
-    Reverb/src/LVREV_Tables.c \
-    Common/src/Abs_32.c \
-    Common/src/InstAlloc.c \
-    Common/src/LoadConst_16.c \
-    Common/src/LoadConst_32.c \
-    Common/src/From2iToMono_32.c \
-    Common/src/Mult3s_32x16.c \
-    Common/src/FO_1I_D32F32C31_TRC_WRA_01.c \
-    Common/src/FO_1I_D32F32Cll_TRC_WRA_01_Init.c \
-    Common/src/DelayAllPass_Sat_32x16To32.c \
-    Common/src/Copy_16.c \
-    Common/src/Mac3s_Sat_32x16.c \
-    Common/src/DelayWrite_32.c \
-    Common/src/Shift_Sat_v32xv32.c \
-    Common/src/Add2_Sat_32x32.c \
-    Common/src/JoinTo2i_32x32.c \
-    Common/src/MonoTo2I_32.c \
-    Common/src/LVM_FO_HPF.c \
-    Common/src/LVM_FO_LPF.c \
-    Common/src/LVM_Polynomial.c \
-    Common/src/LVM_Power10.c \
-    Common/src/LVM_GetOmega.c \
-    Common/src/MixSoft_2St_D32C31_SAT.c \
-    Common/src/MixSoft_1St_D32C31_WRA.c \
-    Common/src/MixInSoft_D32C31_SAT.c \
-    Common/src/LVM_Mixer_TimeConstant.c \
-    Common/src/Core_MixHard_2St_D32C31_SAT.c \
-    Common/src/Core_MixSoft_1St_D32C31_WRA.c \
-    Common/src/Core_MixInSoft_D32C31_SAT.c
-
-LOCAL_MODULE:= libreverb
-
-LOCAL_C_INCLUDES += \
-    $(LOCAL_PATH)/Reverb/lib \
-    $(LOCAL_PATH)/Reverb/src \
-    $(LOCAL_PATH)/Common/lib \
-    $(LOCAL_PATH)/Common/src
-
-LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
new file mode 100644
index 0000000..10fd970
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -0,0 +1,88 @@
+// The wrapper -DBUILD_FLOAT needs to match
+// the lvm library -DBUILD_FLOAT.
+
+// music bundle wrapper
+cc_library_shared {
+    name: "libbundlewrapper",
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    vendor: true,
+    srcs: ["Bundle/EffectBundle.cpp"],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DBUILD_FLOAT",
+        "-DHIGHER_FS",
+
+        "-Wall",
+        "-Werror",
+    ],
+
+    relative_install_path: "soundfx",
+
+    static_libs: ["libmusicbundle"],
+
+    shared_libs: [
+        "libaudioutils",
+        "libcutils",
+        "libdl",
+        "liblog",
+    ],
+
+    local_include_dirs: ["Bundle"],
+
+    header_libs: [
+        "libhardware_headers",
+        "libaudioeffects",
+    ],
+}
+
+// reverb wrapper
+cc_library_shared {
+    name: "libreverbwrapper",
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+
+    vendor: true,
+    srcs: ["Reverb/EffectReverb.cpp"],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-DBUILD_FLOAT",
+        "-DHIGHER_FS",
+
+        "-Wall",
+        "-Werror",
+    ],
+
+    relative_install_path: "soundfx",
+
+    static_libs: ["libreverb"],
+
+    shared_libs: [
+        "libaudioutils",
+        "libcutils",
+        "libdl",
+        "liblog",
+    ],
+
+    local_include_dirs: ["Reverb"],
+
+    header_libs: [
+        "libhardware_headers",
+        "libaudioeffects",
+    ],
+
+    sanitize: {
+        integer_overflow: true,
+    },
+}
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
deleted file mode 100644
index 341dbc2..0000000
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ /dev/null
@@ -1,77 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# The wrapper -DBUILD_FLOAT needs to match
-# the lvm library -DBUILD_FLOAT.
-
-# music bundle wrapper
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-	Bundle/EffectBundle.cpp
-
-LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_MODULE:= libbundlewrapper
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-
-LOCAL_STATIC_LIBRARIES += libmusicbundle
-
-LOCAL_SHARED_LIBRARIES := \
-     libaudioutils \
-     libcutils \
-     libdl \
-     liblog \
-
-LOCAL_C_INCLUDES += \
-	$(LOCAL_PATH)/Bundle \
-	$(LOCAL_PATH)/../lib/Common/lib/ \
-	$(LOCAL_PATH)/../lib/Bundle/lib/ \
-	$(call include-path-for, audio-effects) \
-	$(call include-path-for, audio-utils) \
-
-LOCAL_HEADER_LIBRARIES += libhardware_headers
-include $(BUILD_SHARED_LIBRARY)
-
-
-# reverb wrapper
-include $(CLEAR_VARS)
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-    Reverb/EffectReverb.cpp
-
-LOCAL_CFLAGS += -fvisibility=hidden -DBUILD_FLOAT -DHIGHER_FS
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_MODULE:= libreverbwrapper
-
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-
-LOCAL_STATIC_LIBRARIES += libreverb
-
-LOCAL_SHARED_LIBRARIES := \
-     libaudioutils \
-     libcutils \
-     libdl \
-     liblog \
-
-LOCAL_C_INCLUDES += \
-    $(LOCAL_PATH)/Reverb \
-    $(LOCAL_PATH)/../lib/Common/lib/ \
-    $(LOCAL_PATH)/../lib/Reverb/lib/ \
-    $(call include-path-for, audio-effects) \
-    $(call include-path-for, audio-utils) \
-
-LOCAL_HEADER_LIBRARIES += libhardware_headers
-
-LOCAL_SANITIZE := integer_overflow
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
new file mode 100644
index 0000000..c87635f
--- /dev/null
+++ b/media/libeffects/preprocessing/Android.bp
@@ -0,0 +1,35 @@
+// audio preprocessing wrapper
+cc_library_shared {
+    name: "libaudiopreprocessing",
+
+    vendor: true,
+
+    relative_install_path: "soundfx",
+
+    srcs: ["PreProcessing.cpp"],
+
+    include_dirs: [
+        "external/webrtc",
+        "external/webrtc/webrtc/modules/include",
+        "external/webrtc/webrtc/modules/audio_processing/include",
+    ],
+
+    shared_libs: [
+        "libwebrtc_audio_preprocessing",
+        "libspeexresampler",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: [
+        "-DWEBRTC_POSIX",
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    header_libs: [
+        "libaudioeffects",
+        "libhardware_headers",
+    ],
+}
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
deleted file mode 100644
index 358da8b..0000000
--- a/media/libeffects/preprocessing/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# audio preprocessing wrapper
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE:= libaudiopreprocessing
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES:= \
-    PreProcessing.cpp
-
-LOCAL_C_INCLUDES += \
-    external/webrtc \
-    external/webrtc/webrtc/modules/include \
-    external/webrtc/webrtc/modules/audio_processing/include \
-    $(call include-path-for, audio-effects)
-
-LOCAL_SHARED_LIBRARIES := \
-    libwebrtc_audio_preprocessing \
-    libspeexresampler \
-    libutils \
-    liblog
-
-LOCAL_SHARED_LIBRARIES += libdl
-
-LOCAL_CFLAGS += \
-    -DWEBRTC_POSIX
-
-LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_HEADER_LIBRARIES += libhardware_headers
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/proxy/Android.bp b/media/libeffects/proxy/Android.bp
new file mode 100644
index 0000000..c6abb9e
--- /dev/null
+++ b/media/libeffects/proxy/Android.bp
@@ -0,0 +1,38 @@
+// Copyright 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libeffectproxy",
+    relative_install_path: "soundfx",
+
+    vendor: true,
+    srcs: ["EffectProxy.cpp"],
+
+    cflags: [
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    include_dirs: ["frameworks/av/media/libeffects/factory"],
+
+    header_libs: ["libaudioeffects"],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libdl",
+        "libeffects",
+    ],
+}
diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk
deleted file mode 100644
index c4de30d..0000000
--- a/media/libeffects/proxy/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_MODULE:= libeffectproxy
-LOCAL_MODULE_RELATIVE_PATH := soundfx
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := \
-        EffectProxy.cpp
-
-LOCAL_CFLAGS+= -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libdl libeffects
-
-LOCAL_C_INCLUDES := \
-        system/media/audio_effects/include \
-        frameworks/av/media/libeffects/factory
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index 320c7a9..bcc7ebf 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -25,6 +25,7 @@
 #include "MediaUtils.h"
 
 extern "C" size_t __cfi_shadow_size();
+extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
 
 namespace android {
 
@@ -65,6 +66,14 @@
         maxMem = propVal;
     }
 
+    // If 64-bit Scudo is in use, enforce the hard RSS limit (in MB).
+    if (maxMem != SIZE_MAX && sizeof(void *) == 8 &&
+        &__scudo_set_rss_limit != 0) {
+      __scudo_set_rss_limit(maxMem >> 20, 1);
+      ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
+      return;
+    }
+
     // Increase by the size of the CFI shadow mapping. Most of the shadow is not
     // backed with physical pages, and it is possible for the result to be
     // higher than total physical memory. This is fine for RLIMIT_AS.
diff --git a/media/libmedia/include/media/Crypto.h b/media/libmedia/include/media/Crypto.h
deleted file mode 100644
index b68413d..0000000
--- a/media/libmedia/include/media/Crypto.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CRYPTO_H_
-
-#define CRYPTO_H_
-
-#include <media/ICrypto.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-
-#include "SharedLibrary.h"
-
-namespace android {
-
-struct CryptoFactory;
-struct CryptoPlugin;
-
-struct Crypto : public BnCrypto {
-    Crypto();
-    virtual ~Crypto();
-
-    virtual status_t initCheck() const;
-
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
-
-    virtual status_t createPlugin(
-            const uint8_t uuid[16], const void *data, size_t size);
-
-    virtual status_t destroyPlugin();
-
-    virtual bool requiresSecureDecoderComponent(
-            const char *mime) const;
-
-    virtual void notifyResolution(uint32_t width, uint32_t height);
-
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
-
-    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
-            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const sp<IMemory> &source, size_t offset,
-            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-            const DestinationBuffer &destination, AString *errorDetailMsg);
-
-    virtual void setHeap(const sp<IMemoryHeap>&) {}
-    virtual void unsetHeap(const sp<IMemoryHeap>&) {}
-
-private:
-    mutable Mutex mLock;
-
-    status_t mInitCheck;
-    sp<SharedLibrary> mLibrary;
-    CryptoFactory *mFactory;
-    CryptoPlugin *mPlugin;
-
-    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
-    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
-    static Mutex mMapLock;
-
-    void findFactoryForScheme(const uint8_t uuid[16]);
-    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
-    void closeFactory();
-
-    DISALLOW_EVIL_CONSTRUCTORS(Crypto);
-};
-
-}  // namespace android
-
-#endif  // CRYPTO_H_
diff --git a/media/libmedia/include/media/Drm.h b/media/libmedia/include/media/Drm.h
deleted file mode 100644
index fc869cc..0000000
--- a/media/libmedia/include/media/Drm.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DRM_H_
-
-#define DRM_H_
-
-#include "SharedLibrary.h"
-
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class DrmFactory;
-class DrmPlugin;
-struct DrmSessionClientInterface;
-
-struct Drm : public BnDrm,
-             public IBinder::DeathRecipient,
-             public DrmPluginListener {
-    Drm();
-    virtual ~Drm();
-
-    virtual status_t initCheck() const;
-
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType);
-
-    virtual status_t createPlugin(const uint8_t uuid[16], const String8 &appPackageName);
-
-    virtual status_t destroyPlugin();
-
-    virtual status_t openSession(Vector<uint8_t> &sessionId);
-
-    virtual status_t closeSession(Vector<uint8_t> const &sessionId);
-
-    virtual status_t
-        getKeyRequest(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &initData,
-                      String8 const &mimeType, DrmPlugin::KeyType keyType,
-                      KeyedVector<String8, String8> const &optionalParameters,
-                      Vector<uint8_t> &request, String8 &defaultUrl,
-                      DrmPlugin::KeyRequestType *keyRequestType);
-
-    virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
-                                        Vector<uint8_t> const &response,
-                                        Vector<uint8_t> &keySetId);
-
-    virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
-
-    virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
-                                 Vector<uint8_t> const &keySetId);
-
-    virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
-                                    KeyedVector<String8, String8> &infoMap) const;
-
-    virtual status_t getProvisionRequest(String8 const &certType,
-                                         String8 const &certAuthority,
-                                         Vector<uint8_t> &request,
-                                         String8 &defaulUrl);
-
-    virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
-                                              Vector<uint8_t> &certificate,
-                                              Vector<uint8_t> &wrappedKey);
-
-    virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
-    virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
-
-    virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
-    virtual status_t releaseAllSecureStops();
-
-    virtual status_t getPropertyString(String8 const &name, String8 &value ) const;
-    virtual status_t getPropertyByteArray(String8 const &name,
-                                          Vector<uint8_t> &value ) const;
-    virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
-    virtual status_t setPropertyByteArray(String8 const &name,
-                                          Vector<uint8_t> const &value ) const;
-
-    virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
-                                        String8 const &algorithm);
-
-    virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
-                                     String8 const &algorithm);
-
-    virtual status_t encrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output);
-
-    virtual status_t decrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output);
-
-    virtual status_t sign(Vector<uint8_t> const &sessionId,
-                          Vector<uint8_t> const &keyId,
-                          Vector<uint8_t> const &message,
-                          Vector<uint8_t> &signature);
-
-    virtual status_t verify(Vector<uint8_t> const &sessionId,
-                            Vector<uint8_t> const &keyId,
-                            Vector<uint8_t> const &message,
-                            Vector<uint8_t> const &signature,
-                            bool &match);
-
-    virtual status_t signRSA(Vector<uint8_t> const &sessionId,
-                             String8 const &algorithm,
-                             Vector<uint8_t> const &message,
-                             Vector<uint8_t> const &wrappedKey,
-                             Vector<uint8_t> &signature);
-
-    virtual status_t setListener(const sp<IDrmClient>& listener);
-
-    virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
-                           Vector<uint8_t> const *sessionId,
-                           Vector<uint8_t> const *data);
-
-    virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
-                                      int64_t expiryTimeInMS);
-
-    virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
-                                Vector<DrmPlugin::KeyStatus> const *keyStatusList,
-                                bool hasNewUsableKey);
-
-    virtual void binderDied(const wp<IBinder> &the_late_who);
-
-private:
-    static Mutex mLock;
-
-    status_t mInitCheck;
-
-    sp<DrmSessionClientInterface> mDrmSessionClient;
-
-    sp<IDrmClient> mListener;
-    mutable Mutex mEventLock;
-    mutable Mutex mNotifyLock;
-
-    sp<SharedLibrary> mLibrary;
-    DrmFactory *mFactory;
-    DrmPlugin *mPlugin;
-
-    static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
-    static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
-    static Mutex mMapLock;
-
-    void findFactoryForScheme(const uint8_t uuid[16]);
-    bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
-    void closeFactory();
-    void writeByteArray(Parcel &obj, Vector<uint8_t> const *array);
-
-    DISALLOW_EVIL_CONSTRUCTORS(Drm);
-};
-
-}  // namespace android
-
-#endif  // CRYPTO_H_
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index cdef637..d29e97d 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -68,6 +68,11 @@
     METADATA_KEY_VIDEO_FRAME_COUNT  = 32,
     METADATA_KEY_EXIF_OFFSET     = 33,
     METADATA_KEY_EXIF_LENGTH     = 34,
+    METADATA_KEY_COLOR_STANDARD  = 35,
+    METADATA_KEY_COLOR_TRANSFER  = 36,
+    METADATA_KEY_COLOR_RANGE     = 37,
+    METADATA_KEY_SAMPLERATE      = 38,
+    METADATA_KEY_BITS_PER_SAMPLE = 39,
 
     // Add more here...
 };
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 9d35568..3e4e86c 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -228,6 +228,9 @@
     kKeyIsExif           = 'exif', // bool (int32_t) buffer contains exif data block
 
     kKeyPcmBigEndian     = 'pcmb', // bool (int32_t)
+
+    // Key for ALAC Magic Cookie
+    kKeyAlacMagicCookie  = 'almc', // raw data
 };
 
 enum {
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index c8ddc11..4906a36 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -33,6 +33,8 @@
     cflags: [
         "-Werror",
         "-Wall",
+        // Allow implicit fallthroughs in NuPlayer2Driver.cpp until they are fixed.
+        "-Wno-error=implicit-fallthrough",
     ],
 
     product_variables: {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index bafa653..8eda9b8 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -327,7 +327,7 @@
     switch (mState) {
         case STATE_RUNNING:
             mPlayer->pause();
-            // fall through
+            [[fallthrough]];
 
         case STATE_PAUSED:
             mState = STATE_STOPPED;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 30c0b1c..e3ae02e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1996,7 +1996,7 @@
         mTotalPausedDurationUs += resumeStartTimeUs - mPauseStartTimeUs - 30000;
     }
     double timeOffset = -mTotalPausedDurationUs;
-    if (mCaptureFpsEnable) {
+    if (mCaptureFpsEnable && (mVideoSource == VIDEO_SOURCE_CAMERA)) {
         timeOffset *= mCaptureFps / mFrameRate;
     }
     sp<MetaData> meta = new MetaData;
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 06aedb7..b0bf269 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "MediaExtractorFactory"
 #include <utils/Log.h>
 
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
 #include <binder/IServiceManager.h>
 #include <media/DataSource.h>
 #include <media/MediaAnalyticsItem.h>
@@ -320,17 +322,28 @@
 status_t MediaExtractorFactory::dump(int fd, const Vector<String16>&) {
     Mutex::Autolock autoLock(gPluginMutex);
     String8 out;
-    out.append("Available extractors:\n");
-    if (gPluginsRegistered) {
-        for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
-            out.appendFormat("  %25s: uuid(%s), version(%u), path(%s)\n",
-                    (*it)->def.extractor_name,
-                    (*it)->uuidString.c_str(),
-                    (*it)->def.extractor_version,
-                    (*it)->libPath.c_str());
-        }
+
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+        // dumpExtractors() will append the following string.
+        // out.appendFormat("Permission Denial: "
+        //        "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
+        ALOGE("Permission Denial: can't dump MediaExtractor from pid=%d, uid=%d", pid, uid);
     } else {
-        out.append("  (no plugins registered)\n");
+        out.append("Available extractors:\n");
+        if (gPluginsRegistered) {
+            for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
+                out.appendFormat("  %25s: uuid(%s), version(%u), path(%s)\n",
+                        (*it)->def.extractor_name,
+                        (*it)->uuidString.c_str(),
+                        (*it)->def.extractor_version,
+                        (*it)->libPath.c_str());
+            }
+        } else {
+            out.append("  (no plugins registered)\n");
+        }
     }
     write(fd, out.string(), out.size());
     return OK;
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index e010b3e..610b961 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -132,6 +132,9 @@
         { "date", METADATA_KEY_DATE },
         { "width", METADATA_KEY_VIDEO_WIDTH },
         { "height", METADATA_KEY_VIDEO_HEIGHT },
+        { "colorstandard", METADATA_KEY_COLOR_STANDARD },
+        { "colortransfer", METADATA_KEY_COLOR_TRANSFER },
+        { "colorrange", METADATA_KEY_COLOR_RANGE },
     };
     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c51ac8d..84a641f 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 #include <media/CharacterEncodingDetector.h>
 
 namespace android {
@@ -402,6 +403,25 @@
     return mMetaData.valueAt(index).string();
 }
 
+void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
+    sp<AMessage> format = new AMessage();
+    if (convertMetaDataToMessage(meta, &format) != OK) {
+        return;
+    }
+
+    int32_t standard, transfer, range;
+    if (format->findInt32("color-standard", &standard)
+            && format->findInt32("color-transfer", &transfer)
+            && format->findInt32("color-range", &range)) {
+        ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
+                standard, transfer, range);
+
+        mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
+        mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
+        mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
+    }
+}
+
 void StagefrightMetadataRetriever::parseMetaData() {
     sp<MetaData> meta = mExtractor->getMetaData();
 
@@ -530,6 +550,19 @@
                 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
                     audioBitrate = -1;
                 }
+
+                int32_t bitsPerSample = -1;
+                int32_t sampleRate = -1;
+                trackMeta->findInt32(kKeyBitsPerSample, &bitsPerSample);
+                trackMeta->findInt32(kKeySampleRate, &sampleRate);
+                if (bitsPerSample >= 0) {
+                    sprintf(tmp, "%d", bitsPerSample);
+                    mMetaData.add(METADATA_KEY_BITS_PER_SAMPLE, String8(tmp));
+                }
+                if (sampleRate >= 0) {
+                    sprintf(tmp, "%d", sampleRate);
+                    mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
+                }
             } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
                 hasVideo = true;
 
@@ -541,6 +574,8 @@
                 if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
                     videoFrameCount = 0;
                 }
+
+                parseColorAspects(trackMeta);
             } else if (!strncasecmp("image/", mime, 6)) {
                 int32_t isPrimary;
                 if (trackMeta->findInt32(
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index cf5e91e..c7579bc 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -950,6 +950,56 @@
             msg->setInt32("android._is-hdr", (info & hvcc.kInfoIsHdr) != 0);
         }
 
+        uint32_t isoPrimaries, isoTransfer, isoMatrix, isoRange;
+        if (hvcc.findParam32(kColourPrimaries, &isoPrimaries)
+                && hvcc.findParam32(kTransferCharacteristics, &isoTransfer)
+                && hvcc.findParam32(kMatrixCoeffs, &isoMatrix)
+                && hvcc.findParam32(kVideoFullRangeFlag, &isoRange)) {
+            ALOGV("found iso color aspects : primaris=%d, transfer=%d, matrix=%d, range=%d",
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange);
+
+            ColorAspects aspects;
+            ColorUtils::convertIsoColorAspectsToCodecAspects(
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange, aspects);
+
+            if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+                int32_t primaries;
+                if (meta->findInt32(kKeyColorPrimaries, &primaries)) {
+                    ALOGV("unspecified primaries found, replaced to %d", primaries);
+                    aspects.mPrimaries = static_cast<ColorAspects::Primaries>(primaries);
+                }
+            }
+            if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+                int32_t transferFunction;
+                if (meta->findInt32(kKeyTransferFunction, &transferFunction)) {
+                    ALOGV("unspecified transfer found, replaced to %d", transferFunction);
+                    aspects.mTransfer = static_cast<ColorAspects::Transfer>(transferFunction);
+                }
+            }
+            if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+                int32_t colorMatrix;
+                if (meta->findInt32(kKeyColorMatrix, &colorMatrix)) {
+                    ALOGV("unspecified matrix found, replaced to %d", colorMatrix);
+                    aspects.mMatrixCoeffs = static_cast<ColorAspects::MatrixCoeffs>(colorMatrix);
+                }
+            }
+            if (aspects.mRange == ColorAspects::RangeUnspecified) {
+                int32_t range;
+                if (meta->findInt32(kKeyColorRange, &range)) {
+                    ALOGV("unspecified range found, replaced to %d", range);
+                    aspects.mRange = static_cast<ColorAspects::Range>(range);
+                }
+            }
+
+            int32_t standard, transfer, range;
+            if (ColorUtils::convertCodecColorAspectsToPlatformAspects(
+                    aspects, &range, &standard, &transfer) == OK) {
+                msg->setInt32("color-standard", standard);
+                msg->setInt32("color-transfer", transfer);
+                msg->setInt32("color-range", range);
+            }
+        }
+
         parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
@@ -1085,6 +1135,17 @@
         msg->setBuffer("csd-0", buffer);
 
         parseVp9ProfileLevelFromCsd(buffer, msg);
+    } else if (meta->findData(kKeyAlacMagicCookie, &type, &data, &size)) {
+        ALOGV("convertMetaDataToMessage found kKeyAlacMagicCookie of size %zu\n", size);
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     }
 
     // TODO expose "crypto-key"/kKeyCryptoKey through public api
@@ -1496,6 +1557,8 @@
             if (msg->findBuffer("csd-1", &csd1)) {
                 meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
             }
+        } else if (mime == MEDIA_MIMETYPE_AUDIO_ALAC) {
+            meta->setData(kKeyAlacMagicCookie, 0, csd0->data(), csd0->size());
         }
     }
 
@@ -1578,6 +1641,7 @@
     { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
     { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
     { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
+    { MEDIA_MIMETYPE_AUDIO_ALAC,        AUDIO_FORMAT_ALAC },
     { 0, AUDIO_FORMAT_INVALID }
 };
 
@@ -1668,7 +1732,7 @@
     info.sample_rate = srate;
 
     int32_t cmask = 0;
-    if (!meta->findInt32(kKeyChannelMask, &cmask)) {
+    if (!meta->findInt32(kKeyChannelMask, &cmask) || cmask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
         ALOGV("track of type '%s' does not publish channel mask", mime);
 
         // Try a channel count instead
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
index fd1c90d..7e0ae99 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_abs.cpp
@@ -176,7 +176,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word32 L_abs(register Word32 L_var1)
+Word32 L_abs(Word32 L_var1)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
index f609a73..47e1ee8 100644
--- a/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/l_shr_r.cpp
@@ -190,7 +190,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word32 L_shr_r(register Word32 L_var1, register Word16 var2, Flag *pOverflow)
+Word32 L_shr_r(Word32 L_var1, Word16 var2, Flag *pOverflow)
 {
     Word32 result;
 
diff --git a/media/libstagefright/codecs/amrnb/common/src/negate.cpp b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
index be58d2b..aa36422 100644
--- a/media/libstagefright/codecs/amrnb/common/src/negate.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/negate.cpp
@@ -161,7 +161,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 negate(register Word16 var1)
+Word16 negate(Word16 var1)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrnb/common/src/round.cpp b/media/libstagefright/codecs/amrnb/common/src/round.cpp
index 71d1702..633a8c9 100644
--- a/media/libstagefright/codecs/amrnb/common/src/round.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/round.cpp
@@ -184,7 +184,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 pv_round(register Word32 L_var1, Flag *pOverflow)
+Word16 pv_round(Word32 L_var1, Flag *pOverflow)
 {
     Word16  result;
 
diff --git a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
index 6656f93..cdcc246 100644
--- a/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
+++ b/media/libstagefright/codecs/amrnb/common/src/shr_r.cpp
@@ -193,7 +193,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
-Word16 shr_r(register Word16 var1, register Word16 var2, Flag *pOverflow)
+Word16 shr_r(Word16 var1, Word16 var2, Flag *pOverflow)
 {
     /*----------------------------------------------------------------------------
     ; Define all local variables
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder_basic_op_cequivalent.h b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder_basic_op_cequivalent.h
index 3c7590c..7a86ec2 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder_basic_op_cequivalent.h
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder_basic_op_cequivalent.h
@@ -467,7 +467,12 @@
     __inline  int32 fxp_mac_16by16(int16 var1,  int16 var2, int32 L_add)
     {
 
-        L_add += (int32)var1 * var2;
+        int32 l_orig = L_add;
+        if (__builtin_add_overflow( (int32)var1 * var2, l_orig, &L_add)) {
+            // needs saturation
+            if (l_orig > 0) L_add = MAX_32;
+            else            L_add = MIN_32;
+        }
 
         return L_add;
     }
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 1695c75..e5a85e9 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -51,6 +51,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
 const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
 const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
+const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 25be89f..58758bc 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -53,6 +53,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
 extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
 extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
+extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index f78e125..1a44e1f 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -66,6 +66,7 @@
     sp<ImageDecoder> mImageDecoder;
     int mLastImageIndex;
     void parseMetaData();
+    void parseColorAspects(const sp<MetaData>& meta);
     // Delete album art and clear metadata.
     void clearMetadata();
 
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index 3dd4248..3b298a9 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -157,7 +157,7 @@
                             request->endpoint,
                             request->buffer,
                             request->buffer_length,
-                            0);
+                            1000);
     request->actual_length = result;
     return result;
 }
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6b20bca..42285f8 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -811,7 +811,13 @@
         size_t *encryptedbytes) {
 
     // size needed to store all the crypto data
-    size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+    size_t cryptosize;
+    // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+    if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
+            __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
+        ALOGE("crypto size overflow");
+        return NULL;
+    }
     AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
     if (!ret) {
         ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
index d34214b..2206526 100644
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "APM::SessionRoute"
+#define LOG_TAG "APM_SessionRoute"
 //#define LOG_NDEBUG 0
 
 #include "SessionRoute.h"
@@ -122,19 +122,17 @@
 audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
                                                           const DeviceVector& availableDevices)
 {
-    audio_devices_t device = AUDIO_DEVICE_NONE;
-
     for (size_t index = 0; index < size(); index++) {
         sp<SessionRoute> route = valueAt(index);
         if (streamType == route->mStreamType && route->isActiveOrChanged()
                 && route->mDeviceDescriptor != 0) {
-            device = route->mDeviceDescriptor->type();
+            audio_devices_t device = route->mDeviceDescriptor->type();
             if (!availableDevices.getDevicesFromType(device).isEmpty()) {
-                break;
+                return device;
             }
         }
     }
-    return device;
+    return AUDIO_DEVICE_NONE;
 }
 
 } // namespace android
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_strategy_sonification_respectful.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_strategy_sonification_respectful.pfw
index cee7cd1..b673c4f 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_strategy_sonification_respectful.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_strategy_sonification_respectful.pfw
@@ -534,3 +534,20 @@
 					usb_device = 0
 					hdmi = 0
 
+			conf: None
+				component: /Policy/policy/strategies/sonification_respectful/selected_output_devices/mask
+					earpiece = 0
+					bluetooth_sco = 0
+					bluetooth_sco_headset = 0
+					bluetooth_sco_carkit = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 0
+					bluetooth_a2dp = 0
+					wired_headset = 0
+					wired_headphone = 0
+					line = 0
+					angl_dock_headset = 0
+					dgtl_dock_headset = 0
+					usb_accessory = 0
+					usb_device = 0
+					hdmi = 0
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8e1c237..c9c806a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -15,7 +15,12 @@
  */
 
 #define LOG_TAG "APM_AudioPolicyManager"
-//#define LOG_NDEBUG 0
+
+// Need to keep the log statements even in production builds
+// to enable VERBOSE logging dynamically.
+// You can enable VERBOSE logging as follows:
+// adb shell setprop log.tag.APM_AudioPolicyManager V
+#define LOG_NDEBUG 0
 
 //#define VERY_VERBOSE_LOGGING
 #ifdef VERY_VERBOSE_LOGGING
@@ -861,6 +866,21 @@
         *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
     }
 
+    // Set incall music only if device was explicitly set, and fallback to the device which is
+    // chosen by the engine if not.
+    // FIXME: provide a more generic approach which is not device specific and move this back
+    // to getOutputForDevice.
+    if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+        *stream == AUDIO_STREAM_MUSIC &&
+        audio_is_linear_pcm(config->format) &&
+        isInCall()) {
+        if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
+            *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+        } else {
+            device = mEngine->getDeviceForStrategy(strategy);
+        }
+    }
+
     ALOGV("getOutputForAttr() device 0x%x, sampling rate %d, format %#x, channel mask %#x, "
           "flags %#x",
           device, config->sample_rate, config->format, config->channel_mask, *flags);
@@ -916,11 +936,6 @@
         *flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_VOIP_RX |
                                        AUDIO_OUTPUT_FLAG_DIRECT);
         ALOGV("Set VoIP and Direct output flags for PCM format");
-    } else if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
-        stream == AUDIO_STREAM_MUSIC &&
-        audio_is_linear_pcm(config->format) &&
-        isInCall()) {
-        *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
     }
 
 
@@ -1071,13 +1086,12 @@
     for (audio_io_handle_t output : outputs) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
         if (!outputDesc->isDuplicated()) {
+            if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+                continue;
+            }
             // if a valid format is specified, skip output if not compatible
             if (format != AUDIO_FORMAT_INVALID) {
-                if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-                    if (format != outputDesc->mFormat) {
-                        continue;
-                    }
-                } else if (!audio_is_linear_pcm(format)) {
+                if (!audio_is_linear_pcm(format)) {
                     continue;
                 }
                 if (AudioPort::isBetterFormatMatch(
@@ -4159,6 +4173,9 @@
         status = NO_INIT;
     }
 
+    // Silence ALOGV statements
+    property_set("log.tag." LOG_TAG, "D");
+
     updateDevicesAndOutputs();
     return status;
 }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2bf42b6..ba0244e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -181,7 +181,9 @@
 
     for (auto& cameraId : deviceIds) {
         String8 id8 = String8(cameraId.c_str());
-        onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
+        if (getCameraState(id8) == nullptr) {
+            onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
+        }
     }
 
     return OK;
@@ -208,6 +210,14 @@
     proxyBinder->pingForUserUpdate();
 }
 
+void CameraService::broadcastTorchModeStatus(const String8& cameraId, TorchModeStatus status) {
+    Mutex::Autolock lock(mStatusListenerLock);
+
+    for (auto& i : mListenerList) {
+        i->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
+    }
+}
+
 CameraService::~CameraService() {
     VendorTagDescriptor::clearGlobalVendorTagDescriptor();
     mUidPolicy->unregisterSelf();
@@ -246,6 +256,8 @@
     if (mFlashlight->hasFlashUnit(id)) {
         Mutex::Autolock al(mTorchStatusMutex);
         mTorchStatusMap.add(id, TorchModeStatus::AVAILABLE_OFF);
+
+        broadcastTorchModeStatus(id, TorchModeStatus::AVAILABLE_OFF);
     }
 
     updateCameraNumAndIds();
@@ -398,12 +410,7 @@
         }
     }
 
-    {
-        Mutex::Autolock lock(mStatusListenerLock);
-        for (auto& i : mListenerList) {
-            i->onTorchStatusChanged(mapToInterface(newStatus), String16{cameraId});
-        }
-    }
+    broadcastTorchModeStatus(cameraId, newStatus);
 }
 
 Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
@@ -1549,6 +1556,24 @@
 
 Status CameraService::notifySystemEvent(int32_t eventId,
         const std::vector<int32_t>& args) {
+    const int pid = getCallingPid();
+    const int selfPid = getpid();
+
+    // Permission checks
+    if (pid != selfPid) {
+        // Ensure we're being called by system_server, or similar process with
+        // permissions to notify the camera service about system events
+        if (!checkCallingPermission(
+                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+            const int uid = getCallingUid();
+            ALOGE("Permission Denial: cannot send updates to camera service about system"
+                    " events from pid=%d, uid=%d", pid, uid);
+            return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+                    "No permission to send updates to camera service about system events"
+                    " from pid=%d, uid=%d", pid, uid);
+        }
+    }
+
     ATRACE_CALL();
 
     switch(eventId) {
@@ -1950,8 +1975,6 @@
 status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
         uint32_t flags) {
 
-    const int pid = getCallingPid();
-    const int selfPid = getpid();
 
     // Permission checks
     switch (code) {
@@ -1979,20 +2002,6 @@
             }
             return NO_ERROR;
         }
-        case BnCameraService::NOTIFYSYSTEMEVENT: {
-            if (pid != selfPid) {
-                // Ensure we're being called by system_server, or similar process with
-                // permissions to notify the camera service about system events
-                if (!checkCallingPermission(
-                        String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
-                    const int uid = getCallingUid();
-                    ALOGE("Permission Denial: cannot send updates to camera service about system"
-                            " events from pid=%d, uid=%d", pid, uid);
-                    return PERMISSION_DENIED;
-                }
-            }
-            break;
-        }
     }
 
     return BnCameraService::onTransact(code, data, reply, flags);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8d4bcdb..624d1ca 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -857,6 +857,8 @@
     static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
     static void pingCameraServiceProxy();
 
+    void broadcastTorchModeStatus(const String8& cameraId,
+            hardware::camera::common::V1_0::TorchModeStatus status);
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 1ee216f..84f0a89 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -492,7 +492,6 @@
     ATRACE_CALL();
     SharedParameters::Lock l(client->getParameters());
     Vector<int32_t> outputStreams;
-    uint8_t captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
 
     /**
      * Set up output streams in the request
@@ -522,7 +521,6 @@
 
     if (l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
         outputStreams.push(client->getRecordingStreamId());
-        captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
     }
 
     res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
@@ -532,10 +530,6 @@
                 &mCaptureId, 1);
     }
     if (res == OK) {
-        res = mCaptureRequest.update(ANDROID_CONTROL_CAPTURE_INTENT,
-                &captureIntent, 1);
-    }
-    if (res == OK) {
         res = mCaptureRequest.sort();
     }
 
@@ -683,6 +677,8 @@
         sp<Camera2Client> &client) {
     ATRACE_CALL();
     status_t res;
+    uint8_t captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+
     if (mCaptureRequest.entryCount() == 0) {
         res = client->getCameraDevice()->createDefaultRequest(
                 CAMERA2_TEMPLATE_STILL_CAPTURE,
@@ -695,6 +691,16 @@
         }
     }
 
+    if (params.state == Parameters::VIDEO_SNAPSHOT) {
+        captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
+    }
+    res = mCaptureRequest.update(ANDROID_CONTROL_CAPTURE_INTENT, &captureIntent, 1);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to update capture intent: %s (%d)",
+                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+        return res;
+    }
+
     res = params.updateRequest(&mCaptureRequest);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of capture "
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 8bc208d..ecb980a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -83,8 +83,8 @@
     // from input, and attached to the outputs. In this case, the input queue's
     // dequeueBuffer can still allocate 1 extra buffer before being blocked by
     // the output's attachBuffer().
-    mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
-                                                 mMaxConsumerBuffers+1);
+    mMaxConsumerBuffers++;
+    mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage, mMaxConsumerBuffers);
     if (mBufferItemConsumer == nullptr) {
         return NO_MEMORY;
     }
@@ -108,6 +108,7 @@
     mHeight = height;
     mFormat = format;
     mProducerUsage = producerUsage;
+    mAcquiredInputBuffers = 0;
 
     SP_LOGV("%s: connected", __FUNCTION__);
     return res;
@@ -147,6 +148,7 @@
 
     mMaxHalBuffers = 0;
     mMaxConsumerBuffers = 0;
+    mAcquiredInputBuffers = 0;
     SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
@@ -165,7 +167,9 @@
         return res;
     }
 
-    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+    if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
+        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+    }
 
     return res;
 }
@@ -249,6 +253,10 @@
     // Add new entry into mOutputs
     mOutputs[surfaceId] = gbp;
     mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
+    if (mConsumerBufferCount[surfaceId] > mMaxHalBuffers) {
+        SP_LOGW("%s: Consumer buffer count %zu larger than max. Hal buffers: %zu", __FUNCTION__,
+                mConsumerBufferCount[surfaceId], mMaxHalBuffers);
+    }
     mNotifiers[gbp] = listener;
     mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
 
@@ -266,10 +274,12 @@
         return res;
     }
 
-    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
-    if (res != OK) {
-        SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
-        return res;
+    if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
+        res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+        if (res != OK) {
+            SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
+            return res;
+        }
     }
 
     return res;
@@ -318,11 +328,7 @@
     }
 
     mNotifiers[gbp] = nullptr;
-    if (mConsumerBufferCount[surfaceId] < mMaxHalBuffers) {
-        mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
-    } else {
-        SP_LOGE("%s: Cached consumer buffer count mismatch!", __FUNCTION__);
-    }
+    mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
     mConsumerBufferCount[surfaceId] = 0;
 
     return res;
@@ -497,6 +503,7 @@
         return;
     }
 
+    mAcquiredInputBuffers++;
     SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
             bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
 
@@ -599,6 +606,12 @@
         } else {
             SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
         }
+    } else {
+        if (mAcquiredInputBuffers == 0) {
+            ALOGW("%s: Acquired input buffer count already at zero!", __FUNCTION__);
+        } else {
+            mAcquiredInputBuffers--;
+        }
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index fea1bdb..1eaf2bd 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -269,6 +269,9 @@
     // Latest onFrameAvailable return value
     std::atomic<status_t> mOnFrameAvailableRes{0};
 
+    // Currently acquired input buffers
+    size_t mAcquiredInputBuffers;
+
     String8 mConsumerName;
 };
 
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index d70e27b..e6c676c 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -40,4 +40,7 @@
 pread64: 1
 mremap: 1
 
+# Required by Sanitizers
+sched_yield: 1
+
 @include /system/etc/seccomp_policy/crash_dump.arm64.policy
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 6a72e5b..0182a27 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -58,7 +58,7 @@
 
     if (!dumpAllowed()) {
         std::stringstream ss;
-        ss << "Permission denial: can't dump AAudioService from pid="
+        ss << "Permission Denial: can't dump AAudioService from pid="
                 << IPCThreadState::self()->getCallingPid() << ", uid="
                 << IPCThreadState::self()->getCallingUid() << "\n";
         result = ss.str();