Fix issue 1743700: AudioTrack: setPlaybackRate can not set the playback rate to twice of the ouputSR
Store sample rate on 32 bits instead of 16 bits in audio_track_cblk_t. Removed sampleRate() methods from AudioTrack and AudioRecord: replaced by getSampleRate(). AudioTrack::setSampleRate() no returns a status.
This commit is contained in:
@@ -539,16 +539,17 @@ static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobjec
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static void android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
|
||||
static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
|
||||
jint sampleRateInHz) {
|
||||
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
|
||||
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
|
||||
|
||||
if (lpTrack) {
|
||||
lpTrack->setSampleRate(sampleRateInHz);
|
||||
return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
|
||||
} else {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Unable to retrieve AudioTrack pointer for setSampleRate()");
|
||||
return AUDIOTRACK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +789,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{"native_get_native_frame_count",
|
||||
"()I", (void *)android_media_AudioTrack_get_native_frame_count},
|
||||
{"native_set_playback_rate",
|
||||
"(I)V", (void *)android_media_AudioTrack_set_playback_rate},
|
||||
"(I)I", (void *)android_media_AudioTrack_set_playback_rate},
|
||||
{"native_get_playback_rate",
|
||||
"()I", (void *)android_media_AudioTrack_get_playback_rate},
|
||||
{"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
|
||||
|
||||
@@ -197,7 +197,6 @@ public:
|
||||
|
||||
/* getters, see constructor */
|
||||
|
||||
uint32_t sampleRate() const;
|
||||
int format() const;
|
||||
int channelCount() const;
|
||||
uint32_t frameCount() const;
|
||||
@@ -217,7 +216,7 @@ public:
|
||||
status_t stop();
|
||||
bool stopped() const;
|
||||
|
||||
/* get sample rate for this track
|
||||
/* get sample rate for this record track
|
||||
*/
|
||||
uint32_t getSampleRate();
|
||||
|
||||
@@ -323,7 +322,6 @@ private:
|
||||
sp<ClientRecordThread> mClientRecordThread;
|
||||
Mutex mRecordThreadLock;
|
||||
|
||||
uint32_t mSampleRate;
|
||||
uint32_t mFrameCount;
|
||||
|
||||
audio_track_cblk_t* mCblk;
|
||||
|
||||
@@ -201,7 +201,6 @@ public:
|
||||
/* getters, see constructor */
|
||||
|
||||
int streamType() const;
|
||||
uint32_t sampleRate() const;
|
||||
int format() const;
|
||||
int channelCount() const;
|
||||
uint32_t frameCount() const;
|
||||
@@ -246,7 +245,7 @@ public:
|
||||
|
||||
/* set sample rate for this track, mostly used for games' sound effects
|
||||
*/
|
||||
void setSampleRate(int sampleRate);
|
||||
status_t setSampleRate(int sampleRate);
|
||||
uint32_t getSampleRate();
|
||||
|
||||
/* Enables looping and sets the start and end points of looping.
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define MAX_SAMPLE_RATE 65535
|
||||
#define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
|
||||
// Maximum cumulated timeout milliseconds before restarting audioflinger thread
|
||||
#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
|
||||
@@ -55,9 +54,9 @@ struct audio_track_cblk_t
|
||||
uint16_t volume[2];
|
||||
uint32_t volumeLR;
|
||||
};
|
||||
uint16_t sampleRate;
|
||||
uint16_t channels;
|
||||
int16_t flowControlFlag; // underrun (out) or overrrun (in) indication
|
||||
uint32_t sampleRate;
|
||||
uint8_t channels;
|
||||
uint8_t flowControlFlag; // underrun (out) or overrrun (in) indication
|
||||
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
|
||||
uint8_t forceReady;
|
||||
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
|
||||
|
||||
@@ -1281,7 +1281,7 @@ sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
|
||||
status_t lStatus;
|
||||
|
||||
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
|
||||
if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
|
||||
if (sampleRate > mSampleRate*2) {
|
||||
LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
@@ -1596,8 +1596,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
|
||||
new(mCblk) audio_track_cblk_t();
|
||||
// clear all buffers
|
||||
mCblk->frameCount = frameCount;
|
||||
mCblk->sampleRate = (uint16_t)sampleRate;
|
||||
mCblk->channels = (uint16_t)channelCount;
|
||||
mCblk->sampleRate = sampleRate;
|
||||
mCblk->channels = (uint8_t)channelCount;
|
||||
if (sharedBuffer == 0) {
|
||||
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
||||
@@ -1620,8 +1620,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
|
||||
new(mCblk) audio_track_cblk_t();
|
||||
// clear all buffers
|
||||
mCblk->frameCount = frameCount;
|
||||
mCblk->sampleRate = (uint16_t)sampleRate;
|
||||
mCblk->channels = (uint16_t)channelCount;
|
||||
mCblk->sampleRate = sampleRate;
|
||||
mCblk->channels = (uint8_t)channelCount;
|
||||
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
||||
// Force underrun condition to avoid false underrun callback until first data is
|
||||
@@ -1682,7 +1682,7 @@ int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
|
||||
}
|
||||
|
||||
int AudioFlinger::MixerThread::TrackBase::channelCount() const {
|
||||
return mCblk->channels;
|
||||
return (int)mCblk->channels;
|
||||
}
|
||||
|
||||
void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
|
||||
@@ -2267,12 +2267,6 @@ sp<IAudioRecord> AudioFlinger::openRecord(
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (sampleRate > MAX_SAMPLE_RATE) {
|
||||
LOGE("Sample rate out of range");
|
||||
lStatus = BAD_VALUE;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (mAudioRecordThread == 0) {
|
||||
LOGE("Audio record thread not started");
|
||||
lStatus = NO_INIT;
|
||||
|
||||
@@ -425,8 +425,7 @@ public class AudioTrack
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current playback rate in Hz. Note that this rate may differ from the one set
|
||||
* with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent.
|
||||
* Returns the current playback rate in Hz.
|
||||
*/
|
||||
public int getPlaybackRate() {
|
||||
return native_get_playback_rate();
|
||||
@@ -651,18 +650,13 @@ public class AudioTrack
|
||||
* Sets the playback sample rate for this track. This sets the sampling rate at which
|
||||
* the audio data will be consumed and played back, not the original sampling rate of the
|
||||
* content. Setting it to half the sample rate of the content will cause the playback to
|
||||
* last twice as long, but will also result result in a negative pitch shift.
|
||||
* The current implementation supports a maximum sample rate of 64kHz.
|
||||
* Use {@link #getSampleRate()} to check the rate actually used in hardware after
|
||||
* potential clamping.
|
||||
* last twice as long, but will also result in a negative pitch shift.
|
||||
* The valid sample rate range if from 1Hz to twice the value returned by
|
||||
* {@link #getNativeOutputSampleRate(int)}.
|
||||
* @param sampleRateInHz the sample rate expressed in Hz
|
||||
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
|
||||
* {@link #ERROR_INVALID_OPERATION}
|
||||
*/
|
||||
// FIXME: the implementation should support twice the hardware output sample rate
|
||||
// (see {@link #getNativeOutputSampleRate(int)}), but currently
|
||||
// due to the representation of the sample rate in the native layer, the sample rate
|
||||
// is limited to 65535Hz
|
||||
public int setPlaybackRate(int sampleRateInHz) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
return ERROR_INVALID_OPERATION;
|
||||
@@ -670,8 +664,7 @@ public class AudioTrack
|
||||
if (sampleRateInHz <= 0) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
native_set_playback_rate(sampleRateInHz);
|
||||
return SUCCESS;
|
||||
return native_set_playback_rate(sampleRateInHz);
|
||||
}
|
||||
|
||||
|
||||
@@ -1031,8 +1024,8 @@ public class AudioTrack
|
||||
|
||||
private native final void native_setVolume(float leftVolume, float rightVolume);
|
||||
|
||||
private native final void native_set_playback_rate(int sampleRateInHz);
|
||||
private native final int native_get_playback_rate();
|
||||
private native final int native_set_playback_rate(int sampleRateInHz);
|
||||
private native final int native_get_playback_rate();
|
||||
|
||||
private native final int native_set_marker_pos(int marker);
|
||||
private native final int native_get_marker_pos();
|
||||
|
||||
@@ -185,7 +185,6 @@ status_t AudioRecord::set(
|
||||
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
|
||||
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||
mCblk->out = 0;
|
||||
mSampleRate = sampleRate;
|
||||
mFormat = format;
|
||||
// Update buffer size in case it has been limited by AudioFlinger during track creation
|
||||
mFrameCount = mCblk->frameCount;
|
||||
@@ -196,7 +195,7 @@ status_t AudioRecord::set(
|
||||
mRemainingFrames = notificationFrames;
|
||||
mUserData = user;
|
||||
// TODO: add audio hardware input latency here
|
||||
mLatency = (1000*mFrameCount) / mSampleRate;
|
||||
mLatency = (1000*mFrameCount) / sampleRate;
|
||||
mMarkerPosition = 0;
|
||||
mMarkerReached = false;
|
||||
mNewPosition = 0;
|
||||
@@ -218,11 +217,6 @@ uint32_t AudioRecord::latency() const
|
||||
return mLatency;
|
||||
}
|
||||
|
||||
uint32_t AudioRecord::sampleRate() const
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
int AudioRecord::format() const
|
||||
{
|
||||
return mFormat;
|
||||
@@ -321,6 +315,11 @@ bool AudioRecord::stopped() const
|
||||
return !mActive;
|
||||
}
|
||||
|
||||
uint32_t AudioRecord::getSampleRate()
|
||||
{
|
||||
return mCblk->sampleRate;
|
||||
}
|
||||
|
||||
status_t AudioRecord::setMarkerPosition(uint32_t marker)
|
||||
{
|
||||
if (mCbf == 0) return INVALID_OPERATION;
|
||||
|
||||
@@ -243,7 +243,6 @@ status_t AudioTrack::set(
|
||||
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
|
||||
mVolume[LEFT] = 1.0f;
|
||||
mVolume[RIGHT] = 1.0f;
|
||||
mSampleRate = sampleRate;
|
||||
mStreamType = streamType;
|
||||
mFormat = format;
|
||||
mChannelCount = channelCount;
|
||||
@@ -254,7 +253,7 @@ status_t AudioTrack::set(
|
||||
mNotificationFrames = notificationFrames;
|
||||
mRemainingFrames = notificationFrames;
|
||||
mUserData = user;
|
||||
mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
|
||||
mLatency = afLatency + (1000*mFrameCount) / sampleRate;
|
||||
mLoopCount = 0;
|
||||
mMarkerPosition = 0;
|
||||
mMarkerReached = false;
|
||||
@@ -281,11 +280,6 @@ int AudioTrack::streamType() const
|
||||
return mStreamType;
|
||||
}
|
||||
|
||||
uint32_t AudioTrack::sampleRate() const
|
||||
{
|
||||
return mSampleRate;
|
||||
}
|
||||
|
||||
int AudioTrack::format() const
|
||||
{
|
||||
return mFormat;
|
||||
@@ -438,24 +432,23 @@ void AudioTrack::getVolume(float* left, float* right)
|
||||
*right = mVolume[RIGHT];
|
||||
}
|
||||
|
||||
void AudioTrack::setSampleRate(int rate)
|
||||
status_t AudioTrack::setSampleRate(int rate)
|
||||
{
|
||||
int afSamplingRate;
|
||||
|
||||
if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
|
||||
return;
|
||||
return NO_INIT;
|
||||
}
|
||||
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
|
||||
if (rate <= 0) rate = 1;
|
||||
if (rate > afSamplingRate*2) rate = afSamplingRate*2;
|
||||
if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
|
||||
if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
|
||||
|
||||
mCblk->sampleRate = (uint16_t)rate;
|
||||
mCblk->sampleRate = rate;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
uint32_t AudioTrack::getSampleRate()
|
||||
{
|
||||
return uint32_t(mCblk->sampleRate);
|
||||
return mCblk->sampleRate;
|
||||
}
|
||||
|
||||
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
|
||||
@@ -866,7 +859,7 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
|
||||
result.append(buffer);
|
||||
snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted);
|
||||
snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted);
|
||||
result.append(buffer);
|
||||
snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
|
||||
result.append(buffer);
|
||||
|
||||
Reference in New Issue
Block a user