文档章节

Android学习(九)AudioTrack(3)

lipandroid
 lipandroid
发布于 2015/10/13 15:51
字数 661
阅读 39
收藏 0

AudioTrack3

  if (memoryMode == javaAudioTrackFields.MODE_STREAM) {

 

        lpTrack->set(

            atStreamType,// stream type

            sampleRateInHertz,

            format,// word length, PCM

            channels,

            frameCount,

            0,// flags

            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)

            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack

            0,// shared mem

            true,// thread can call Java

            sessionId);// audio session ID

           

    }

分析传入的回调函数audioCallback定义:

static void audioCallback(int event, void* user, void *info) {

    if (event == AudioTrack::EVENT_MORE_DATA) {

        // set size to 0 to signal we're not using the callback to write more data 看注释在读取数据时不是通过回调函数来获取数据的

        AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;

        pBuff->size = 0; 

    

    }

java层中有调用:

mAudioTrack.write(audioBuffer, 0, mAudioMinBufSize);//track中写数据

static jint android_media_AudioTrack_native_write(JNIEnv *env,  jobject thiz,

                                                  jbyteArray javaAudioData,

                                                  jint offsetInBytes, jint sizeInBytes,

                                                  jint javaAudioFormat) {

 

    jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);

 

 

jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,

                  jint offsetInBytes, jint sizeInBytes) {

    // give the data to the native AudioTrack object (the data starts at the offset)

    ssize_t written = 0;

    // regular write() or copy the data to the AudioTrack's shared memory?

    if (pTrack->sharedBuffer() == 0) {

        written = pTrack->write(data + offsetInBytes, sizeInBytes);

    }

分析AudioTrack中的write

ssize_t AudioTrack::write(const void* buffer, size_t userSize)

{

 

    if (mSharedBuffer != 0) return INVALID_OPERATION;

 

    ssize_t written = 0;

    const int8_t *src = (const int8_t *)buffer;

    Buffer audioBuffer;

 

    do {

        audioBuffer.frameCount = userSize/frameSize();à以帧为单位

       

        status_t err = obtainBuffer(&audioBuffer, -1);à obtainBuffer从共享内存中得到一块空闲的数据块

 

        size_t toWrite;

 

        if (mFormat == AudioSystem::PCM_8_BIT && !(mFlags & AudioSystem::OUTPUT_FLAG_DIRECT)) {

            // Divide capacity by 2 to take expansion into account

            toWrite = audioBuffer.size>>1;à PCM_8转换为PCM_16

            // 8 to 16 bit conversion

            int count = toWrite;

            int16_t *dst = (int16_t *)(audioBuffer.i8);

            while(count--) {

                *dst++ = (int16_t)(*src++^0x80) << 8;

            }

        } else {

            toWrite = audioBuffer.size;à数据大小

            memcpy(audioBuffer.i8, src, toWrite);à地址在audioBuffer.i8

            src += toWrite;

        }

        userSize -= toWrite;

        written += toWrite;

 

        releaseBuffer(&audioBuffer);à更新写位置,同时会触发消费者

    } while (userSize);

 

    return written;

}

write函数仅利用memcpy来传递数据,消费者和生存者的协调,则是通过obtainBufferreleaseBuffer完成的。

分析obtainBuffer

status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)

{

    int active;

    status_t result;

    audio_track_cblk_t* cblk = mCblk;

    uint32_t framesReq = audioBuffer->frameCount;

    uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;

 

    audioBuffer->frameCount  = 0;

    audioBuffer->size = 0;

 

    uint32_t framesAvail = cblk->framesAvailable();à获取当前可写空间大小

 

    if (framesAvail == 0) {

        cblk->lock.lock();

        goto start_loop_here;

        while (framesAvail == 0) {

            …

            if (!(cblk->flags & CBLK_INVALID_MSK)) {

                result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));à如果没有可写空间则等待一段时间

            }

            …

                    cblk->waitTimeMs = 0;

 

                if (--waitCount == 0) {

                    cblk->lock.unlock();

                    return TIMED_OUT;

                }

            }

            // read the server count again

        start_loop_here:

            framesAvail = cblk->framesAvailable_l();

        }

        cblk->lock.unlock();

    }

 

 

    uint32_t u = cblk->user;àuser为可写空间的起始地址

    uint32_t bufferEnd = cblk->userBase + cblk->frameCount;

 

    if (u + framesReq > bufferEnd) {

        framesReq = bufferEnd - u;

    }

 

    audioBuffer->flags = mMuted ? Buffer::MUTE : 0;

    audioBuffer->channelCount = mChannelCount;

    audioBuffer->frameCount = framesReq;

    audioBuffer->size = framesReq * cblk->frameSize;

    if (AudioSystem::isLinearPCM(mFormat)) {

        audioBuffer->format = AudioSystem::PCM_16_BIT;

    } else {

        audioBuffer->format = mFormat;

    }

    audioBuffer->raw = (int8_t *)cblk->buffer(u);à调用buffer,得到可写空间的首地址

    active = mActive;

    return active ? status_t(NO_ERROR) : status_t(STOPPED);

}

obtainBuffer函数的功能,就是从mCblk管理的数据缓冲中得到一块可写空间。

void AudioTrack::releaseBuffer(Buffer* audioBuffer)

{

    audio_track_cblk_t* cblk = mCblk;

    cblk->stepUser(audioBuffer->frameCount);

}

releaseBuffer则是在使用完这块空间后更新写指针的位置。

© 著作权归作者所有

lipandroid
粉丝 1
博文 19
码字总数 20690
作品 0
武汉
私信 提问
android只用能AudioTrack播放实时音频

还有一篇:http://blog.51cto.com/13591594/2068009 (其项目地址: https://github.com/979451341/Audio-and-video-learning-materials ) 今天,简单讲讲AudioTrack的使用方法。 1、Android......

whoisliang
2018/11/12
29
0
Android使用FFmpeg(四)--ffmpeg实现音频播放(使用AudioTrack进行播放)

关于 Android使用FFmpeg(一)--编译ffmpeg Android使用FFmpeg(二)--Android Studio配置ffmpeg Android使用FFmpeg(三)--ffmpeg实现视频播放 Android使用FFmpeg(四)--ffmpeg实现音频播放(使用A...

天王盖地虎626
01/14
25
0
【记录】FFmpeg音视频学习

1.编译FFmpeg 环境配置看这里: [windows下编译FFmpeg] 编译到Android则需要额外配置: 1、修改ffmpeg项目根目录下的configure文件 将文件中的如下四行: SLIBNAMEWITHMAJOR='$(SLIBNAME).$...

Dovar_66
2018/11/07
0
0
audiotrack 无法获取声音

我使用android 和pc 机语音的通话,pc机是写好了的。(声音未经过处理) 在android上我用的是audiorecord 和audiotrack 。android 客户端上audiorecord 和audiotrack的使用都可以。 但是and...

krole
2017/01/18
299
0
Android AudioTrack播放(解码)音频

-- MediaPlayer,AudioTrack 1.MediaPlayer能够播放多种格式的声音文件,比如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer包括了AudioTrack。 2.AudioTrack仅仅能播放已经解码的PCM流,假设是文...

desaco
2018/12/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

全面兼容IE6/IE7/IE8/FF的CSS HACK写法

浏览器市场的混乱,给设计师造成很大的麻烦,设计的页面兼容完这个浏览器还得兼容那个浏览器,本来ie6跟ff之间的兼容是很容易解决的。加上个ie7会麻烦点,ie8的出现就更头疼了,原来hack ie...

前端老手
17分钟前
3
0
常用快递电子面单批量打印api接口对接demo-JAVA示例

目前有三种方式对接电子面单: 1.快递公司:各家快递公司逐一对接接口 2.菜鸟:支持常用15家快递电子面单打印 3.快递鸟:仅对接一次,支持常用30多家主流快递电子面单打印 目前也是支持批量打...

程序的小猿
20分钟前
6
0
Yii 框架中rule规则必须搭配验证函数才能使用

public $store_id;public $user_id;public $page;public $limit;public $list;public $mch_list;public $cart_id;public $is_community;public $shop_id;public $cart_typ......

chenhongjiang
22分钟前
4
0
Flutter使用Rammus实现阿里云推送

前言: 最近新的Flutter项目有“阿里云推送通知”的需求,就是Flutter的App启动后检测到有新的通知,点击通知栏然后跳转到指定的页面。在这里我使用的是第三方插件Rammus来实现通知的推送,之...

EmilyWu
22分钟前
42
0
Knative 实战:三步走!基于 Knative Serverless 技术实现一个短网址服务

短网址顾名思义就是使用比较短的网址代替很长的网址。维基百科上面的解释是这样的: 短网址又称网址缩短、缩短网址、URL 缩短等,指的是一种互联网上的技术与服务,此服务可以提供一个非常短...

阿里巴巴云原生
38分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部