Merge "MediaSession2: Add caller to the callback methods"
diff --git a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
index b83851a..1e282d1 100644
--- a/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
+++ b/media/libaaudio/examples/loopback/src/LoopbackAnalyzer.h
@@ -410,8 +410,7 @@
 
 
 static void printAudioScope(float sample) {
-    const int maxStars = 80
-    ; // arbitrary, fits on one line
+    const int maxStars = 80; // arbitrary, fits on one line
     char c = '*';
     if (sample < -1.0) {
         sample = -1.0;
@@ -555,7 +554,7 @@
                 break;
 
             case STATE_WAITING_FOR_SILENCE:
-                // Output silence.
+                // Output silence and wait for the echos to die down.
                 numSamples = numFrames * outputChannelCount;
                 for (int i = 0; i < numSamples; i++) {
                     outputData[i] = 0;
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index f2254ce..39d079e 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -128,7 +128,7 @@
 
             myData->audioRecording.write(myData->inputData,
                                         myData->actualInputChannelCount,
-                                        numFrames);
+                                         framesRead);
 
             int32_t numSamples = framesRead * myData->actualInputChannelCount;
             convertPcm16ToFloat(myData->inputData, myData->conversionBuffer, numSamples);
@@ -161,17 +161,17 @@
 static void usage() {
     printf("Usage: aaudio_loopback [OPTION]...\n\n");
     AAudioArgsParser::usage();
-    printf("          -C{channels}      number of input channels\n");
-    printf("          -g{gain}          recirculating loopback gain\n");
-    printf("          -P{inPerf}        set input AAUDIO_PERFORMANCE_MODE*\n");
-    printf("              n for _NONE\n");
-    printf("              l for _LATENCY\n");
-    printf("              p for _POWER_SAVING\n");
-    printf("          -t{test}          select test mode\n");
-    printf("              m for sine magnitude\n");
-    printf("              e for echo latency (default)\n");
-    printf("              f for file latency, analyzes %s\n\n", FILENAME_ECHOS);
-    printf("          -X  use EXCLUSIVE mode for input\n");
+    printf("      -C{channels}      number of input channels\n");
+    printf("      -g{gain}          recirculating loopback gain\n");
+    printf("      -P{inPerf}        set input AAUDIO_PERFORMANCE_MODE*\n");
+    printf("          n for _NONE\n");
+    printf("          l for _LATENCY\n");
+    printf("          p for _POWER_SAVING\n");
+    printf("      -t{test}          select test mode\n");
+    printf("          m for sine magnitude\n");
+    printf("          e for echo latency (default)\n");
+    printf("          f for file latency, analyzes %s\n\n", FILENAME_ECHOS);
+    printf("      -X  use EXCLUSIVE mode for input\n");
     printf("Example:  aaudio_loopback -n2 -pl -Pl -x\n");
 }
 
@@ -448,7 +448,7 @@
     }
 
     if (loopbackData.loopbackProcessor->getResult() < 0) {
-        printf("Test failed!\n");
+        printf("ERROR: Could not get a good loopback signal. Probably because the volume was too low.\n");
     } else {
         printf("input error = %d = %s\n",
                loopbackData.inputError, AAudio_convertResultToText(loopbackData.inputError));
@@ -467,11 +467,16 @@
         }
 
         int written = loopbackData.loopbackProcessor->save(FILENAME_ECHOS);
-        printf("main() wrote %d mono samples to %s on Android device\n", written,
-               FILENAME_ECHOS);
-        printf("main() loopbackData.audioRecording.getSampleRate() = %d\n", loopbackData.audioRecording.getSampleRate());
+        if (written > 0) {
+            printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
+                   written, FILENAME_ECHOS);
+        }
+
         written = loopbackData.audioRecording.save(FILENAME_ALL);
-        printf("main() wrote %d mono samples to %s on Android device\n", written, FILENAME_ALL);
+        if (written > 0) {
+            printf("main() wrote %8d mono samples to \"%s\" on Android device\n",
+                   written, FILENAME_ALL);
+        }
     }
 
 finish:
@@ -481,9 +486,8 @@
     delete[] loopbackData.inputData;
     delete[] outputData;
 
-    printf(RESULT_TAG "error = %d = %s\n", result, AAudio_convertResultToText(result));
+    printf(RESULT_TAG "result = %s\n", AAudio_convertResultToText(result));
     if ((result != AAUDIO_OK)) {
-        printf("error %d = %s\n", result, AAudio_convertResultToText(result));
         return EXIT_FAILURE;
     } else {
         printf("SUCCESS\n");
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 4fc5b9f..eb6925a 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -19,7 +19,8 @@
 
 #define MAX_CHANNELS                     8
 
-#include <cctype>
+//#include <cctype>
+#include <dlfcn.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,6 +30,63 @@
 
 #include "AAudioExampleUtils.h"
 
+
+static void (*s_setUsage)(AAudioStreamBuilder* builder, aaudio_usage_t usage) = nullptr;
+static void (*s_setContentType)(AAudioStreamBuilder* builder,
+                                aaudio_content_type_t contentType) = nullptr;
+static void (*s_setInputPreset)(AAudioStreamBuilder* builder,
+                                aaudio_input_preset_t inputPreset) = nullptr;
+
+static bool s_loadAttempted = false;
+static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
+static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
+static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
+
+// Link to test functions in shared library.
+static void loadFutureFunctions() {
+    if (s_loadAttempted)  return; // only try once
+    s_loadAttempted = true;
+
+    void *handle = dlopen("libaaudio.so", RTLD_NOW);
+    if (handle != nullptr) {
+        s_setUsage = (void (*)(AAudioStreamBuilder *, aaudio_usage_t))
+                dlsym(handle, "AAudioStreamBuilder_setUsage");
+        if (s_setUsage == nullptr) goto error;
+
+        s_setContentType = (void (*)(AAudioStreamBuilder *, aaudio_content_type_t))
+                dlsym(handle, "AAudioStreamBuilder_setContentType");
+        if (s_setContentType == nullptr) goto error;
+
+        s_setInputPreset = (void (*)(AAudioStreamBuilder *, aaudio_input_preset_t))
+                dlsym(handle, "AAudioStreamBuilder_setInputPreset");
+        if (s_setInputPreset == nullptr) goto error;
+
+        s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
+                dlsym(handle, "AAudioStream_getUsage");
+        if (s_getUsage == nullptr) goto error;
+
+        s_getContentType = (aaudio_content_type_t (*)(AAudioStream *))
+                dlsym(handle, "AAudioStream_getContentType");
+        if (s_getContentType == nullptr) goto error;
+
+        s_getInputPreset = (aaudio_input_preset_t (*)(AAudioStream *))
+                dlsym(handle, "AAudioStream_getInputPreset");
+        if (s_getInputPreset == nullptr) goto error;
+    }
+    return;
+
+error:
+    // prevent any calls to these functions
+    s_setUsage = nullptr;
+    s_setContentType = nullptr;
+    s_setInputPreset = nullptr;
+    s_getUsage = nullptr;
+    s_getContentType = nullptr;
+    s_getInputPreset = nullptr;
+    dlclose(handle);
+    return;
+}
+
 // TODO use this as a base class within AAudio
 class AAudioParameters {
 public:
@@ -140,9 +198,24 @@
         AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
         AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
         AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
-        AAudioStreamBuilder_setUsage(builder, mUsage);
-        AAudioStreamBuilder_setContentType(builder, mContentType);
-        AAudioStreamBuilder_setInputPreset(builder, mInputPreset);
+
+        // Call P functions if supported.
+        loadFutureFunctions();
+        if (s_setUsage != nullptr) {
+            s_setUsage(builder, mUsage);
+        } else if (mUsage != AAUDIO_UNSPECIFIED){
+            printf("WARNING: setUsage not supported");
+        }
+        if (s_setContentType != nullptr) {
+            s_setContentType(builder, mContentType);
+        } else if (mUsage != AAUDIO_UNSPECIFIED){
+            printf("WARNING: setContentType not supported");
+        }
+        if (s_setInputPreset != nullptr) {
+            s_setInputPreset(builder, mInputPreset);
+        } else if (mUsage != AAUDIO_UNSPECIFIED){
+            printf("WARNING: setInputPreset not supported");
+        }
     }
 
 private:
@@ -332,14 +405,21 @@
         printf("  PerformanceMode: requested = %d, actual = %d\n",
                getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
 
-        printf("  Usage:        requested = %d, actual = %d\n",
-               getUsage(), AAudioStream_getUsage(stream));
-        printf("  ContentType:  requested = %d, actual = %d\n",
-               getContentType(), AAudioStream_getContentType(stream));
+        loadFutureFunctions();
 
-        if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT) {
-            printf("  InputPreset:  requested = %d, actual = %d\n",
-                   getInputPreset(), AAudioStream_getInputPreset(stream));
+        if (s_setUsage != nullptr) {
+            printf("  Usage:        requested = %d, actual = %d\n",
+                   getUsage(), s_getUsage(stream));
+        }
+        if (s_getContentType != nullptr) {
+            printf("  ContentType:  requested = %d, actual = %d\n",
+                   getContentType(), s_getContentType(stream));
+        }
+
+        if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT
+            && s_getInputPreset != nullptr) {
+                printf("  InputPreset:  requested = %d, actual = %d\n",
+                       getInputPreset(), s_getInputPreset(stream));
         }
 
         printf("  Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index b611160..6b25302 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -104,7 +104,7 @@
     request.setUserId(getuid());
     request.setProcessId(getpid());
     request.setSharingModeMatchRequired(isSharingModeMatchRequired());
-    request.setInService(mInService);
+    request.setInService(isInService());
 
     request.getConfiguration().setDeviceId(getDeviceId());
     request.getConfiguration().setSampleRate(getSampleRate());
@@ -118,11 +118,24 @@
 
     request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
 
+    mDeviceChannelCount = getSamplesPerFrame(); // Assume it will be the same. Update if not.
+
     mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
+    if (mServiceStreamHandle < 0
+            && request.getConfiguration().getSamplesPerFrame() == 1 // mono?
+            && getDirection() == AAUDIO_DIRECTION_OUTPUT
+            && !isInService()) {
+        // if that failed then try switching from mono to stereo if OUTPUT.
+        // Only do this in the client. Otherwise we end up with a mono mixer in the service
+        // that writes to a stereo MMAP stream.
+        ALOGD("%s - openStream() returned %d, try switching from MONO to STEREO",
+              __func__, mServiceStreamHandle);
+        request.getConfiguration().setSamplesPerFrame(2); // stereo
+        mServiceStreamHandle = mServiceInterface.openStream(request, configurationOutput);
+    }
     if (mServiceStreamHandle < 0) {
-        result = mServiceStreamHandle;
-        ALOGE("%s - openStream() returned %d", __func__, result);
-        return result;
+        ALOGE("%s - openStream() returned %d", __func__, mServiceStreamHandle);
+        return mServiceStreamHandle;
     }
 
     result = configurationOutput.validate();
@@ -130,8 +143,12 @@
         goto error;
     }
     // Save results of the open.
+    if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
+        setSamplesPerFrame(configurationOutput.getSamplesPerFrame());
+    }
+    mDeviceChannelCount = configurationOutput.getSamplesPerFrame();
+
     setSampleRate(configurationOutput.getSampleRate());
-    setSamplesPerFrame(configurationOutput.getSamplesPerFrame());
     setDeviceId(configurationOutput.getDeviceId());
     setSessionId(configurationOutput.getSessionId());
     setSharingMode(configurationOutput.getSharingMode());
@@ -160,7 +177,6 @@
         goto error;
     }
 
-
     // Validate result from server.
     framesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
     if (framesPerBurst < MIN_FRAMES_PER_BURST || framesPerBurst > MAX_FRAMES_PER_BURST) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 0f54f8c..0e0724b 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -138,7 +138,14 @@
     // Calculate timeout for an operation involving framesPerOperation.
     int64_t calculateReasonableTimeout(int32_t framesPerOperation);
 
-    aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    aaudio_format_t getDeviceFormat() const { return mDeviceFormat; }
+
+    int32_t getDeviceChannelCount() const { return mDeviceChannelCount; }
+
+    /**
+     * @return true if running in audio service, versus in app process
+     */
+    bool isInService() const { return mInService; }
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
 
@@ -187,6 +194,11 @@
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
 
     int64_t                  mServiceLatencyNanos = 0;
+
+    // Sometimes the hardware is operating with a different format or channel count from the app.
+    // Then we require conversion in AAudio.
+    aaudio_format_t          mDeviceFormat = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t                  mDeviceChannelCount = 0;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 62f0fc8..0719fe1 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -176,16 +176,16 @@
         int32_t numSamples = framesToProcess * getSamplesPerFrame();
 
         // TODO factor this out into a utility function
-        if (mDeviceFormat == getFormat()) {
+        if (getDeviceFormat() == getFormat()) {
             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
-        } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16
+        } else if (getDeviceFormat() == AAUDIO_FORMAT_PCM_I16
                    && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
             AAudioConvert_pcm16ToFloat(
                     (const int16_t *) wrappingBuffer.data[partIndex],
                     (float *) destination,
                     numSamples,
                     1.0f);
-        } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT
+        } else if (getDeviceFormat() == AAUDIO_FORMAT_PCM_FLOAT
                    && getFormat() == AAUDIO_FORMAT_PCM_I16) {
             AAudioConvert_floatToPcm16(
                     (const float *) wrappingBuffer.data[partIndex],
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index a0a0a54..11b43c3 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -206,7 +206,7 @@
     // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
     //              buffer, numFrames);
     WrappingBuffer wrappingBuffer;
-    uint8_t *source = (uint8_t *) buffer;
+    uint8_t *byteBuffer = (uint8_t *) buffer;
     int32_t framesLeft = numFrames;
 
     mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
@@ -220,69 +220,26 @@
             if (framesToWrite > framesAvailable) {
                 framesToWrite = framesAvailable;
             }
+
             int32_t numBytes = getBytesPerFrame() * framesToWrite;
-            int32_t numSamples = framesToWrite * getSamplesPerFrame();
             // Data conversion.
             float levelFrom;
             float levelTo;
-            bool ramping = mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
-            // The formats are validated when the stream is opened so we do not have to
-            // check for illegal combinations here.
-            // TODO factor this out into a utility function
-            if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
-                if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-                    AAudio_linearRamp(
-                            (const float *) source,
-                            (float *) wrappingBuffer.data[partIndex],
-                            framesToWrite,
-                            getSamplesPerFrame(),
-                            levelFrom,
-                            levelTo);
-                } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
-                    if (ramping) {
-                        AAudioConvert_floatToPcm16(
-                                (const float *) source,
-                                (int16_t *) wrappingBuffer.data[partIndex],
-                                framesToWrite,
-                                getSamplesPerFrame(),
-                                levelFrom,
-                                levelTo);
-                    } else {
-                        AAudioConvert_floatToPcm16(
-                                (const float *) source,
-                                (int16_t *) wrappingBuffer.data[partIndex],
-                                numSamples,
-                                levelTo);
-                    }
-                }
-            } else if (getFormat() == AAUDIO_FORMAT_PCM_I16) {
-                if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-                    if (ramping) {
-                        AAudioConvert_pcm16ToFloat(
-                                (const int16_t *) source,
-                                (float *) wrappingBuffer.data[partIndex],
-                                framesToWrite,
-                                getSamplesPerFrame(),
-                                levelFrom,
-                                levelTo);
-                    } else {
-                        AAudioConvert_pcm16ToFloat(
-                                (const int16_t *) source,
-                                (float *) wrappingBuffer.data[partIndex],
-                                numSamples,
-                                levelTo);
-                    }
-                } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
-                    AAudio_linearRamp(
-                            (const int16_t *) source,
-                            (int16_t *) wrappingBuffer.data[partIndex],
-                            framesToWrite,
-                            getSamplesPerFrame(),
-                            levelFrom,
-                            levelTo);
-                }
-            }
-            source += numBytes;
+            mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
+
+            AAudioDataConverter::FormattedData source(
+                    (void *)byteBuffer,
+                    getFormat(),
+                    getSamplesPerFrame());
+            AAudioDataConverter::FormattedData destination(
+                    wrappingBuffer.data[partIndex],
+                    getDeviceFormat(),
+                    getDeviceChannelCount());
+
+            AAudioDataConverter::convert(source, destination, framesToWrite,
+                                         levelFrom, levelTo);
+
+            byteBuffer += numBytes;
             framesLeft -= framesToWrite;
         } else {
             break;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 854c691..40b31b9 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -27,6 +27,7 @@
 #include <aaudio/AAudioTesting.h>
 #include <math.h>
 #include <system/audio-base.h>
+#include <assert.h>
 
 #include "utility/AAudioUtilities.h"
 
@@ -72,7 +73,7 @@
                                 int16_t *destination,
                                 int32_t numSamples,
                                 float amplitude) {
-    float scaler = amplitude;
+    const float scaler = amplitude;
     for (int i = 0; i < numSamples; i++) {
         float sample = *source++;
         *destination++ = clipAndClampFloatToPcm16(sample, scaler);
@@ -103,7 +104,7 @@
                                 float *destination,
                                 int32_t numSamples,
                                 float amplitude) {
-    float scaler = amplitude / SHORT_SCALE;
+    const float scaler = amplitude / SHORT_SCALE;
     for (int i = 0; i < numSamples; i++) {
         destination[i] = source[i] * scaler;
     }
@@ -117,7 +118,7 @@
                                 float amplitude1,
                                 float amplitude2) {
     float scaler = amplitude1 / SHORT_SCALE;
-    float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
+    const float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
     for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
         for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
             *destination++ = *source++ * scaler;
@@ -134,7 +135,7 @@
                        float amplitude1,
                        float amplitude2) {
     float scaler = amplitude1;
-    float delta = (amplitude2 - amplitude1) / numFrames;
+    const float delta = (amplitude2 - amplitude1) / numFrames;
     for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
         for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
             float sample = *source++;
@@ -158,7 +159,7 @@
                        float amplitude2) {
     // Because we are converting from int16 to 1nt16, we do not have to scale by 1/32768.
     float scaler = amplitude1;
-    float delta = (amplitude2 - amplitude1) / numFrames;
+    const float delta = (amplitude2 - amplitude1) / numFrames;
     for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
         for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
             // No need to clip because int16_t range is inherently limited.
@@ -169,6 +170,255 @@
     }
 }
 
+// *************************************************************************************
+// Convert Mono To Stereo at the same time as converting format.
+void AAudioConvert_formatMonoToStereo(const float *source,
+                                      int16_t *destination,
+                                      int32_t numFrames,
+                                      float amplitude) {
+    const float scaler = amplitude;
+    for (int i = 0; i < numFrames; i++) {
+        float sample = *source++;
+        int16_t sample16 = clipAndClampFloatToPcm16(sample, scaler);
+        *destination++ = sample16;
+        *destination++ = sample16;
+    }
+}
+
+void AAudioConvert_formatMonoToStereo(const float *source,
+                                      int16_t *destination,
+                                      int32_t numFrames,
+                                      float amplitude1,
+                                      float amplitude2) {
+    // divide by numFrames so that we almost reach amplitude2
+    const float delta = (amplitude2 - amplitude1) / numFrames;
+    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
+        const float scaler = amplitude1 + (frameIndex * delta);
+        const float sample = *source++;
+        int16_t sample16 = clipAndClampFloatToPcm16(sample, scaler);
+        *destination++ = sample16;
+        *destination++ = sample16;
+    }
+}
+
+void AAudioConvert_formatMonoToStereo(const int16_t *source,
+                                      float *destination,
+                                      int32_t numFrames,
+                                      float amplitude) {
+    const float scaler = amplitude / SHORT_SCALE;
+    for (int i = 0; i < numFrames; i++) {
+        float sample = source[i] * scaler;
+        *destination++ = sample;
+        *destination++ = sample;
+    }
+}
+
+// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
+void AAudioConvert_formatMonoToStereo(const int16_t *source,
+                                      float *destination,
+                                      int32_t numFrames,
+                                      float amplitude1,
+                                      float amplitude2) {
+    const float scaler1 = amplitude1 / SHORT_SCALE;
+    const float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
+    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
+        float scaler = scaler1 + (frameIndex * delta);
+        float sample = source[frameIndex] * scaler;
+        *destination++ = sample;
+        *destination++ = sample;
+    }
+}
+
+// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
+void AAudio_linearRampMonoToStereo(const float *source,
+                                   float *destination,
+                                   int32_t numFrames,
+                                   float amplitude1,
+                                   float amplitude2) {
+    const float delta = (amplitude2 - amplitude1) / numFrames;
+    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
+        float sample = *source++;
+
+        // Clip to valid range of a float sample to prevent excessive volume.
+        if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
+        else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
+
+        const float scaler = amplitude1 + (frameIndex * delta);
+        float sampleScaled = sample * scaler;
+        *destination++ = sampleScaled;
+        *destination++ = sampleScaled;
+    }
+}
+
+// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
+void AAudio_linearRampMonoToStereo(const int16_t *source,
+                                   int16_t *destination,
+                                   int32_t numFrames,
+                                   float amplitude1,
+                                   float amplitude2) {
+    // Because we are converting from int16 to 1nt16, we do not have to scale by 1/32768.
+    const float delta = (amplitude2 - amplitude1) / numFrames;
+    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
+        const float scaler = amplitude1 + (frameIndex * delta);
+        // No need to clip because int16_t range is inherently limited.
+        const float sample =  *source++ * scaler;
+        int16_t sample16 = (int16_t) roundf(sample);
+        *destination++ = sample16;
+        *destination++ = sample16;
+    }
+}
+
+// *************************************************************************************
+void AAudioDataConverter::convert(
+        const FormattedData &source,
+        const FormattedData &destination,
+        int32_t numFrames,
+        float levelFrom,
+        float levelTo) {
+
+    if (source.channelCount == 1 && destination.channelCount == 2) {
+        convertMonoToStereo(source,
+                            destination,
+                            numFrames,
+                            levelFrom,
+                            levelTo);
+    } else {
+        // We only support mono to stereo conversion. Otherwise source and destination
+        // must match.
+        assert(source.channelCount == destination.channelCount);
+        convertChannelsMatch(source,
+                             destination,
+                             numFrames,
+                             levelFrom,
+                             levelTo);
+    }
+}
+
+void AAudioDataConverter::convertMonoToStereo(
+        const FormattedData &source,
+        const FormattedData &destination,
+        int32_t numFrames,
+        float levelFrom,
+        float levelTo) {
+
+    // The formats are validated when the stream is opened so we do not have to
+    // check for illegal combinations here.
+    if (source.format == AAUDIO_FORMAT_PCM_FLOAT) {
+        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
+            AAudio_linearRampMonoToStereo(
+                    (const float *) source.data,
+                    (float *) destination.data,
+                    numFrames,
+                    levelFrom,
+                    levelTo);
+        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
+            if (levelFrom != levelTo) {
+                AAudioConvert_formatMonoToStereo(
+                        (const float *) source.data,
+                        (int16_t *) destination.data,
+                        numFrames,
+                        levelFrom,
+                        levelTo);
+            } else {
+                AAudioConvert_formatMonoToStereo(
+                        (const float *) source.data,
+                        (int16_t *) destination.data,
+                        numFrames,
+                        levelTo);
+            }
+        }
+    } else if (source.format == AAUDIO_FORMAT_PCM_I16) {
+        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
+            if (levelFrom != levelTo) {
+                AAudioConvert_formatMonoToStereo(
+                        (const int16_t *) source.data,
+                        (float *) destination.data,
+                        numFrames,
+                        levelFrom,
+                        levelTo);
+            } else {
+                AAudioConvert_formatMonoToStereo(
+                        (const int16_t *) source.data,
+                        (float *) destination.data,
+                        numFrames,
+                        levelTo);
+            }
+        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
+            AAudio_linearRampMonoToStereo(
+                    (const int16_t *) source.data,
+                    (int16_t *) destination.data,
+                    numFrames,
+                    levelFrom,
+                    levelTo);
+        }
+    }
+}
+
+void AAudioDataConverter::convertChannelsMatch(
+        const FormattedData &source,
+        const FormattedData &destination,
+        int32_t numFrames,
+        float levelFrom,
+        float levelTo) {
+    const int32_t numSamples = numFrames * source.channelCount;
+
+    // The formats are validated when the stream is opened so we do not have to
+    // check for illegal combinations here.
+    if (source.format == AAUDIO_FORMAT_PCM_FLOAT) {
+        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
+            AAudio_linearRamp(
+                    (const float *) source.data,
+                    (float *) destination.data,
+                    numFrames,
+                    source.channelCount,
+                    levelFrom,
+                    levelTo);
+        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
+            if (levelFrom != levelTo) {
+                AAudioConvert_floatToPcm16(
+                        (const float *) source.data,
+                        (int16_t *) destination.data,
+                        numFrames,
+                        source.channelCount,
+                        levelFrom,
+                        levelTo);
+            } else {
+                AAudioConvert_floatToPcm16(
+                        (const float *) source.data,
+                        (int16_t *) destination.data,
+                        numSamples,
+                        levelTo);
+            }
+        }
+    } else if (source.format == AAUDIO_FORMAT_PCM_I16) {
+        if (destination.format == AAUDIO_FORMAT_PCM_FLOAT) {
+            if (levelFrom != levelTo) {
+                AAudioConvert_pcm16ToFloat(
+                        (const int16_t *) source.data,
+                        (float *) destination.data,
+                        numFrames,
+                        source.channelCount,
+                        levelFrom,
+                        levelTo);
+            } else {
+                AAudioConvert_pcm16ToFloat(
+                        (const int16_t *) source.data,
+                        (float *) destination.data,
+                        numSamples,
+                        levelTo);
+            }
+        } else if (destination.format == AAUDIO_FORMAT_PCM_I16) {
+            AAudio_linearRamp(
+                    (const int16_t *) source.data,
+                    (int16_t *) destination.data,
+                    numFrames,
+                    source.channelCount,
+                    levelFrom,
+                    levelTo);
+        }
+    }
+}
+
 status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
     // This covers the case for AAUDIO_OK and for positive results.
     if (result >= 0) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index dc6a671..cea88fb 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -159,6 +159,41 @@
                        float amplitude1,
                        float amplitude2);
 
+class AAudioDataConverter {
+public:
+
+    struct FormattedData {
+
+        FormattedData(void *data, aaudio_format_t format, int32_t channelCount)
+            : data(data)
+            , format(format)
+            , channelCount(channelCount) {}
+
+        const void            *data = nullptr;
+        const aaudio_format_t  format = AAUDIO_FORMAT_UNSPECIFIED;
+        const int32_t          channelCount = 1;
+    };
+
+    static void convert(const FormattedData &source,
+                        const FormattedData &destination,
+                        int32_t numFrames,
+                        float levelFrom,
+                        float levelTo);
+
+private:
+    static void convertMonoToStereo(const FormattedData &source,
+                                    const FormattedData &destination,
+                                    int32_t numFrames,
+                                    float levelFrom,
+                                    float levelTo);
+
+    static void convertChannelsMatch(const FormattedData &source,
+                                     const FormattedData &destination,
+                                     int32_t numFrames,
+                                     float levelFrom,
+                                     float levelTo);
+};
+
 /**
  * Calculate the number of bytes and prevent numeric overflow.
  * @param numFrames frame count
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 5a33975..5716727 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1030,7 +1030,7 @@
     bool lResult = false;
     status_t lStatus;
 
-    if ((toneType < 0) || (toneType >= NUM_TONES))
+    if (toneType >= NUM_TONES)
         return lResult;
 
     toneType = getToneForRegion(toneType);
diff --git a/media/libstagefright/codec2/client/Android.bp b/media/libstagefright/codec2/client/Android.bp
new file mode 100644
index 0000000..0129e15
--- /dev/null
+++ b/media/libstagefright/codec2/client/Android.bp
@@ -0,0 +1,30 @@
+cc_library {
+    name: "libstagefright_codec2_client",
+
+    srcs: [
+        "client.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.media.bufferpool@1.0",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_codec2_hidl@1.0",
+        "libutils",
+        "vendor.google.media.c2@1.0",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "libstagefright_codec2",
+    ],
+
+}
+
diff --git a/media/libstagefright/codec2/client/client.cpp b/media/libstagefright/codec2/client/client.cpp
new file mode 100644
index 0000000..5a176dc
--- /dev/null
+++ b/media/libstagefright/codec2/client/client.cpp
@@ -0,0 +1,509 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2Client-interfaces"
+#include <log/log.h>
+
+#include <media/stagefright/codec2/client.h>
+
+#include <codec2/hidl/1.0/types.h>
+
+#include <vendor/google/media/c2/1.0/IComponentListener.h>
+#include <vendor/google/media/c2/1.0/IConfigurable.h>
+#include <vendor/google/media/c2/1.0/IComponentInterface.h>
+#include <vendor/google/media/c2/1.0/IComponent.h>
+#include <vendor/google/media/c2/1.0/IComponentStore.h>
+
+#include <hidl/HidlSupport.h>
+
+#include <limits>
+#include <type_traits>
+
+namespace /* unnamed */ {
+
+// TODO: Find the appropriate error code for this
+constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
+
+} // unnamed namespace
+
+namespace android {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using namespace ::vendor::google::media::c2::V1_0;
+using namespace ::vendor::google::media::c2::V1_0::implementation;
+
+// Codec2ConfigurableClient
+
+const C2String& Codec2ConfigurableClient::getName() const {
+    return mName;
+}
+
+Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
+    return static_cast<Base*>(mBase.get());
+}
+
+Codec2ConfigurableClient::Codec2ConfigurableClient(
+        const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
+    Return<void> transStatus = base->getName(
+            [this](const hidl_string& name) {
+                mName = name.c_str();
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("Cannot obtain name from IConfigurable.");
+    }
+}
+
+c2_status_t Codec2ConfigurableClient::query(
+        const std::vector<C2Param::Index> &indices,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2Param>>* const params) const {
+    hidl_vec<ParamIndex> hidlIndices(indices.size());
+    size_t i = 0;
+    for (const C2Param::Index& index : indices) {
+        hidlIndices[i++] = static_cast<ParamIndex>(index.operator uint32_t());
+    }
+    c2_status_t status;
+    Return<void> transStatus = base()->query(
+            hidlIndices,
+            mayBlock == C2_MAY_BLOCK,
+            [&status, params](Status s, const Params& p) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                status = copyParamsFromBlob(params, p);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("query -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+c2_status_t Codec2ConfigurableClient::config(
+        const std::vector<C2Param*> &params,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+    Params hidlParams;
+    Status hidlStatus = createParamsBlob(&hidlParams, params);
+    if (hidlStatus != Status::OK) {
+        ALOGE("config -- bad input.");
+        return C2_TRANSACTION_FAILED;
+    }
+    c2_status_t status;
+    Return<void> transStatus = base()->config(
+            hidlParams,
+            mayBlock == C2_MAY_BLOCK,
+            [&status, &params, failures](
+                    Status s,
+                    const hidl_vec<SettingResult> f,
+                    const Params& o) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                failures->clear();
+                failures->resize(f.size());
+                size_t i = 0;
+                for (const SettingResult& sf : f) {
+                    status = objcpy(&(*failures)[i++], sf);
+                    if (status != C2_OK) {
+                        return;
+                    }
+                }
+                status = updateParamsFromBlob(params, o);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("config -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+c2_status_t Codec2ConfigurableClient::querySupportedParams(
+        std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
+    // TODO: Cache and query properly!
+    c2_status_t status;
+    Return<void> transStatus = base()->querySupportedParams(
+            std::numeric_limits<uint32_t>::min(),
+            std::numeric_limits<uint32_t>::max(),
+            [&status, params](
+                    Status s,
+                    const hidl_vec<ParamDescriptor>& p) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                params->resize(p.size());
+                size_t i = 0;
+                for (const ParamDescriptor& sp : p) {
+                    status = objcpy(&(*params)[i++], sp);
+                    if (status != C2_OK) {
+                        return;
+                    }
+                }
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("querySupportedParams -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+c2_status_t Codec2ConfigurableClient::querySupportedValues(
+        std::vector<C2FieldSupportedValuesQuery>& fields,
+        c2_blocking_t mayBlock) const {
+    hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
+    for (size_t i = 0; i < fields.size(); ++i) {
+        Status hidlStatus = objcpy(&inFields[i], fields[i]);
+        if (hidlStatus != Status::OK) {
+            ALOGE("querySupportedValues -- bad input");
+            return C2_TRANSACTION_FAILED;
+        }
+    }
+
+    c2_status_t status;
+    Return<void> transStatus = base()->querySupportedValues(
+            inFields,
+            mayBlock == C2_MAY_BLOCK,
+            [&status, &inFields, &fields](
+                    Status s,
+                    const hidl_vec<FieldSupportedValuesQueryResult>& r) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                if (r.size() != fields.size()) {
+                    ALOGE("querySupportedValues -- input and output lists "
+                            "have different sizes.");
+                    status = C2_CORRUPTED;
+                    return;
+                }
+                for (size_t i = 0; i < fields.size(); ++i) {
+                    status = objcpy(&fields[i], inFields[i], r[i]);
+                    if (status != C2_OK) {
+                        return;
+                    }
+                }
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("querySupportedValues -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+// Codec2Client
+
+Codec2Client::Base* Codec2Client::base() const {
+    return static_cast<Base*>(mBase.get());
+}
+
+Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base) :
+        Codec2ConfigurableClient(base), mListed(false) {
+}
+
+c2_status_t Codec2Client::createComponent(
+        const C2String& name,
+        const std::shared_ptr<Codec2Client::Listener>& listener,
+        std::shared_ptr<Codec2Client::Component>* const component) {
+
+    // TODO: Add support for Bufferpool
+
+    struct HidlListener : public IComponentListener {
+        std::shared_ptr<Codec2Client::Listener> base;
+        std::weak_ptr<Codec2Client::Component> component;
+
+        virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
+            std::list<std::unique_ptr<C2Work>> workItems;
+            c2_status_t status = objcpy(&workItems, workBundle);
+            if (status != C2_OK) {
+                ALOGE("onWorkDone -- received corrupted WorkBundle. "
+                        "Error code: %d", static_cast<int>(status));
+                return Void();
+            }
+            base->onWorkDone(component, workItems);
+            return Void();
+        }
+
+        virtual Return<void> onTripped(
+                const hidl_vec<SettingResult>& settingResults) override {
+            std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
+                    settingResults.size());
+            c2_status_t status;
+            for (size_t i = 0; i < settingResults.size(); ++i) {
+                std::unique_ptr<C2SettingResult> c2SettingResult;
+                status = objcpy(&c2SettingResult, settingResults[i]);
+                if (status != C2_OK) {
+                    ALOGE("onTripped -- received corrupted SettingResult. "
+                            "Error code: %d", static_cast<int>(status));
+                    return Void();
+                }
+                c2SettingResults[i] = std::move(c2SettingResult);
+            }
+            base->onTripped(component, c2SettingResults);
+            return Void();
+        }
+
+        virtual Return<void> onError(Status s, uint32_t errorCode) override {
+            base->onError(component, s == Status::OK ?
+                    errorCode : static_cast<c2_status_t>(s));
+            return Void();
+        }
+    };
+
+    c2_status_t status;
+    sp<HidlListener> hidlListener = new HidlListener();
+    hidlListener->base = listener;
+    Return<void> transStatus = base()->createComponent(
+            name,
+            hidlListener,
+            nullptr,
+            [&status, component](
+                    Status s,
+                    const sp<IComponent>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *component = std::make_shared<Codec2Client::Component>(c);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("createComponent -- failed transaction.");
+        return C2_TRANSACTION_FAILED;
+    }
+    if (status != C2_OK) {
+        ALOGE("createComponent -- failed to create component.");
+        return status;
+    }
+    hidlListener->component = *component;
+    return status;
+}
+
+c2_status_t Codec2Client::createInterface(
+        const C2String& name,
+        std::shared_ptr<Codec2Client::Interface>* const interface) {
+    c2_status_t status;
+    Return<void> transStatus = base()->createInterface(
+            name,
+            [&status, interface](
+                    Status s,
+                    const sp<IComponentInterface>& i) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *interface = std::make_shared<Codec2Client::Interface>(i);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("createInterface -- failed transaction.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+const std::vector<C2Component::Traits>& Codec2Client::listComponents()
+        const {
+    if (mListed) {
+        return mTraitsList;
+    }
+    Return<void> transStatus = base()->listComponents(
+            [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
+                mTraitsList.resize(t.size());
+                mAliasesBuffer.resize(t.size());
+                for (size_t i = 0; i < t.size(); ++i) {
+                    c2_status_t status = objcpy(
+                            &mTraitsList[i], &mAliasesBuffer[i], t[i]);
+                    if (status != C2_OK) {
+                        ALOGE("listComponents -- corrupted output.");
+                        return;
+                    }
+                }
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("listComponents -- failed transaction.");
+    }
+    mListed = true;
+    return mTraitsList;
+}
+
+c2_status_t Codec2Client::copyBuffer(
+        const std::shared_ptr<C2Buffer>& src,
+        const std::shared_ptr<C2Buffer>& dst) {
+    // TODO: Implement?
+    (void)src;
+    (void)dst;
+    ALOGE("copyBuffer not implemented");
+    return C2_OMITTED;
+}
+
+std::shared_ptr<C2ParamReflector>
+        Codec2Client::getParamReflector() {
+    // TODO: Implement this once there is a way to construct C2StructDescriptor
+    // dynamically.
+    ALOGE("getParamReflector -- not implemented.");
+    return nullptr;
+}
+
+std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
+        const char* instanceName, bool waitForService) {
+    sp<Base> baseStore = waitForService ?
+            Base::getService(instanceName) :
+            Base::tryGetService(instanceName);
+    if (!baseStore) {
+        if (waitForService) {
+            ALOGE("Codec2.0 service inaccessible. Check the device manifest.");
+        } else {
+            ALOGW("Codec2.0 service not available right now. Try again later.");
+        }
+        return nullptr;
+    }
+    return std::make_shared<Codec2Client>(baseStore);
+}
+
+// Codec2Client::Listener
+
+Codec2Client::Listener::~Listener() {
+}
+
+// Codec2Client::Component
+
+Codec2Client::Component::Base* Codec2Client::Component::base() const {
+    return static_cast<Base*>(mBase.get());
+}
+
+Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
+        Codec2Client::Configurable(base) {
+}
+
+c2_status_t Codec2Client::Component::createBlockPool(
+        C2Allocator::id_t id,
+        C2BlockPool::local_id_t* localId,
+        std::shared_ptr<Codec2Client::Configurable>* configurable) {
+    c2_status_t status;
+    Return<void> transStatus = base()->createBlockPool(
+            static_cast<uint32_t>(id),
+            [&status, localId, configurable](
+                    Status s,
+                    uint64_t pId,
+                    const sp<IConfigurable>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *localId = static_cast<C2BlockPool::local_id_t>(pId);
+                *configurable = std::make_shared<Codec2Client::Configurable>(c);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("createBlockPool -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+c2_status_t Codec2Client::Component::queue(
+        std::list<std::unique_ptr<C2Work>>* const items) {
+    WorkBundle workBundle;
+    Status hidlStatus = objcpy(&workBundle, *items);
+    if (hidlStatus != Status::OK) {
+        ALOGE("queue -- bad input.");
+        return C2_TRANSACTION_FAILED;
+    }
+    Return<Status> transStatus = base()->queue(workBundle);
+    if (!transStatus.isOk()) {
+        ALOGE("queue -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+c2_status_t Codec2Client::Component::flush(
+        C2Component::flush_mode_t mode,
+        std::list<std::unique_ptr<C2Work>>* const flushedWork) {
+    (void)mode; // Flush mode isn't supported in HIDL yet.
+    c2_status_t status;
+    Return<void> transStatus = base()->flush(
+            [&status, flushedWork](
+                    Status s, const WorkBundle& wb) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                status = objcpy(flushedWork, wb);
+            });
+    if (!transStatus.isOk()) {
+        ALOGE("flush -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
+c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
+    Return<Status> transStatus = base()->drain(
+            mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
+    if (!transStatus.isOk()) {
+        ALOGE("drain -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+c2_status_t Codec2Client::Component::start() {
+    Return<Status> transStatus = base()->start();
+    if (!transStatus.isOk()) {
+        ALOGE("start -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+c2_status_t Codec2Client::Component::stop() {
+    Return<Status> transStatus = base()->stop();
+    if (!transStatus.isOk()) {
+        ALOGE("stop -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+c2_status_t Codec2Client::Component::reset() {
+    Return<Status> transStatus = base()->reset();
+    if (!transStatus.isOk()) {
+        ALOGE("reset -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+c2_status_t Codec2Client::Component::release() {
+    Return<Status> transStatus = base()->release();
+    if (!transStatus.isOk()) {
+        ALOGE("release -- transaction failed.");
+        return C2_TRANSACTION_FAILED;
+    }
+    return static_cast<c2_status_t>(static_cast<Status>(transStatus));
+}
+
+
+
+
+}  // namespace android
+
diff --git a/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h b/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h
new file mode 100644
index 0000000..1bbf459
--- /dev/null
+++ b/media/libstagefright/codec2/client/include/media/stagefright/codec2/client.h
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+#ifndef CODEC2_CLIENT_INTERFACES_H_
+#define CODEC2_CLIENT_INTERFACES_H_
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <utils/StrongPointer.h>
+
+#include <memory>
+
+/**
+ * This file contains minimal interfaces for the framework to access Codec2.0.
+ *
+ * Codec2Client is the main class that contains the following inner classes:
+ * - Listener
+ * - Configurable
+ * - Interface
+ * - Component
+ *
+ * Classes in Codec2Client, interfaces in Codec2.0, and  HIDL interfaces are
+ * related as follows:
+ * - Codec2Client <==> C2ComponentStore <==> IComponentStore
+ * - Codec2Client::Listener <==> C2Component::Listener <==> IComponentListener
+ * - Codec2Client::Configurable <==> [No equivalent] <==> IConfigurable
+ * - Codec2Client::Interface <==> C2ComponentInterface <==> IComponentInterface
+ * - Codec2Client::Component <==> C2Component <==> IComponent
+ *
+ * The entry point is Codec2Client::CreateFromService(), which creates a
+ * Codec2Client object. From Codec2Client, Interface and Component objects can
+ * be created by calling createComponent() and createInterface().
+ *
+ * createComponent() takes a Listener object, which must be implemented by the
+ * user.
+ *
+ * At the present, createBlockPool() is the only method that yields a
+ * Configurable object. Note, however, that Interface, Component and
+ * Codec2Client are all subclasses of Configurable.
+ */
+
+// Forward declaration of HIDL interfaces
+namespace vendor {
+namespace google {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+struct IConfigurable;
+struct IComponentInterface;
+struct IComponent;
+struct IComponentStore;
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace google
+} // namespace vendor
+
+namespace android {
+
+// This class is supposed to be called Codec2Client::Configurable, but forward
+// declaration of an inner class is not possible.
+struct Codec2ConfigurableClient {
+
+    typedef ::vendor::google::media::c2::V1_0::IConfigurable Base;
+
+    const C2String& getName() const;
+
+    c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params) const;
+
+    c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            );
+
+    c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const;
+
+    c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const;
+
+    // base cannot be null.
+    Codec2ConfigurableClient(const sp<Base>& base);
+
+protected:
+    C2String mName;
+    sp<Base> mBase;
+
+    Base* base() const;
+
+    friend struct Codec2Client;
+};
+
+struct Codec2Client : public Codec2ConfigurableClient {
+
+    typedef ::vendor::google::media::c2::V1_0::IComponentStore Base;
+
+    struct Listener;
+
+    typedef Codec2ConfigurableClient Configurable;
+
+    typedef Configurable Interface; // These two types may diverge in the future.
+
+    struct Component;
+
+    typedef Codec2Client Store;
+
+    c2_status_t createComponent(
+            const C2String& name,
+            const std::shared_ptr<Listener>& listener,
+            std::shared_ptr<Component>* const component);
+
+    c2_status_t createInterface(
+            const C2String& name,
+            std::shared_ptr<Interface>* const interface);
+
+    const std::vector<C2Component::Traits>&
+            listComponents() const;
+
+    c2_status_t copyBuffer(
+            const std::shared_ptr<C2Buffer>& src,
+            const std::shared_ptr<C2Buffer>& dst);
+
+    std::shared_ptr<C2ParamReflector> getParamReflector();
+
+    static std::shared_ptr<Codec2Client> CreateFromService(
+            const char* instanceName,
+            bool waitForService = true);
+
+    // base cannot be null.
+    Codec2Client(const sp<Base>& base);
+
+protected:
+    mutable bool mListed;
+    mutable std::vector<C2Component::Traits> mTraitsList;
+    mutable std::vector<std::unique_ptr<std::vector<std::string>>>
+            mAliasesBuffer;
+
+    Base* base() const;
+};
+
+struct Codec2Client::Listener {
+
+    virtual void onWorkDone(
+            const std::weak_ptr<Codec2Client::Component>& comp,
+            const std::list<std::unique_ptr<C2Work>>& workItems) = 0;
+
+    virtual void onTripped(
+            const std::weak_ptr<Codec2Client::Component>& comp,
+            const std::vector<std::shared_ptr<C2SettingResult>>& settingResults
+            ) = 0;
+
+    virtual void onError(
+            const std::weak_ptr<Codec2Client::Component>& comp,
+            uint32_t errorCode) = 0;
+
+    virtual ~Listener();
+
+};
+
+struct Codec2Client::Component : public Codec2Client::Configurable {
+
+    typedef ::vendor::google::media::c2::V1_0::IComponent Base;
+
+    c2_status_t createBlockPool(
+            C2Allocator::id_t id,
+            C2BlockPool::local_id_t* localId,
+            std::shared_ptr<Codec2Client::Configurable>* configurable);
+
+    c2_status_t queue(
+            std::list<std::unique_ptr<C2Work>>* const items);
+
+    c2_status_t flush(
+            C2Component::flush_mode_t mode,
+            std::list<std::unique_ptr<C2Work>>* const flushedWork);
+
+    c2_status_t drain(C2Component::drain_mode_t mode);
+
+    c2_status_t start();
+
+    c2_status_t stop();
+
+    c2_status_t reset();
+
+    c2_status_t release();
+
+    // base cannot be null.
+    Component(const sp<Base>& base);
+
+protected:
+    Base* base() const;
+
+    friend struct Codec2Client;
+};
+
+}  // namespace android
+
+#endif  // CODEC2_CLIENT_INTERFACES_H_
+
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp b/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
index bbcd630..2b34fde 100644
--- a/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
+++ b/media/libstagefright/codec2/hidl/impl/1.0/Component.cpp
@@ -48,7 +48,7 @@
     virtual c2_status_t query(
             const std::vector<C2Param::Index>& indices,
             c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>>* const params) override {
+            std::vector<std::unique_ptr<C2Param>>* const params) const override {
         return mIntf->query_vb({}, indices, mayBlock, params);
     }
 
@@ -108,7 +108,9 @@
             for (const std::shared_ptr<C2SettingResult> &c2result :
                     c2settingResult) {
                 if (c2result) {
-                    objcpy(&settingResults[ix++], *c2result);
+                    if (objcpy(&settingResults[ix++], *c2result) != Status::OK) {
+                        break;
+                    }
                 }
             }
             settingResults.resize(ix);
@@ -166,7 +168,6 @@
     if (objcpy(&c2works, workBundle) != C2_OK) {
         return Status::CORRUPTED;
     }
-    (void)workBundle;
     return static_cast<Status>(mComponent->queue_nb(&c2works));
 }
 
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp b/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
index d42d67a..4d51fba 100644
--- a/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
+++ b/media/libstagefright/codec2/hidl/impl/1.0/ComponentStore.cpp
@@ -54,7 +54,7 @@
     c2_status_t query(
             const std::vector<C2Param::Index> &indices,
             c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>> *const params) override {
+            std::vector<std::unique_ptr<C2Param>> *const params) const override {
         // Assume all params are blocking
         // TODO: Filter for supported params
         if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
@@ -201,7 +201,7 @@
     // TODO implement
     (void)src;
     (void)dst;
-    return Status {};
+    return Status::OMITTED;
 }
 
 }  // namespace implementation
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
index 94d2e6d..da90996 100644
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/ConfigurableC2Intf.h
@@ -49,7 +49,7 @@
     virtual c2_status_t query(
             const std::vector<C2Param::Index> &indices,
             c2_blocking_t mayBlock,
-            std::vector<std::unique_ptr<C2Param>>* const params) = 0;
+            std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
     /** C2ComponentInterface::config_vb */
     virtual c2_status_t config(
             const std::vector<C2Param*> &params,
@@ -60,7 +60,7 @@
             std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
     /** C2ComponentInterface::querySupportedParams_nb */
     virtual c2_status_t querySupportedValues(
-            std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const = 0;
+            std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
 
     virtual ~ConfigurableC2Intf() = default;
 
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
index 41ee275..1eace56 100644
--- a/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
+++ b/media/libstagefright/codec2/hidl/impl/1.0/include/codec2/hidl/1.0/types.h
@@ -53,77 +53,79 @@
 typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
 
 // C2SettingResult -> SettingResult
-Status C2_HIDE objcpy(
+Status objcpy(
         SettingResult* d,
         const C2SettingResult& s);
 
-// SettingResult -> C2SettingResult
-c2_status_t C2_HIDE objcpy(
-        C2SettingResult* d,
+// SettingResult -> std::unique_ptr<C2SettingResult>
+c2_status_t objcpy(
+        std::unique_ptr<C2SettingResult>* d,
         const SettingResult& s);
 
 // C2ParamDescriptor -> ParamDescriptor
-Status C2_HIDE objcpy(
+Status objcpy(
         ParamDescriptor* d,
         const C2ParamDescriptor& s);
 
-// ParamDescriptor -> std::unique_ptr<C2ParamDescriptor>
-c2_status_t C2_HIDE objcpy(
-        std::unique_ptr<C2ParamDescriptor>* d,
+// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
+c2_status_t objcpy(
+        std::shared_ptr<C2ParamDescriptor>* d,
         const ParamDescriptor& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status C2_HIDE objcpy(
+Status objcpy(
         FieldSupportedValuesQuery* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t C2_HIDE objcpy(
+c2_status_t objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& s);
 
 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status C2_HIDE objcpy(
+Status objcpy(
         FieldSupportedValuesQueryResult* d,
         const C2FieldSupportedValuesQuery& s);
 
 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-c2_status_t C2_HIDE objcpy(
+c2_status_t objcpy(
         C2FieldSupportedValuesQuery* d,
         const FieldSupportedValuesQuery& sq,
         const FieldSupportedValuesQueryResult& sr);
 
 // C2Component::Traits -> ComponentTraits
-Status C2_HIDE objcpy(
+Status objcpy(
         IComponentStore::ComponentTraits* d,
         const C2Component::Traits& s);
 
-// ComponentTraits -> C2Component::Traits
-c2_status_t C2_HIDE objcpy(
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+// Note: The output d is only valid as long as aliasesBuffer remains alive.
+c2_status_t objcpy(
         C2Component::Traits* d,
+        std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s);
 
 // C2StructDescriptor -> StructDescriptor
-Status C2_HIDE objcpy(
+Status objcpy(
         StructDescriptor* d,
         const C2StructDescriptor& s);
 
 // StructDescriptor -> C2StructDescriptor
 // TODO: This cannot be implemented yet because C2StructDescriptor does not
 // allow dynamic construction/modification.
-c2_status_t C2_HIDE objcpy(
+c2_status_t objcpy(
         C2StructDescriptor* d,
         const StructDescriptor& s);
 
 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
 // TODO: Connect with Bufferpool
-Status C2_HIDE objcpy(
+Status objcpy(
         WorkBundle* d,
         const std::list<std::unique_ptr<C2Work>>& s);
 
 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
 // TODO: Connect with Bufferpool
-c2_status_t C2_HIDE objcpy(
+c2_status_t objcpy(
         std::list<std::unique_ptr<C2Work>>* d,
         const WorkBundle& s);
 
@@ -159,6 +161,29 @@
         hidl_vec<uint8_t> *blob,
         const std::vector<std::unique_ptr<C2Tuning>> &params);
 
+/**
+ * Parses a params blob and create a vector of C2Params whose members are copies
+ * of the params in the blob.
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+c2_status_t copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Param>>* params,
+        Params blob);
+
+/**
+ * Parses a params blob and applies updates to params
+ * \param[in,out] params params to be updated
+ * \param[in] blob parameter blob containing updates
+ * \retval C2_OK if the full blob was parsed and params was updated
+ * \retval C2_BAD_VALUE otherwise
+ */
+c2_status_t updateParamsFromBlob(
+        const std::vector<C2Param*>& params,
+        const Params& blob);
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/libstagefright/codec2/hidl/impl/1.0/types.cpp b/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
index 14ced2e..f14c21a 100644
--- a/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
+++ b/media/libstagefright/codec2/hidl/impl/1.0/types.cpp
@@ -31,6 +31,7 @@
 #include <C2Component.h>
 #include <util/C2ParamUtils.h>
 
+#include <unordered_map>
 #include <algorithm>
 
 namespace vendor {
@@ -264,25 +265,26 @@
     return Status::OK;
 }
 
-// ComponentTraits -> C2Component::Traits
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
 c2_status_t objcpy(
         C2Component::Traits* d,
+        std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
         const IComponentStore::ComponentTraits& s) {
-    d->name = s.name;
-
-    // TODO: Currently, we do not have any domain values defined in Codec2.0.
+    d->name = s.name.c_str();
     d->domain = static_cast<C2Component::domain_t>(s.domainOther);
-
-    // TODO: Currently, we do not have any kind values defined in Codec2.0.
     d->kind = static_cast<C2Component::kind_t>(s.kindOther);
-
     d->rank = static_cast<C2Component::rank_t>(s.rank);
-
     d->mediaType = s.mediaType.c_str();
 
-    // TODO: Currently, aliases are pointers to static strings. This is not
-    // supported by HIDL.
-    d->aliases.clear();
+    // aliasesBuffer must not be resized after this.
+    *aliasesBuffer = std::make_unique<std::vector<std::string>>(
+            s.aliases.size());
+    (*aliasesBuffer)->resize(s.aliases.size());
+    std::vector<C2StringLiteral> dAliases(s.aliases.size());
+    for (size_t i = 0; i < s.aliases.size(); ++i) {
+        (**aliasesBuffer)[i] = s.aliases[i].c_str();
+        d->aliases[i] = (**aliasesBuffer)[i].c_str();
+    }
     return C2_OK;
 }
 
@@ -366,48 +368,60 @@
     return Status::OK;
 }
 
-// SettingResult -> C2SettingResult
-c2_status_t objcpy(C2SettingResult *d, const SettingResult &s) {
+// SettingResult -> std::unique_ptr<C2SettingResult>
+c2_status_t objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+    *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+            .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
+    if (!*d) {
+        return C2_NO_MEMORY;
+    }
+
+    // failure
     switch (s.failure) {
     case SettingResult::Failure::READ_ONLY:
-        d->failure = C2SettingResult::READ_ONLY;
+        (*d)->failure = C2SettingResult::READ_ONLY;
         break;
     case SettingResult::Failure::MISMATCH:
-        d->failure = C2SettingResult::MISMATCH;
+        (*d)->failure = C2SettingResult::MISMATCH;
         break;
     case SettingResult::Failure::BAD_VALUE:
-        d->failure = C2SettingResult::BAD_VALUE;
+        (*d)->failure = C2SettingResult::BAD_VALUE;
         break;
     case SettingResult::Failure::BAD_TYPE:
-        d->failure = C2SettingResult::BAD_TYPE;
+        (*d)->failure = C2SettingResult::BAD_TYPE;
         break;
     case SettingResult::Failure::BAD_PORT:
-        d->failure = C2SettingResult::BAD_PORT;
+        (*d)->failure = C2SettingResult::BAD_PORT;
         break;
     case SettingResult::Failure::BAD_INDEX:
-        d->failure = C2SettingResult::BAD_INDEX;
+        (*d)->failure = C2SettingResult::BAD_INDEX;
         break;
     case SettingResult::Failure::CONFLICT:
-        d->failure = C2SettingResult::CONFLICT;
+        (*d)->failure = C2SettingResult::CONFLICT;
         break;
     case SettingResult::Failure::UNSUPPORTED:
-        d->failure = C2SettingResult::UNSUPPORTED;
+        (*d)->failure = C2SettingResult::UNSUPPORTED;
         break;
     case SettingResult::Failure::INFO_CONFLICT:
-        d->failure = C2SettingResult::INFO_CONFLICT;
+        (*d)->failure = C2SettingResult::INFO_CONFLICT;
         break;
     default:
-        d->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
+        (*d)->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
     }
-    c2_status_t status = objcpy(&d->field, s.field);
+
+    // field
+    c2_status_t status = objcpy(&(*d)->field, s.field);
     if (status != C2_OK) {
         return status;
     }
-    d->conflicts.clear();
+
+    // conflicts
+    (*d)->conflicts.clear();
+    (*d)->conflicts.reserve(s.conflicts.size());
     for (const ParamFieldValues& sConflict : s.conflicts) {
-        d->conflicts.emplace_back(
+        (*d)->conflicts.emplace_back(
                 C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
-        status = objcpy(&d->conflicts.back(), sConflict);
+        status = objcpy(&(*d)->conflicts.back(), sConflict);
         if (status != C2_OK) {
             return status;
         }
@@ -426,13 +440,13 @@
 }
 
 // ParamDescriptor -> C2ParamDescriptor
-c2_status_t objcpy(std::unique_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+c2_status_t objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
     std::vector<C2Param::Index> dDependencies;
     dDependencies.reserve(s.dependencies.size());
     for (const ParamIndex& sDependency : s.dependencies) {
         dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
     }
-    *d = std::make_unique<C2ParamDescriptor>(
+    *d = std::make_shared<C2ParamDescriptor>(
             C2Param::Index(static_cast<uint32_t>(s.index)),
             static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
             C2String(s.name.c_str()),
@@ -1058,10 +1072,8 @@
             dWorklet->failures.clear();
             dWorklet->failures.reserve(sWorklet.failures.size());
             for (const SettingResult& sFailure : sWorklet.failures) {
-                std::unique_ptr<C2SettingResult> dFailure(
-                        new C2SettingResult { .field = C2ParamFieldValues {
-                        C2ParamFieldBuilder(), nullptr } });
-                status = objcpy(dFailure.get(), sFailure);
+                std::unique_ptr<C2SettingResult> dFailure;
+                status = objcpy(&dFailure, sFailure);
                 if (status != C2_OK) {
                     ALOGE("Failed to create C2SettingResult in C2Worklet.");
                     return C2_BAD_VALUE;
@@ -1176,6 +1188,74 @@
     return _createParamsBlob(blob, params);
 }
 
+// Params -> std::vector<std::unique_ptr<C2Param>>
+c2_status_t copyParamsFromBlob(
+        std::vector<std::unique_ptr<C2Param>>* params,
+        Params blob) {
+    std::vector<C2Param*> paramPointers;
+    c2_status_t status = parseParamsBlob(&paramPointers, blob);
+    if (status != C2_OK) {
+        ALOGE("copyParamsFromBlob -- blob parsing failed.");
+        return status;
+    }
+    params->resize(paramPointers.size());
+    size_t i = 0;
+    for (C2Param* const& paramPointer : paramPointers) {
+        if (!paramPointer) {
+            ALOGE("copyParamsFromBlob -- corrupted params blob.");
+            return C2_BAD_VALUE;
+        }
+        (*params)[i++] = C2Param::Copy(*paramPointer);
+    }
+    return C2_OK;
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+c2_status_t updateParamsFromBlob(
+        const std::vector<C2Param*>& params,
+        const Params& blob) {
+    std::unordered_map<uint32_t, C2Param*> index2param;
+    for (C2Param* const& param : params) {
+        if (!param) {
+            ALOGE("updateParamsFromBlob -- corrupted input params.");
+            return C2_BAD_VALUE;
+        }
+        if (index2param.find(param->index()) == index2param.end()) {
+            index2param.emplace(param->index(), param);
+        }
+    }
+
+    std::vector<C2Param*> paramPointers;
+    c2_status_t status = parseParamsBlob(&paramPointers, blob);
+    if (status != C2_OK) {
+        ALOGE("updateParamsFromBlob -- blob parsing failed.");
+        return status;
+    }
+
+    for (C2Param* const& paramPointer : paramPointers) {
+        if (!paramPointer) {
+            ALOGE("updateParamsFromBlob -- corrupted param in blob.");
+            return C2_BAD_VALUE;
+        }
+        decltype(index2param)::iterator i = index2param.find(
+                paramPointer->index());
+        if (i == index2param.end()) {
+            ALOGW("updateParamsFromBlob -- unseen param index.");
+            continue;
+        }
+        if (!i->second->updateFrom(*paramPointer)) {
+            ALOGE("updateParamsFromBlob -- mismatching sizes: "
+                    "%u vs %u (index = %u).",
+                    static_cast<unsigned>(params.size()),
+                    static_cast<unsigned>(paramPointer->size()),
+                    static_cast<unsigned>(i->first));
+            return C2_BAD_VALUE;
+        }
+    }
+    return C2_OK;
+}
+
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp b/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
index 3571ed5..1b1b9be 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
+++ b/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
@@ -43,8 +43,8 @@
     return Void();
 }
 
-Accessor::Accessor(const std::shared_ptr<C2Allocator> &allocator, bool linear)
-    : mImpl(new Impl(allocator, linear)) {}
+Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
+    : mImpl(new Impl(allocator)) {}
 
 Accessor::~Accessor() {
 }
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.h b/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
index 6fd82ba..ad42245 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
+++ b/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
@@ -20,7 +20,6 @@
 #include <android/hardware/media/bufferpool/1.0/IAccessor.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
-#include <C2Buffer.h>
 #include <BufferPoolTypes.h>
 #include "BufferStatus.h"
 
@@ -53,9 +52,8 @@
      * Creates a buffer pool accessor which uses the specified allocator.
      *
      * @param allocator buffer allocator.
-     * @param linear    whether the allocator is linear or not.
      */
-    Accessor(const std::shared_ptr<C2Allocator> &allocator, bool linear);
+    explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
 
     /** Destructs a buffer pool accessor. */
     ~Accessor();
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
index f8aec53..32d76c0 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
+++ b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
@@ -22,7 +22,6 @@
 #include <time.h>
 #include <unistd.h>
 #include <utils/Log.h>
-#include <C2Buffer.h>
 #include "AccessorImpl.h"
 #include "Connection.h"
 
@@ -38,48 +37,18 @@
     BufferId mId;
     size_t mOwnerCount;
     size_t mTransactionCount;
-    const bool mLinear;
-    const std::shared_ptr<C2LinearAllocation> mLinearAllocation;
-    const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
+    const std::shared_ptr<BufferPoolAllocation> mAllocation;
     const std::vector<uint8_t> mConfig;
 
     InternalBuffer(
             BufferId id,
-            const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
             const std::vector<uint8_t> &allocConfig)
             : mId(id), mOwnerCount(0), mTransactionCount(0),
-            mLinear(true), mLinearAllocation(alloc),
-            mGraphicAllocation(nullptr),
-            mConfig(allocConfig) {}
-
-    InternalBuffer(
-            BufferId id,
-            const std::shared_ptr<C2GraphicAllocation> &alloc,
-            const std::vector<uint8_t> &allocConfig)
-            : mId(id), mOwnerCount(0), mTransactionCount(0),
-            mLinear(false), mLinearAllocation(nullptr),
-            mGraphicAllocation(alloc),
-            mConfig(allocConfig) {}
+            mAllocation(alloc), mConfig(allocConfig) {}
 
     const native_handle_t *handle() {
-        if (mLinear) {
-            return mLinearAllocation->handle();
-        } else {
-            return mGraphicAllocation->handle();
-        }
-    }
-
-    // TODO : support non exact matching. e.g) capacity
-    bool isRecyclable(const std::vector<uint8_t> &config) {
-        if (mConfig.size() == config.size()) {
-            for (size_t i = 0; i < config.size(); ++i) {
-                if (mConfig[i] != config[i]) {
-                    return false;
-                }
-            }
-                return true;
-        }
-        return false;
+        return mAllocation->handle();
     }
 };
 
@@ -154,8 +123,8 @@
 uint32_t Accessor::Impl::sSeqId = time(NULL);
 
 Accessor::Impl::Impl(
-        const std::shared_ptr<C2Allocator> &allocator, bool linear)
-        : mAllocator(allocator), mLinear(linear) {}
+        const std::shared_ptr<BufferPoolAllocator> &allocator)
+        : mAllocator(allocator) {}
 
 Accessor::Impl::~Impl() {
 }
@@ -193,14 +162,8 @@
     std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
     mBufferPool.processStatusMessages();
     ResultStatus status = ResultStatus::OK;
-    if (!mBufferPool.getFreeBuffer(params, bufferId, handle)) {
-        if (mLinear) {
-            status = mBufferPool.getNewLinearBuffer(
-                    mAllocator, params, bufferId, handle);
-        } else {
-            status = mBufferPool.getNewGraphicBuffer(
-                    mAllocator, params, bufferId, handle);
-        }
+    if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
+        status = mBufferPool.getNewBuffer(mAllocator, params, bufferId, handle);
         ALOGV("create a buffer %d : %u %p",
               status == ResultStatus::OK, *bufferId, *handle);
     }
@@ -437,12 +400,13 @@
 }
 
 bool Accessor::Impl::BufferPool::getFreeBuffer(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
         const std::vector<uint8_t> &params, BufferId *pId,
         const native_handle_t** handle) {
     auto bufferIt = mFreeBuffers.begin();
     for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
         BufferId bufferId = *bufferIt;
-        if (mBuffers[bufferId]->isRecyclable(params)) {
+        if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
             break;
         }
     }
@@ -457,81 +421,30 @@
     return false;
 }
 
-ResultStatus Accessor::Impl::BufferPool::getNewLinearBuffer(
-        const std::shared_ptr<C2Allocator> &allocator,
+ResultStatus Accessor::Impl::BufferPool::getNewBuffer(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
         const std::vector<uint8_t> &params, BufferId *pId,
         const native_handle_t** handle) {
-    union LinearParam {
-        struct {
-            uint32_t capacity;
-            C2MemoryUsage usage;
-        } data;
-        uint8_t array[0];
-        LinearParam() : data{0, {0, 0}} {}
-    } linearParam;
-    memcpy(&linearParam, params.data(),
-           std::min(sizeof(linearParam), params.size()));
-    std::shared_ptr<C2LinearAllocation> linearAlloc;
-    c2_status_t status = allocator->newLinearAllocation(
-            linearParam.data.capacity, linearParam.data.usage, &linearAlloc);
-    if (status == C2_OK) {
+    std::shared_ptr<BufferPoolAllocation> alloc;
+    ResultStatus status = allocator->allocate(params, &alloc);
+
+    if (status == ResultStatus::OK) {
         BufferId bufferId = mSeq++;
         std::unique_ptr<InternalBuffer> buffer =
                 std::make_unique<InternalBuffer>(
-                        bufferId, linearAlloc, params);
+                        bufferId, alloc, params);
         if (buffer) {
             auto res = mBuffers.insert(std::make_pair(
                     bufferId, std::move(buffer)));
             if (res.second) {
-                *handle = linearAlloc->handle();
+                *handle = alloc->handle();
                 *pId = bufferId;
                 return ResultStatus::OK;
             }
         }
         return ResultStatus::NO_MEMORY;
     }
-    // TODO: map C2 error code
-    return ResultStatus::CRITICAL_ERROR;
-}
-
-ResultStatus Accessor::Impl::BufferPool::getNewGraphicBuffer(
-        const std::shared_ptr<C2Allocator> &allocator,
-        const std::vector<uint8_t> &params, BufferId *pId,
-        const native_handle_t** handle) {
-    union GraphicParam {
-        struct {
-            uint32_t width;
-            uint32_t height;
-            uint32_t format;
-            C2MemoryUsage usage;
-        } data;
-        uint8_t array[0];
-        GraphicParam() : data{0, 0, 0, {0, 0}} {}
-    } graphicParam;
-    memcpy(&graphicParam, params.data(),
-           std::min(sizeof(graphicParam), params.size()));
-    std::shared_ptr<C2GraphicAllocation> graphicAlloc;
-    c2_status_t status = allocator->newGraphicAllocation(
-            graphicParam.data.width, graphicParam.data.height,
-            graphicParam.data.format, graphicParam.data.usage, &graphicAlloc);
-    if (status == C2_OK) {
-        BufferId bufferId = mSeq;
-        std::unique_ptr<InternalBuffer> buffer =
-                std::make_unique<InternalBuffer>(
-                        bufferId, graphicAlloc, params);
-        if (buffer) {
-            auto res = mBuffers.insert(std::make_pair(
-                    bufferId, std::move(buffer)));
-            if (res.second) {
-                *handle = graphicAlloc->handle();
-                *pId = bufferId;
-                return ResultStatus::OK;
-            }
-        }
-        return ResultStatus::NO_MEMORY;
-    }
-    // TODO: map C2 error code
-    return ResultStatus::CRITICAL_ERROR;
+    return status;
 }
 
 }  // namespace implementation
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
index 92d926c..1260550 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
+++ b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
@@ -35,7 +35,7 @@
  * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
 class Accessor::Impl {
 public:
-    Impl(const std::shared_ptr<C2Allocator> &allocator, bool linear);
+    Impl(const std::shared_ptr<BufferPoolAllocator> &allocator);
 
     ~Impl();
 
@@ -64,8 +64,7 @@
     static uint32_t sSeqId;
     static int32_t sPid;
 
-    const std::shared_ptr<C2Allocator> mAllocator;
-    bool mLinear;
+    const std::shared_ptr<BufferPoolAllocator> mAllocator;
 
     /**
      * Buffer pool implementation.
@@ -172,6 +171,7 @@
         /**
          * Recycles a existing free buffer if it is possible.
          *
+         * @param allocator the buffer allocator
          * @param params    the allocation parameters.
          * @param pId       the id of the recycled buffer.
          * @param handle    the native handle of the recycled buffer.
@@ -179,40 +179,25 @@
          * @return {@code true} when a buffer is recycled, {@code false}
          *         otherwise.
          */
-        bool getFreeBuffer(const std::vector<uint8_t> &params, BufferId *pId,
-                           const native_handle_t **handle);
+        bool getFreeBuffer(
+                const std::shared_ptr<BufferPoolAllocator> &allocator,
+                const std::vector<uint8_t> &params,
+                BufferId *pId, const native_handle_t **handle);
 
         /**
-         * Creates a new linear buffer.
+         * Creates a new buffer.
          *
-         * @param allocator the linear buffer allocator
+         * @param allocator the buffer allocator
          * @param params    the allocator parameters
          * @param pId       the buffer id for the newly allocated buffer.
          * @param handle    the native handle for the newly allocated buffer.
          *
-         * @return OK when a linear allocation is successfully allocated.
+         * @return OK when an allocation is successfully allocated.
          *         NO_MEMORY when there is no memory.
          *         CRITICAL_ERROR otherwise.
          */
-        ResultStatus getNewLinearBuffer(
-                const std::shared_ptr<C2Allocator> &allocator,
-                const std::vector<uint8_t> &params, BufferId *pId,
-                const native_handle_t **handle);
-
-        /**
-         * Creates a new graphic buffer.
-         *
-         * @param allocator the graphic buffer allocator
-         * @param params    the allocator parameters
-         * @param pId       the buffer id for the newly allocated buffer.
-         * @param handle    the native handle for the newly allocated buffer.
-         *
-         * @return OK when a graphic allocation is successfully allocated.
-         *         NO_MEMORY when there is no memory.
-         *         CRITICAL_ERROR otherwise.
-         */
-        ResultStatus getNewGraphicBuffer(
-                const std::shared_ptr<C2Allocator> &allocator,
+        ResultStatus getNewBuffer(
+                const std::shared_ptr<BufferPoolAllocator> &allocator,
                 const std::vector<uint8_t> &params, BufferId *pId,
                 const native_handle_t **handle);
 
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
index c7aa07b..1ea1f35 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/Android.bp
+++ b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
@@ -24,7 +24,6 @@
         "libhidlbase",
         "libhidltransport",
         "liblog",
-        "libstagefright_codec2",
         "libutils",
         "android.hardware.media.bufferpool@1.0",
     ],
diff --git a/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp b/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
index 97efee4..89aee8b 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
+++ b/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
@@ -36,8 +36,7 @@
     ResultStatus registerSender(const sp<IAccessor> &accessor,
                                 ConnectionId *pConnectionId);
 
-    ResultStatus create(const std::shared_ptr<C2Allocator> &allocator,
-                        bool linear,
+    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
                         ConnectionId *pConnectionId);
 
     ResultStatus close(ConnectionId connectionId);
@@ -139,10 +138,9 @@
 }
 
 ResultStatus ClientManager::Impl::create(
-        const std::shared_ptr<C2Allocator> &allocator,
-        bool linear,
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
         ConnectionId *pConnectionId) {
-    const sp<Accessor> accessor = new Accessor(allocator, linear);
+    const sp<Accessor> accessor = new Accessor(allocator);
     if (!accessor || !accessor->isValid()) {
         return ResultStatus::CRITICAL_ERROR;
     }
@@ -273,11 +271,10 @@
 }
 
 ResultStatus ClientManager::create(
-        const std::shared_ptr<C2Allocator> &allocator,
-        bool linear,
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
         ConnectionId *pConnectionId) {
     if (mImpl) {
-        return mImpl->create(allocator, linear, pConnectionId);
+        return mImpl->create(allocator, pConnectionId);
     }
     return ResultStatus::CRITICAL_ERROR;
 }
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h b/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
index 4b7363f..0cf023c 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
+++ b/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
@@ -22,9 +22,8 @@
 #include <fmq/MessageQueue.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
-#include <C2Buffer.h>
 
-struct C2_HIDE _C2BlockPoolData {
+struct __attribute__((visibility("hidden"))) _C2BlockPoolData {
     uint32_t mId; //BufferId
     native_handle_t *mHandle;
 
@@ -57,6 +56,52 @@
 typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
 typedef BufferStatusQueue::Descriptor QueueDescriptor;
 
+/**
+ * Allocation wrapper class for buffer pool.
+ */
+struct BufferPoolAllocation {
+    const native_handle_t *mHandle;
+
+    const native_handle_t *handle() {
+        return mHandle;
+    }
+
+    BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
+
+    ~BufferPoolAllocation() {};
+};
+
+/**
+ * Allocator wrapper class for buffer pool.
+ */
+class BufferPoolAllocator {
+public:
+
+    /**
+     * Allocate an allocation(buffer) for bufer pool.
+     *
+     * @param params    allocation parameters
+     * @param alloc     created allocation
+     *
+     * @return OK when an allocation is created successfully.
+     */
+    virtual ResultStatus allocate(
+            const std::vector<uint8_t> &params,
+            std::shared_ptr<BufferPoolAllocation> *alloc) = 0;
+
+    /**
+     * Returns whether allocation parameters of an old allocation are
+     * compatible with new allocation parameters.
+     */
+    virtual bool compatible(const std::vector<uint8_t> &newParams,
+                            const std::vector<uint8_t> &oldParams) = 0;
+
+protected:
+    BufferPoolAllocator() = default;
+
+    virtual ~BufferPoolAllocator() = default;
+};
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace bufferpool
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h b/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
index 412fa59..f91f46b 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
+++ b/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
@@ -20,7 +20,6 @@
 #include <android/hardware/media/bufferpool/1.0/IClientManager.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
-#include <C2Buffer.h>
 #include <memory>
 #include <BufferPoolTypes.h>
 
@@ -52,7 +51,6 @@
      * Creates a local connection with a newly created buffer pool.
      *
      * @param allocator     for new buffer allocation.
-     * @param linear        whether the allocator is linear or not.
      * @param pConnectionId Id of the created connection. This is
      *                      system-wide unique.
      *
@@ -61,8 +59,7 @@
      *         NO_MEMORY when there is no memory.
      *         CRITICAL_ERROR otherwise.
      */
-    ResultStatus create(const std::shared_ptr<C2Allocator> &allocator,
-                        bool linear,
+    ResultStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
                         ConnectionId *pConnectionId);
 
     /**
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
index 074d4bc..62286f3 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/Android.bp
@@ -18,6 +18,7 @@
     name: "VtsVndkHidlBufferpoolV1_0TargetSingleTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "allocator.cpp",
         "single.cpp",
     ],
     static_libs: [
@@ -37,6 +38,7 @@
     name: "VtsVndkHidlBufferpoolV1_0TargetMultiTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "allocator.cpp",
         "multi.cpp",
     ],
     static_libs: [
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp
new file mode 100644
index 0000000..230ee3f
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#include <C2Buffer.h>
+#include "allocator.h"
+
+union Params {
+  struct {
+    uint32_t capacity;
+    C2MemoryUsage usage;
+  } data;
+  uint8_t array[0];
+  Params() : data{0, {0, 0}} {}
+  Params(uint32_t size)
+      : data{size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
+};
+
+struct AllocationDtor {
+  AllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
+      : mAlloc(alloc) {}
+
+  void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+  const std::shared_ptr<C2LinearAllocation> mAlloc;
+};
+
+ResultStatus VtsBufferPoolAllocator::allocate(
+    const std::vector<uint8_t> &params,
+    std::shared_ptr<BufferPoolAllocation> *alloc) {
+  Params ionParams;
+  memcpy(&ionParams, params.data(), std::min(sizeof(Params), params.size()));
+
+  std::shared_ptr<C2LinearAllocation> linearAlloc;
+  c2_status_t status = mAllocator->newLinearAllocation(
+      ionParams.data.capacity, ionParams.data.usage, &linearAlloc);
+  if (status == C2_OK && linearAlloc) {
+    BufferPoolAllocation *ptr = new BufferPoolAllocation(linearAlloc->handle());
+    if (ptr) {
+      *alloc = std::shared_ptr<BufferPoolAllocation>(
+          ptr, AllocationDtor(linearAlloc));
+      if (*alloc) {
+        return ResultStatus::OK;
+      }
+      delete ptr;
+      return ResultStatus::NO_MEMORY;
+    }
+  }
+  return ResultStatus::CRITICAL_ERROR;
+}
+
+bool VtsBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
+                                        const std::vector<uint8_t> &oldParams) {
+  size_t newSize = newParams.size();
+  size_t oldSize = oldParams.size();
+  if (newSize == oldSize) {
+    for (size_t i = 0; i < newSize; ++i) {
+      if (newParams[i] != oldParams[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+void getVtsAllocatorParams(std::vector<uint8_t> *params) {
+  constexpr static int kAllocationSize = 1024 * 10;
+  Params ionParams(kAllocationSize);
+
+  params->assign(ionParams.array, ionParams.array + sizeof(ionParams));
+}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h
new file mode 100644
index 0000000..2fbb7fb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/allocator.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
+#define VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
+
+#include <BufferPoolTypes.h>
+
+using android::hardware::media::bufferpool::V1_0::ResultStatus;
+using android::hardware::media::bufferpool::V1_0::implementation::
+    BufferPoolAllocation;
+using android::hardware::media::bufferpool::V1_0::implementation::
+    BufferPoolAllocator;
+
+// buffer allocator for the tests
+class VtsBufferPoolAllocator : public BufferPoolAllocator {
+ public:
+  VtsBufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
+      : mAllocator(allocator) {}
+
+  ~VtsBufferPoolAllocator() override {}
+
+  ResultStatus allocate(const std::vector<uint8_t> &params,
+                        std::shared_ptr<BufferPoolAllocation> *alloc) override;
+
+  bool compatible(const std::vector<uint8_t> &newParams,
+                  const std::vector<uint8_t> &oldParams) override;
+
+ private:
+  const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+// retrieve buffer allocator paramters
+void getVtsAllocatorParams(std::vector<uint8_t> *params);
+
+#endif  // VTS_VNDK_HIDL_BUFFERPOOL_V1_0_ALLOCATOR_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
index 3ad8b6c..35127b8 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/multi.cpp
@@ -35,6 +35,7 @@
 #include <iostream>
 #include <memory>
 #include <vector>
+#include "allocator.h"
 
 using android::C2AllocatorIon;
 using android::C2PlatformAllocatorStore;
@@ -50,9 +51,6 @@
 
 namespace {
 
-// Buffer allocation size for tests.
-constexpr static int kAllocationSize = 1024 * 10;
-
 // communication message types between processes.
 enum PipeCommand : int32_t {
     INIT_OK = 0,
@@ -95,11 +93,14 @@
     mManager = ClientManager::getInstance();
     ASSERT_NE(mManager, nullptr);
 
-    mAllocator =
+    std::shared_ptr<C2Allocator> allocator =
         std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
+    ASSERT_TRUE((bool)allocator);
+
+    mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
     ASSERT_TRUE((bool)mAllocator);
 
-    status = mManager->create(mAllocator, true, &mConnectionId);
+    status = mManager->create(mAllocator, &mConnectionId);
     ASSERT_TRUE(status == ResultStatus::OK);
 
     status = mManager->getAccessor(mConnectionId, &mAccessor);
@@ -121,26 +122,12 @@
 
   android::sp<ClientManager> mManager;
   android::sp<IAccessor> mAccessor;
-  std::shared_ptr<C2Allocator> mAllocator;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
   ConnectionId mConnectionId;
   pid_t mReceiverPid;
   int mCommandPipeFds[2];
   int mResultPipeFds[2];
 
-  void getAllocationParams(std::vector<uint8_t>* vecParams) {
-    union Params {
-      struct {
-        uint32_t capacity;
-        C2MemoryUsage usage;
-      } data;
-      uint8_t array[0];
-      Params()
-          : data{kAllocationSize,
-                 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
-    } params;
-    vecParams->assign(params.array, params.array + sizeof(params));
-  }
-
   bool sendMessage(int *pipes, const PipeMessage &message) {
     int ret = write(pipes[1], message.array, sizeof(PipeMessage));
     return ret == sizeof(PipeMessage);
@@ -211,7 +198,7 @@
     int64_t postUs;
     std::vector<uint8_t> vecParams;
 
-    getAllocationParams(&vecParams);
+    getVtsAllocatorParams(&vecParams);
     status = mManager->allocate(mConnectionId, vecParams, &sbuffer);
     ASSERT_TRUE(status == ResultStatus::OK);
 
diff --git a/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp b/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
index 89eb631..c8878f3 100644
--- a/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
+++ b/media/libstagefright/codec2/vndk/bufferpool/vts/single.cpp
@@ -32,6 +32,7 @@
 #include <iostream>
 #include <memory>
 #include <vector>
+#include "allocator.h"
 
 using android::C2AllocatorIon;
 using android::C2PlatformAllocatorStore;
@@ -45,9 +46,6 @@
 
 namespace {
 
-// Buffer allocation size for tests.
-constexpr static int kAllocationSize = 1024 * 10;
-
 // Number of iteration for buffer allocation test.
 constexpr static int kNumAllocationTest = 3;
 
@@ -63,11 +61,14 @@
     mManager = ClientManager::getInstance();
     ASSERT_NE(mManager, nullptr);
 
-    mAllocator =
+    std::shared_ptr<C2Allocator> allocator =
         std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
+    ASSERT_TRUE((bool)allocator);
+
+    mAllocator = std::make_shared<VtsBufferPoolAllocator>(allocator);
     ASSERT_TRUE((bool)mAllocator);
 
-    status = mManager->create(mAllocator, true, &mConnectionId);
+    status = mManager->create(mAllocator, &mConnectionId);
     ASSERT_TRUE(status == ResultStatus::OK);
 
     status = mManager->getAccessor(mConnectionId, &mAccessor);
@@ -91,23 +92,10 @@
 
   android::sp<ClientManager> mManager;
   android::sp<IAccessor> mAccessor;
-  std::shared_ptr<C2Allocator> mAllocator;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
   ConnectionId mConnectionId;
   ConnectionId mReceiverId;
 
-  void getAllocationParams(std::vector<uint8_t>* vecParams) {
-    union Params {
-      struct {
-        uint32_t capacity;
-        C2MemoryUsage usage;
-      } data;
-      uint8_t array[0];
-      Params()
-          : data{kAllocationSize,
-                 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}} {}
-    } params;
-    vecParams->assign(params.array, params.array + sizeof(params));
-  }
 };
 
 // Buffer allocation test.
@@ -116,7 +104,7 @@
 TEST_F(BufferpoolSingleTest, AllocateBuffer) {
   ResultStatus status;
   std::vector<uint8_t> vecParams;
-  getAllocationParams(&vecParams);
+  getVtsAllocatorParams(&vecParams);
 
   std::shared_ptr<_C2BlockPoolData> buffer[kNumAllocationTest];
   for (int i = 0; i < kNumAllocationTest; ++i) {
@@ -136,7 +124,7 @@
 TEST_F(BufferpoolSingleTest, RecycleBuffer) {
   ResultStatus status;
   std::vector<uint8_t> vecParams;
-  getAllocationParams(&vecParams);
+  getVtsAllocatorParams(&vecParams);
 
   BufferId bid[kNumRecycleTest];
   for (int i = 0; i < kNumRecycleTest; ++i) {
@@ -156,7 +144,7 @@
 TEST_F(BufferpoolSingleTest, TransferBuffer) {
   ResultStatus status;
   std::vector<uint8_t> vecParams;
-  getAllocationParams(&vecParams);
+  getVtsAllocatorParams(&vecParams);
   std::shared_ptr<_C2BlockPoolData> sbuffer, rbuffer;
 
   TransactionId transactionId;
diff --git a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
index 471d3f4..17b200f 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
@@ -20,6 +20,7 @@
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.SessionCallback;
 import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.OnSessionTokensChangedListener;
 import android.media.session.PlaybackState;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -30,7 +31,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.UUID;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.Assert.*;
@@ -210,9 +213,128 @@
         assertTrue(foundTestLibraryService);
     }
 
+    @Test
+    public void testAddOnSessionTokensChangedListener() throws InterruptedException {
+        TokensChangedListener listener = new TokensChangedListener();
+        mManager.addOnSessionTokensChangedListener(sHandlerExecutor, listener);
+
+        listener.reset();
+        MediaSession2 session1 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertTrue(listener.findToken(session1.getToken()));
+
+        listener.reset();
+        session1.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+
+        listener.reset();
+        MediaSession2 session2 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertTrue(listener.findToken(session2.getToken()));
+
+        listener.reset();
+        MediaSession2 session3 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertTrue(listener.findToken(session2.getToken()));
+        assertTrue(listener.findToken(session3.getToken()));
+
+        listener.reset();
+        session2.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertFalse(listener.findToken(session2.getToken()));
+        assertTrue(listener.findToken(session3.getToken()));
+
+        listener.reset();
+        session3.close();
+        assertTrue(listener.await());
+        assertFalse(listener.findToken(session1.getToken()));
+        assertFalse(listener.findToken(session2.getToken()));
+        assertFalse(listener.findToken(session3.getToken()));
+
+        mManager.removeOnSessionTokensChangedListener(listener);
+    }
+
+    @Test
+    public void testRemoveOnSessionTokensChangedListener() throws InterruptedException {
+        TokensChangedListener listener = new TokensChangedListener();
+        mManager.addOnSessionTokensChangedListener(sHandlerExecutor, listener);
+
+        listener.reset();
+        MediaSession2 session1 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertTrue(listener.await());
+
+        mManager.removeOnSessionTokensChangedListener(listener);
+
+        listener.reset();
+        session1.close();
+        assertFalse(listener.await());
+
+        listener.reset();
+        MediaSession2 session2 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertFalse(listener.await());
+
+        listener.reset();
+        MediaSession2 session3 = new MediaSession2.Builder(mContext)
+                .setPlayer(new MockPlayer(0))
+                .setId(UUID.randomUUID().toString())
+                .build();
+        assertFalse(listener.await());
+
+        listener.reset();
+        session2.close();
+        assertFalse(listener.await());
+
+        listener.reset();
+        session3.close();
+        assertFalse(listener.await());
+    }
+
     // Ensures if the session creation/release is notified to the server.
     private void ensureChangeInSession() throws InterruptedException {
         // TODO(jaewan): Wait by listener.
         Thread.sleep(WAIT_TIME_MS);
     }
+
+    private class TokensChangedListener implements OnSessionTokensChangedListener {
+        private CountDownLatch mLatch;
+        private List<SessionToken2> mTokens;
+
+        private void reset() {
+            mLatch = new CountDownLatch(1);
+            mTokens = null;
+        }
+
+        private boolean await() throws InterruptedException {
+            return mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+        }
+
+        private boolean findToken(SessionToken2 token) {
+            return mTokens.contains(token);
+        }
+
+        @Override
+        public void onSessionTokensChanged(List<SessionToken2> tokens) {
+            mTokens = tokens;
+            mLatch.countDown();
+        }
+    }
 }
diff --git a/packages/MediaComponents/test/src/android/media/MockPlayer.java b/packages/MediaComponents/test/src/android/media/MockPlayer.java
index da4acb5..05962cf 100644
--- a/packages/MediaComponents/test/src/android/media/MockPlayer.java
+++ b/packages/MediaComponents/test/src/android/media/MockPlayer.java
@@ -63,6 +63,11 @@
     }
 
     @Override
+    public void reset() {
+        // no-op
+    }
+
+    @Override
     public void play() {
         mPlayCalled = true;
         if (mCountDownLatch != null) {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index ac3202b..c708fee 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -32,7 +32,6 @@
 #include "AAudioService.h"
 #include "AAudioServiceStreamMMAP.h"
 #include "AAudioServiceStreamShared.h"
-#include "AAudioServiceStreamMMAP.h"
 #include "binding/IAAudioService.h"
 #include "ServiceUtilities.h"