Sample rate 0 means a route-dependent rate
Remove check for primary _output_ [sic] sampling rate for fast capture.
Clean up AudioRecord handling of frame count and sample rate.
Clean up AudioTrack handling of notification period updates.
Make AudioRecord and AudioTrack more similar in order of operation, comments, and whitespace.
Bug: 25641253
Bug: 21019153
Change-Id: I24a6677945987fc39a9bf93f70357e4bc7410f98
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 521557d..b0bc2d0 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -145,7 +145,7 @@
* Parameters:
*
* inputSource: Select the audio input to record from (e.g. AUDIO_SOURCE_DEFAULT).
- * sampleRate: Data sink sampling rate in Hz.
+ * sampleRate: Data sink sampling rate in Hz. Zero means to use the source sample rate.
* format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
* 16 bits per sample).
* channelMask: Channel mask, such that audio_is_input_channel(channelMask) is true.
@@ -258,6 +258,7 @@
bool stopped() const;
/* Return the sink sample rate for this record track in Hz.
+ * If specified as zero in constructor or set(), this will be the source sample rate.
* Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
*/
uint32_t getSampleRate() const { return mSampleRate; }
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index a4b8571..e0fb603 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -167,7 +167,10 @@
*
* streamType: Select the type of audio stream this track is attached to
* (e.g. AUDIO_STREAM_MUSIC).
- * sampleRate: Data source sampling rate in Hz.
+ * sampleRate: Data source sampling rate in Hz. Zero means to use the sink sample rate.
+ * A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
+ * 0 will not work with current policy implementation for direct output
+ * selection where an exact match is needed for sampling rate.
* format: Audio format. For mixed tracks, any PCM format supported by server is OK.
* For direct and offloaded tracks, the possible format(s) depends on the
* output sink.
@@ -395,11 +398,14 @@
status_t setAuxEffectSendLevel(float level);
void getAuxEffectSendLevel(float* level) const;
- /* Set source sample rate for this track in Hz, mostly used for games' sound effects
+ /* Set source sample rate for this track in Hz, mostly used for games' sound effects.
+ * Zero is not permitted.
*/
status_t setSampleRate(uint32_t sampleRate);
- /* Return current source sample rate in Hz */
+ /* Return current source sample rate in Hz.
+ * If specified as zero in constructor or set(), this will be the sink sample rate.
+ */
uint32_t getSampleRate() const;
/* Return the original source sample rate in Hz. This corresponds to the sample rate
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1701f80..fef20d9 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -191,10 +191,6 @@
mAttributes.source, mAttributes.flags, mAttributes.tags);
}
- if (sampleRate == 0) {
- ALOGE("Invalid sample rate %u", sampleRate);
- return BAD_VALUE;
- }
mSampleRate = sampleRate;
// these below should probably come from the audioFlinger too...
@@ -517,28 +513,72 @@
return NO_INIT;
}
- // Fast tracks must be at the primary _output_ [sic] sampling rate,
- // because there is currently no concept of a primary input sampling rate
- uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate();
- if (afSampleRate == 0) {
- ALOGW("getPrimaryOutputSamplingRate failed");
+ if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ }
+ audio_io_handle_t input;
+
+ status_t status;
+ status = AudioSystem::getInputForAttr(&mAttributes, &input,
+ (audio_session_t)mSessionId,
+ // FIXME compare to AudioTrack
+ IPCThreadState::self()->getCallingUid(),
+ mSampleRate, mFormat, mChannelMask,
+ mFlags, mSelectedDeviceId);
+
+ if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE) {
+ ALOGE("Could not get audio input for session %d, record source %d, sample rate %u, "
+ "format %#x, channel mask %#x, flags %#x",
+ mSessionId, mAttributes.source, mSampleRate, mFormat, mChannelMask, mFlags);
+ return BAD_VALUE;
+ }
+ {
+ // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
+ // we must release it ourselves if anything goes wrong.
+
+#if 0
+ size_t afFrameCount;
+ status = AudioSystem::getFrameCount(input, &afFrameCount);
+ if (status != NO_ERROR) {
+ ALOGE("getFrameCount(input=%d) status %d", input, status);
+ goto release;
+ }
+#endif
+
+ uint32_t afSampleRate;
+ status = AudioSystem::getSamplingRate(input, &afSampleRate);
+ if (status != NO_ERROR) {
+ ALOGE("getSamplingRate(input=%d) status %d", input, status);
+ goto release;
+ }
+ if (mSampleRate == 0) {
+ mSampleRate = afSampleRate;
}
// Client can only express a preference for FAST. Server will perform additional tests.
- if ((mFlags & AUDIO_INPUT_FLAG_FAST) && !((
+ if (mFlags & AUDIO_INPUT_FLAG_FAST) {
+ bool useCaseAllowed =
// either of these use cases:
// use case 1: callback transfer mode
(mTransfer == TRANSFER_CALLBACK) ||
// use case 2: obtain/release mode
- (mTransfer == TRANSFER_OBTAIN)) &&
- // matching sample rate
- (mSampleRate == afSampleRate))) {
- ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, primary %u Hz",
+ (mTransfer == TRANSFER_OBTAIN);
+ // sample rates must also match
+ bool fastAllowed = useCaseAllowed && (mSampleRate == afSampleRate);
+ if (!fastAllowed) {
+ ALOGW("AUDIO_INPUT_FLAG_FAST denied by client; transfer %d, "
+ "track %u Hz, input %u Hz",
mTransfer, mSampleRate, afSampleRate);
- // once denied, do not request again if IAudioRecord is re-created
- mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
+ // once denied, do not request again if IAudioRecord is re-created
+ mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
+ }
}
+ // The notification frame count is the period between callbacks, as suggested by the client
+ // but moderated by the server. For record, the calculations are done entirely on server side.
+ size_t notificationFrames = mNotificationFramesReq;
+ size_t frameCount = mReqFrameCount;
+
IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
pid_t tid = -1;
@@ -549,35 +589,10 @@
}
}
- if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
- }
-
- audio_io_handle_t input;
- status_t status = AudioSystem::getInputForAttr(&mAttributes, &input,
- (audio_session_t)mSessionId,
- IPCThreadState::self()->getCallingUid(),
- mSampleRate, mFormat, mChannelMask,
- mFlags, mSelectedDeviceId);
-
- if (status != NO_ERROR) {
- ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
- "channel mask %#x, session %d, flags %#x",
- mAttributes.source, mSampleRate, mFormat, mChannelMask, mSessionId, mFlags);
- return BAD_VALUE;
- }
- {
- // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
- // we must release it ourselves if anything goes wrong.
-
- size_t frameCount = mReqFrameCount;
size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
// but we will still need the original value also
int originalSessionId = mSessionId;
- // The notification frame count is the period between callbacks, as suggested by the server.
- size_t notificationFrames = mNotificationFramesReq;
-
sp<IMemory> iMem; // for cblk
sp<IMemory> bufferMem;
sp<IAudioRecord> record = audioFlinger->openRecord(input,
@@ -660,11 +675,13 @@
}
}
- // Make sure that application is notified with sufficient margin before overrun
- if (notificationFrames == 0 || notificationFrames > frameCount) {
- ALOGW("Received notificationFrames %zu for frameCount %zu", notificationFrames, frameCount);
+ // Make sure that application is notified with sufficient margin before overrun.
+ // The computation is done on server side.
+ if (mNotificationFramesReq > 0 && notificationFrames != mNotificationFramesReq) {
+ ALOGW("Server adjusted notificationFrames from %u to %zu for frameCount %zu",
+ mNotificationFramesReq, notificationFrames, frameCount);
}
- mNotificationFramesAct = notificationFrames;
+ mNotificationFramesAct = (uint32_t) notificationFrames;
// We retain a copy of the I/O handle, but don't own the reference
mInput = input;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 36c1d10..8e02900 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1192,6 +1192,7 @@
mSampleRate = mAfSampleRate;
mOriginalSampleRate = mAfSampleRate;
}
+
// Client can only express a preference for FAST. Server will perform additional tests.
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
bool useCaseAllowed =
@@ -1207,7 +1208,7 @@
// sample rates must also match
bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
if (!fastAllowed) {
- ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d,"
+ ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, "
"track %u Hz, output %u Hz",
mTransfer, mSampleRate, mAfSampleRate);
// once denied, do not request again if IAudioTrack is re-created
@@ -1215,13 +1216,6 @@
}
}
- // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
- // n = 1 fast track with single buffering; nBuffering is ignored
- // n = 2 fast track with double buffering
- // n = 2 normal track, (including those with sample rate conversion)
- // n >= 3 very high latency or very small notification interval (unused).
- const uint32_t nBuffering = 2;
-
mNotificationFramesAct = mNotificationFramesReq;
size_t frameCount = mReqFrameCount;
@@ -1320,6 +1314,7 @@
// AudioFlinger now owns the reference to the I/O handle,
// so we are no longer responsible for releasing it.
+ // FIXME compare to AudioRecord
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
@@ -1383,14 +1378,25 @@
//return NO_INIT;
}
}
- // Make sure that application is notified with sufficient margin before underrun
+
+ // Make sure that application is notified with sufficient margin before underrun.
+ // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
+ // n = 1 fast track with single buffering; nBuffering is ignored
+ // n = 2 fast track with double buffering
+ // n = 2 normal track, (including those with sample rate conversion)
+ // n >= 3 very high latency or very small notification interval (unused).
+ // FIXME Move the computation from client side to server side,
+ // and allow nBuffering to be larger than 1 for OpenSL ES, like it can be for Java.
if (mSharedBuffer == 0 && audio_is_linear_pcm(mFormat)) {
- // Theoretically double-buffering is not required for fast tracks,
- // due to tighter scheduling. But in practice, to accommodate kernels with
- // scheduling jitter, and apps with computation jitter, we use double-buffering
- // for fast tracks just like normal streaming tracks.
- if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount / nBuffering) {
- mNotificationFramesAct = frameCount / nBuffering;
+ size_t maxNotificationFrames = frameCount;
+ if (!(trackFlags & IAudioFlinger::TRACK_FAST)) {
+ const uint32_t nBuffering = 2;
+ maxNotificationFrames /= nBuffering;
+ }
+ if (mNotificationFramesAct == 0 || mNotificationFramesAct > maxNotificationFrames) {
+ ALOGW("Client adjusted notificationFrames from %u to %zu for frameCount %zu",
+ mNotificationFramesAct, maxNotificationFrames, frameCount);
+ mNotificationFramesAct = (uint32_t) maxNotificationFrames;
}
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 273cfe1..fb1ece4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -564,6 +564,7 @@
PlaybackThread *srcThread,
PlaybackThread *dstThread,
bool reRegister);
+
// return thread associated with primary hardware device, or NULL
PlaybackThread *primaryPlaybackThread_l() const;
audio_devices_t primaryOutputDevice_l() const;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a684c1e..2bc3596 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6249,11 +6249,11 @@
((frameCount == 0) || (frameCount == mPipeFramesP2)) &&
// PCM data
audio_is_linear_pcm(format) &&
- // native format
+ // hardware format
(format == mFormat) &&
- // native channel mask
+ // hardware channel mask
(channelMask == mChannelMask) &&
- // native hardware sample rate
+ // hardware sample rate
(sampleRate == mSampleRate) &&
// record thread has an associated fast capture
hasFastCapture() &&