Android(安卓)Audio Subsystem - AudioTrack - write
1.AudioTrack:: write ()
Frameworks/base/media/java/android/media/AudioTrack.java
public intwrite(byte[] audioData, int offsetInBytes, int sizeInBytes) {
if (mState == STATE_UNINITIALIZED) {
return ERROR_INVALID_OPERATION;
}
if ( (audioData == null) ||(offsetInBytes < 0 ) || (sizeInBytes < 0)
|| (offsetInBytes + sizeInBytes< 0) // detect integer overflow
|| (offsetInBytes + sizeInBytes >audioData.length)) {
return ERROR_BAD_VALUE;
}
int ret =native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
if ((mDataLoadMode == MODE_STATIC)
&& (mState ==STATE_NO_STATIC_DATA)
&& (ret > 0)) {
// benign race with respect toother APIs that read mState
mState = STATE_INITIALIZED;
}
return ret;
}
public int write(short[] audioData, intoffsetInShorts, int sizeInShorts) {
if (mState == STATE_UNINITIALIZED) {
return ERROR_INVALID_OPERATION;
}
if ( (audioData == null) ||(offsetInShorts < 0 ) || (sizeInShorts < 0)
|| (offsetInShorts +sizeInShorts < 0) // detect integeroverflow
|| (offsetInShorts +sizeInShorts > audioData.length)) {
return ERROR_BAD_VALUE;
}
int ret =native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
if ((mDataLoadMode == MODE_STATIC)
&& (mState ==STATE_NO_STATIC_DATA)
&& (ret > 0)) {
// benign race with respect toother APIs that read mState
mState = STATE_INITIALIZED;
}
return ret;
}
2.android_media_AudioTrack_native_write_short ()
frameworks/base/core/jni/android_media_AudioTrack.cpp
static jintandroid_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thiz,
jbyteArrayjavaAudioData,
jint offsetInBytes, jint sizeInBytes,
jint javaAudioFormat) {
//ALOGV("android_media_AudioTrack_native_write_byte(offset=%d,sizeInBytes=%d) called",
//offsetInBytes, sizeInBytes);
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
// 从JAVA 环境中得到本地 AudioTrack对象
if (lpTrack == NULL) {
jniThrowException(env,"java/lang/IllegalStateException",
"Unable to retrieve AudioTrackpointer for write()");
return 0;
}
// get the pointer for the audio data fromthe java array
// NOTE: We may useGetPrimitiveArrayCritical() when the JNI implementation changes in such
// a way that it becomes much moreefficient. When doing so, we will have to prevent the
// AudioSystem callback to be called whilein critical section (in case of media server
// process crash for instance)
jbyte* cAudioData = NULL;
if (javaAudioData) {
cAudioData = (jbyte*)env->GetByteArrayElements(javaAudioData, NULL);
if (cAudioData == NULL) {
ALOGE("Error retrieving sourceof audio data to play, can't play");
return 0; // out of memory or no datato load
}
} else {
ALOGE("NULL java array of audiodata to play, can't play");
return 0;
}
jint written =writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
env->ReleaseByteArrayElements(javaAudioData,cAudioData, 0);
//ALOGV("write wrote %d (tried %d)bytes in the native AudioTrack with offset %d",
//(int)written, (int)(sizeInBytes), (int)offsetInBytes);
return written;
}
static jintandroid_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
jshortArray javaAudioData,
jint offsetInShorts, jint sizeInShorts,
jintjavaAudioFormat) {
return(android_media_AudioTrack_native_write_byte(env, thiz,
(jbyteArray) javaAudioData,
offsetInShorts*2, sizeInShorts*2,
javaAudioFormat)
/ 2);
}
3.writeToTrack ()
frameworks/base/core/jni/android_media_AudioTrack.cpp
jintwriteToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte*data,
jint offsetInBytes, jintsizeInBytes) {
// give the data to the native AudioTrackobject (the data starts at the offset)
ssize_t written = 0;
// regular write() or copy the data to theAudioTrack's shared memory?
if (track->sharedBuffer() == 0) {
// stream mode
// 调用本地的write方法
written =track->write(data + offsetInBytes, sizeInBytes);
} else {// static mode
if (audioFormat ==javaAudioTrackFields.PCM16) {
// writing to shared memory, checkfor capacity
if ((size_t)sizeInBytes >track->sharedBuffer()->size()) {
sizeInBytes =track->sharedBuffer()->size();
}
memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes,sizeInBytes);
written = sizeInBytes;
} else if (audioFormat ==javaAudioTrackFields.PCM8) {
// data contains 8bit data we needto expand to 16bit before copying
// to the shared memory
// writing to shared memory, checkfor capacity,
// note that input data will occupy2X the input space due to 8 to 16bit conversion
if (((size_t)sizeInBytes)*2 >track->sharedBuffer()->size()) {
sizeInBytes =track->sharedBuffer()->size() / 2;
}
int count = sizeInBytes;
int16_t *dst = (int16_t*)track->sharedBuffer()->pointer();
const int8_t *src = (const int8_t*)(data + offsetInBytes);
while (count--) {
*dst++ = (int16_t)(*src++^0x80)<< 8;
}
// even though we wrote2*sizeInBytes, we only report sizeInBytes as written to hide
// the 8bit mixer restriction fromthe user of this function
written = sizeInBytes;
}
}
return written;
}
4.说明
一块共享内存
一个控制结构
通过共享内存传递数据
通过控制结构协调生产者和消费者线程
5.AudioTrack::write()
Frameworks/av/media/libmedia/AudioTrack.cpp
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{
if (mSharedBuffer != 0 ||mIsTimed) {
returnINVALID_OPERATION;
}
if (ssize_t(userSize) <0) {
// Sanity-check: useris most-likely passing an error code, and it would
// make the returnvalue ambiguous (actualSize vs error).
ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
buffer,userSize, userSize);
return BAD_VALUE;
}
ALOGV("write %p: %dbytes, mActive=%d", this, userSize, mActive);
if (userSize == 0) {
return 0;
}
// acquire a strongreference on the IMemory and IAudioTrack so that they cannot be destroyed
// while we are accessing the cblk
mLock.lock();
sp<IAudioTrack> audioTrack = mAudioTrack;
sp<IMemory> iMem = mCblkMemory;
mLock.unlock();
// since mLock is unlockedthe IAudioTrack and shared memory may be re-created,
// so all cblk referencesmight still refer to old shared memory, but that should be benign
ssize_t written = 0;
const int8_t *src = (constint8_t *)buffer;
Buffer audioBuffer;
size_t frameSz =frameSize();
do {
audioBuffer.frameCount= userSize/frameSz;
status_t err = obtainBuffer(&audioBuffer, -1);
if (err < 0) {
// out of buffers,return #bytes written
if (err ==status_t(NO_MORE_BUFFERS)) {
break;
}
returnssize_t(err);
}
size_t toWrite;
if (mFormat ==AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
// Divide capacityby 2 to take expansion into account
toWrite =audioBuffer.size>>1;
memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) src, toWrite);
} else {
toWrite =audioBuffer.size;
memcpy(audioBuffer.i8, src, toWrite);
}
src += toWrite;
userSize -= toWrite;
written += toWrite;
releaseBuffer(&audioBuffer);
} while (userSize >=frameSz);
return written;
}
更多相关文章
- Android(安卓)开发 Eclipse 内存调整
- Android(安卓)获取内存信息
- Android音量控制调节
- Android控制ScrollView滑动速度
- android: MapView加载多个 overlay 内存溢出
- Android(安卓)滑动效果代码分享
- Android(安卓)Studio之内存分析
- AndroidManifest.xml文件详解(uses-configuration)
- android 背光控制 HAL层分析