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) {
|
jint sampleRateInHz) {
|
||||||
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
|
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
|
||||||
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
|
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
|
||||||
|
|
||||||
if (lpTrack) {
|
if (lpTrack) {
|
||||||
lpTrack->setSampleRate(sampleRateInHz);
|
return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
|
||||||
} else {
|
} else {
|
||||||
jniThrowException(env, "java/lang/IllegalStateException",
|
jniThrowException(env, "java/lang/IllegalStateException",
|
||||||
"Unable to retrieve AudioTrack pointer for setSampleRate()");
|
"Unable to retrieve AudioTrack pointer for setSampleRate()");
|
||||||
|
return AUDIOTRACK_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,7 +789,7 @@ static JNINativeMethod gMethods[] = {
|
|||||||
{"native_get_native_frame_count",
|
{"native_get_native_frame_count",
|
||||||
"()I", (void *)android_media_AudioTrack_get_native_frame_count},
|
"()I", (void *)android_media_AudioTrack_get_native_frame_count},
|
||||||
{"native_set_playback_rate",
|
{"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",
|
{"native_get_playback_rate",
|
||||||
"()I", (void *)android_media_AudioTrack_get_playback_rate},
|
"()I", (void *)android_media_AudioTrack_get_playback_rate},
|
||||||
{"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
|
{"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
|
||||||
|
|||||||
@@ -197,7 +197,6 @@ public:
|
|||||||
|
|
||||||
/* getters, see constructor */
|
/* getters, see constructor */
|
||||||
|
|
||||||
uint32_t sampleRate() const;
|
|
||||||
int format() const;
|
int format() const;
|
||||||
int channelCount() const;
|
int channelCount() const;
|
||||||
uint32_t frameCount() const;
|
uint32_t frameCount() const;
|
||||||
@@ -217,7 +216,7 @@ public:
|
|||||||
status_t stop();
|
status_t stop();
|
||||||
bool stopped() const;
|
bool stopped() const;
|
||||||
|
|
||||||
/* get sample rate for this track
|
/* get sample rate for this record track
|
||||||
*/
|
*/
|
||||||
uint32_t getSampleRate();
|
uint32_t getSampleRate();
|
||||||
|
|
||||||
@@ -323,7 +322,6 @@ private:
|
|||||||
sp<ClientRecordThread> mClientRecordThread;
|
sp<ClientRecordThread> mClientRecordThread;
|
||||||
Mutex mRecordThreadLock;
|
Mutex mRecordThreadLock;
|
||||||
|
|
||||||
uint32_t mSampleRate;
|
|
||||||
uint32_t mFrameCount;
|
uint32_t mFrameCount;
|
||||||
|
|
||||||
audio_track_cblk_t* mCblk;
|
audio_track_cblk_t* mCblk;
|
||||||
|
|||||||
@@ -201,7 +201,6 @@ public:
|
|||||||
/* getters, see constructor */
|
/* getters, see constructor */
|
||||||
|
|
||||||
int streamType() const;
|
int streamType() const;
|
||||||
uint32_t sampleRate() const;
|
|
||||||
int format() const;
|
int format() const;
|
||||||
int channelCount() const;
|
int channelCount() const;
|
||||||
uint32_t frameCount() const;
|
uint32_t frameCount() const;
|
||||||
@@ -246,7 +245,7 @@ public:
|
|||||||
|
|
||||||
/* set sample rate for this track, mostly used for games' sound effects
|
/* set sample rate for this track, mostly used for games' sound effects
|
||||||
*/
|
*/
|
||||||
void setSampleRate(int sampleRate);
|
status_t setSampleRate(int sampleRate);
|
||||||
uint32_t getSampleRate();
|
uint32_t getSampleRate();
|
||||||
|
|
||||||
/* Enables looping and sets the start and end points of looping.
|
/* 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)
|
#define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO)
|
||||||
// Maximum cumulated timeout milliseconds before restarting audioflinger thread
|
// 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
|
#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];
|
uint16_t volume[2];
|
||||||
uint32_t volumeLR;
|
uint32_t volumeLR;
|
||||||
};
|
};
|
||||||
uint16_t sampleRate;
|
uint32_t sampleRate;
|
||||||
uint16_t channels;
|
uint8_t channels;
|
||||||
int16_t flowControlFlag; // underrun (out) or overrrun (in) indication
|
uint8_t flowControlFlag; // underrun (out) or overrrun (in) indication
|
||||||
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
|
uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord
|
||||||
uint8_t forceReady;
|
uint8_t forceReady;
|
||||||
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
|
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
|
||||||
|
|||||||
@@ -1281,7 +1281,7 @@ sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
|
|||||||
status_t lStatus;
|
status_t lStatus;
|
||||||
|
|
||||||
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
|
// 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);
|
LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
|
||||||
lStatus = BAD_VALUE;
|
lStatus = BAD_VALUE;
|
||||||
goto Exit;
|
goto Exit;
|
||||||
@@ -1596,8 +1596,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
|
|||||||
new(mCblk) audio_track_cblk_t();
|
new(mCblk) audio_track_cblk_t();
|
||||||
// clear all buffers
|
// clear all buffers
|
||||||
mCblk->frameCount = frameCount;
|
mCblk->frameCount = frameCount;
|
||||||
mCblk->sampleRate = (uint16_t)sampleRate;
|
mCblk->sampleRate = sampleRate;
|
||||||
mCblk->channels = (uint16_t)channelCount;
|
mCblk->channels = (uint8_t)channelCount;
|
||||||
if (sharedBuffer == 0) {
|
if (sharedBuffer == 0) {
|
||||||
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||||
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
||||||
@@ -1620,8 +1620,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase(
|
|||||||
new(mCblk) audio_track_cblk_t();
|
new(mCblk) audio_track_cblk_t();
|
||||||
// clear all buffers
|
// clear all buffers
|
||||||
mCblk->frameCount = frameCount;
|
mCblk->frameCount = frameCount;
|
||||||
mCblk->sampleRate = (uint16_t)sampleRate;
|
mCblk->sampleRate = sampleRate;
|
||||||
mCblk->channels = (uint16_t)channelCount;
|
mCblk->channels = (uint8_t)channelCount;
|
||||||
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||||
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t));
|
||||||
// Force underrun condition to avoid false underrun callback until first data is
|
// 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 {
|
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 {
|
void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
|
||||||
@@ -2267,12 +2267,6 @@ sp<IAudioRecord> AudioFlinger::openRecord(
|
|||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampleRate > MAX_SAMPLE_RATE) {
|
|
||||||
LOGE("Sample rate out of range");
|
|
||||||
lStatus = BAD_VALUE;
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAudioRecordThread == 0) {
|
if (mAudioRecordThread == 0) {
|
||||||
LOGE("Audio record thread not started");
|
LOGE("Audio record thread not started");
|
||||||
lStatus = NO_INIT;
|
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
|
* Returns the current playback rate in Hz.
|
||||||
* with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent.
|
|
||||||
*/
|
*/
|
||||||
public int getPlaybackRate() {
|
public int getPlaybackRate() {
|
||||||
return native_get_playback_rate();
|
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
|
* 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
|
* 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
|
* 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.
|
* last twice as long, but will also result in a negative pitch shift.
|
||||||
* The current implementation supports a maximum sample rate of 64kHz.
|
* The valid sample rate range if from 1Hz to twice the value returned by
|
||||||
* Use {@link #getSampleRate()} to check the rate actually used in hardware after
|
* {@link #getNativeOutputSampleRate(int)}.
|
||||||
* potential clamping.
|
|
||||||
* @param sampleRateInHz the sample rate expressed in Hz
|
* @param sampleRateInHz the sample rate expressed in Hz
|
||||||
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
|
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
|
||||||
* {@link #ERROR_INVALID_OPERATION}
|
* {@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) {
|
public int setPlaybackRate(int sampleRateInHz) {
|
||||||
if (mState != STATE_INITIALIZED) {
|
if (mState != STATE_INITIALIZED) {
|
||||||
return ERROR_INVALID_OPERATION;
|
return ERROR_INVALID_OPERATION;
|
||||||
@@ -670,8 +664,7 @@ public class AudioTrack
|
|||||||
if (sampleRateInHz <= 0) {
|
if (sampleRateInHz <= 0) {
|
||||||
return ERROR_BAD_VALUE;
|
return ERROR_BAD_VALUE;
|
||||||
}
|
}
|
||||||
native_set_playback_rate(sampleRateInHz);
|
return native_set_playback_rate(sampleRateInHz);
|
||||||
return SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1031,7 +1024,7 @@ public class AudioTrack
|
|||||||
|
|
||||||
private native final void native_setVolume(float leftVolume, float rightVolume);
|
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_set_playback_rate(int sampleRateInHz);
|
||||||
private native final int native_get_playback_rate();
|
private native final int native_get_playback_rate();
|
||||||
|
|
||||||
private native final int native_set_marker_pos(int marker);
|
private native final int native_set_marker_pos(int marker);
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ status_t AudioRecord::set(
|
|||||||
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
|
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
|
||||||
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
|
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
|
||||||
mCblk->out = 0;
|
mCblk->out = 0;
|
||||||
mSampleRate = sampleRate;
|
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
// Update buffer size in case it has been limited by AudioFlinger during track creation
|
// Update buffer size in case it has been limited by AudioFlinger during track creation
|
||||||
mFrameCount = mCblk->frameCount;
|
mFrameCount = mCblk->frameCount;
|
||||||
@@ -196,7 +195,7 @@ status_t AudioRecord::set(
|
|||||||
mRemainingFrames = notificationFrames;
|
mRemainingFrames = notificationFrames;
|
||||||
mUserData = user;
|
mUserData = user;
|
||||||
// TODO: add audio hardware input latency here
|
// TODO: add audio hardware input latency here
|
||||||
mLatency = (1000*mFrameCount) / mSampleRate;
|
mLatency = (1000*mFrameCount) / sampleRate;
|
||||||
mMarkerPosition = 0;
|
mMarkerPosition = 0;
|
||||||
mMarkerReached = false;
|
mMarkerReached = false;
|
||||||
mNewPosition = 0;
|
mNewPosition = 0;
|
||||||
@@ -218,11 +217,6 @@ uint32_t AudioRecord::latency() const
|
|||||||
return mLatency;
|
return mLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AudioRecord::sampleRate() const
|
|
||||||
{
|
|
||||||
return mSampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioRecord::format() const
|
int AudioRecord::format() const
|
||||||
{
|
{
|
||||||
return mFormat;
|
return mFormat;
|
||||||
@@ -321,6 +315,11 @@ bool AudioRecord::stopped() const
|
|||||||
return !mActive;
|
return !mActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t AudioRecord::getSampleRate()
|
||||||
|
{
|
||||||
|
return mCblk->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
status_t AudioRecord::setMarkerPosition(uint32_t marker)
|
status_t AudioRecord::setMarkerPosition(uint32_t marker)
|
||||||
{
|
{
|
||||||
if (mCbf == 0) return INVALID_OPERATION;
|
if (mCbf == 0) return INVALID_OPERATION;
|
||||||
|
|||||||
@@ -243,7 +243,6 @@ status_t AudioTrack::set(
|
|||||||
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
|
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
|
||||||
mVolume[LEFT] = 1.0f;
|
mVolume[LEFT] = 1.0f;
|
||||||
mVolume[RIGHT] = 1.0f;
|
mVolume[RIGHT] = 1.0f;
|
||||||
mSampleRate = sampleRate;
|
|
||||||
mStreamType = streamType;
|
mStreamType = streamType;
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
mChannelCount = channelCount;
|
mChannelCount = channelCount;
|
||||||
@@ -254,7 +253,7 @@ status_t AudioTrack::set(
|
|||||||
mNotificationFrames = notificationFrames;
|
mNotificationFrames = notificationFrames;
|
||||||
mRemainingFrames = notificationFrames;
|
mRemainingFrames = notificationFrames;
|
||||||
mUserData = user;
|
mUserData = user;
|
||||||
mLatency = afLatency + (1000*mFrameCount) / mSampleRate;
|
mLatency = afLatency + (1000*mFrameCount) / sampleRate;
|
||||||
mLoopCount = 0;
|
mLoopCount = 0;
|
||||||
mMarkerPosition = 0;
|
mMarkerPosition = 0;
|
||||||
mMarkerReached = false;
|
mMarkerReached = false;
|
||||||
@@ -281,11 +280,6 @@ int AudioTrack::streamType() const
|
|||||||
return mStreamType;
|
return mStreamType;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AudioTrack::sampleRate() const
|
|
||||||
{
|
|
||||||
return mSampleRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AudioTrack::format() const
|
int AudioTrack::format() const
|
||||||
{
|
{
|
||||||
return mFormat;
|
return mFormat;
|
||||||
@@ -438,24 +432,23 @@ void AudioTrack::getVolume(float* left, float* right)
|
|||||||
*right = mVolume[RIGHT];
|
*right = mVolume[RIGHT];
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioTrack::setSampleRate(int rate)
|
status_t AudioTrack::setSampleRate(int rate)
|
||||||
{
|
{
|
||||||
int afSamplingRate;
|
int afSamplingRate;
|
||||||
|
|
||||||
if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
|
if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
|
||||||
return;
|
return NO_INIT;
|
||||||
}
|
}
|
||||||
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
|
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
|
||||||
if (rate <= 0) rate = 1;
|
if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
|
||||||
if (rate > afSamplingRate*2) rate = afSamplingRate*2;
|
|
||||||
if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
|
|
||||||
|
|
||||||
mCblk->sampleRate = (uint16_t)rate;
|
mCblk->sampleRate = rate;
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AudioTrack::getSampleRate()
|
uint32_t AudioTrack::getSampleRate()
|
||||||
{
|
{
|
||||||
return uint32_t(mCblk->sampleRate);
|
return mCblk->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
|
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);
|
result.append(buffer);
|
||||||
snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
|
snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount);
|
||||||
result.append(buffer);
|
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);
|
result.append(buffer);
|
||||||
snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
|
snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency);
|
||||||
result.append(buffer);
|
result.append(buffer);
|
||||||
|
|||||||
Reference in New Issue
Block a user