Merge "NuPlayer: fix track error notification"
diff --git a/drm/mediacas/plugins/mock/Android.mk b/drm/mediacas/plugins/mock/Android.mk
index a97fac6..a1d61da 100644
--- a/drm/mediacas/plugins/mock/Android.mk
+++ b/drm/mediacas/plugins/mock/Android.mk
@@ -28,6 +28,8 @@
LOCAL_SHARED_LIBRARIES := \
libutils liblog
+LOCAL_HEADER_LIBRARIES := media_plugin_headers
+
LOCAL_C_INCLUDES += \
$(TOP)/frameworks/av/include \
$(TOP)/frameworks/native/include/media \
diff --git a/drm/mediadrm/plugins/mock/Android.bp b/drm/mediadrm/plugins/mock/Android.bp
index 7f44819..abd1884 100644
--- a/drm/mediadrm/plugins/mock/Android.bp
+++ b/drm/mediadrm/plugins/mock/Android.bp
@@ -22,6 +22,8 @@
vendor: true,
relative_install_path: "mediadrm",
+ header_libs: ["media_plugin_headers"],
+
shared_libs: [
"libutils",
"liblog",
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 7dbc19e..d689e25 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
#include <system/audio.h>
+#include <media/AudioClient.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -37,12 +38,6 @@
DIRECTION_INPUT, /**< open a capture mmap stream */
} stream_direction_t;
- class Client {
- public:
- uid_t clientUid;
- pid_t clientPid;
- String16 packageName;
- };
/**
* Open a playback or capture stream in MMAP mode at the audio HAL.
*
@@ -53,13 +48,14 @@
* \param[in,out] config audio parameters (sampling rate, format ...) for the stream.
* Requested parameters as input,
* Actual parameters as output
- * \param[in] client a Client struct describing the first client using this stream.
+ * \param[in] client a AudioClient struct describing the first client using this stream.
* \param[in,out] deviceId audio device the stream should preferably be routed to/from
* Requested as input,
* Actual as output
* \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify
* condition changes affecting the stream operation
* \param[out] interface the MmapStreamInterface interface controlling the created stream
+ * \param[out] same unique handle as the one used for the first client stream started.
* \return OK if the stream was successfully created.
* NO_INIT if AudioFlinger is not properly initialized
* BAD_VALUE if the stream cannot be opened because of invalid arguments
@@ -68,10 +64,11 @@
static status_t openMmapStream(stream_direction_t direction,
const audio_attributes_t *attr,
audio_config_base_t *config,
- const Client& client,
+ const AudioClient& client,
audio_port_handle_t *deviceId,
const sp<MmapStreamCallback>& callback,
- sp<MmapStreamInterface>& interface);
+ sp<MmapStreamInterface>& interface,
+ audio_port_handle_t *handle);
/**
* Retrieve information on the mmap buffer used for audio samples transfer.
@@ -105,13 +102,13 @@
* Start a stream operating in mmap mode.
* createMmapBuffer() must be called before calling start()
*
- * \param[in] client a Client struct describing the client starting on this stream.
+ * \param[in] client a AudioClient struct describing the client starting on this stream.
* \param[out] handle unique handle for this instance. Used with stop().
* \return OK in case of success.
* NO_INIT in case of initialization error
* INVALID_OPERATION if called out of sequence
*/
- virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0;
+ virtual status_t start(const AudioClient& client, audio_port_handle_t *handle) = 0;
/**
* Stop a stream operating in mmap mode.
diff --git a/include/media/omx/1.0/Conversion.h b/include/media/omx/1.0/Conversion.h
new file mode 120000
index 0000000..06d0ae8
--- /dev/null
+++ b/include/media/omx/1.0/Conversion.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/Conversion.h
\ No newline at end of file
diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/include/media/omx/1.0/WGraphicBufferSource.h
new file mode 120000
index 0000000..a875e8b
--- /dev/null
+++ b/include/media/omx/1.0/WGraphicBufferSource.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/WGraphicBufferSource.h
\ No newline at end of file
diff --git a/include/media/omx/1.0/WOmx.h b/include/media/omx/1.0/WOmx.h
new file mode 120000
index 0000000..196b306
--- /dev/null
+++ b/include/media/omx/1.0/WOmx.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/WOmx.h
\ No newline at end of file
diff --git a/include/media/omx/1.0/WOmxBufferSource.h b/include/media/omx/1.0/WOmxBufferSource.h
new file mode 120000
index 0000000..8237c6c
--- /dev/null
+++ b/include/media/omx/1.0/WOmxBufferSource.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxBufferSource.h
\ No newline at end of file
diff --git a/include/media/omx/1.0/WOmxNode.h b/include/media/omx/1.0/WOmxNode.h
new file mode 120000
index 0000000..f30d59c
--- /dev/null
+++ b/include/media/omx/1.0/WOmxNode.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxNode.h
\ No newline at end of file
diff --git a/include/media/omx/1.0/WOmxObserver.h b/include/media/omx/1.0/WOmxObserver.h
new file mode 120000
index 0000000..1b86143
--- /dev/null
+++ b/include/media/omx/1.0/WOmxObserver.h
@@ -0,0 +1 @@
+/usr/local/google/home/pawin/master/frameworks/av/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxObserver.h
\ No newline at end of file
diff --git a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
index 1338b86..edf644a 100644
--- a/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
+++ b/media/libaaudio/examples/input_monitor/src/input_monitor.cpp
@@ -26,30 +26,18 @@
#include "AAudioExampleUtils.h"
#include "AAudioSimpleRecorder.h"
-#define SAMPLE_RATE 48000
-
-#define NUM_SECONDS 10
-
+// TODO support FLOAT
+#define REQUIRED_FORMAT AAUDIO_FORMAT_PCM_I16
#define MIN_FRAMES_TO_READ 48 /* arbitrary, 1 msec at 48000 Hz */
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
{
- (void)argc; // unused
-
+ AAudioArgsParser argParser;
aaudio_result_t result;
AAudioSimpleRecorder recorder;
int actualSamplesPerFrame;
int actualSampleRate;
- const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
- aaudio_format_t actualDataFormat;
-
- const int requestedInputChannelCount = 2; // Can affect whether we get a FAST path.
-
- //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
- const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
- //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
- //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
- const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+ aaudio_format_t actualDataFormat;
aaudio_sharing_mode_t actualSharingMode;
AAudioStream *aaudioStream = nullptr;
@@ -70,18 +58,18 @@
printf("%s - Monitor input level using AAudio\n", argv[0]);
- AAudio_setMMapPolicy(AAUDIO_POLICY_ALWAYS);
+ argParser.setFormat(REQUIRED_FORMAT);
+ if (argParser.parseArgs(argc, argv)) {
+ return EXIT_FAILURE;
+ }
- recorder.setPerformanceMode(requestedPerformanceMode);
- recorder.setSharingMode(requestedSharingMode);
-
- result = recorder.open(requestedInputChannelCount, 48000, requestedDataFormat,
- nullptr, nullptr, nullptr);
+ result = recorder.open(argParser);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - recorder.open() returned %d\n", result);
goto finish;
}
aaudioStream = recorder.getStream();
+ argParser.compareWithStream(aaudioStream);
deviceId = AAudioStream_getDeviceId(aaudioStream);
printf("deviceId = %d\n", deviceId);
@@ -91,11 +79,6 @@
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
printf("SamplesPerFrame = %d\n", actualSampleRate);
- actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
- printf("SharingMode: requested = %s, actual = %s\n",
- getSharingModeText(requestedSharingMode),
- getSharingModeText(actualSharingMode));
-
// This is the number of frames that are written in one chunk by a DMA controller
// or a DSP.
framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
@@ -110,14 +93,12 @@
printf("DataFormat: framesPerRead = %d\n",framesPerRead);
actualDataFormat = AAudioStream_getFormat(aaudioStream);
- printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
+ printf("DataFormat: requested = %d, actual = %d\n",
+ REQUIRED_FORMAT, actualDataFormat);
// TODO handle other data formats
- assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16);
+ assert(actualDataFormat == REQUIRED_FORMAT);
- printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode,
- AAudioStream_getPerformanceMode(aaudioStream));
-
- // Allocate a buffer for the audio data.
+ // Allocate a buffer for the PCM_16 audio data.
data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame];
if (data == nullptr) {
fprintf(stderr, "ERROR - could not allocate data buffer\n");
@@ -136,7 +117,7 @@
printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
// Record for a while.
- framesToRecord = actualSampleRate * NUM_SECONDS;
+ framesToRecord = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToRecord;
while (framesLeft > 0) {
// Read audio data from the stream.
@@ -176,6 +157,8 @@
goto finish;
}
+ argParser.compareWithStream(aaudioStream);
+
finish:
recorder.close();
delete[] data;
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 9f06ee7..45a3beb 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -20,7 +20,6 @@
#include <assert.h>
#include <cctype>
#include <math.h>
-#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
new file mode 100644
index 0000000..54217a5
--- /dev/null
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2017 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 AAUDIO_EXAMPLE_ARGS_PARSER_H
+#define AAUDIO_EXAMPLE_ARGS_PARSER_H
+
+#include <cctype>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+#include <AAudioExampleUtils.h>
+
+// TODO use this as a base class within AAudio
+class AAudioParameters {
+public:
+
+ /**
+ * This is also known as samplesPerFrame.
+ */
+ int32_t getChannelCount() const {
+ return mChannelCount;
+ }
+
+ void setChannelCount(int32_t channelCount) {
+ mChannelCount = channelCount;
+ }
+
+ int32_t getSampleRate() const {
+ return mSampleRate;
+ }
+
+ void setSampleRate(int32_t sampleRate) {
+ mSampleRate = sampleRate;
+ }
+
+ aaudio_format_t getFormat() const {
+ return mFormat;
+ }
+
+ void setFormat(aaudio_format_t format) {
+ mFormat = format;
+ }
+
+ aaudio_sharing_mode_t getSharingMode() const {
+ return mSharingMode;
+ }
+
+ void setSharingMode(aaudio_sharing_mode_t sharingMode) {
+ mSharingMode = sharingMode;
+ }
+
+ int32_t getBufferCapacity() const {
+ return mBufferCapacity;
+ }
+
+ void setBufferCapacity(int32_t frames) {
+ mBufferCapacity = frames;
+ }
+
+ int32_t getPerformanceMode() const {
+ return mPerformanceMode;
+ }
+
+ void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
+ mPerformanceMode = performanceMode;
+ }
+
+ int32_t getDeviceId() const {
+ return mDeviceId;
+ }
+
+ void setDeviceId(int32_t deviceId) {
+ mDeviceId = deviceId;
+ }
+
+ int32_t getNumberOfBursts() const {
+ return mNumberOfBursts;
+ }
+
+ void setNumberOfBursts(int32_t numBursts) {
+ mNumberOfBursts = numBursts;
+ }
+
+ /**
+ * Apply these parameters to a stream builder.
+ * @param builder
+ */
+ void applyParameters(AAudioStreamBuilder *builder) const {
+ AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
+ AAudioStreamBuilder_setFormat(builder, mFormat);
+ AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+ AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+ AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
+ AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+ AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+ }
+
+private:
+ int32_t mChannelCount = AAUDIO_UNSPECIFIED;
+ aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
+ int32_t mSampleRate = AAUDIO_UNSPECIFIED;
+
+ int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
+ int32_t mDeviceId = AAUDIO_UNSPECIFIED;
+ aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
+ aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
+
+ int32_t mNumberOfBursts = AAUDIO_UNSPECIFIED;
+};
+
+class AAudioArgsParser : public AAudioParameters {
+public:
+ AAudioArgsParser() = default;
+ ~AAudioArgsParser() = default;
+
+ enum {
+ DEFAULT_DURATION_SECONDS = 5
+ };
+
+ /**
+ * @param arg
+ * @return true if the argument was not handled
+ */
+ bool parseArg(const char *arg) {
+ bool unrecognized = false;
+ if (arg[0] == '-') {
+ char option = arg[1];
+ switch (option) {
+ case 'b':
+ setBufferCapacity(atoi(&arg[2]));
+ break;
+ case 'c':
+ setChannelCount(atoi(&arg[2]));
+ break;
+ case 'd':
+ mDurationSeconds = atoi(&arg[2]);
+ break;
+ case 'm':
+ AAudio_setMMapPolicy(AAUDIO_POLICY_AUTO);
+ break;
+ case 'n':
+ setNumberOfBursts(atoi(&arg[2]));
+ break;
+ case 'p':
+ setPerformanceMode(parsePerformanceMode(arg[2]));
+ break;
+ case 'r':
+ setSampleRate(atoi(&arg[2]));
+ break;
+ case 'x':
+ setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
+ break;
+ default:
+ unrecognized = true;
+ break;
+ }
+ }
+ return unrecognized;
+ }
+
+ /**
+ *
+ * @param argc
+ * @param argv
+ * @return true if an unrecognized argument was passed
+ */
+ bool parseArgs(int argc, const char **argv) {
+ for (int i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (parseArg(arg)) {
+ usage();
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ static void usage() {
+ printf("-c{channels} -d{duration} -m -n{burstsPerBuffer} -p{perfMode} -r{rate} -x\n");
+ printf(" Default values are UNSPECIFIED unless otherwise stated.\n");
+ printf(" -b{bufferCapacity} frames\n");
+ printf(" -c{channels} for example 2 for stereo\n");
+ printf(" -d{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
+ printf(" -m enable MMAP\n");
+ printf(" -n{numberOfBursts} for setBufferSize\n");
+ printf(" -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
+ printf(" n for _NONE\n");
+ printf(" l for _LATENCY\n");
+ printf(" p for _POWER_SAVING;\n");
+ printf(" -r{sampleRate} for example 44100\n");
+ printf(" -x to use EXCLUSIVE mode\n");
+ }
+
+ static aaudio_performance_mode_t parsePerformanceMode(char c) {
+ aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
+ switch (c) {
+ case 'n':
+ mode = AAUDIO_PERFORMANCE_MODE_NONE;
+ break;
+ case 'l':
+ mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
+ break;
+ case 'p':
+ mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
+ break;
+ default:
+ printf("ERROR invalid performance mode %c\n", c);
+ break;
+ }
+ return mode;
+ }
+
+ /**
+ * Print stream parameters in comparison with requested values.
+ * @param stream
+ */
+ void compareWithStream(AAudioStream *stream) {
+
+ printf(" DeviceId: requested = %d, actual = %d\n",
+ getDeviceId(), AAudioStream_getDeviceId(stream));
+
+ aaudio_stream_state_t state = AAudioStream_getState(stream);
+ printf(" State: %s\n", AAudio_convertStreamStateToText(state));
+
+ // Check to see what kind of stream we actually got.
+ printf(" SampleRate: requested = %d, actual = %d\n",
+ getSampleRate(), AAudioStream_getSampleRate(stream));
+
+ printf(" ChannelCount: requested = %d, actual = %d\n",
+ getChannelCount(), AAudioStream_getChannelCount(stream));
+
+ printf(" DataFormat: requested = %d, actual = %d\n",
+ getFormat(), AAudioStream_getFormat(stream));
+
+ int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+ int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
+ printf(" Buffer: burst = %d\n", framesPerBurst);
+ if (framesPerBurst > 0) {
+ printf(" Buffer: size = %d = (%d * %d) + %d\n",
+ sizeFrames,
+ (sizeFrames / framesPerBurst),
+ framesPerBurst,
+ (sizeFrames % framesPerBurst));
+ }
+ printf(" Capacity: requested = %d, actual = %d\n", getBufferCapacity(),
+ AAudioStream_getBufferCapacityInFrames(stream));
+
+ printf(" SharingMode: requested = %s, actual = %s\n",
+ getSharingModeText(getSharingMode()),
+ getSharingModeText(AAudioStream_getSharingMode(stream)));
+
+ printf(" PerformanceMode: requested = %d, actual = %d\n",
+ getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
+ printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
+ ? "yes" : "no");
+
+ }
+
+ int32_t getDurationSeconds() const {
+ return mDurationSeconds;
+ }
+
+ void setDurationSeconds(int32_t seconds) {
+ mDurationSeconds = seconds;
+ }
+
+private:
+ int32_t mDurationSeconds = DEFAULT_DURATION_SECONDS;
+};
+
+#endif // AAUDIO_EXAMPLE_ARGS_PARSER_H
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index aaeb25f..19f8aff 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -23,6 +23,7 @@
#include <sched.h>
#include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
#include "SineGenerator.h"
//#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -55,15 +56,23 @@
mRequestedPerformanceMode = requestedPerformanceMode;
}
+ // TODO Extract a common base class for record and playback.
/**
* Also known as "sample rate"
* Only call this after open() has been called.
*/
- int32_t getFramesPerSecond() {
+ int32_t getFramesPerSecond() const {
+ return getSampleRate(); // alias
+ }
+
+ /**
+ * Only call this after open() has been called.
+ */
+ int32_t getSampleRate() const {
if (mStream == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- return AAudioStream_getSampleRate(mStream);;
+ return AAudioStream_getSampleRate(mStream);
}
/**
@@ -73,57 +82,83 @@
if (mStream == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- return AAudioStream_getChannelCount(mStream);;
+ return AAudioStream_getChannelCount(mStream);
}
/**
* Open a stream
*/
+ aaudio_result_t open(const AAudioParameters ¶meters,
+ AAudioStream_dataCallback dataCallback = nullptr,
+ AAudioStream_errorCallback errorCallback = nullptr,
+ void *userContext = nullptr) {
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ AAudioStreamBuilder *builder = nullptr;
+ result = AAudio_createStreamBuilder(&builder);
+ if (result != AAUDIO_OK) return result;
+
+ parameters.applyParameters(builder); // apply args
+
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+
+ if (dataCallback != nullptr) {
+ AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+ }
+ if (errorCallback != nullptr) {
+ AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+ }
+ //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+ //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
+
+ // Open an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
+
+ if (result == AAUDIO_OK) {
+ int32_t sizeInBursts = parameters.getNumberOfBursts();
+ if (sizeInBursts > 0) {
+ int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+ AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+ }
+ }
+
+ AAudioStreamBuilder_delete(builder);
+ return result;
+ }
+
aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
- AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+ AAudioStream_dataCallback dataProc,
+ AAudioStream_errorCallback errorProc,
void *userContext) {
aaudio_result_t result = AAUDIO_OK;
// Use an AAudioStreamBuilder to contain requested parameters.
- result = AAudio_createStreamBuilder(&mBuilder);
+ AAudioStreamBuilder *builder = nullptr;
+ result = AAudio_createStreamBuilder(&builder);
if (result != AAUDIO_OK) return result;
- //AAudioStreamBuilder_setSampleRate(mBuilder, 44100);
- AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
- AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+ AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+ AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
+
+ AAudioStreamBuilder_setChannelCount(builder, channelCount);
+ AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+ AAudioStreamBuilder_setFormat(builder, format);
+
if (dataProc != nullptr) {
- AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+ AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
}
if (errorProc != nullptr) {
- AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+ AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
}
- AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
- AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
- AAudioStreamBuilder_setFormat(mBuilder, format);
- //AAudioStreamBuilder_setFramesPerDataCallback(mBuilder, CALLBACK_SIZE_FRAMES);
- AAudioStreamBuilder_setBufferCapacityInFrames(mBuilder, 48 * 8);
-
- //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_NONE;
- aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
- //aaudio_performance_mode_t perfMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
- AAudioStreamBuilder_setPerformanceMode(mBuilder, perfMode);
+ //AAudioStreamBuilder_setFramesPerDataCallback(builder, CALLBACK_SIZE_FRAMES);
+ //AAudioStreamBuilder_setBufferCapacityInFrames(builder, 48 * 8);
// Open an AAudioStream using the Builder.
- result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
- if (result != AAUDIO_OK) goto finish1;
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
- printf("AAudioStream_getFramesPerBurst() = %d\n",
- AAudioStream_getFramesPerBurst(mStream));
- printf("AAudioStream_getBufferSizeInFrames() = %d\n",
- AAudioStream_getBufferSizeInFrames(mStream));
- printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
- AAudioStream_getBufferCapacityInFrames(mStream));
- printf("AAudioStream_getPerformanceMode() = %d, requested %d\n",
- AAudioStream_getPerformanceMode(mStream), perfMode);
-
- finish1:
- AAudioStreamBuilder_delete(mBuilder);
- mBuilder = nullptr;
+ AAudioStreamBuilder_delete(builder);
return result;
}
@@ -132,8 +167,6 @@
printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout);
AAudioStream_close(mStream);
mStream = nullptr;
- AAudioStreamBuilder_delete(mBuilder);
- mBuilder = nullptr;
}
return AAUDIO_OK;
}
@@ -178,7 +211,6 @@
}
private:
- AAudioStreamBuilder *mBuilder = nullptr;
AAudioStream *mStream = nullptr;
aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
diff --git a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
index b26b2ea..6be9112 100644
--- a/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
+++ b/media/libaaudio/examples/utils/AAudioSimpleRecorder.h
@@ -20,10 +20,12 @@
#define AAUDIO_SIMPLE_RECORDER_H
#include <aaudio/AAudio.h>
+#include "AAudioArgsParser.h"
//#define SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
#define SHARING_MODE AAUDIO_SHARING_MODE_SHARED
#define PERFORMANCE_MODE AAUDIO_PERFORMANCE_MODE_NONE
+
/**
* Simple wrapper for AAudio that opens an input stream either in callback or blocking read mode.
*/
@@ -54,11 +56,18 @@
* Also known as "sample rate"
* Only call this after open() has been called.
*/
- int32_t getFramesPerSecond() {
+ int32_t getFramesPerSecond() const {
+ return getSampleRate(); // alias
+ }
+
+ /**
+ * Only call this after open() has been called.
+ */
+ int32_t getSampleRate() const {
if (mStream == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- return AAudioStream_getSampleRate(mStream);;
+ return AAudioStream_getSampleRate(mStream);
}
/**
@@ -77,53 +86,85 @@
if (mStream == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- return AAudioStream_getFramesRead(mStream);;
+ return AAudioStream_getFramesRead(mStream);
+ }
+
+ aaudio_result_t open(const AAudioParameters ¶meters,
+ AAudioStream_dataCallback dataCallback = nullptr,
+ AAudioStream_errorCallback errorCallback = nullptr,
+ void *userContext = nullptr) {
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ AAudioStreamBuilder *builder = nullptr;
+ result = AAudio_createStreamBuilder(&builder);
+ if (result != AAUDIO_OK) return result;
+
+ parameters.applyParameters(builder); // apply args
+
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+
+ if (dataCallback != nullptr) {
+ AAudioStreamBuilder_setDataCallback(builder, dataCallback, userContext);
+ }
+ if (errorCallback != nullptr) {
+ AAudioStreamBuilder_setErrorCallback(builder, errorCallback, userContext);
+ }
+
+ // Open an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
+ if (result != AAUDIO_OK) {
+ fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+
+ if (result == AAUDIO_OK) {
+ int32_t sizeInBursts = parameters.getNumberOfBursts();
+ if (sizeInBursts > 0) {
+ int32_t framesPerBurst = AAudioStream_getFramesPerBurst(mStream);
+ AAudioStream_setBufferSizeInFrames(mStream, sizeInBursts * framesPerBurst);
+ }
+ }
+
+ AAudioStreamBuilder_delete(builder);
+ return result;
}
/**
* Open a stream
*/
aaudio_result_t open(int channelCount, int sampSampleRate, aaudio_format_t format,
- AAudioStream_dataCallback dataProc, AAudioStream_errorCallback errorProc,
+ AAudioStream_dataCallback dataProc,
+ AAudioStream_errorCallback errorProc,
void *userContext) {
aaudio_result_t result = AAUDIO_OK;
// Use an AAudioStreamBuilder to contain requested parameters.
- result = AAudio_createStreamBuilder(&mBuilder);
+ AAudioStreamBuilder *builder = nullptr;
+ result = AAudio_createStreamBuilder(&builder);
if (result != AAUDIO_OK) return result;
- AAudioStreamBuilder_setDirection(mBuilder, AAUDIO_DIRECTION_INPUT);
- AAudioStreamBuilder_setPerformanceMode(mBuilder, mRequestedPerformanceMode);
- AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
+ AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_INPUT);
+ AAudioStreamBuilder_setPerformanceMode(builder, mRequestedPerformanceMode);
+ AAudioStreamBuilder_setSharingMode(builder, mRequestedSharingMode);
if (dataProc != nullptr) {
- AAudioStreamBuilder_setDataCallback(mBuilder, dataProc, userContext);
+ AAudioStreamBuilder_setDataCallback(builder, dataProc, userContext);
}
if (errorProc != nullptr) {
- AAudioStreamBuilder_setErrorCallback(mBuilder, errorProc, userContext);
+ AAudioStreamBuilder_setErrorCallback(builder, errorProc, userContext);
}
- AAudioStreamBuilder_setChannelCount(mBuilder, channelCount);
- AAudioStreamBuilder_setSampleRate(mBuilder, sampSampleRate);
- AAudioStreamBuilder_setFormat(mBuilder, format);
+ AAudioStreamBuilder_setChannelCount(builder, channelCount);
+ AAudioStreamBuilder_setSampleRate(builder, sampSampleRate);
+ AAudioStreamBuilder_setFormat(builder, format);
// Open an AAudioStream using the Builder.
- result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - AAudioStreamBuilder_openStream() returned %d %s\n",
result, AAudio_convertResultToText(result));
- goto finish1;
}
- printf("AAudioStream_getFramesPerBurst() = %d\n",
- AAudioStream_getFramesPerBurst(mStream));
- printf("AAudioStream_getBufferSizeInFrames() = %d\n",
- AAudioStream_getBufferSizeInFrames(mStream));
- printf("AAudioStream_getBufferCapacityInFrames() = %d\n",
- AAudioStream_getBufferCapacityInFrames(mStream));
- return result;
-
- finish1:
- AAudioStreamBuilder_delete(mBuilder);
- mBuilder = nullptr;
+ AAudioStreamBuilder_delete(builder);
return result;
}
@@ -132,8 +173,6 @@
printf("call AAudioStream_close(%p)\n", mStream); fflush(stdout);
AAudioStream_close(mStream);
mStream = nullptr;
- AAudioStreamBuilder_delete(mBuilder);
- mBuilder = nullptr;
}
return AAUDIO_OK;
}
@@ -186,7 +225,6 @@
}
private:
- AAudioStreamBuilder *mBuilder = nullptr;
AAudioStream *mStream = nullptr;
aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index b9269e6..0125c0f 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -23,39 +23,22 @@
#include <aaudio/AAudioTesting.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
+#include "AAudioArgsParser.h"
-#define SAMPLE_RATE 48000
#define NUM_SECONDS 4
-//#define MMAP_POLICY AAUDIO_UNSPECIFIED
-//#define MMAP_POLICY AAUDIO_POLICY_NEVER
-//#define MMAP_POLICY AAUDIO_POLICY_AUTO
-#define MMAP_POLICY AAUDIO_POLICY_ALWAYS
-
-#define REQUESTED_FORMAT AAUDIO_FORMAT_PCM_I16
-
-//#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_SHARED
-#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE
-
-
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
{
- (void)argc; // unused
-
+ AAudioArgsParser argParser;
AAudioSimplePlayer player;
SineThreadedData_t myData;
- aaudio_result_t result = AAUDIO_OK;
+ aaudio_result_t result = AAUDIO_OK;
- const int requestedChannelCount = 2;
- int actualChannelCount = 0;
- const int requestedSampleRate = SAMPLE_RATE;
- int actualSampleRate = 0;
- aaudio_format_t requestedDataFormat = REQUESTED_FORMAT;
+ int32_t actualChannelCount = 0;
+ int32_t actualSampleRate = 0;
aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
- aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
AAudioStream *aaudioStream = nullptr;
- aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
int32_t framesPerBurst = 0;
int32_t framesPerWrite = 0;
int32_t bufferCapacity = 0;
@@ -64,61 +47,37 @@
int32_t xRunCount = 0;
float *floatData = nullptr;
int16_t *shortData = nullptr;
- int32_t deviceId;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine wave using AAudio\n", argv[0]);
+ printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]);
- AAudio_setMMapPolicy(MMAP_POLICY);
- printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy());
+ if (argParser.parseArgs(argc, argv)) {
+ return EXIT_FAILURE;
+ }
- player.setSharingMode(REQUESTED_SHARING_MODE);
-
- result = player.open(requestedChannelCount, requestedSampleRate, requestedDataFormat,
- nullptr, nullptr, &myData);
+ result = player.open(argParser);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.open() returned %d\n", result);
goto finish;
}
aaudioStream = player.getStream();
- // Request stream properties.
- deviceId = AAudioStream_getDeviceId(aaudioStream);
- printf("deviceId = %d\n", deviceId);
+ argParser.compareWithStream(aaudioStream);
- state = AAudioStream_getState(aaudioStream);
- printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
-
- // Check to see what kind of stream we actually got.
+ actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
- printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
+ actualDataFormat = AAudioStream_getFormat(aaudioStream);
myData.sineOsc1.setup(440.0, actualSampleRate);
myData.sineOsc2.setup(660.0, actualSampleRate);
- actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
- printf("ChannelCount: requested = %d, actual = %d\n",
- requestedChannelCount, actualChannelCount);
-
- actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
- printf("SharingMode: requested = %s, actual = %s\n",
- getSharingModeText(REQUESTED_SHARING_MODE),
- getSharingModeText(actualSharingMode));
-
- // This is the number of frames that are read in one chunk by a DMA controller
- // or a DSP or a mixer.
- framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
- printf("Buffer: bufferSize = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream));
- bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
- printf("Buffer: bufferCapacity = %d, remainder = %d\n",
- bufferCapacity, bufferCapacity % framesPerBurst);
-
// Some DMA might use very short bursts of 16 frames. We don't need to write such small
// buffers. But it helps to use a multiple of the burst size for predictable scheduling.
+ framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
framesPerWrite = framesPerBurst;
while (framesPerWrite < 48) {
framesPerWrite *= 2;
@@ -126,13 +85,6 @@
printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
- printf("PerformanceMode = %d\n", AAudioStream_getPerformanceMode(aaudioStream));
- printf("is MMAP used? = %s\n", AAudioStream_isMMapUsed(aaudioStream) ? "yes" : "no");
-
- actualDataFormat = AAudioStream_getFormat(aaudioStream);
- printf("DataFormat: requested = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat);
- // TODO handle other data formats
-
// Allocate a buffer for the audio data.
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
floatData = new float[framesPerWrite * actualChannelCount];
@@ -151,11 +103,11 @@
goto finish;
}
- state = AAudioStream_getState(aaudioStream);
- printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
+ printf("after start, state = %s\n",
+ AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream)));
// Play for a while.
- framesToPlay = actualSampleRate * NUM_SECONDS;
+ framesToPlay = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToPlay;
while (framesLeft > 0) {
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 69145aa..2211b72 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -27,36 +27,42 @@
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
-#define NUM_SECONDS 5
-
// Application data that gets passed to the callback.
#define MAX_FRAME_COUNT_RECORDS 256
-int main(int argc, char **argv)
+int main(int argc, const char **argv)
{
- (void)argc; // unused
+ AAudioArgsParser argParser;
AAudioSimplePlayer player;
SineThreadedData_t myData;
aaudio_result_t result;
+ int32_t actualSampleRate;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
- printf("%s - Play a sine sweep using an AAudio callback\n", argv[0]);
+
+ printf("%s - Play a sine sweep using an AAudio callback V0.1.1\n", argv[0]);
myData.schedulerChecked = false;
- result = player.open(2, 44100, AAUDIO_FORMAT_PCM_FLOAT,
+ if (argParser.parseArgs(argc, argv)) {
+ return EXIT_FAILURE;
+ }
+
+ result = player.open(argParser,
SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.open() returned %d\n", result);
goto error;
}
- printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond());
- printf("player.getChannelCount() = %d\n", player.getChannelCount());
- myData.sineOsc1.setup(440.0, 48000);
+
+ argParser.compareWithStream(player.getStream());
+
+ actualSampleRate = player.getSampleRate();
+ myData.sineOsc1.setup(440.0, actualSampleRate);
myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
- myData.sineOsc2.setup(660.0, 48000);
+ myData.sineOsc2.setup(660.0, actualSampleRate);
myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
#if 0
@@ -73,8 +79,9 @@
goto error;
}
- printf("Sleep for %d seconds while audio plays in a callback thread.\n", NUM_SECONDS);
- for (int second = 0; second < NUM_SECONDS; second++)
+ printf("Sleep for %d seconds while audio plays in a callback thread.\n",
+ argParser.getDurationSeconds());
+ for (int second = 0; second < argParser.getDurationSeconds(); second++)
{
const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
(void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 469f0a8..89ae85c 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -97,6 +97,17 @@
aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) override;
+ aaudio_result_t startClient(aaudio_handle_t streamHandle __unused,
+ const android::AudioClient& client __unused,
+ audio_port_handle_t *clientHandle) override {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ aaudio_result_t stopClient(aaudio_handle_t streamHandle __unused,
+ audio_port_handle_t clientHandle __unused) override {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {
// TODO This is just a stub so we can have a client Binder to pass to the service.
// TODO Implemented in a later CL.
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index 7368062..a64405b 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -18,6 +18,7 @@
#define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
#include <utils/StrongPointer.h>
+#include <media/AudioClient.h>
#include "binding/AAudioServiceDefinitions.h"
#include "binding/AAudioStreamRequest.h"
@@ -86,6 +87,13 @@
virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) = 0;
+
+ virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+ const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) = 0;
+
+ virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+ audio_port_handle_t clientHandle) = 0;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 8a765ad..abdcf5b 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -52,8 +52,12 @@
status = parcel->writeBool(mSharingModeMatchRequired);
if (status != NO_ERROR) goto error;
+ status = parcel->writeBool(mInService);
+ if (status != NO_ERROR) goto error;
+
status = mConfiguration.writeToParcel(parcel);
if (status != NO_ERROR) goto error;
+
return NO_ERROR;
error:
@@ -74,8 +78,12 @@
status = parcel->readBool(&mSharingModeMatchRequired);
if (status != NO_ERROR) goto error;
+ status = parcel->readBool(&mInService);
+ if (status != NO_ERROR) goto error;
+
status = mConfiguration.readFromParcel(parcel);
if (status != NO_ERROR) goto error;
+
return NO_ERROR;
error:
@@ -91,5 +99,7 @@
ALOGD("AAudioStreamRequest mUserId = %d", mUserId);
ALOGD("AAudioStreamRequest mProcessId = %d", mProcessId);
ALOGD("AAudioStreamRequest mDirection = %d", mDirection);
+ ALOGD("AAudioStreamRequest mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
+ ALOGD("AAudioStreamRequest mInService = %d", mInService);
mConfiguration.dump();
}
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 462246b..b0fa96a 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -76,6 +76,14 @@
return mConfiguration;
}
+ bool isInService() const {
+ return mInService;
+ }
+
+ void setInService(bool inService) {
+ mInService = inService;
+ }
+
virtual status_t writeToParcel(Parcel* parcel) const override;
virtual status_t readFromParcel(const Parcel* parcel) override;
@@ -90,6 +98,7 @@
pid_t mProcessId;
aaudio_direction_t mDirection;
bool mSharingModeMatchRequired = false;
+ bool mInService = false; // Stream opened by AAudioservice
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ff13fc2..7b01e44 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -16,7 +16,7 @@
// This file is used in both client and server processes.
// This is needed to make sense of the logs more easily.
-#define LOG_TAG (mInService ? "AAudioService" : "AAudio")
+#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -93,6 +93,7 @@
request.setProcessId(getpid());
request.setDirection(getDirection());
request.setSharingModeMatchRequired(isSharingModeMatchRequired());
+ request.setInService(mInService);
request.getConfiguration().setDeviceId(getDeviceId());
request.getConfiguration().setSampleRate(getSampleRate());
@@ -326,6 +327,21 @@
return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
}
+aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mServiceInterface.startClient(mServiceStreamHandle, client, clientHandle);
+}
+
+aaudio_result_t AudioStreamInternal::stopClient(audio_port_handle_t clientHandle) {
+ if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mServiceInterface.stopClient(mServiceStreamHandle, clientHandle);
+}
+
aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 257a702..109e425 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -87,6 +87,11 @@
//PlayerBase virtuals
virtual void destroy();
+ aaudio_result_t startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle);
+
+ aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
protected:
aaudio_result_t processData(void *buffer,
@@ -170,7 +175,6 @@
AudioEndpointParcelable mEndPointParcelable; // description of the buffers filled by service
EndpointDescriptor mEndpointDescriptor; // buffer description with resolved addresses
-
};
} /* namespace aaudio */
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index d320320..ceba211 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -323,6 +323,7 @@
return BAD_VALUE;
}
data.write(attr, sizeof(audio_attributes_t));
+ data.writeInt32(*input);
data.writeInt32(session);
data.writeInt32(pid);
data.writeInt32(uid);
@@ -1024,6 +1025,7 @@
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_attributes_t attr;
data.read(&attr, sizeof(audio_attributes_t));
+ audio_io_handle_t input = (audio_io_handle_t)data.readInt32();
audio_session_t session = (audio_session_t)data.readInt32();
pid_t pid = (pid_t)data.readInt32();
uid_t uid = (uid_t)data.readInt32();
@@ -1033,7 +1035,6 @@
audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32();
audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
- audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
status_t status = getInputForAttr(&attr, &input, session, pid, uid,
&config,
flags, &selectedDeviceId, &portId);
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
new file mode 100644
index 0000000..9efd76d
--- /dev/null
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_AUDIO_CLIENT_H
+#define ANDROID_AUDIO_CLIENT_H
+
+#include <system/audio.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class AudioClient {
+ public:
+ AudioClient() :
+ clientUid(-1), clientPid(-1), packageName("") {}
+
+ uid_t clientUid;
+ pid_t clientPid;
+ String16 packageName;
+};
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_CLIENT_H
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index bbe97ee..043c84a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,7 +1,7 @@
cc_library_headers {
name: "libmedia_headers",
vendor_available: true,
- export_include_dirs: ["include"],
+ export_include_dirs: ["include", "omx/1.0/include"],
}
cc_library {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 43130eb..a073081 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,7 +29,7 @@
#include <utils/NativeHandle.h>
#include <gui/IGraphicBufferProducer.h>
-#include <omx/1.0/WOmxNode.h>
+#include <media/omx/1.0/WOmxNode.h>
#include <android/IGraphicBufferSource.h>
#include <android/IOMXBufferSource.h>
diff --git a/include/media/omx/1.0/Conversion.h b/media/libmedia/omx/1.0/include/media/omx/1.0/Conversion.h
similarity index 100%
rename from include/media/omx/1.0/Conversion.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/Conversion.h
diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/media/libmedia/omx/1.0/include/media/omx/1.0/WGraphicBufferSource.h
similarity index 100%
rename from include/media/omx/1.0/WGraphicBufferSource.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/WGraphicBufferSource.h
diff --git a/include/media/omx/1.0/WOmx.h b/media/libmedia/omx/1.0/include/media/omx/1.0/WOmx.h
similarity index 100%
rename from include/media/omx/1.0/WOmx.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/WOmx.h
diff --git a/include/media/omx/1.0/WOmxBufferSource.h b/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxBufferSource.h
similarity index 100%
rename from include/media/omx/1.0/WOmxBufferSource.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/WOmxBufferSource.h
diff --git a/include/media/omx/1.0/WOmxNode.h b/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxNode.h
similarity index 100%
rename from include/media/omx/1.0/WOmxNode.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/WOmxNode.h
diff --git a/include/media/omx/1.0/WOmxObserver.h b/media/libmedia/omx/1.0/include/media/omx/1.0/WOmxObserver.h
similarity index 100%
rename from include/media/omx/1.0/WOmxObserver.h
rename to media/libmedia/omx/1.0/include/media/omx/1.0/WOmxObserver.h
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 0a9f791..6da1ec1 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -245,8 +245,12 @@
if (sInitComplete)
return;
- registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
- registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
+ IFactory* factory = new NuPlayerFactory();
+ if (registerFactory_l(factory, NU_PLAYER) != OK)
+ delete factory;
+ factory = new TestPlayerFactory();
+ if (registerFactory_l(factory, TEST_PLAYER) != OK)
+ delete factory;
sInitComplete = true;
}
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index e3f4876..2b5b4ff 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -892,23 +892,14 @@
ofs.close();
}
-// converts a time series into a map. key: buffer period length. value: count
-static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
- // TODO allow buckets of variable resolution
- std::map<int, int> buckets;
- for (size_t i = 1; i < samples.size(); ++i) {
- ++buckets[deltaMs(samples[i - 1], samples[i])];
- }
- return buckets;
-}
-
void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
{
// CallStack cs(LOG_TAG);
mFd = fd;
mIndent = indent;
String8 timestamp, body;
- PerformanceAnalysis performanceAnalyzer; // used to call analysis functions
+ // FIXME: this is not thread safe
+ static PerformanceAnalysis performanceAnalysis; // used to store data and to call analysis functions
size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
if (lost > 0) {
body.appendFormat("warning: lost %zu bytes worth of events", lost);
@@ -930,29 +921,7 @@
memcpy(&hash, &(data->hash), sizeof(hash));
int64_t ts;
memcpy(&ts, &data->ts, sizeof(ts));
- const std::pair<log_hash_t, int> key(hash, data->author);
- // TODO might want to filter excessively high outliers, which are usually caused
- // by the thread being inactive.
- mHists[key].push_back(ts);
- // store time series data for each reader in order to bucket it once there
- // is enough data. Then, it is written to recentHists as a histogram.
- mTimeStampSeries[data->author].push_back(ts);
- // if length of the time series has reached kShortHistSize samples, do 1) and 2):
- if (mTimeStampSeries[data->author].size() >= kShortHistSize) {
- // 1) analyze the series to store all outliers and their exact timestamps:
- performanceAnalyzer.storeOutlierData(data->author, mTimeStampSeries[data->author]);
- // 2) compute its histogram, append this to mRecentHists and erase the time series
- mRecentHists.emplace_front(data->author,
- buildBuckets(mTimeStampSeries[data->author]));
- // do not let mRecentHists exceed capacity
- // TODO: turn the FIFO queue into a circular buffer
- if (mRecentHists.size() >= kRecentHistsCapacity) {
- mRecentHists.pop_back();
- }
- mTimeStampSeries.erase(data->author);
- }
- // if an element in mHists has not grown for a long time, delete
- // TODO copy histogram data only to mRecentHistsBuffer and pop oldest
+ performanceAnalysis.logTsEntry(data->author, ts);
++entry;
break;
}
@@ -967,12 +936,10 @@
break;
}
}
- performanceAnalyzer.reportPerformance(&body, mRecentHists);
+ performanceAnalysis.reportPerformance(&body);
if (!body.isEmpty()) {
dumpLine(timestamp, body);
}
- // comment in for tests
- // performanceAnalyzer.testFunction();
}
void NBLog::Reader::dump(int fd, size_t indent)
diff --git a/media/libnbaio/PerformanceAnalysis.cpp b/media/libnbaio/PerformanceAnalysis.cpp
index 84b7635..fa8f47e 100644
--- a/media/libnbaio/PerformanceAnalysis.cpp
+++ b/media/libnbaio/PerformanceAnalysis.cpp
@@ -45,8 +45,21 @@
namespace android {
-PerformanceAnalysis::PerformanceAnalysis() : findGlitch(false) {
- kPeriodMsCPU = static_cast<int>(PerformanceAnalysis::kPeriodMs * kRatio);
+PerformanceAnalysis::PerformanceAnalysis() {
+ // These variables will be (FIXME) learned from the data
+ kPeriodMs = 4; // typical buffer period (mode)
+ // average number of Ms spent processing buffer
+ kPeriodMsCPU = static_cast<int>(kPeriodMs * kRatio);
+}
+
+// converts a time series into a map. key: buffer period length. value: count
+static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
+ // TODO allow buckets of variable resolution
+ std::map<int, int> buckets;
+ for (size_t i = 1; i < samples.size(); ++i) {
+ ++buckets[deltaMs(samples[i - 1], samples[i])];
+ }
+ return buckets;
}
static int widthOf(int x) {
@@ -58,76 +71,164 @@
return width;
}
+// Takes a single buffer period timestamp entry with author information and stores it
+// in a temporary series of timestamps. Once the series is full, the data is analyzed,
+// stored, and emptied.
+// TODO: decide whether author or file location information is more important to store
+// for now, only stores author (thread)
+void PerformanceAnalysis::logTsEntry(int author, int64_t ts) {
+ // TODO might want to filter excessively high outliers, which are usually caused
+ // by the thread being inactive.
+ // Store time series data for each reader in order to bucket it once there
+ // is enough data. Then, write to recentHists as a histogram.
+ mTimeStampSeries[author].push_back(ts);
+ // if length of the time series has reached kShortHistSize samples, do 1) and 2):
+ if (mTimeStampSeries[author].size() >= kShortHistSize) {
+ // 1) analyze the series to store all outliers and their exact timestamps:
+ storeOutlierData(mTimeStampSeries[author]);
+ // 2) detect peaks in the outlier series
+ detectPeaks();
+ // 3) compute its histogram, append this to mRecentHists and erase the time series
+ // FIXME: need to store the timestamp of the beginning of each histogram
+ // FIXME: Restore LOG_HIST_FLUSH to separate histograms at every end-of-stream event
+ // A histogram should not span data between audio off/on timespans
+ mRecentHists.emplace_back(author,
+ buildBuckets(mTimeStampSeries[author]));
+ // do not let mRecentHists exceed capacity
+ // ALOGD("mRecentHists size: %d", static_cast<int>(mRecentHists.size()));
+ if (mRecentHists.size() >= kRecentHistsCapacity) {
+ // ALOGD("popped back mRecentHists");
+ mRecentHists.pop_front();
+ }
+ mTimeStampSeries[author].clear();
+ }
+}
+
+// Given a series of outlier intervals (mOutlier data),
+// looks for changes in distribution (peaks), which can be either positive or negative.
+// The function sets the mean to the starting value and sigma to 0, and updates
+// them as long as no peak is detected. When a value is more than 'threshold'
+// standard deviations from the mean, a peak is detected and the mean and sigma
+// are set to the peak value and 0.
+void PerformanceAnalysis::detectPeaks() {
+ if (mOutlierData.empty()) {
+ ALOGD("peak detector called on empty array");
+ return;
+ }
+
+ // compute mean of the distribution. Used to check whether a value is large
+ const double kTypicalDiff = std::accumulate(
+ mOutlierData.begin(), mOutlierData.end(), 0,
+ [](auto &a, auto &b){return a + b.first;}) / mOutlierData.size();
+ // ALOGD("typicalDiff %f", kTypicalDiff);
+
+ // iterator at the beginning of a sequence, or updated to the most recent peak
+ std::deque<std::pair<uint64_t, uint64_t>>::iterator start = mOutlierData.begin();
+ // the mean and standard deviation are updated every time a peak is detected
+ // initialize first time. The mean from the previous sequence is stored
+ // for the next sequence. Here, they are initialized for the first time.
+ if (mPeakDetectorMean < 0) {
+ mPeakDetectorMean = static_cast<double>(start->first);
+ mPeakDetectorSd = 0;
+ }
+ auto sqr = [](auto x){ return x * x; };
+ for (auto it = mOutlierData.begin(); it != mOutlierData.end(); ++it) {
+ // no surprise occurred:
+ // the new element is a small number of standard deviations from the mean
+ if ((fabs(it->first - mPeakDetectorMean) < kStddevThreshold * mPeakDetectorSd) ||
+ // or: right after peak has been detected, the delta is smaller than average
+ (mPeakDetectorSd == 0 && fabs(it->first - mPeakDetectorMean) < kTypicalDiff)) {
+ // update the mean and sd:
+ // count number of elements (distance between start interator and current)
+ const int kN = std::distance(start, it) + 1;
+ // usual formulas for mean and sd
+ mPeakDetectorMean = std::accumulate(start, it + 1, 0.0,
+ [](auto &a, auto &b){return a + b.first;}) / kN;
+ mPeakDetectorSd = sqrt(std::accumulate(start, it + 1, 0.0,
+ [=](auto &a, auto &b){ return a + sqr(b.first - mPeakDetectorMean);})) /
+ ((kN > 1)? kN - 1 : kN); // kN - 1: mean is correlated with variance
+ // ALOGD("value, mean, sd: %f, %f, %f", static_cast<double>(it->first), mean, sd);
+ }
+ // surprising value: store peak timestamp and reset mean, sd, and start iterator
+ else {
+ mPeakTimestamps.emplace_back(it->second);
+ // TODO: remove pop_front once a circular buffer is in place
+ if (mPeakTimestamps.size() >= kShortHistSize) {
+ ALOGD("popped back mPeakTimestamps");
+ mPeakTimestamps.pop_front();
+ }
+ mPeakDetectorMean = static_cast<double>(it->first);
+ mPeakDetectorSd = 0;
+ start = it;
+ }
+ }
+ //for (const auto &it : mPeakTimestamps) {
+ // ALOGE("mPeakTimestamps %f", static_cast<double>(it));
+ //}
+ return;
+}
+
+// Called by LogTsEntry. The input is a vector of timestamps.
+// Finds outliers and writes to mOutlierdata.
+// Each value in mOutlierdata consists of: <outlier timestamp, time elapsed since previous outlier>.
+// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
+// This function is applied to the time series before it is converted into a histogram.
+void PerformanceAnalysis::storeOutlierData(const std::vector<int64_t> ×tamps) {
+ if (timestamps.size() < 1) {
+ ALOGE("storeOutlierData called on empty vector");
+ return;
+ }
+ // first pass: need to initialize
+ if (mElapsed == 0) {
+ mPrevNs = timestamps[0];
+ }
+ for (const auto &ts: timestamps) {
+ const uint64_t diffMs = static_cast<uint64_t>(deltaMs(mPrevNs, ts));
+ if (diffMs >= static_cast<uint64_t>(kOutlierMs)) {
+ mOutlierData.emplace_back(mElapsed, static_cast<uint64_t>(mPrevNs));
+ // Remove oldest value if the vector is full
+ // TODO: remove pop_front once circular buffer is in place
+ // FIXME: change kShortHistSize to some other constant. Make sure it is large
+ // enough that data will never be lost before being written to a long-term FIFO
+ if (mOutlierData.size() >= kShortHistSize) {
+ ALOGD("popped back mOutlierData");
+ mOutlierData.pop_front();
+ }
+ mElapsed = 0;
+ }
+ mElapsed += diffMs;
+ mPrevNs = ts;
+ }
+}
+
+
// FIXME: delete this temporary test code, recycled for various new functions
void PerformanceAnalysis::testFunction() {
// produces values (4: 5000000), (13: 18000000)
// ns timestamps of buffer periods
const std::vector<int64_t>kTempTestData = {1000000, 4000000, 5000000,
16000000, 18000000, 28000000};
- const int kTestAuthor = 1;
- PerformanceAnalysis::storeOutlierData(kTestAuthor, kTempTestData);
+ PerformanceAnalysis::storeOutlierData(kTempTestData);
for (const auto &outlier: mOutlierData) {
ALOGE("PerformanceAnalysis test %lld: %lld",
static_cast<long long>(outlier.first), static_cast<long long>(outlier.second));
}
+ detectPeaks();
}
-// Each pair consists of: <outlier timestamp, time elapsed since previous outlier>.
-// The timestamp of the beginning of the outlier is recorded.
-// The elapsed time is from the timestamp of the previous outlier
-// e.g. timestamps (ms) 1, 4, 5, 16, 18, 28 will produce pairs (4, 5), (13, 18).
-// This function is applied to the time series before it is converted into a histogram.
-void PerformanceAnalysis::storeOutlierData(
- int author, const std::vector<int64_t> ×tamps) {
- if (timestamps.size() < 1) {
- ALOGE("storeOutlierData called on empty vector");
- return;
- }
- author++; // temp to avoid unused error until this value is
- // either TODO: used or discarded from the arglist
- author--;
- uint64_t elapsed = 0;
- int64_t prev = timestamps.at(0);
- for (const auto &ts: timestamps) {
- const uint64_t diff = static_cast<uint64_t>(deltaMs(prev, ts));
- if (diff >= static_cast<uint64_t>(kOutlierMs)) {
- mOutlierData.emplace_back(elapsed, static_cast<uint64_t>(prev));
- elapsed = 0;
- }
- elapsed += diff;
- prev = ts;
- }
- // ALOGE("storeOutlierData: result length %zu", outlierData.size());
- // for (const auto &outlier: OutlierData) {
- // ALOGE("PerformanceAnalysis test %lld: %lld",
- // static_cast<long long>(outlier.first), static_cast<long long>(outlier.second));
- //}
-}
-
-// TODO: implement peak detector
-/*
- static void peakDetector() {
- return;
- } */
-
-// TODO put this function in separate file. Make it return a std::string instead of modifying body
-// TODO create a subclass of Reader for this and related work
+// TODO Make it return a std::string instead of modifying body --> is this still relevant?
// FIXME: as can be seen when printing the values, the outlier timestamps typically occur
// in the first histogram 35 to 38 indices from the end (most often 35).
-// TODO: build histogram buckets earlier and discard timestamps to save memory
// TODO consider changing all ints to uint32_t or uint64_t
-void PerformanceAnalysis::reportPerformance(String8 *body,
- const std::deque<std::pair
- <int, short_histogram>> &shortHists,
- int maxHeight) {
- if (shortHists.size() < 1) {
+void PerformanceAnalysis::reportPerformance(String8 *body, int maxHeight) {
+ if (mRecentHists.size() < 1) {
+ ALOGD("reportPerformance: mRecentHists is empty");
return;
}
- // this is temporary code, which only prints out one histogram
- // of all data stored in buffer. The data is not erased, only overwritten.
+ ALOGD("reportPerformance: hists size %d", static_cast<int>(mRecentHists.size()));
// TODO: more elaborate data analysis
std::map<int, int> buckets;
- for (const auto &shortHist: shortHists) {
+ for (const auto &shortHist: mRecentHists) {
for (const auto &countPair : shortHist.second) {
buckets[countPair.first] += countPair.second;
}
@@ -222,14 +323,4 @@
return;
}
-bool PerformanceAnalysis::isFindGlitch() const
-{
- return findGlitch;
-}
-
-void PerformanceAnalysis::setFindGlitch(bool s)
-{
- findGlitch = s;
-}
-
} // namespace android
diff --git a/media/libnbaio/include/media/nbaio/NBLog.h b/media/libnbaio/include/media/nbaio/NBLog.h
index 6b08e94..0b5e24d 100644
--- a/media/libnbaio/include/media/nbaio/NBLog.h
+++ b/media/libnbaio/include/media/nbaio/NBLog.h
@@ -406,6 +406,7 @@
public:
// A snapshot of a readers buffer
+ // This is raw data. No analysis has been done on it
class Snapshot {
public:
Snapshot() : mData(NULL), mLost(0) {}
@@ -445,6 +446,7 @@
// get snapshot of readers fifo buffer, effectively consuming the buffer
std::unique_ptr<Snapshot> getSnapshot();
// dump a particular snapshot of the reader
+ // TODO: move dump to PerformanceAnalysis. Model/view/controller design
void dump(int fd, size_t indent, Snapshot & snap);
// dump the current content of the reader's buffer (call getSnapshot() and previous dump())
void dump(int fd, size_t indent = 0);
@@ -452,9 +454,6 @@
private:
- // TODO: decide whether these belong in NBLog::Reader or in PerformanceAnalysis
- static const int kShortHistSize = 50; // number of samples in a short-term histogram
- static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
static const std::set<Event> startingTypes;
static const std::set<Event> endingTypes;
/*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
@@ -467,23 +466,6 @@
audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
// non-NULL unless constructor fails
- // stores a short-term histogram of size determined by kShortHistSize
- // TODO: unsigned, unsigned
- using short_histogram = std::map<int, int>;
-
- // each pair contains a sequence of timestamps (one histogram's worth)
- // pair's log_hash_t is the hash of the source code location where the timestamp was taken
- // pair's int points to the Reader that originated the entry
- std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
-
- // mHistsCopy stores timestamp vectors whose key is the reader thread index.
- // TODO remove old mHists after changing the code
- std::map<int, std::vector<int64_t>> mTimeStampSeries;
-
- // stores fixed-size short buffer period histograms with hash and thread data
- // TODO: Turn it into a circular buffer for better data flow
- std::deque<std::pair<int, short_histogram>> mRecentHists;
-
// TODO: it might be clearer, instead of a direct map from source location to vector of
// timestamps, if we instead first mapped from source location to an object that
// represented that location. And one_of its fields would be a vector of timestamps.
diff --git a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
index 32ae38b..89699bf 100644
--- a/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
+++ b/media/libnbaio/include/media/nbaio/PerformanceAnalysis.h
@@ -22,79 +22,119 @@
#include <map>
#include <deque>
#include <vector>
+#include "NBLog.h"
namespace android {
class String8;
class PerformanceAnalysis {
-
+ // This class stores and analyzes audio processing wakeup timestamps from NBLog
+ // FIXME: currently, all performance data is stored in deques. Need to add a mutex.
+ // FIXME: continue this way until analysis is done in a separate thread. Then, use
+ // the fifo writer utilities.
public:
-PerformanceAnalysis();
+ PerformanceAnalysis();
-// stores a short-term histogram of size determined by kShortHistSize
-// TODO: unsigned, unsigned
-// CHECK: is there a better way to use short_histogram than to write 'using'
-// both in this header file and in NBLog.h?
-using short_histogram = std::map<int, int>;
+ // FIXME: decide whether to use 64 or 32 bits
+ typedef uint64_t log_hash_t;
-// returns a vector of pairs <outlier timestamp, time elapsed since previous outlier
-// called by NBLog::Reader::dump before data is converted into histogram
-// TODO: currently, the elapsed time
-// The resolution is only as good as the ms duration of one shortHist
-void storeOutlierData(int author, const std::vector<int64_t> ×tamps);
+ // stores a short-term histogram of size determined by kShortHistSize
+ // key: observed buffer period. value: count
+ // TODO: unsigned, unsigned
+ // TODO: change this name to histogram
+ using short_histogram = std::map<int, int>;
-// TODO: delete this. temp for testing
-void testFunction();
+ using outlierInterval = uint64_t;
+ // int64_t timestamps are converted to uint64_t in PerformanceAnalysis::storeOutlierData,
+ // and all further analysis functions use uint64_t.
+ using timestamp = uint64_t;
+ using timestamp_raw = int64_t;
-// Given a series, looks for changes in distribution (peaks)
-// Returns a 'signal' array of the same length as the series, where each
-// value is mapped to -1, 0, or 1 based on whether a negative or positive peak
-// was detected, or no significant change occurred.
-// The function sets the mean to the starting value and sigma to 0, and updates
-// them as long as no peak is detected. When a value is more than 'threshold'
-// standard deviations from the mean, a peak is detected and the mean and sigma
-// are set to the peak value and 0.
-// static void peakDetector();
+ // Writes wakeup timestamp entry to log and runs analysis
+ // author is the thread ID
+ // TODO: check. if the thread has multiple histograms, is author info correct
+ // FIXME: remove author from arglist. Want to call these function separately on
+ // each thread’s data.
+ // FIXME: decide whether to store the hash (source file location) instead
+ // FIXME: If thread has multiple histograms, check that code works and correct
+ // author is stored (test with multiple threads). Need to check that the current
+ // code is not receiving data from multiple threads. This could cause odd values.
+ void logTsEntry(int author, timestamp_raw ts);
-// input: series of short histograms. output: prints an analysis of the
-// data to the console
-// TODO: change this so that it writes the analysis to the long-term
-// circular buffer and prints an analyses both for the short and long-term
-void reportPerformance(String8 *body,
- const std::deque<std::pair
- <int, short_histogram>> &shortHists,
- int maxHeight = 10);
+ // FIXME: make peakdetector and storeOutlierData a single function
+ // Input: mOutlierData. Looks at time elapsed between outliers
+ // finds significant changes in the distribution
+ // writes timestamps of significant changes to mPeakTimestamps
+ void detectPeaks();
-// if findGlitch is true, log warning when buffer periods caused glitch
-// TODO adapt this to the analysis in reportPerformance instead of logging
-void alertIfGlitch(const std::vector<int64_t> &samples);
-bool isFindGlitch() const;
-void setFindGlitch(bool s);
+ // runs analysis on timestamp series before it is converted to a histogram
+ // finds outliers
+ // writes to mOutlierData <time elapsed since previous outlier, outlier timestamp>
+ void storeOutlierData(const std::vector<timestamp_raw> ×tamps);
-~PerformanceAnalysis() {}
+ // input: series of short histograms. Generates a string of analysis of the buffer periods
+ // TODO: WIP write more detailed analysis
+ // FIXME: move this data visualization to a separate class. Model/view/controller
+ void reportPerformance(String8 *body, int maxHeight = 10);
+
+ // TODO: delete this. temp for testing
+ void testFunction();
+
+ // This function used to detect glitches in a time series
+ // TODO incorporate this into the analysis (currently unused)
+ void alertIfGlitch(const std::vector<timestamp_raw> &samples);
+
+ ~PerformanceAnalysis() {}
private:
-// stores outlier analysis
-std::vector<std::pair<uint64_t, uint64_t>> mOutlierData;
+ // stores outlier analysis: <elapsed time between outliers in ms, outlier timestamp>
+ std::deque<std::pair<outlierInterval, timestamp>> mOutlierData;
-// stores long-term audio performance data
-// TODO: Turn it into a circular buffer
-std::deque<std::pair<int, int>> mPerformanceAnalysis;
+ // stores each timestamp at which a peak was detected
+ // a peak is a moment at which the average outlier interval changed significantly
+ std::deque<timestamp> mPeakTimestamps;
-// alert if a local buffer period sequence caused an audio glitch
-bool findGlitch;
-//TODO: measure these from the data (e.g., mode) as they may change.
-//const int kGlitchThreshMs = 7;
-// const int kMsPerSec = 1000;
-const int kNumBuff = 3; // number of buffers considered in local history
-const int kPeriodMs = 4; // current period length is ideally 4 ms
-const int kOutlierMs = 7; // values greater or equal to this cause glitches every time
-// DAC processing time for 4 ms buffer
-static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length
-int kPeriodMsCPU; //compute based on kPeriodLen and kRatio
+ // FIFO of small histograms
+ // stores fixed-size short buffer period histograms with hash and thread data
+ // TODO: Turn it into a circular buffer for better data flow
+ std::deque<std::pair<int, short_histogram>> mRecentHists;
+
+ // map from author to vector of timestamps, collected from NBLog
+ // when a vector reaches its maximum size, analysis is run and the data is deleted
+ std::map<int, std::vector<timestamp_raw>> mTimeStampSeries;
+
+ // TODO: measure these from the data (e.g., mode) as they may change.
+ // const int kGlitchThreshMs = 7;
+ // const int kMsPerSec = 1000;
+
+ // Parameters used when detecting outliers
+ // TODO: learn some of these from the data, delete unused ones
+ // FIXME: decide whether to make kPeriodMs static.
+ // The non-const values are (TODO: will be) learned from the data
+ static const int kNumBuff = 3; // number of buffers considered in local history
+ int kPeriodMs; // current period length is ideally 4 ms
+ static const int kOutlierMs = 7; // values greater or equal to this cause glitches
+ // DAC processing time for 4 ms buffer
+ static constexpr double kRatio = 0.75; // estimate of CPU time as ratio of period length
+ int kPeriodMsCPU; // compute based on kPeriodLen and kRatio
+
+ // Peak detection: number of standard deviations from mean considered a significant change
+ static const int kStddevThreshold = 5;
+
+ static const int kRecentHistsCapacity = 100; // number of short-term histograms stored in memory
+ static const int kShortHistSize = 50; // number of samples in a short-term histogram
+
+ // these variables are stored in-class to ensure continuity while analyzing the timestamp
+ // series one short sequence at a time: the variables are not re-initialized every time.
+ // FIXME: create inner class for these variables and decide which other ones to add to it
+ double mPeakDetectorMean = -1;
+ double mPeakDetectorSd = -1;
+ // variables for storeOutlierData
+ uint64_t mElapsed = 0;
+ int64_t mPrevNs = -1;
};
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 142ae07..6491ceb 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -960,7 +960,9 @@
return NO_MEMORY;
}
hidlMem = mapMemory(hidlMemToken);
-
+ if (hidlMem == nullptr) {
+ return NO_MEMORY;
+ }
err = mOMXNode->useBuffer(
portIndex, hidlMemToken, &info.mBufferID);
} else {
@@ -1008,6 +1010,9 @@
return NO_MEMORY;
}
hidlMem = mapMemory(hidlMemToken);
+ if (hidlMem == nullptr) {
+ return NO_MEMORY;
+ }
info.mData = new SharedMemoryBuffer(format, hidlMem);
info.mMemRef = hidlMem;
} else {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 61a2b5f..6ed0d0e 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -972,6 +972,14 @@
}
if (handle != nullptr) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
+ if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
+ ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)",
+ __FUNCTION__, heap->getHeapID(), mMemoryHeapBase->getHeapID());
+ return;
+ }
uint32_t batchSize = 0;
{
Mutex::Autolock autoLock(mBatchLock);
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index f89688c..cff4a33 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -68,7 +68,7 @@
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumInputBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 8192;
+ def.nBufferSize = 32768;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index b0faee1..c6fa4ae 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1052,6 +1052,10 @@
case OMXBuffer::kBufferTypeHidlMemory: {
sp<IHidlMemory> hidlMemory = mapMemory(omxBuffer.mHidlMemory);
+ if (hidlMemory == nullptr) {
+ ALOGE("OMXNodeInstance useBuffer() failed to map memory");
+ return NO_MEMORY;
+ }
return useBuffer_l(portIndex, NULL, hidlMemory, buffer);
}
default:
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d850aa9..38c9687 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -260,10 +260,11 @@
status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_direction_t direction,
const audio_attributes_t *attr,
audio_config_base_t *config,
- const MmapStreamInterface::Client& client,
+ const AudioClient& client,
audio_port_handle_t *deviceId,
const sp<MmapStreamCallback>& callback,
- sp<MmapStreamInterface>& interface)
+ sp<MmapStreamInterface>& interface,
+ audio_port_handle_t *handle)
{
sp<AudioFlinger> af;
{
@@ -273,7 +274,7 @@
status_t ret = NO_INIT;
if (af != 0) {
ret = af->openMmapStream(
- direction, attr, config, client, deviceId, callback, interface);
+ direction, attr, config, client, deviceId, callback, interface, handle);
}
return ret;
}
@@ -281,10 +282,11 @@
status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t direction,
const audio_attributes_t *attr,
audio_config_base_t *config,
- const MmapStreamInterface::Client& client,
+ const AudioClient& client,
audio_port_handle_t *deviceId,
const sp<MmapStreamCallback>& callback,
- sp<MmapStreamInterface>& interface)
+ sp<MmapStreamInterface>& interface,
+ audio_port_handle_t *handle)
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
@@ -293,7 +295,7 @@
audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
- audio_io_handle_t io;
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER;
@@ -325,6 +327,7 @@
if (thread != 0) {
interface = new MmapThreadHandle(thread);
thread->configure(attr, streamType, sessionId, callback, portId);
+ *handle = portId;
} else {
ret = NO_INIT;
}
@@ -1279,7 +1282,7 @@
if (thread == NULL) {
thread = (ThreadBase *)checkMmapThread_l(ioHandle);
if (thread == NULL) {
- String8("");
+ return String8("");
}
}
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2e0bc66..8a96c1d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -294,10 +294,11 @@
status_t openMmapStream(MmapStreamInterface::stream_direction_t direction,
const audio_attributes_t *attr,
audio_config_base_t *config,
- const MmapStreamInterface::Client& client,
+ const AudioClient& client,
audio_port_handle_t *deviceId,
const sp<MmapStreamCallback>& callback,
- sp<MmapStreamInterface>& interface);
+ sp<MmapStreamInterface>& interface,
+ audio_port_handle_t *handle);
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;
@@ -596,7 +597,7 @@
virtual status_t createMmapBuffer(int32_t minSizeFrames,
struct audio_mmap_buffer_info *info);
virtual status_t getMmapPosition(struct audio_mmap_position *position);
- virtual status_t start(const MmapStreamInterface::Client& client,
+ virtual status_t start(const AudioClient& client,
audio_port_handle_t *handle);
virtual status_t stop(audio_port_handle_t handle);
virtual status_t standby();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6329f20..7871ae6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7544,7 +7544,7 @@
return mThread->getMmapPosition(position);
}
-status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client,
audio_port_handle_t *handle)
{
@@ -7638,77 +7638,75 @@
return mHalStream->getMmapPosition(position);
}
-status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client,
+status_t AudioFlinger::MmapThread::start(const AudioClient& client,
audio_port_handle_t *handle)
{
- ALOGV("%s clientUid %d mStandby %d", __FUNCTION__, client.clientUid, mStandby);
+ ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
+ client.clientUid, mStandby, mPortId, *handle);
if (mHalStream == 0) {
return NO_INIT;
}
status_t ret;
- audio_session_t sessionId;
- audio_port_handle_t portId;
- if (mActiveTracks.size() == 0) {
+ if (*handle == mPortId) {
// for the first track, reuse portId and session allocated when the stream was opened
ret = mHalStream->start();
if (ret != NO_ERROR) {
ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
return ret;
}
- portId = mPortId;
- sessionId = mSessionId;
mStandby = false;
+ return NO_ERROR;
+ }
+
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+
+ audio_io_handle_t io = mId;
+ if (isOutput()) {
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = mSampleRate;
+ config.channel_mask = mChannelMask;
+ config.format = mFormat;
+ audio_stream_type_t stream = streamType();
+ audio_output_flags_t flags =
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+ audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ ret = AudioSystem::getOutputForAttr(&mAttr, &io,
+ mSessionId,
+ &stream,
+ client.clientUid,
+ &config,
+ flags,
+ &deviceId,
+ &portId);
} else {
- // for other tracks than first one, get a new port ID from APM.
- sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
- audio_io_handle_t io;
- if (isOutput()) {
- audio_config_t config = AUDIO_CONFIG_INITIALIZER;
- config.sample_rate = mSampleRate;
- config.channel_mask = mChannelMask;
- config.format = mFormat;
- audio_stream_type_t stream = streamType();
- audio_output_flags_t flags =
- (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
- audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
- ret = AudioSystem::getOutputForAttr(&mAttr, &io,
- sessionId,
- &stream,
- client.clientUid,
- &config,
- flags,
- &deviceId,
- &portId);
- } else {
- audio_config_base_t config;
- config.sample_rate = mSampleRate;
- config.channel_mask = mChannelMask;
- config.format = mFormat;
- audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
- ret = AudioSystem::getInputForAttr(&mAttr, &io,
- sessionId,
- client.clientPid,
- client.clientUid,
- &config,
- AUDIO_INPUT_FLAG_MMAP_NOIRQ,
- &deviceId,
- &portId);
- }
- // APM should not chose a different input or output stream for the same set of attributes
- // and audo configuration
- if (ret != NO_ERROR || io != mId) {
- ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
- __FUNCTION__, ret, io, mId);
- return BAD_VALUE;
- }
+ audio_config_base_t config;
+ config.sample_rate = mSampleRate;
+ config.channel_mask = mChannelMask;
+ config.format = mFormat;
+ audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ ret = AudioSystem::getInputForAttr(&mAttr, &io,
+ mSessionId,
+ client.clientPid,
+ client.clientUid,
+ &config,
+ AUDIO_INPUT_FLAG_MMAP_NOIRQ,
+ &deviceId,
+ &portId);
+ }
+ // APM should not chose a different input or output stream for the same set of attributes
+ // and audo configuration
+ if (ret != NO_ERROR || io != mId) {
+ ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
+ __FUNCTION__, ret, io, mId);
+ return BAD_VALUE;
}
if (isOutput()) {
- ret = AudioSystem::startOutput(mId, streamType(), sessionId);
+ ret = AudioSystem::startOutput(mId, streamType(), mSessionId);
} else {
- ret = AudioSystem::startInput(mId, sessionId);
+ ret = AudioSystem::startInput(mId, mSessionId);
}
// abort if start is rejected by audio policy manager
@@ -7716,9 +7714,9 @@
ALOGE("%s: error start rejected by AudioPolicyManager = %d", __FUNCTION__, ret);
if (mActiveTracks.size() != 0) {
if (isOutput()) {
- AudioSystem::releaseOutput(mId, streamType(), sessionId);
+ AudioSystem::releaseOutput(mId, streamType(), mSessionId);
} else {
- AudioSystem::releaseInput(mId, sessionId);
+ AudioSystem::releaseInput(mId, mSessionId);
}
} else {
mHalStream->stop();
@@ -7726,12 +7724,11 @@
return PERMISSION_DENIED;
}
- sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, sessionId,
- client.clientUid, client.clientPid,
- portId);
+ sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId,
+ client.clientUid, client.clientPid, portId);
mActiveTracks.add(track);
- sp<EffectChain> chain = getEffectChain_l(sessionId);
+ sp<EffectChain> chain = getEffectChain_l(mSessionId);
if (chain != 0) {
chain->setStrategy(AudioSystem::getStrategyForStream(streamType()));
chain->incTrackCnt();
@@ -7739,10 +7736,9 @@
}
*handle = portId;
-
broadcast_l();
- ALOGV("%s DONE handle %d stream %p", __FUNCTION__, portId, mHalStream.get());
+ ALOGV("%s DONE handle %d stream %p", __FUNCTION__, *handle, mHalStream.get());
return NO_ERROR;
}
@@ -7755,6 +7751,11 @@
return NO_INIT;
}
+ if (handle == mPortId) {
+ mHalStream->stop();
+ return NO_ERROR;
+ }
+
sp<MmapTrack> track;
for (const sp<MmapTrack> &t : mActiveTracks) {
if (handle == t->portId()) {
@@ -7770,14 +7771,10 @@
if (isOutput()) {
AudioSystem::stopOutput(mId, streamType(), track->sessionId());
- if (mActiveTracks.size() != 0) {
- AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
- }
+ AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
} else {
AudioSystem::stopInput(mId, track->sessionId());
- if (mActiveTracks.size() != 0) {
- AudioSystem::releaseInput(mId, track->sessionId());
- }
+ AudioSystem::releaseInput(mId, track->sessionId());
}
sp<EffectChain> chain = getEffectChain_l(track->sessionId());
@@ -7788,9 +7785,6 @@
broadcast_l();
- if (mActiveTracks.size() == 0) {
- mHalStream->stop();
- }
return NO_ERROR;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index cc11ddb..22d78eb 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1482,7 +1482,7 @@
status_t createMmapBuffer(int32_t minSizeFrames,
struct audio_mmap_buffer_info *info);
status_t getMmapPosition(struct audio_mmap_position *position);
- status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+ status_t start(const AudioClient& client, audio_port_handle_t *handle);
status_t stop(audio_port_handle_t handle);
status_t standby();
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index ded2285..4f79ed2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -71,7 +71,7 @@
virtual void toAudioPort(struct audio_port *port) const;
- virtual void importAudioPort(const sp<AudioPort>& port);
+ virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 2e653e2..cedf22d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -52,6 +52,7 @@
audio_channel_mask_t channelMask() const { return mConfig.channel_mask; }
audio_input_flags_t flags() const { return mFlags; }
uid_t uid() const { return mRecordClientInfo.uid; }
+ void setUid(uid_t uid) { mRecordClientInfo.uid = uid; }
bool matches(const sp<AudioSession> &other) const;
bool isSoundTrigger() const { return mIsSoundTrigger; }
uint32_t openCount() const { return mOpenCount; } ;
@@ -65,7 +66,7 @@
virtual void onSessionInfoUpdate() const;
private:
- const record_client_info_t mRecordClientInfo;
+ record_client_info_t mRecordClientInfo;
const struct audio_config_base mConfig;
const audio_input_flags_t mFlags;
bool mIsSoundTrigger;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 9a52d22..1a644d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -48,7 +48,7 @@
// AudioPort
virtual void attach(const sp<HwModule>& module);
virtual void toAudioPort(struct audio_port *port) const;
- virtual void importAudioPort(const sp<AudioPort>& port);
+ virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
audio_port_handle_t getId() const;
status_t dump(int fd, int spaces, int index, bool verbose = true) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 6ed2cb7..fcf9070 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -128,7 +128,7 @@
port->num_gains = i;
}
-void AudioPort::importAudioPort(const sp<AudioPort>& port)
+void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
{
size_t indexToImport;
for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index f0e48b6..a2c1165 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -263,7 +263,10 @@
strncpy(port->ext.device.address, mAddress.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN);
}
-void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port) {
+void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) {
+ if (!force && !port->hasDynamicAudioProfile()) {
+ return;
+ }
AudioPort::importAudioPort(port);
port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 77b0182..55c364f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1495,6 +1495,43 @@
"session %d, flags %#x",
attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
+ // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+ // possible
+ if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+ *input != AUDIO_IO_HANDLE_NONE) {
+ ssize_t index = mInputs.indexOfKey(*input);
+ if (index < 0) {
+ ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+ return BAD_VALUE;
+ }
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+ if (audioSession == 0) {
+ ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+ return BAD_VALUE;
+ }
+ // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+ // The second call is for the first active client and sets the UID. Any further call
+ // corresponds to a new client and is only permitted from the same UId.
+ if (audioSession->openCount() == 1) {
+ audioSession->setUid(uid);
+ } else if (audioSession->uid() != uid) {
+ ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+ uid, session, audioSession->uid());
+ return INVALID_OPERATION;
+ }
+ audioSession->changeOpenCount(1);
+ *inputType = API_INPUT_LEGACY;
+ if (*portId == AUDIO_PORT_HANDLE_NONE) {
+ *portId = AudioPort::getNextUniqueId();
+ }
+ DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+ *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+ : AUDIO_PORT_HANDLE_NONE;
+ ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+ return NO_ERROR;
+ }
+
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
@@ -1898,6 +1935,11 @@
continue;
}
+ if ((audioSession->flags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0 &&
+ activeDesc->getId() == inputDesc->getId()) {
+ continue;
+ }
+
audio_source_t activeSource = activeDesc->inputSource(true);
if (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) {
if (activeSource == AUDIO_SOURCE_HOTWORD) {
@@ -3724,7 +3766,7 @@
sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
if (!devDesc->isAttached()) {
devDesc->attach(mHwModules[i]);
- devDesc->importAudioPort(inProfile);
+ devDesc->importAudioPort(inProfile, true);
}
}
}
@@ -4087,8 +4129,8 @@
continue;
}
- ALOGV("opening output for device %08x with params %s profile %p",
- device, address.string(), profile.get());
+ ALOGV("opening output for device %08x with params %s profile %p name %s",
+ device, address.string(), profile.get(), profile->getName().string());
desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
desc->mDevice = device;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -4337,6 +4379,10 @@
config.channel_mask = desc->mChannelMask;
config.format = desc->mFormat;
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+
+ ALOGV("opening inputput for device %08x with params %s profile %p name %s",
+ desc->mDevice, address.string(), profile.get(), profile->getName().string());
+
status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
&input,
&config,
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 02d4a19..ec2f5b9 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioEndpointManager"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -104,6 +104,8 @@
// If we can't find an existing one then open a new one.
if (endpoint == nullptr) {
+ // we must call openStream with audioserver identity
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
switch(direction) {
case AAUDIO_DIRECTION_INPUT:
capture = new AAudioServiceEndpointCapture(audioService);
@@ -138,6 +140,7 @@
}
ALOGD("AAudioEndpointManager::openEndpoint(), created %p for device = %d, dir = %d",
endpoint, configuration.getDeviceId(), (int)direction);
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
if (endpoint != nullptr) {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 669bb54..3992719 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -50,8 +50,9 @@
android::AAudioService::AAudioService()
: BnAAudioService() {
- mCachedProcessId = getpid();
- mCachedUserId = getuid(); // TODO consider using geteuid()
+ mAudioClient.clientUid = getuid(); // TODO consider using geteuid()
+ mAudioClient.clientPid = getpid();
+ mAudioClient.packageName = String16("");
AAudioClientTracker::getInstance().setAAudioService(this);
}
@@ -92,7 +93,7 @@
// Enforce limit on client processes.
pid_t pid = request.getProcessId();
- if (pid != mCachedProcessId) {
+ if (pid != mAudioClient.clientPid) {
int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
if (count >= MAX_STREAMS_PER_PROCESS) {
ALOGE("AAudioService::openStream(): exceeded max streams per process %d >= %d",
@@ -107,7 +108,13 @@
}
if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- serviceStream = new AAudioServiceStreamMMAP(mCachedUserId);
+ // only trust audioserver for in service indication
+ bool inService = false;
+ if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+ mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+ inService = request.isInService();
+ }
+ serviceStream = new AAudioServiceStreamMMAP(mAudioClient, inService);
result = serviceStream->open(request, configurationOutput);
if (result != AAUDIO_OK) {
// fall back to using a shared stream
@@ -132,8 +139,6 @@
result, AAudio_convertResultToText(result));
return result;
} else {
- const uid_t ownerUserId = request.getUserId(); // only set by service, not by client
- serviceStream->setOwnerUserId(ownerUserId);
aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream.get());
if (handle < 0) {
ALOGE("AAudioService::openStream(): handle table full");
@@ -143,7 +148,6 @@
ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
serviceStream->setHandle(handle);
pid_t pid = request.getProcessId();
- serviceStream->setOwnerProcessId(pid);
AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
}
return handle;
@@ -181,8 +185,8 @@
const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
const uid_t ownerUserId = serviceStream->getOwnerUserId();
bool callerOwnsIt = callingUserId == ownerUserId;
- bool serverCalling = callingUserId == mCachedUserId;
- bool serverOwnsIt = ownerUserId == mCachedUserId;
+ bool serverCalling = callingUserId == mAudioClient.clientUid;
+ bool serverOwnsIt = ownerUserId == mAudioClient.clientUid;
bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
if (!allowed) {
ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
@@ -212,6 +216,7 @@
ALOGE("AAudioService::startStream(), illegal stream handle = 0x%0x", streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
+
aaudio_result_t result = serviceStream->start();
return result;
}
@@ -286,3 +291,26 @@
serviceStream->setRegisteredThread(0);
return AAUDIO_OK;
}
+
+aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
+ const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream == nullptr) {
+ ALOGE("AAudioService::startClient(), illegal stream handle = 0x%0x",
+ streamHandle);
+ return AAUDIO_ERROR_INVALID_HANDLE;
+ }
+ return serviceStream->startClient(client, clientHandle);
+}
+
+aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
+ audio_port_handle_t clientHandle) {
+ AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream == nullptr) {
+ ALOGE("AAudioService::stopClient(), illegal stream handle = 0x%0x",
+ streamHandle);
+ return AAUDIO_ERROR_INVALID_HANDLE;
+ }
+ return serviceStream->stopClient(clientHandle);
+}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index f84ac4c..8421efc 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -21,6 +21,7 @@
#include <pthread.h>
#include <binder/BinderService.h>
+#include <media/AudioClient.h>
#include <aaudio/AAudio.h>
#include "utility/HandleTracker.h"
@@ -72,14 +73,20 @@
virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t tid);
+ virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
+ const android::AudioClient& client,
+ audio_port_handle_t *clientHandle);
+
+ virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
+ audio_port_handle_t clientHandle);
+
private:
aaudio::AAudioServiceStreamBase *convertHandleToServiceStream(aaudio_handle_t streamHandle) const;
HandleTracker mHandleTracker;
- uid_t mCachedUserId = -1;
- pid_t mCachedProcessId = -1;
+ android::AudioClient mAudioClient;
enum constants {
DEFAULT_AUDIO_PRIORITY = 2
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index b519829..5895974 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceEndpoint"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -94,7 +94,7 @@
}
aaudio_result_t AAudioServiceEndpoint::close() {
- return getStreamInternal()->close();
+ return getStreamInternal()->close();
}
// TODO, maybe use an interface to reduce exposure
@@ -113,26 +113,25 @@
aaudio_result_t AAudioServiceEndpoint::startStream(sp<AAudioServiceStreamShared> sharedStream) {
// TODO use real-time technique to avoid mutex, eg. atomic command FIFO
+ aaudio_result_t result = AAUDIO_OK;
std::lock_guard<std::mutex> lock(mLockStreams);
- mRunningStreams.push_back(sharedStream);
- if (mRunningStreams.size() == 1) {
+ if (++mRunningStreams == 1) {
+ result = getStreamInternal()->requestStart();
startSharingThread_l();
}
- return AAUDIO_OK;
+ return result;
}
aaudio_result_t AAudioServiceEndpoint::stopStream(sp<AAudioServiceStreamShared> sharedStream) {
int numRunningStreams = 0;
{
std::lock_guard<std::mutex> lock(mLockStreams);
- mRunningStreams.erase(
- std::remove(mRunningStreams.begin(), mRunningStreams.end(), sharedStream),
- mRunningStreams.end());
- numRunningStreams = mRunningStreams.size();
+ numRunningStreams = --mRunningStreams;
}
if (numRunningStreams == 0) {
// Don't call this under a lock because the callbackLoop also uses the lock.
stopSharingThread();
+ getStreamInternal()->requestStop();
}
return AAUDIO_OK;
}
@@ -163,11 +162,8 @@
void AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::lock_guard<std::mutex> lock(mLockStreams);
- for(auto baseStream : mRunningStreams) {
- baseStream->onStop();
- }
- mRunningStreams.clear();
for(auto sharedStream : mRegisteredStreams) {
+ sharedStream->stop();
sharedStream->disconnect();
}
mRegisteredStreams.clear();
@@ -189,3 +185,4 @@
return true;
}
+
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a78d3fa..ed995e5 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -79,7 +79,7 @@
std::vector<android::sp<AAudioServiceStreamShared>> mRegisteredStreams;
- std::vector<android::sp<AAudioServiceStreamShared>> mRunningStreams;
+ size_t mRunningStreams = 0;
private:
aaudio_result_t startSharingThread_l();
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index a144c54..6a37330 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -57,9 +57,7 @@
void *AAudioServiceEndpointCapture::callbackLoop() {
ALOGD("AAudioServiceEndpointCapture(): callbackLoop() entering");
int32_t underflowCount = 0;
-
- aaudio_result_t result = getStreamInternal()->requestStart();
-
+ aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
// result might be a frame count
@@ -78,21 +76,21 @@
// Distribute data to each active stream.
{ // use lock guard
std::lock_guard <std::mutex> lock(mLockStreams);
- for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
- FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
- if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
- getFramesPerBurst()) {
- underflowCount++;
- } else {
- fifo->write(mDistributionBuffer, getFramesPerBurst());
+ for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+ if (sharedStream->isRunning()) {
+ FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+ if (fifo->getFifoControllerBase()->getEmptyFramesAvailable() <
+ getFramesPerBurst()) {
+ underflowCount++;
+ } else {
+ fifo->write(mDistributionBuffer, getFramesPerBurst());
+ }
+ sharedStream->markTransferTime(AudioClock::getNanoseconds());
}
- sharedStream->markTransferTime(AudioClock::getNanoseconds());
}
}
}
- result = getStreamInternal()->requestStop();
-
ALOGD("AAudioServiceEndpointCapture(): callbackLoop() exiting, %d underflows", underflowCount);
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 1afcc1e..86ccde0 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -68,9 +68,7 @@
void *AAudioServiceEndpointPlay::callbackLoop() {
ALOGD("AAudioServiceEndpointPlay(): callbackLoop() entering");
int32_t underflowCount = 0;
-
- aaudio_result_t result = getStreamInternal()->requestStart();
-
+ aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
// result might be a frame count
@@ -79,13 +77,15 @@
mMixer.clear();
{ // use lock guard
std::lock_guard <std::mutex> lock(mLockStreams);
- for (sp<AAudioServiceStreamShared> sharedStream : mRunningStreams) {
- FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
- float volume = 1.0; // to match legacy volume
- bool underflowed = mMixer.mix(fifo, volume);
- underflowCount += underflowed ? 1 : 0;
- // TODO log underflows in each stream
- sharedStream->markTransferTime(AudioClock::getNanoseconds());
+ for (sp<AAudioServiceStreamShared> sharedStream : mRegisteredStreams) {
+ if (sharedStream->isRunning()) {
+ FifoBuffer *fifo = sharedStream->getDataFifoBuffer();
+ float volume = 1.0; // to match legacy volume
+ bool underflowed = mMixer.mix(fifo, volume);
+ underflowCount += underflowed ? 1 : 0;
+ // TODO log underflows in each stream
+ sharedStream->markTransferTime(AudioClock::getNanoseconds());
+ }
}
}
@@ -102,8 +102,6 @@
}
}
- result = getStreamInternal()->requestStop();
-
ALOGD("AAudioServiceEndpointPlay(): callbackLoop() exiting, %d underflows", underflowCount);
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 52b1801..e0f6ad4 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamBase"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -38,6 +38,9 @@
AAudioServiceStreamBase::AAudioServiceStreamBase()
: mUpMessageQueue(nullptr)
, mAAudioThread() {
+ mMmapClient.clientUid = -1;
+ mMmapClient.clientPid = -1;
+ mMmapClient.packageName = String16("");
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
@@ -45,7 +48,8 @@
// If the stream is deleted when OPEN or in use then audio resources will leak.
// This would indicate an internal error. So we want to find this ASAP.
LOG_ALWAYS_FATAL_IF(!(mState == AAUDIO_STREAM_STATE_CLOSED
- || mState == AAUDIO_STREAM_STATE_UNINITIALIZED),
+ || mState == AAUDIO_STREAM_STATE_UNINITIALIZED
+ || mState == AAUDIO_STREAM_STATE_DISCONNECTED),
"service stream still open, state = %d", mState);
}
@@ -58,13 +62,18 @@
result << " framesPerBurst = " << mFramesPerBurst << "\n";
result << " channelCount = " << mSamplesPerFrame << "\n";
result << " capacityFrames = " << mCapacityInFrames << "\n";
- result << " owner uid = " << mOwnerUserId << "\n";
+ result << " owner uid = " << mMmapClient.clientUid << "\n";
return result.str();
}
aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
aaudio::AAudioStreamConfiguration &configurationOutput) {
+
+ mMmapClient.clientUid = request.getUserId();
+ mMmapClient.clientPid = request.getProcessId();
+ mMmapClient.packageName.setTo(String16("")); // FIXME what should we do here?
+
std::lock_guard<std::mutex> lock(mLockUpMessageQueue);
if (mUpMessageQueue != nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
@@ -86,6 +95,9 @@
}
aaudio_result_t AAudioServiceStreamBase::start() {
+ if (isRunning()) {
+ return AAUDIO_OK;
+ }
sendServiceEvent(AAUDIO_SERVICE_EVENT_STARTED);
mState = AAUDIO_STREAM_STATE_STARTED;
mThreadEnabled.store(true);
@@ -94,32 +106,34 @@
aaudio_result_t AAudioServiceStreamBase::pause() {
aaudio_result_t result = AAUDIO_OK;
- if (isRunning()) {
- sendCurrentTimestamp();
- mThreadEnabled.store(false);
- result = mAAudioThread.stop();
- if (result != AAUDIO_OK) {
- disconnect();
- return result;
- }
- sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
+ if (!isRunning()) {
+ return result;
}
+ sendCurrentTimestamp();
+ mThreadEnabled.store(false);
+ result = mAAudioThread.stop();
+ if (result != AAUDIO_OK) {
+ disconnect();
+ return result;
+ }
+ sendServiceEvent(AAUDIO_SERVICE_EVENT_PAUSED);
mState = AAUDIO_STREAM_STATE_PAUSED;
return result;
}
aaudio_result_t AAudioServiceStreamBase::stop() {
aaudio_result_t result = AAUDIO_OK;
- if (isRunning()) {
- // TODO wait for data to be played out
- sendCurrentTimestamp(); // warning - this calls a virtual function
- result = stopTimestampThread();
- if (result != AAUDIO_OK) {
- disconnect();
- return result;
- }
- sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
+ if (!isRunning()) {
+ return result;
}
+ // TODO wait for data to be played out
+ sendCurrentTimestamp(); // warning - this calls a virtual function
+ result = stopTimestampThread();
+ if (result != AAUDIO_OK) {
+ disconnect();
+ return result;
+ }
+ sendServiceEvent(AAUDIO_SERVICE_EVENT_STOPPED);
mState = AAUDIO_STREAM_STATE_STOPPED;
return result;
}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index c7df6f3..93a522e 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -27,6 +27,7 @@
#include "binding/AudioEndpointParcelable.h"
#include "binding/AAudioServiceMessage.h"
#include "utility/AAudioUtilities.h"
+#include <media/AudioClient.h>
#include "SharedRingBuffer.h"
#include "AAudioThread.h"
@@ -85,9 +86,19 @@
*/
virtual aaudio_result_t flush();
+ virtual aaudio_result_t startClient(const android::AudioClient& client __unused,
+ audio_port_handle_t *clientHandle __unused) {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle __unused) {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
bool isRunning() const {
return mState == AAUDIO_STREAM_STATE_STARTED;
}
+
// -------------------------------------------------------------------
/**
@@ -124,17 +135,11 @@
void disconnect();
uid_t getOwnerUserId() const {
- return mOwnerUserId;
- }
- void setOwnerUserId(uid_t uid) {
- mOwnerUserId = uid;
+ return mMmapClient.clientUid;
}
pid_t getOwnerProcessId() const {
- return mOwnerProcessId;
- }
- void setOwnerProcessId(pid_t pid) {
- mOwnerProcessId = pid;
+ return mMmapClient.clientPid;
}
aaudio_handle_t getHandle() const {
@@ -164,24 +169,25 @@
aaudio_stream_state_t mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
- pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
+ pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
- SharedRingBuffer* mUpMessageQueue;
- std::mutex mLockUpMessageQueue;
+ SharedRingBuffer* mUpMessageQueue;
+ std::mutex mLockUpMessageQueue;
- AAudioThread mAAudioThread;
+ AAudioThread mAAudioThread;
// This is used by one thread to tell another thread to exit. So it must be atomic.
- std::atomic<bool> mThreadEnabled;
+ std::atomic<bool> mThreadEnabled;
- aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
- int32_t mFramesPerBurst = 0;
- int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
- int32_t mSampleRate = AAUDIO_UNSPECIFIED;
- int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED;
- uid_t mOwnerUserId = -1;
- pid_t mOwnerProcessId = -1;
+ aaudio_format_t mAudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
+ int32_t mFramesPerBurst = 0;
+ int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+ int32_t mSampleRate = AAUDIO_UNSPECIFIED;
+ int32_t mCapacityInFrames = AAUDIO_UNSPECIFIED;
+ android::AudioClient mMmapClient;
+ audio_port_handle_t mClientHandle = AUDIO_PORT_HANDLE_NONE;
+
private:
- aaudio_handle_t mHandle = -1;
+ aaudio_handle_t mHandle = -1;
};
} /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamExclusive.h b/services/oboeservice/AAudioServiceStreamExclusive.h
deleted file mode 100644
index db382a3..0000000
--- a/services/oboeservice/AAudioServiceStreamExclusive.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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 AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-#define AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
-
-#include "AAudioServiceStreamMMAP.h"
-
-namespace aaudio {
-
-/**
- * Exclusive mode stream in the AAudio service.
- *
- * This is currently a stub.
- * We may move code from AAudioServiceStreamMMAP into this class.
- * If not, then it will be removed.
- */
-class AAudioServiceStreamExclusive : public AAudioServiceStreamMMAP {
-
-public:
- AAudioServiceStreamExclusive() {};
- virtual ~AAudioServiceStreamExclusive() = default;
-};
-
-} /* namespace aaudio */
-
-#endif //AAUDIO_AAUDIO_SERVICE_STREAM_EXCLUSIVE_H
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 1b80486..68be3c3 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamMMAP"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -41,19 +41,21 @@
* Service Stream that uses an MMAP buffer.
*/
-AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(uid_t serviceUid)
+AAudioServiceStreamMMAP::AAudioServiceStreamMMAP(const android::AudioClient& serviceClient,
+ bool inService)
: AAudioServiceStreamBase()
, mMmapStreamCallback(new MyMmapStreamCallback(*this))
, mPreviousFrameCounter(0)
, mMmapStream(nullptr)
- , mCachedUserId(serviceUid) {
+ , mServiceClient(serviceClient)
+ , mInService(inService) {
}
aaudio_result_t AAudioServiceStreamMMAP::close() {
if (mState == AAUDIO_STREAM_STATE_CLOSED) {
return AAUDIO_OK;
}
-
+ stop();
if (mMmapStream != 0) {
mMmapStream.clear(); // TODO review. Is that all we have to do?
// Apparently the above close is asynchronous. An attempt to open a new device
@@ -90,9 +92,6 @@
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
audio_port_handle_t deviceId = configurationInput.getDeviceId();
-
- mMmapClient.clientUid = request.getUserId();
- mMmapClient.clientPid = request.getProcessId();
aaudio_direction_t direction = request.getDirection();
// Fill in config
@@ -123,8 +122,6 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
- mMmapClient.packageName.setTo(String16("aaudio_service")); // FIXME what should we do here?
-
MmapStreamInterface::stream_direction_t streamDirection = (direction == AAUDIO_DIRECTION_OUTPUT)
? MmapStreamInterface::DIRECTION_OUTPUT : MmapStreamInterface::DIRECTION_INPUT;
@@ -135,7 +132,8 @@
mMmapClient,
&deviceId,
mMmapStreamCallback,
- mMmapStream);
+ mMmapStream,
+ &mPortHandle);
if (status != OK) {
ALOGE("openMmapStream returned status %d", status);
return AAUDIO_ERROR_UNAVAILABLE;
@@ -172,7 +170,7 @@
mCapacityInFrames = -mCapacityInFrames;
} else {
// exclusive mode is only possible if the final fd destination is inside audioserver
- if ((mMmapClient.clientUid != mCachedUserId) &&
+ if ((mMmapClient.clientUid != mServiceClient.clientUid) &&
configurationInput.getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
// Fallback is handled by caller but indicate what is possible in case
// this is used in the future
@@ -223,15 +221,21 @@
* Start the flow of data.
*/
aaudio_result_t AAudioServiceStreamMMAP::start() {
+ if (isRunning()) {
+ return AAUDIO_OK;
+ }
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result;
- status_t status = mMmapStream->start(mMmapClient, &mPortHandle);
+ status_t status = mMmapStream->start(mServiceClient, &mPortHandle);
if (status != OK) {
ALOGE("AAudioServiceStreamMMAP::start() mMmapStream->start() returned %d", status);
disconnect();
result = AAudioConvert_androidToAAudioResult(status);
} else {
result = AAudioServiceStreamBase::start();
+ if (!mInService && result == AAUDIO_OK) {
+ startClient(mMmapClient, &mClientHandle);
+ }
}
return result;
}
@@ -240,18 +244,28 @@
* Stop the flow of data such that start() can resume with loss of data.
*/
aaudio_result_t AAudioServiceStreamMMAP::pause() {
+ if (!isRunning()) {
+ return AAUDIO_OK;
+ }
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
aaudio_result_t result1 = AAudioServiceStreamBase::pause();
+ if (!mInService) {
+ stopClient(mClientHandle);
+ }
status_t status = mMmapStream->stop(mPortHandle);
mFramesRead.reset32();
return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
}
aaudio_result_t AAudioServiceStreamMMAP::stop() {
+ if (!isRunning()) {
+ return AAUDIO_OK;
+ }
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-
aaudio_result_t result1 = AAudioServiceStreamBase::stop();
+ if (!mInService) {
+ stopClient(mClientHandle);
+ }
aaudio_result_t status = mMmapStream->stop(mPortHandle);
mFramesRead.reset32();
return (result1 != AAUDIO_OK) ? result1 : AAudioConvert_androidToAAudioResult(status);
@@ -266,6 +280,15 @@
return AAudioServiceStreamBase::flush();;
}
+aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle) {
+ return AAudioConvert_androidToAAudioResult(mMmapStream->start(client, clientHandle));
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::stopClient(audio_port_handle_t clientHandle) {
+ return AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
+}
+
aaudio_result_t AAudioServiceStreamMMAP::getFreeRunningPosition(int64_t *positionFrames,
int64_t *timeNanos) {
struct audio_mmap_position position;
@@ -301,11 +324,11 @@
void AAudioServiceStreamMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
ALOGD("AAudioServiceStreamMMAP::onRoutingChanged() called with %d, old = %d",
- deviceId, mPortHandle);
- if (mPortHandle > 0 && mPortHandle != deviceId) {
+ deviceId, mDeviceId);
+ if (mDeviceId != AUDIO_PORT_HANDLE_NONE && mDeviceId != deviceId) {
disconnect();
}
- mPortHandle = deviceId;
+ mDeviceId = deviceId;
};
/**
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 257bea9..533e5a8 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -43,7 +43,7 @@
, public android::MmapStreamCallback {
public:
- AAudioServiceStreamMMAP(uid_t serviceUid);
+ AAudioServiceStreamMMAP(const android::AudioClient& serviceClient, bool inService);
virtual ~AAudioServiceStreamMMAP() = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
@@ -77,6 +77,11 @@
aaudio_result_t close() override;
+ virtual aaudio_result_t startClient(const android::AudioClient& client,
+ audio_port_handle_t *clientHandle);
+
+ virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle);
+
/**
* Send a MMAP/NOIRQ buffer timestamp to the client.
*/
@@ -131,9 +136,10 @@
// Interface to the AudioFlinger MMAP support.
android::sp<android::MmapStreamInterface> mMmapStream;
struct audio_mmap_buffer_info mMmapBufferinfo;
- android::MmapStreamInterface::Client mMmapClient;
- audio_port_handle_t mPortHandle = -1; // TODO review best default
- uid_t mCachedUserId = -1;
+ audio_port_handle_t mPortHandle = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
+ android::AudioClient mServiceClient;
+ bool mInService = false;
};
} // namespace aaudio
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 8bb34d1..fe488cb 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "AAudioService"
+#define LOG_TAG "AAudioServiceStreamShared"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
@@ -191,6 +191,9 @@
* An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
*/
aaudio_result_t AAudioServiceStreamShared::start() {
+ if (isRunning()) {
+ return AAUDIO_OK;
+ }
AAudioServiceEndpoint *endpoint = mServiceEndpoint;
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
@@ -201,7 +204,10 @@
ALOGE("AAudioServiceStreamShared::start() mServiceEndpoint returned %d", result);
disconnect();
} else {
- result = AAudioServiceStreamBase::start();
+ result = endpoint->getStreamInternal()->startClient(mMmapClient, &mClientHandle);
+ if (result == AAUDIO_OK) {
+ result = AAudioServiceStreamBase::start();
+ }
}
return result;
}
@@ -212,10 +218,14 @@
* An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
*/
aaudio_result_t AAudioServiceStreamShared::pause() {
+ if (!isRunning()) {
+ return AAUDIO_OK;
+ }
AAudioServiceEndpoint *endpoint = mServiceEndpoint;
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
+ endpoint->getStreamInternal()->stopClient(mClientHandle);
aaudio_result_t result = endpoint->stopStream(this);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamShared::pause() mServiceEndpoint returned %d", result);
@@ -225,10 +235,14 @@
}
aaudio_result_t AAudioServiceStreamShared::stop() {
+ if (!isRunning()) {
+ return AAUDIO_OK;
+ }
AAudioServiceEndpoint *endpoint = mServiceEndpoint;
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
+ endpoint->getStreamInternal()->stopClient(mClientHandle);
aaudio_result_t result = endpoint->stopStream(this);
if (result != AAUDIO_OK) {
ALOGE("AAudioServiceStreamShared::stop() mServiceEndpoint returned %d", result);
@@ -248,7 +262,7 @@
return AAUDIO_ERROR_INVALID_STATE;
}
if (mState != AAUDIO_STREAM_STATE_PAUSED) {
- ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
+ ALOGE("AAudioServiceStreamShared::flush() stream not paused, state = %s",
AAudio_convertStreamStateToText(mState));
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -261,11 +275,12 @@
return AAUDIO_OK;
}
+ stop();
+
AAudioServiceEndpoint *endpoint = mServiceEndpoint;
if (endpoint == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- endpoint->stopStream(this);
endpoint->unregisterStream(this);
@@ -277,7 +292,6 @@
delete mAudioDataQueue;
mAudioDataQueue = nullptr;
}
-
return AAudioServiceStreamBase::close();
}
@@ -293,9 +307,6 @@
return AAUDIO_OK;
}
-void AAudioServiceStreamShared::onStop() {
-}
-
void AAudioServiceStreamShared::markTransferTime(int64_t nanoseconds) {
mMarkedPosition = mAudioDataQueue->getFifoBuffer()->getReadCounter();
mMarkedTime = nanoseconds;
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 742c5af..6b67337 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -87,8 +87,6 @@
*/
void markTransferTime(int64_t nanoseconds);
- void onStop();
-
protected:
aaudio_result_t getDownDataDescription(AudioEndpointParcelable &parcelable) override;