Merge "Sample rate 0 means a route-dependent rate" into nyc-dev
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() &&