Merge "audio policy: add new audio devices"
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 678d642..563c0b5 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -25,6 +25,7 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
 extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
+extern const char *MEDIA_MIMETYPE_VIDEO_HEVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index dd869f6..2f000d7 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -146,10 +146,22 @@
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*);
 
 /**
- * Release and optionally render the specified buffer.
+ * If you are done with a buffer, use this call to return the buffer to
+ * the codec. If you previously specified a surface when configuring this
+ * video decoder you can optionally render the buffer.
  */
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
+/**
+ * If you are done with a buffer, use this call to update its surface timestamp
+ * and return it to the codec to render it on the output surface. If you
+ * have not specified an output surface when configuring this video codec,
+ * this call will simply return the buffer to the codec.
+ *
+ * For more details, see the Java documentation for MediaCodec.releaseOutputBuffer.
+ */
+media_status_t AMediaCodec_releaseOutputBufferAtTime(
+        AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
 
@@ -163,20 +175,30 @@
         AMediaCodec*, OnCodecEvent callback, void *userdata);
 
 
-enum {
+typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
-};
+} cryptoinfo_mode_t;
 
 /**
- * create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
+ * Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
  * crypto info, rather than one obtained from AMediaExtractor.
+ *
+ * AMediaCodecCryptoInfo describes the structure of an (at least
+ * partially) encrypted input sample.
+ * A buffer's data is considered to be partitioned into "subsamples",
+ * each subsample starts with a (potentially empty) run of plain,
+ * unencrypted bytes followed by a (also potentially empty) run of
+ * encrypted bytes.
+ * numBytesOfClearData can be null to indicate that all data is encrypted.
+ * This information encapsulates per-sample metadata as outlined in
+ * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
  */
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
         int numsubsamples,
         uint8_t key[16],
         uint8_t iv[16],
-        uint32_t mode,
+        cryptoinfo_mode_t mode,
         size_t *clearbytes,
         size_t *encryptedbytes);
 
@@ -186,11 +208,35 @@
  */
 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
 
+/**
+ * The number of subsamples that make up the buffer's contents.
+ */
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
+
+/**
+ * A 16-byte opaque key
+ */
 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst);
+
+/**
+ * A 16-byte initialization vector
+ */
 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst);
-uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*);
+
+/**
+ * The type of encryption that has been applied,
+ * one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
+ */
+cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*);
+
+/**
+ * The number of leading unencrypted bytes in each subsample.
+ */
 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst);
+
+/**
+ * The number of trailing encrypted bytes in each subsample.
+ */
 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst);
 
 #ifdef __cplusplus
diff --git a/include/ndk/NdkMediaCrypto.h b/include/ndk/NdkMediaCrypto.h
index 83eaad2..90374c5 100644
--- a/include/ndk/NdkMediaCrypto.h
+++ b/include/ndk/NdkMediaCrypto.h
@@ -29,6 +29,7 @@
 #define _NDK_MEDIA_CRYPTO_H
 
 #include <sys/types.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/ndk/NdkMediaDrm.h b/include/ndk/NdkMediaDrm.h
index 04c371c..10afdd9 100644
--- a/include/ndk/NdkMediaDrm.h
+++ b/include/ndk/NdkMediaDrm.h
@@ -27,7 +27,7 @@
 #ifndef _NDK_MEDIA_DRM_H
 #define _NDK_MEDIA_DRM_H
 
-#include <NdkMediaError.h>
+#include "NdkMediaError.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -77,7 +77,7 @@
     EVENT_VENDOR_DEFINED = 4
 } AMediaDrmEventType;
 
-typedef void (*AMediaDrmEventListener)(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+typedef void (*AMediaDrmEventListener)(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         AMediaDrmEventType eventType, int extra, const uint8_t *data, size_t dataSize);
 
 
@@ -115,13 +115,13 @@
  * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
  * returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use
  */
-media_status_t AMediaDrm_openSession(AMediaDrm *, AMediaDrmSessionId &sessionId);
+media_status_t AMediaDrm_openSession(AMediaDrm *, AMediaDrmSessionId *sessionId);
 
 /**
  * Close a session on the MediaDrm object that was previously opened
  * with AMediaDrm_openSession.
  */
-media_status_t AMediaDrm_closeSession(AMediaDrm *, const AMediaDrmSessionId &sessionId);
+media_status_t AMediaDrm_closeSession(AMediaDrm *, const AMediaDrmSessionId *sessionId);
 
 typedef enum AMediaDrmKeyType {
     /**
@@ -198,10 +198,10 @@
  * returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
  * problem with the device certificate.
 */
-media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope &scope,
+media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope *scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
-        const uint8_t *&keyRequest, size_t &keyRequestSize);
+        const uint8_t **keyRequest, size_t *keyRequestSize);
 
 /**
  * A key response is received from the license server by the app, then it is
@@ -220,8 +220,8 @@
  * responseSize should be set to the size of the response in bytes
  */
 
-media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope &scope,
-        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId);
+media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope *scope,
+        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId);
 
 /**
  * Restore persisted offline keys into a new session.  keySetId identifies the
@@ -230,15 +230,15 @@
  * sessionId is the session ID for the DRM session
  * keySetId identifies the saved key set to restore
  */
-media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId &sessionId,
-        const AMediaDrmKeySetId &keySetId);
+media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId *sessionId,
+        const AMediaDrmKeySetId *keySetId);
 
 /**
  * Remove the current keys from a session.
  *
  * keySetId identifies keys to remove
  */
-media_status_t AMediaDrm_removeKeys(AMediaDrm *, const AMediaDrmSessionId &keySetId);
+media_status_t AMediaDrm_removeKeys(AMediaDrm *, const AMediaDrmSessionId *keySetId);
 
 /**
  * Request an informative description of the key status for the session.  The status is
@@ -253,8 +253,8 @@
  * to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
  * and numPairs will be set to the number of pairs available.
  */
-media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId &sessionId,
-        AMediaDrmKeyValue *keyValuePairs, size_t &numPairs);
+media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId *sessionId,
+        AMediaDrmKeyValue *keyValuePairs, size_t *numPairs);
 
 
 /**
@@ -272,8 +272,8 @@
  *       the provisioning request should be sent to.  It will remain accessible until
  *       the next call to getProvisionRequest.
  */
-media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t *&provisionRequest,
-        size_t &provisionRequestSize, const char *&serverUrl);
+media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t **provisionRequest,
+        size_t *provisionRequestSize, const char **serverUrl);
 
 
 /**
@@ -313,7 +313,7 @@
  * number required.
  */
 media_status_t AMediaDrm_getSecureStops(AMediaDrm *,
-        AMediaDrmSecureStop *secureStops, size_t &numSecureStops);
+        AMediaDrmSecureStop *secureStops, size_t *numSecureStops);
 
 /**
  * Process the SecureStop server response message ssRelease.  After authenticating
@@ -322,7 +322,7 @@
  * ssRelease is the server response indicating which secure stops to release
  */
 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
-        const AMediaDrmSecureStop &ssRelease);
+        const AMediaDrmSecureStop *ssRelease);
 
 /**
  * String property name: identifies the maker of the DRM engine plugin
@@ -355,7 +355,7 @@
  * will remain valid until the next call to AMediaDrm_getPropertyString.
  */
 media_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
-        const char *&propertyValue);
+        const char **propertyValue);
 
 /**
  * Byte array property name: the device unique identifier is established during
@@ -370,7 +370,7 @@
  * will remain valid until the next call to AMediaDrm_getPropertyByteArray.
  */
 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
-        AMediaDrmByteArray &propertyValue);
+        AMediaDrmByteArray *propertyValue);
 
 /**
  * Set a DRM engine plugin String property value.
@@ -409,7 +409,7 @@
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
  */
-media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize);
 
@@ -420,7 +420,7 @@
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
  */
-media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize);
 
@@ -433,7 +433,7 @@
  * by the 16 byte keyId.  The key must have been loaded into the session using
  * provideKeyResponse.
  */
-media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
         uint8_t *signature, size_t *signatureSize);
 
@@ -444,7 +444,7 @@
  * use is identified by the 16 byte keyId.  The key must have been loaded into the
  * session using provideKeyResponse.
  */
-media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
         const uint8_t *signature, size_t signatureSize);
 
diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h
index 2ba69fb..5a319d7 100644
--- a/include/ndk/NdkMediaExtractor.h
+++ b/include/ndk/NdkMediaExtractor.h
@@ -114,6 +114,16 @@
  */
 bool AMediaExtractor_advance(AMediaExtractor*);
 
+typedef enum {
+    AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC,
+    AMEDIAEXTRACTOR_SEEK_NEXT_SYNC,
+    AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC
+} SeekMode;
+
+/**
+ *
+ */
+media_status_t AMediaExtractor_seekTo(AMediaExtractor*, int64_t seekPosUs, SeekMode mode);
 
 /**
  * mapping of crypto scheme uuid to the scheme specific data for that scheme
@@ -146,7 +156,6 @@
     AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED = 2,
 };
 
-
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/include/ndk/NdkMediaMuxer.h b/include/ndk/NdkMediaMuxer.h
index db183e9..1ddc51d 100644
--- a/include/ndk/NdkMediaMuxer.h
+++ b/include/ndk/NdkMediaMuxer.h
@@ -56,16 +56,59 @@
  */
 media_status_t AMediaMuxer_delete(AMediaMuxer*);
 
-media_status_t AMediaMuxer_setLocation(AMediaMuxer*, float latitude, float longtitude);
+/**
+ * Set and store the geodata (latitude and longitude) in the output file.
+ * This method should be called before AMediaMuxer_start. The geodata is stored
+ * in udta box if the output format is AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, and is
+ * ignored for other output formats.
+ * The geodata is stored according to ISO-6709 standard.
+ *
+ * Both values are specified in degrees.
+ * Latitude must be in the range [-90, 90].
+ * Longitude must be in the range [-180, 180].
+ */
+media_status_t AMediaMuxer_setLocation(AMediaMuxer*, float latitude, float longitude);
 
+/**
+ * Sets the orientation hint for output video playback.
+ * This method should be called before AMediaMuxer_start. Calling this
+ * method will not rotate the video frame when muxer is generating the file,
+ * but add a composition matrix containing the rotation angle in the output
+ * video if the output format is AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4, so that a
+ * video player can choose the proper orientation for playback.
+ * Note that some video players may choose to ignore the composition matrix
+ * during playback.
+ * The angle is specified in degrees, clockwise.
+ * The supported angles are 0, 90, 180, and 270 degrees.
+ */
 media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees);
 
+/**
+ * Adds a track with the specified format.
+ * Returns the index of the new track or a negative value in case of failure,
+ * which can be interpreted as a media_status_t.
+ */
 ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format);
 
+/**
+ * Start the muxer. Should be called after AMediaMuxer_addTrack and
+ * before AMediaMuxer_writeSampleData.
+ */
 media_status_t AMediaMuxer_start(AMediaMuxer*);
 
+/**
+ * Stops the muxer.
+ * Once the muxer stops, it can not be restarted.
+ */
 media_status_t AMediaMuxer_stop(AMediaMuxer*);
 
+/**
+ * Writes an encoded sample into the muxer.
+ * The application needs to make sure that the samples are written into
+ * the right tracks. Also, it needs to make sure the samples for each track
+ * are written in chronological order (e.g. in the order they are provided
+ * by the encoder.)
+ */
 media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
         size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info);
 
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 3901e79..5116d1e 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <audio_utils/minifloat.h>
 #include <utils/threads.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
@@ -110,11 +111,8 @@
                 // force to 32-bit.  The client and server may have different typedefs for size_t.
                 uint32_t    mMinimum;       // server wakes up client if available >= mMinimum
 
-                // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
-                // Left channel is in [0:15], right channel is in [16:31].
-                // Always read and write the combined pair atomically.
-                // For AudioTrack only, not used by AudioRecord.
-                uint32_t    mVolumeLR;
+                // Stereo gains for AudioTrack only, not used by AudioRecord.
+                gain_minifloat_packed_t mVolumeLR;
 
                 uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                                             // or 0 == default. Write-only client, read-only server.
@@ -285,8 +283,8 @@
         mCblk->mSendLevel = uint16_t(sendLevel * 0x1000);
     }
 
-    // caller must limit to 0 <= volumeLR <= 0x10001000
-    void        setVolumeLR(uint32_t volumeLR) {
+    // set stereo gains
+    void        setVolumeLR(gain_minifloat_packed_t volumeLR) {
         mCblk->mVolumeLR = volumeLR;
     }
 
@@ -405,7 +403,7 @@
     // return value of these methods must be validated by the caller
     uint32_t    getSampleRate() const { return mCblk->mSampleRate; }
     uint16_t    getSendLevel_U4_12() const { return mCblk->mSendLevel; }
-    uint32_t    getVolumeLR() const { return mCblk->mVolumeLR; }
+    gain_minifloat_packed_t getVolumeLR() const { return mCblk->mVolumeLR; }
 
     // estimated total number of filled frames available to server to read,
     // which may include non-contiguous frames
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 661fde9..6686f27 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -118,7 +118,7 @@
         hasBacks = true;
     }
 
-    const int numChan = popcount(mask);
+    const int numChan = audio_channel_count_from_out_mask(mask);
     const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
     const bool hasLFE =
             ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
@@ -629,7 +629,8 @@
             ALOGE("Downmix_Configure error: input channel mask can't be 0");
             return -EINVAL;
         }
-        pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels);
+        pDownmixer->input_channel_count =
+                audio_channel_count_from_out_mask(pConfig->inputCfg.channels);
     }
 
     Downmix_Reset(pDownmixer, init);
@@ -997,7 +998,7 @@
         hasBacks = true;
     }
 
-    const int numChan = popcount(mask);
+    const int numChan = audio_channel_count_from_out_mask(mask);
     const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
     const bool hasLFE =
             ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index a96a703..cf98f56 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -879,8 +879,8 @@
 int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
 {
     uint32_t sr;
-    uint32_t inCnl = popcount(config->inputCfg.channels);
-    uint32_t outCnl = popcount(config->outputCfg.channels);
+    uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
+    uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
 
     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
         config->inputCfg.format != config->outputCfg.format ||
@@ -1035,7 +1035,7 @@
             config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
         return -EINVAL;
     }
-    uint32_t inCnl = popcount(config->inputCfg.channels);
+    uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
     int status = session->apm->set_num_reverse_channels(inCnl);
     if (status < 0) {
         return -EINVAL;
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 47cab62..e5089da 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -207,7 +207,8 @@
     pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
 
     // measurement initialization
-    pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels);
+    pContext->mChannelCount =
+            audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
     pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
     pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
     pContext->mMeasurementBufferIdx = 0;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 97ab8f8..1c808d0 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -51,7 +51,8 @@
 
     // We double the size of input buffer for ping pong use of record buffer.
     // Assumes audio_is_linear_pcm(format)
-    if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) {
+    if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
+            audio_bytes_per_sample(format))) == 0) {
         ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
             sampleRate, format, channelMask);
         return BAD_VALUE;
@@ -193,7 +194,7 @@
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
     mChannelCount = channelCount;
 
     if (audio_is_linear_pcm(format)) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index aaaa3f1..7d3ecc5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -19,6 +19,7 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AudioTrack"
 
+#include <math.h>
 #include <sys/resource.h>
 #include <audio_utils/primitives.h>
 #include <binder/IPCThreadState.h>
@@ -290,7 +291,7 @@
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
     mChannelCount = channelCount;
 
     // AudioFlinger does not currently support 8-bit data in shared memory
@@ -566,7 +567,9 @@
 
 status_t AudioTrack::setVolume(float left, float right)
 {
-    if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
+    // This duplicates a test by AudioTrack JNI, but that is not the only caller
+    if (isnanf(left) || left < GAIN_FLOAT_ZERO || left > GAIN_FLOAT_UNITY ||
+            isnanf(right) || right < GAIN_FLOAT_ZERO || right > GAIN_FLOAT_UNITY) {
         return BAD_VALUE;
     }
 
@@ -574,7 +577,7 @@
     mVolume[AUDIO_INTERLEAVE_LEFT] = left;
     mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
 
-    mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+    mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
 
     if (isOffloaded_l()) {
         mAudioTrack->signal();
@@ -589,7 +592,8 @@
 
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
-    if (level < 0.0f || level > 1.0f) {
+    // This duplicates a test by AudioTrack JNI, but that is not the only caller
+    if (isnanf(level) || level < GAIN_FLOAT_ZERO || level > GAIN_FLOAT_UNITY) {
         return BAD_VALUE;
     }
 
@@ -1137,8 +1141,7 @@
         mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
         mProxy = mStaticProxy;
     }
-    mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) |
-            uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000));
+    mProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
     mProxy->setSendLevel(mSendLevel);
     mProxy->setSampleRate(mSampleRate);
     mProxy->setEpoch(epoch);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 323b675..27a3718 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -27,7 +27,7 @@
 
 audio_track_cblk_t::audio_track_cblk_t()
     : mServer(0), mFutex(0), mMinimum(0),
-    mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
+    mVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY), mSampleRate(0), mSendLevel(0), mFlags(0)
 {
     memset(&u, 0, sizeof(u));
 }
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 74e5013..9b239b1 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -186,7 +186,7 @@
         read(fd, buf, sizeof(buf));
         lseek(fd, offset, SEEK_SET);
 
-        long ident = *((long*)buf);
+        uint32_t ident = *((uint32_t*)buf);
 
         // Ogg vorbis?
         if (ident == 0x5367674f) // 'OggS'
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index af8f365..6aab48a 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -46,7 +46,8 @@
         uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
         audio_channel_mask_t channelMask =
                 (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFormat = Format_from_SR_C(sampleRate,
+                audio_channel_count_from_in_mask(channelMask), streamFormat);
         mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers);
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index c28d34d..0d5f935 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -43,7 +43,8 @@
         uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
         audio_channel_mask_t channelMask =
                 (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFormat = Format_from_SR_C(sampleRate,
+                audio_channel_count_from_out_mask(channelMask), streamFormat);
         mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 2e8e412..8f154be 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -990,6 +990,8 @@
             "audio_decoder.g711alaw", "audio_encoder.g711alaw" },
         { MEDIA_MIMETYPE_VIDEO_AVC,
             "video_decoder.avc", "video_encoder.avc" },
+        { MEDIA_MIMETYPE_VIDEO_HEVC,
+            "video_decoder.hevc", "video_encoder.hevc" },
         { MEDIA_MIMETYPE_VIDEO_MPEG4,
             "video_decoder.mpeg4", "video_encoder.mpeg4" },
         { MEDIA_MIMETYPE_VIDEO_H263,
@@ -1811,6 +1813,7 @@
     OMX_VIDEO_CODINGTYPE mVideoCodingType;
 } kVideoCodingMapEntry[] = {
     { MEDIA_MIMETYPE_VIDEO_AVC, OMX_VIDEO_CodingAVC },
+    { MEDIA_MIMETYPE_VIDEO_HEVC, OMX_VIDEO_CodingHEVC },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, OMX_VIDEO_CodingMPEG4 },
     { MEDIA_MIMETYPE_VIDEO_H263, OMX_VIDEO_CodingH263 },
     { MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 },
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index c670bb4..8229e55 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -23,6 +23,7 @@
 const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
 const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
 const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
 const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
 const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index d3e546a..5bc3f2f 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -35,7 +35,8 @@
     frameworks/av/services/medialog \
     frameworks/av/services/audioflinger \
     frameworks/av/services/audiopolicy \
-    frameworks/av/services/camera/libcameraservice
+    frameworks/av/services/camera/libcameraservice \
+    $(call include-path-for, audio-utils)
 
 LOCAL_MODULE:= mediaserver
 LOCAL_32_BIT_ONLY := true
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 9e2aa67..bd2541f 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -341,6 +341,13 @@
 }
 
 EXPORT
+media_status_t AMediaCodec_releaseOutputBufferAtTime(
+        AMediaCodec *mData, size_t idx, int64_t timestampNs) {
+    ALOGV("render @ %lld", timestampNs);
+    return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
+}
+
+EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) {
     mData->mCallback = callback;
     mData->mCallbackUserData = userdata;
@@ -351,7 +358,7 @@
         int numsubsamples;
         uint8_t key[16];
         uint8_t iv[16];
-        uint32_t mode;
+        cryptoinfo_mode_t mode;
         size_t *clearbytes;
         size_t *encryptedbytes;
 } AMediaCodecCryptoInfo;
@@ -396,7 +403,7 @@
         int numsubsamples,
         uint8_t key[16],
         uint8_t iv[16],
-        uint32_t mode,
+        cryptoinfo_mode_t mode,
         size_t *clearbytes,
         size_t *encryptedbytes) {
 
@@ -459,9 +466,9 @@
 }
 
 EXPORT
-uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
+cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
     if (!ci) {
-        return AMEDIA_ERROR_INVALID_OBJECT;
+        return (cryptoinfo_mode_t) AMEDIA_ERROR_INVALID_OBJECT;
     }
     return ci->mode;
 }
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index f982275..a0cbb70 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -101,7 +101,7 @@
             return;
     }
 
-    (*mListener)(mObj, sessionId, ndkEventType, extra, data, dataSize);
+    (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
 
     delete [] sessionId.ptr;
     delete [] data;
@@ -236,29 +236,35 @@
 }
 
 EXPORT
-media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
+media_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId *sessionId) {
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     Vector<uint8_t> session;
     status_t status = mObj->mDrm->openSession(session);
     if (status == OK) {
         mObj->mIds.push_front(session);
         List<idvec_t>::iterator iter = mObj->mIds.begin();
-        sessionId.ptr = iter->array();
-        sessionId.length = iter->size();
+        sessionId->ptr = iter->array();
+        sessionId->length = iter->size();
     }
     return AMEDIA_OK;
 }
 
 EXPORT
-media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
+media_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId) {
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
 
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, sessionId, iter)) {
+    if (!findId(mObj, *sessionId, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     mObj->mDrm->closeSession(*iter);
@@ -267,20 +273,20 @@
 }
 
 EXPORT
-media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
+media_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope *scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
-        const uint8_t *&keyRequest, size_t &keyRequestSize) {
+        const uint8_t **keyRequest, size_t *keyRequestSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    if (!mimeType) {
+    if (!mimeType || !scope || !keyRequest || !keyRequestSize) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, scope, iter)) {
+    if (!findId(mObj, *scope, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
@@ -311,25 +317,25 @@
     if (status != OK) {
         return translateStatus(status);
     } else {
-        keyRequest = mObj->mKeyRequest.array();
-        keyRequestSize = mObj->mKeyRequest.size();
+        *keyRequest = mObj->mKeyRequest.array();
+        *keyRequestSize = mObj->mKeyRequest.size();
     }
     return AMEDIA_OK;
 }
 
 EXPORT
-media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
-        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
+media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope *scope,
+        const uint8_t *response, size_t responseSize, AMediaDrmKeySetId *keySetId) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    if (!response || !responseSize) {
+    if (!scope || !response || !responseSize || !keySetId) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, scope, iter)) {
+    if (!findId(mObj, *scope, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     Vector<uint8_t> mdResponse;
@@ -340,41 +346,47 @@
     if (status == OK) {
         mObj->mIds.push_front(mdKeySetId);
         List<idvec_t>::iterator iter = mObj->mIds.begin();
-        keySetId.ptr = iter->array();
-        keySetId.length = iter->size();
+        keySetId->ptr = iter->array();
+        keySetId->length = iter->size();
     } else {
-        keySetId.ptr = NULL;
-        keySetId.length = 0;
+        keySetId->ptr = NULL;
+        keySetId->length = 0;
     }
     return AMEDIA_OK;
 }
 
 EXPORT
-media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
-        const AMediaDrmKeySetId &keySetId) {
+media_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
+        const AMediaDrmKeySetId *keySetId) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId || !keySetId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, sessionId, iter)) {
+    if (!findId(mObj, *sessionId, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
     Vector<uint8_t> keySet;
-    keySet.appendArray(keySetId.ptr, keySetId.length);
+    keySet.appendArray(keySetId->ptr, keySetId->length);
     return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
 }
 
 EXPORT
-media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
+media_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId *keySetId) {
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!keySetId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     List<idvec_t>::iterator iter;
     status_t status;
-    if (!findId(mObj, keySetId, iter)) {
+    if (!findId(mObj, *keySetId, iter)) {
         Vector<uint8_t> keySet;
-        keySet.appendArray(keySetId.ptr, keySetId.length);
+        keySet.appendArray(keySetId->ptr, keySetId->length);
         status = mObj->mDrm->removeKeys(keySet);
     } else {
         status = mObj->mDrm->removeKeys(*iter);
@@ -384,25 +396,28 @@
 }
 
 EXPORT
-media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
-        AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
+media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
+        AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId || !numPairs) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, sessionId, iter)) {
+    if (!findId(mObj, *sessionId, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
     status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
     if (status != OK) {
-        numPairs = 0;
+        *numPairs = 0;
         return translateStatus(status);
     }
 
-    if (mObj->mQueryResults.size() > numPairs) {
-        numPairs = mObj->mQueryResults.size();
+    if (mObj->mQueryResults.size() > *numPairs) {
+        *numPairs = mObj->mQueryResults.size();
         return AMEDIA_DRM_SHORT_BUFFER;
     }
 
@@ -410,17 +425,17 @@
         keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
         keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
     }
-    numPairs = mObj->mQueryResults.size();
+    *numPairs = mObj->mQueryResults.size();
     return AMEDIA_OK;
 }
 
 EXPORT
-media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
-        size_t &provisionRequestSize, const char *&serverUrl) {
+media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t **provisionRequest,
+        size_t *provisionRequestSize, const char **serverUrl) {
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    if (!provisionRequestSize || !serverUrl) {
+    if (!provisionRequest || !provisionRequestSize || !*provisionRequestSize || !serverUrl) {
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
@@ -429,9 +444,9 @@
     if (status != OK) {
         return translateStatus(status);
     } else {
-        provisionRequest = mObj->mProvisionRequest.array();
-        provisionRequestSize = mObj->mProvisionRequest.size();
-        serverUrl = mObj->mProvisionUrl.string();
+        *provisionRequest = mObj->mProvisionRequest.array();
+        *provisionRequestSize = mObj->mProvisionRequest.size();
+        *serverUrl = mObj->mProvisionUrl.string();
     }
     return AMEDIA_OK;
 }
@@ -455,17 +470,20 @@
 
 EXPORT
 media_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
-        AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
+        AMediaDrmSecureStop *secureStops, size_t *numSecureStops) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!numSecureStops) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
     if (status != OK) {
-        numSecureStops = 0;
+        *numSecureStops = 0;
         return translateStatus(status);
     }
-    if (numSecureStops < mObj->mSecureStops.size()) {
+    if (*numSecureStops < mObj->mSecureStops.size()) {
         return AMEDIA_DRM_SHORT_BUFFER;
     }
     List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
@@ -476,59 +494,68 @@
         ++iter;
         ++i;
     }
-    numSecureStops = mObj->mSecureStops.size();
+    *numSecureStops = mObj->mSecureStops.size();
     return AMEDIA_OK;
 }
 
 EXPORT
 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
-        const AMediaDrmSecureStop &ssRelease) {
+        const AMediaDrmSecureStop *ssRelease) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!ssRelease) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
 
     Vector<uint8_t> release;
-    release.appendArray(ssRelease.ptr, ssRelease.length);
+    release.appendArray(ssRelease->ptr, ssRelease->length);
     return translateStatus(mObj->mDrm->releaseSecureStops(release));
 }
 
 
 EXPORT
 media_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
-        const char *&propertyValue) {
+        const char **propertyValue) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!propertyName || !propertyValue) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
 
     status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
             mObj->mPropertyString);
 
     if (status == OK) {
-        propertyValue = mObj->mPropertyString.string();
+        *propertyValue = mObj->mPropertyString.string();
     } else {
-        propertyValue = NULL;
+        *propertyValue = NULL;
     }
     return translateStatus(status);
 }
 
 EXPORT
 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
-        const char *propertyName, AMediaDrmByteArray &propertyValue) {
+        const char *propertyName, AMediaDrmByteArray *propertyValue) {
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!propertyName || !propertyValue) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
 
     status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
             mObj->mPropertyByteArray);
 
     if (status == OK) {
-        propertyValue.ptr = mObj->mPropertyByteArray.array();
-        propertyValue.length = mObj->mPropertyByteArray.size();
+        propertyValue->ptr = mObj->mPropertyByteArray.array();
+        propertyValue->length = mObj->mPropertyByteArray.size();
     } else {
-        propertyValue.ptr = NULL;
-        propertyValue.length = 0;
+        propertyValue->ptr = NULL;
+        propertyValue->length = 0;
     }
     return translateStatus(status);
 }
@@ -598,31 +625,40 @@
 }
 
 EXPORT
-media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize) {
-    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
             input, output, dataSize, true);
 }
 
 EXPORT
-media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
         const uint8_t *input, uint8_t *output, size_t dataSize) {
-    return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return encrypt_decrypt_common(mObj, *sessionId, cipherAlgorithm, keyId, iv,
             input, output, dataSize, false);
 }
 
 EXPORT
-media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
         uint8_t *signature, size_t *signatureSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, sessionId, iter)) {
+    if (!findId(mObj, *sessionId, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
@@ -650,15 +686,18 @@
 }
 
 EXPORT
-media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+media_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
         const uint8_t *signature, size_t signatureSize) {
 
     if (!mObj || mObj->mDrm == NULL) {
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
+    if (!sessionId) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
     List<idvec_t>::iterator iter;
-    if (!findId(mObj, sessionId, iter)) {
+    if (!findId(mObj, *sessionId, iter)) {
         return AMEDIA_DRM_SESSION_NOT_OPENED;
     }
 
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 563358f..b0a9590 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -150,6 +150,20 @@
 }
 
 EXPORT
+media_status_t AMediaExtractor_seekTo(AMediaExtractor *ex, int64_t seekPosUs, SeekMode mode) {
+    android::MediaSource::ReadOptions::SeekMode sfmode;
+    if (mode == AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC) {
+        sfmode = android::MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
+    } else if (mode == AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC) {
+        sfmode = android::MediaSource::ReadOptions::SEEK_CLOSEST_SYNC;
+    } else {
+        sfmode = android::MediaSource::ReadOptions::SEEK_NEXT_SYNC;
+    }
+
+    return translate_error(ex->mImpl->seekTo(seekPosUs, sfmode));
+}
+
+EXPORT
 ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
     //ALOGV("readSampleData");
     sp<ABuffer> tmp = new ABuffer(buffer, capacity);
@@ -331,7 +345,7 @@
             numSubSamples,
             (uint8_t*) key,
             (uint8_t*) iv,
-            mode,
+            (cryptoinfo_mode_t) mode,
             (size_t*) cleardata,
             (size_t*) crypteddata);
 }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 11170c2..45e17f8 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1837,7 +1837,8 @@
     if (status == BAD_VALUE &&
         reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
         (config.sample_rate <= 2 * reqSamplingRate) &&
-        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannelMask) <= FCC_2)) {
+        (audio_channel_count_from_in_mask(config.channel_mask) <= FCC_2) &&
+        (audio_channel_count_from_in_mask(reqChannelMask) <= FCC_2)) {
         // FIXME describe the change proposed by HAL (save old values so we can log them here)
         ALOGV("openInput() reopening with proposed sampling rate and channel mask");
         inStream = NULL;
@@ -1857,7 +1858,8 @@
             TEE_SINK_OLD,   // copy input using an existing pipe
         } kind;
         NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common),
-                                        popcount(inStream->common.get_channels(&inStream->common)));
+                audio_channel_count_from_in_mask(
+                        inStream->common.get_channels(&inStream->common)));
         if (!mTeeSinkInputEnabled) {
             kind = TEE_SINK_NO;
         } else if (!Format_isValid(format)) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d69d6a2..d2ded9a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -82,9 +82,6 @@
 
 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
 
-#define MAX_GAIN 4096.0f
-#define MAX_GAIN_INT 0x1000
-
 #define INCLUDING_FROM_AUDIOFLINGER_H
 
 class AudioFlinger :
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 2d67efb..805eaa4 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -159,7 +159,6 @@
     if (names != 0) {
         int n = __builtin_ctz(names);
         ALOGV("add track (%d)", n);
-        mTrackNames |= 1 << n;
         // assume default parameters for the track, except where noted below
         track_t* t = &mState.tracks[n];
         t->needs = 0;
@@ -175,10 +174,10 @@
         // no initialization needed
         // t->prevAuxLevel
         // t->frameCount
-        t->channelCount = 2;
+        t->channelCount = audio_channel_count_from_out_mask(channelMask);
         t->enabled = false;
         t->format = 16;
-        t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
+        t->channelMask = channelMask;
         t->sessionId = sessionId;
         // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
         t->bufferProvider = NULL;
@@ -196,12 +195,14 @@
         t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
 
         status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
-        if (status == OK) {
-            return TRACK0 + n;
+        if (status != OK) {
+            ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
+            return -1;
         }
-        ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix",
-                channelMask);
+        mTrackNames |= 1 << n;
+        return TRACK0 + n;
     }
+    ALOGE("AudioMixer::getTrackName out of available tracks");
     return -1;
 }
 
@@ -215,7 +216,7 @@
 
 status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask)
 {
-    uint32_t channelCount = popcount(mask);
+    uint32_t channelCount = audio_channel_count_from_out_mask(mask);
     ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
     status_t status = OK;
     if (channelCount > MAX_NUM_CHANNELS) {
@@ -410,7 +411,7 @@
             audio_channel_mask_t mask =
                 static_cast<audio_channel_mask_t>(reinterpret_cast<uintptr_t>(value));
             if (track.channelMask != mask) {
-                uint32_t channelCount = popcount(mask);
+                uint32_t channelCount = audio_channel_count_from_out_mask(mask);
                 ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
                 track.channelMask = mask;
                 track.channelCount = channelCount;
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index e5e120c..09e63a6 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -30,6 +30,9 @@
 #include <system/audio.h>
 #include <media/nbaio/NBLog.h>
 
+// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
+#define MAX_GAIN_INT AudioMixer::UNITY_GAIN
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -91,6 +94,7 @@
         REMOVE          = 0x4102, // Remove the sample rate converter on this track name;
                                   // the track is restored to the mix sample rate.
         // for target RAMP_VOLUME and VOLUME (8 channels max)
+        // FIXME use float for these 3 to improve the dynamic range
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
         AUXLEVEL        = 0x4210,
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index ccc4825..4170fd4 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -270,6 +270,7 @@
     sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
     sp<EffectModule> getEffectFromId_l(int id);
     sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
+    // FIXME use float to improve the dynamic range
     bool setVolume_l(uint32_t *left, uint32_t *right);
     void setDevice_l(audio_devices_t device);
     void setMode_l(audio_mode_t mode);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 5cb42cc..1caed11 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -224,17 +224,13 @@
             AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
             ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
             if (mixer != NULL) {
-                // calling getTrackName with default channel mask and a random invalid
-                //   sessionId (no effects here)
-                name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO, -555);
+                name = mixer->getTrackName(fastTrack->mChannelMask, AUDIO_SESSION_OUTPUT_MIX);
                 ALOG_ASSERT(name >= 0);
                 fastTrackNames[i] = name;
                 mixer->setBufferProvider(name, bufferProvider);
                 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                         (void *) mixBuffer);
                 // newly allocated track names default to full scale volume
-                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
-                        (void *)(uintptr_t)fastTrack->mChannelMask);
                 mixer->enable(name);
             }
             generations[i] = fastTrack->mGeneration;
@@ -257,9 +253,9 @@
                     mixer->setBufferProvider(name, bufferProvider);
                     if (fastTrack->mVolumeProvider == NULL) {
                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                                (void *)0x1000);
+                                (void *) MAX_GAIN_INT);
                         mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                                (void *)0x1000);
+                                (void *) MAX_GAIN_INT);
                     }
                     mixer->setParameter(name, AudioMixer::RESAMPLE,
                             AudioMixer::REMOVE, NULL);
@@ -312,11 +308,13 @@
             int name = fastTrackNames[i];
             ALOG_ASSERT(name >= 0);
             if (fastTrack->mVolumeProvider != NULL) {
-                uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
+                gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
-                        (void *)(uintptr_t)(vlr & 0xFFFF));
+                        (void *) (uintptr_t)
+                            (float_from_gain(gain_minifloat_unpack_left(vlr)) * MAX_GAIN_INT));
                 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
-                        (void *)(uintptr_t)(vlr >> 16));
+                        (void *) (uintptr_t)
+                            (float_from_gain(gain_minifloat_unpack_right(vlr)) * MAX_GAIN_INT));
             }
             // FIXME The current implementation of framesReady() for fast tracks
             // takes a tryLock, which can block
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index be1a376..e388fb3 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_STATE_H
 #define ANDROID_AUDIO_FAST_MIXER_STATE_H
 
+#include <audio_utils/minifloat.h>
 #include <system/audio.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/nbaio/NBAIO.h>
@@ -29,9 +30,8 @@
 
 class VolumeProvider {
 public:
-    // Return the track volume in U4_12 format: left in lower half, right in upper half. The
-    // provider implementation is responsible for validating that the return value is in range.
-    virtual uint32_t getVolumeLR() = 0;
+    // The provider implementation is responsible for validating that the return value is in range.
+    virtual gain_minifloat_packed_t getVolumeLR() = 0;
 protected:
     VolumeProvider() { }
     virtual ~VolumeProvider() { }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 08b1728..6f1f293 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -65,7 +65,7 @@
             void        signal();
 
 // implement FastMixerState::VolumeProvider interface
-    virtual uint32_t    getVolumeLR();
+    virtual gain_minifloat_packed_t getVolumeLR();
 
     virtual status_t    setSyncEvent(const sp<SyncEvent>& event);
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2d4e025..ce08ff1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -35,6 +35,7 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
+#include <audio_utils/minifloat.h>
 
 // NBAIO implementations
 #include <media/nbaio/AudioStreamOutSink.h>
@@ -1730,7 +1731,7 @@
         LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output; "
                 "must be AUDIO_CHANNEL_OUT_STEREO", mChannelMask);
     }
-    mChannelCount = popcount(mChannelMask);
+    mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
     mFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
     if (!audio_is_valid_format(mFormat)) {
         LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat);
@@ -3255,21 +3256,23 @@
                 float typeVolume = mStreamTypes[track->streamType()].volume;
                 float v = masterVolume * typeVolume;
                 AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
-                uint32_t vlr = proxy->getVolumeLR();
-                vl = vlr & 0xFFFF;
-                vr = vlr >> 16;
+                gain_minifloat_packed_t vlr = proxy->getVolumeLR();
+                float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
+                float vrf = float_from_gain(gain_minifloat_unpack_right(vlr));
                 // track volumes come from shared memory, so can't be trusted and must be clamped
-                if (vl > MAX_GAIN_INT) {
-                    ALOGV("Track left volume out of range: %04X", vl);
-                    vl = MAX_GAIN_INT;
+                if (vlf > GAIN_FLOAT_UNITY) {
+                    ALOGV("Track left volume out of range: %.3g", vlf);
+                    vlf = GAIN_FLOAT_UNITY;
                 }
-                if (vr > MAX_GAIN_INT) {
-                    ALOGV("Track right volume out of range: %04X", vr);
-                    vr = MAX_GAIN_INT;
+                if (vrf > GAIN_FLOAT_UNITY) {
+                    ALOGV("Track right volume out of range: %.3g", vrf);
+                    vrf = GAIN_FLOAT_UNITY;
                 }
                 // now apply the master volume and stream type volume
-                vl = (uint32_t)(v * vl) << 12;
-                vr = (uint32_t)(v * vr) << 12;
+                // FIXME we're losing the wonderful dynamic range in the minifloat representation
+                float v8_24 = v * (MAX_GAIN_INT * MAX_GAIN_INT);
+                vl = (uint32_t) (v8_24 * vlf);
+                vr = (uint32_t) (v8_24 * vrf);
                 // assuming master volume and stream type volume each go up to 1.0,
                 // vl and vr are now in 8.24 format
 
@@ -3296,6 +3299,7 @@
                 track->mHasVolumeController = false;
             }
 
+            // FIXME Use float
             // Convert volumes from 8.24 to 4.12 format
             // This additional clamping is needed in case chain->setVolume_l() overshot
             vl = (vl + (1 << 11)) >> 12;
@@ -3750,13 +3754,17 @@
         float typeVolume = mStreamTypes[track->streamType()].volume;
         float v = mMasterVolume * typeVolume;
         AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
-        uint32_t vlr = proxy->getVolumeLR();
-        float v_clamped = v * (vlr & 0xFFFF);
-        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-        left = v_clamped/MAX_GAIN;
-        v_clamped = v * (vlr >> 16);
-        if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
-        right = v_clamped/MAX_GAIN;
+        gain_minifloat_packed_t vlr = proxy->getVolumeLR();
+        left = float_from_gain(gain_minifloat_unpack_left(vlr));
+        if (left > GAIN_FLOAT_UNITY) {
+            left = GAIN_FLOAT_UNITY;
+        }
+        left *= v;
+        right = float_from_gain(gain_minifloat_unpack_right(vlr));
+        if (right > GAIN_FLOAT_UNITY) {
+            right = GAIN_FLOAT_UNITY;
+        }
+        right *= v;
     }
 
     if (lastTrack) {
@@ -4152,7 +4160,10 @@
         mMixerStatus = MIXER_DRAIN_ALL;
         threadLoop_drain();
     }
-    mCallbackThread->exit();
+    if (mUseAsyncWrite) {
+        ALOG_ASSERT(mCallbackThread != 0);
+        mCallbackThread->exit();
+    }
     PlaybackThread::threadLoop_exit();
 }
 
@@ -5564,8 +5575,8 @@
                 reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
                 (mInput->stream->common.get_sample_rate(&mInput->stream->common)
                         <= (2 * samplingRate)) &&
-                popcount(mInput->stream->common.get_channels(&mInput->stream->common))
-                        <= FCC_2 &&
+                audio_channel_count_from_in_mask(
+                        mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 &&
                 (channelMask == AUDIO_CHANNEL_IN_MONO ||
                         channelMask == AUDIO_CHANNEL_IN_STEREO)) {
                 status = NO_ERROR;
@@ -5619,7 +5630,7 @@
 {
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
     mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
-    mChannelCount = popcount(mChannelMask);
+    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
     mFormat = mInput->stream->common.get_format(&mInput->stream->common);
     if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
         ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6dc7f30..de1782d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -34,6 +34,7 @@
 
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
+#include <audio_utils/minifloat.h>
 
 // ----------------------------------------------------------------------------
 
@@ -81,7 +82,9 @@
         mSampleRate(sampleRate),
         mFormat(format),
         mChannelMask(channelMask),
-        mChannelCount(popcount(channelMask)),
+        mChannelCount(isOut ?
+                audio_channel_count_from_out_mask(channelMask) :
+                audio_channel_count_from_in_mask(channelMask)),
         mFrameSize(audio_is_linear_pcm(format) ?
                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
         mFrameCount(frameCount),
@@ -459,7 +462,7 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
 {
-    uint32_t vlr = mAudioTrackServerProxy->getVolumeLR();
+    gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
     if (isFastTrack()) {
         sprintf(buffer, "    F %2d", mFastIndex);
     } else if (mName >= AudioMixer::TRACK0) {
@@ -532,8 +535,8 @@
             stateChar,
             mFillingUpStatus,
             mAudioTrackServerProxy->getSampleRate(),
-            20.0 * log10((vlr & 0xFFFF) / 4096.0),
-            20.0 * log10((vlr >> 16) / 4096.0),
+            20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
+            20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
             mCblk->mServer,
             mMainBuffer,
             mAuxBuffer,
@@ -959,27 +962,27 @@
 
 // implement VolumeBufferProvider interface
 
-uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR()
+gain_minifloat_packed_t AudioFlinger::PlaybackThread::Track::getVolumeLR()
 {
     // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs
     ALOG_ASSERT(isFastTrack() && (mCblk != NULL));
-    uint32_t vlr = mAudioTrackServerProxy->getVolumeLR();
-    uint32_t vl = vlr & 0xFFFF;
-    uint32_t vr = vlr >> 16;
+    gain_minifloat_packed_t vlr = mAudioTrackServerProxy->getVolumeLR();
+    float vl = float_from_gain(gain_minifloat_unpack_left(vlr));
+    float vr = float_from_gain(gain_minifloat_unpack_right(vlr));
     // track volumes come from shared memory, so can't be trusted and must be clamped
-    if (vl > MAX_GAIN_INT) {
-        vl = MAX_GAIN_INT;
+    if (vl > GAIN_FLOAT_UNITY) {
+        vl = GAIN_FLOAT_UNITY;
     }
-    if (vr > MAX_GAIN_INT) {
-        vr = MAX_GAIN_INT;
+    if (vr > GAIN_FLOAT_UNITY) {
+        vr = GAIN_FLOAT_UNITY;
     }
     // now apply the cached master volume and stream type volume;
     // this is trusted but lacks any synchronization or barrier so may be stale
     float v = mCachedVolume;
     vl *= v;
     vr *= v;
-    // re-combine into U4.16
-    vlr = (vr << 16) | (vl & 0xFFFF);
+    // re-combine into packed minifloat
+    vlr = gain_minifloat_pack(gain_from_float(vl), gain_from_float(vr));
     // FIXME look at mute, pause, and stop flags
     return vlr;
 }
@@ -1590,7 +1593,7 @@
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
-        mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000));
+        mClientProxy->setVolumeLR(GAIN_MINIFLOAT_PACKED_UNITY);
         mClientProxy->setSendLevel(0.0);
         mClientProxy->setSampleRate(sampleRate);
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize,
@@ -1849,7 +1852,7 @@
 
     mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
 
-    uint32_t channelCount = popcount(channelMask);
+    uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
     // FIXME I don't understand either of the channel count checks
     if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 &&
             channelCount <= FCC_2) {