aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
{
+ // Call here as well because the AAudioService will call this without calling build().
+ aaudio_result_t result = builder.validate();
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
// Copy parameters from the Builder because the Builder may be deleted after this call.
mSamplesPerFrame = builder.getSamplesPerFrame();
mSampleRate = builder.getSampleRate();
ALOGI("AudioStream::open() device = %d, perfMode = %d, callbackFrames = %d",
mDeviceId, mPerformanceMode, mFramesPerDataCallback);
- // Check for values that are ridiculously out of range to prevent math overflow exploits.
- // The service will do a better check.
- if (mSamplesPerFrame < 0 || mSamplesPerFrame > 128) {
- ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
- return AAUDIO_ERROR_OUT_OF_RANGE;
- }
-
- switch(mFormat) {
- case AAUDIO_FORMAT_UNSPECIFIED:
- case AAUDIO_FORMAT_PCM_I16:
- case AAUDIO_FORMAT_PCM_FLOAT:
- break; // valid
- default:
- ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat);
- return AAUDIO_ERROR_INVALID_FORMAT;
- // break;
- }
-
- if (mSampleRate != AAUDIO_UNSPECIFIED && (mSampleRate < 8000 || mSampleRate > 1000000)) {
- ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
- return AAUDIO_ERROR_INVALID_RATE;
- }
-
- switch(mPerformanceMode) {
- case AAUDIO_PERFORMANCE_MODE_NONE:
- case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
- case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
- break;
- default:
- ALOGE("AudioStream::open(): illegal performanceMode %d", mPerformanceMode);
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
- }
return AAUDIO_OK;
}
#define AAUDIO_MMAP_POLICY_DEFAULT AAUDIO_POLICY_NEVER
#define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT AAUDIO_POLICY_NEVER
+// These values are for a pre-check before we ask the lower level service to open a stream.
+// So they are just outside the maximum conceivable range of value,
+// on the edge of being ridiculous.
+// TODO These defines should be moved to a central place in audio.
+#define SAMPLES_PER_FRAME_MIN 1
+// TODO Remove 8 channel limitation.
+#define SAMPLES_PER_FRAME_MAX FCC_8
+#define SAMPLE_RATE_HZ_MIN 8000
+// HDMI supports up to 32 channels at 1536000 Hz.
+#define SAMPLE_RATE_HZ_MAX 1600000
+#define FRAMES_PER_DATA_CALLBACK_MIN 1
+#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024)
+
/*
* AudioStreamBuilder
*/
// Exact behavior is controlled by MMapPolicy.
aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
AudioStream *audioStream = nullptr;
+ if (streamPtr == nullptr) {
+ ALOGE("AudioStreamBuilder::build() streamPtr is null");
+ return AAUDIO_ERROR_NULL;
+ }
*streamPtr = nullptr;
+ aaudio_result_t result = validate();
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
// The API setting is the highest priority.
aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy();
// If not specified then get from a system property.
bool allowMMap = mmapPolicy != AAUDIO_POLICY_NEVER;
bool allowLegacy = mmapPolicy != AAUDIO_POLICY_ALWAYS;
- aaudio_result_t result = builder_createStream(getDirection(), sharingMode,
- allowMMap, &audioStream);
+ result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
if (result == AAUDIO_OK) {
// Open the stream using the parameters from the builder.
result = audioStream->open(*this);
return result;
}
+
+aaudio_result_t AudioStreamBuilder::validate() const {
+
+ // Check for values that are ridiculously out of range to prevent math overflow exploits.
+ // The service will do a better check.
+ if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
+ && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
+ ALOGE("AudioStreamBuilder: channelCount out of range = %d", mSamplesPerFrame);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ if (mDeviceId < 0) {
+ ALOGE("AudioStreamBuilder: deviceId out of range = %d", mDeviceId);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ switch (mSharingMode) {
+ case AAUDIO_SHARING_MODE_EXCLUSIVE:
+ case AAUDIO_SHARING_MODE_SHARED:
+ break;
+ default:
+ ALOGE("AudioStreamBuilder: illegal sharingMode = %d", mSharingMode);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
+ switch (mFormat) {
+ case AAUDIO_FORMAT_UNSPECIFIED:
+ case AAUDIO_FORMAT_PCM_I16:
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ break; // valid
+ default:
+ ALOGE("AudioStreamBuilder: audioFormat not valid = %d", mFormat);
+ return AAUDIO_ERROR_INVALID_FORMAT;
+ // break;
+ }
+
+ switch (mDirection) {
+ case AAUDIO_DIRECTION_INPUT:
+ case AAUDIO_DIRECTION_OUTPUT:
+ break; // valid
+ default:
+ ALOGE("AudioStreamBuilder: direction not valid = %d", mDirection);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
+ if (mSampleRate != AAUDIO_UNSPECIFIED
+ && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
+ ALOGE("AudioStreamBuilder: sampleRate out of range = %d", mSampleRate);
+ return AAUDIO_ERROR_INVALID_RATE;
+ }
+
+ if (mBufferCapacity < 0) {
+ ALOGE("AudioStreamBuilder: bufferCapacity out of range = %d", mBufferCapacity);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ switch (mPerformanceMode) {
+ case AAUDIO_PERFORMANCE_MODE_NONE:
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ break;
+ default:
+ ALOGE("AudioStreamBuilder: illegal performanceMode = %d", mPerformanceMode);
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ // break;
+ }
+
+ // Prevent ridiculous values from causing problems.
+ if (mFramesPerDataCallback != AAUDIO_UNSPECIFIED
+ && (mFramesPerDataCallback < FRAMES_PER_DATA_CALLBACK_MIN
+ || mFramesPerDataCallback > FRAMES_PER_DATA_CALLBACK_MAX)) {
+ ALOGE("AudioStreamBuilder: framesPerDataCallback out of range = %d",
+ mFramesPerDataCallback);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+
+ return AAUDIO_OK;
+}
\ No newline at end of file