Android Audio Code Analysis 13-AudioTrack: getPosition Function

Source: Internet
Author: User

We plan to use the interfaces used in the test code as the points, and take the call relationship between interfaces as the lines to gradually crack the Audio veil in Android.


**************************************** * Source Code ************************************** ***********
Public void testPlaybackHeadPositionAfterInit () throws Exception {
// Constants for test
Final String TEST_NAME = "testPlaybackHeadPositionAfterInit ";
Final int test_sr= 22050;
Final int TEST_CONF = AudioFormat. CHANNEL_OUT_STEREO;
Final int TEST_FORMAT = AudioFormat. ENCODING_PCM_16BIT;
Final int TEST_MODE = AudioTrack. MODE_STREAM;
Final int TEST_STREAM_TYPE = AudioManager. STREAM_MUSIC;

// -------- Initialization --------------
AudioTrack = new AudioTrack (TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
AudioTrack. getMinBufferSize (TEST_SR, TEST_CONF, TEST_FORMAT), TEST_MODE );
// -------- Test --------------
AssumeTrue (TEST_NAME, track. getState () = AudioTrack. STATE_INITIALIZED );
AssertTrue (TEST_NAME, track. getPlaybackHeadPosition () = 0 );
// -------- Tear down --------------
Track. release ();
}
**************************************** **************************************** **************
Source code path:
Frameworks \ base \ media \ tests \ mediaframeworktest \ src \ com \ android \ mediaframeworktest \ functional \ MediaAudioTrackTest. java


################ ################
// Test case 1: getPlaybackHeadPosition () at 0 after initialization
Public void testPlaybackHeadPositionAfterInit () throws Exception {
// Constants for test
Final String TEST_NAME = "testPlaybackHeadPositionAfterInit ";
Final int test_sr= 22050;
Final int TEST_CONF = AudioFormat. CHANNEL_OUT_STEREO;
Final int TEST_FORMAT = AudioFormat. ENCODING_PCM_16BIT;
Final int TEST_MODE = AudioTrack. MODE_STREAM;
Final int TEST_STREAM_TYPE = AudioManager. STREAM_MUSIC;

// -------- Initialization --------------
AudioTrack = new AudioTrack (TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
AudioTrack. getMinBufferSize (TEST_SR, TEST_CONF, TEST_FORMAT), TEST_MODE );
// -------- Test --------------
AssumeTrue (TEST_NAME, track. getState () = AudioTrack. STATE_INITIALIZED );
// What You Want to see today is the following getPlaybackHeadPosition Function
// Because the play function is not called before getPlaybackHeadPosition, that is, the playback is not started, the obtained position should be 0.
AssertTrue (TEST_NAME, track. getPlaybackHeadPosition () = 0 );
++ GetPlaybackHeadPosition ++ ++
/**
* Returns the playback head position expressed in frames
*/
Public int getPlaybackHeadPosition (){
// Very direct
// The android_media_AudioTrack_get_position function is called.
Return native_get_position ();
++ Android_media_AudioTrack_get_position ++ ++
Path: frameworks \ base \ core \ jni \ android_media_AudioTrack.cpp


Static jint android_media_AudioTrack_get_position (JNIEnv * env, jobject thiz ){

AudioTrack * lpTrack = (AudioTrack *) env-> GetIntField (
Thiz, javaAudioTrackFields. nativeTrackInJavaObj );
Uint32_t position = 0;

If (lpTrack ){
LpTrack-> getPosition (& position );
Return (jint) position;
++ AudioTrack :: getPosition ++
Status_t AudioTrack: getPosition (uint32_t * position)
{
If (position = 0) return BAD_VALUE;


* Position = mCblk-> server;


Return NO_ERROR;
}


Server is a member variable of mCblk, and mCblk is an audio_track_cblk_t object.
The server is assigned a value in the audio_track_cblk_t: stepServer function.
In addition, mCblk-> server has been assigned a value in the AudioTrack: setPosition function.
++ AudioTrack :: setPosition ++
Status_t AudioTrack: setPosition (uint32_t position)
{
Mutex: Autolock _ l (mCblk-> lock );


If (! Stopped () return INVALID_OPERATION;


If (position> mCblk-> user) return BAD_VALUE;


MCblk-> server = position;
MCblk-> flags | = CBLK_FORCEREADY_ON;


Return NO_ERROR;
}


The following two functions in the android_media_AudioTrack.cpp file call AudioTrack: setPosition:
Android_media_AudioTrack_set_pos_update_period Function
Android_media_AudioTrack_set_position Function
These interfaces are used on the java layer.
Imagine the use case, drag the current cursor?
--------------------------------- AudioTrack: setPosition -------------------------------
++ Audio_track_cblk_t :: stepServer ++
Bool audio_track_cblk_t: stepServer (uint32_t frameCount)
{
// The code below simulates lock-with-timeout
// We MUST do this to protect the AudioFlinger server
// As this lock is shared with the client.
Status_t err;


Err = lock. tryLock ();
If (err =-EBUSY) {// just wait a bit
Usleep (1000 );
Err = lock. tryLock ();
}
If (err! = NO_ERROR ){
// Probably, the client just died.
Return false;
}


Uint64_t s = this-> server;


S + = frameCount;
If (flags & CBLK_DIRECTION_MSK ){
// Mark that we have read the first buffer so that next time stepUser () is called
// We switch to normal obtainBuffer () timeout period
If (bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS ){
BufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS-1;
}
// It is possible that we receive a flush ()
// While the mixer is processing a block: in this case,
// StepServer () is called After the flush () has reset u & s and
// We have s> u
If (s> this-> user ){
LOGW ("stepServer occured after track reset ");
S = this-> user;
}
}


If (s> = loopEnd ){
LOGW_IF (s> loopEnd, "stepServer: s % llu> loopEnd % llu", s, loopEnd );
S = loopStart;
If (-- loopCount = 0 ){
LoopEnd = ULLONG_MAX;
LoopStart = ULLONG_MAX;
}
}
If (s> = serverBase + this-> frameCount ){
ServerBase + = this-> frameCount;
}


This-> server = s;


Cv. signal ();
Lock. unlock ();
Return true;
}


The AudioFlinger: ThreadBase: TrackBase: step Function audio_track_cblk_t: stepServer is called.
++ AudioFlinger: ThreadBase: TrackBase :: step ++
Bool AudioFlinger: ThreadBase: TrackBase: step (){
Bool result;
Audio_track_cblk_t * cblk = this-> cblk ();


Result = cblk-> stepServer (mFrameCount );
If (! Result ){
LOGV ("stepServer failed acquiring cblk mutex ");
MFlags | = STEPSERVER_FAILED;
}
Return result;
}


Function AudioFlinger: PlaybackThread: Track: getNextBuffer and function AudioFlinger: RecordThread: RecordTrack: getNextBuffer
The AudioFlinger: ThreadBase: TrackBase: step function is called.
Here we only look at the function AudioFlinger: PlaybackThread: Track: getNextBuffer.
++ AudioFlinger: PlaybackThread: Track :: getNextBuffer ++
Status_t AudioFlinger: PlaybackThread: Track: getNextBuffer (AudioBufferProvider: Buffer * buffer)
{
Audio_track_cblk_t * cblk = this-> cblk ();
Uint32_t framesReady;
Uint32_t framesReq = buffer-> frameCount;


// Check if last stepServer failed, try to step now
If (mFlags & TrackBase: STEPSERVER_FAILED ){
If (! Step () goto getNextBuffer_exit;
LOGV ("stepServer recovered ");
MFlags & = ~ TrackBase: STEPSERVER_FAILED;
}


FramesReady = cblk-> framesReady ();


If (LIKELY (framesReady )){
Uint64_t s = cblk-> server;
Uint64_t bufferEnd = cblk-> serverBase + cblk-> frameCount;


BufferEnd = (cblk-> loopEnd <bufferEnd )? Cblk-> loopEnd: bufferEnd;
If (framesReq> framesReady ){
FramesReq = framesReady;
}
If (s + framesReq> bufferEnd ){
FramesReq = bufferEnd-s;
}


Buffer-> raw = getBuffer (s, framesReq );
If (buffer-> raw = 0) goto getNextBuffer_exit;


Buffer-> frameCount = framesReq;
Return NO_ERROR;
}


GetNextBuffer_exit:
Buffer-> raw = 0;
Buffer-> frameCount = 0;
LOGV ("getNextBuffer () no more data for track % d on thread % p", mName, mThread. unsafe_get ());
Return NOT_ENOUGH_DATA;
}


This function has already been read while reading framesReady, so I will not talk about it more.
----------------------------- AudioFlinger: PlaybackThread: Track: getNextBuffer -----------------------------------
---------------------------- AudioFlinger: ThreadBase: TrackBase: step ----------------------------------
--------------------------------- Audio_track_cblk_t: stepServer -------------------------------
------------------------------ AudioTrack: getPosition --------------------------------
} Else {
JniThrowException (env, "java/lang/IllegalStateException ",
"Unable to retrieve AudioTrack pointer for getPosition ()");
Return AUDIOTRACK_ERROR;
}
}
---------------------------- Android_media_AudioTrack_get_position ----------------------------------
}
------------------------------- GetPlaybackHeadPosition ---------------------------------
// -------- Tear down --------------
Track. release ();
}
######################################## ###################


& Summary &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&
Get position is actually the location of the server in the audio_track_cblk_t object.
The server location is changed when set position or step server is used.
The application will set position.
When Get next buffer is used, the server is step.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&

From: Jiangfeng's column

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.