关于android下audioflinger+alsa+a2dp+pcm+bluez+sbc编码理解

来源:互联网 发布:2008数据库紧急模式 编辑:程序博客网 时间:2024/06/07 06:36

首先audioflinger创建音频hw类-比如alsa类,如果打开了with_a2dp编译选项,那么随后a2dpaudiointerface类将
作为audioflinger最终使用的hw类,[luther.gliethttp]
如果打开一个device,将调用a2dpaudiointerface::openoutputstream,如果该device不是a2dp设备,那么
a2dpaudiointerface类将直接调用alsa类提供的函数openoutputstream打开实际的alsa设备,
可见android系统a2dp功能根本就用不到alsa的任何东西,即便audio驱动没有完成a2dp仍然可独立使用[luther.gliethttp].


对于media等音频的发送,首先是由audioflinger将通过借助binder采用ashmem共享文件方式推入数据的各个track
进行mixer,所有mixer后的最终pcm数据将被推入moutput->write(curbuf, mixbuffersize);也就是
a2dpaudiointerface::a2dpaudiostreamout::write(const void* buffer, size_t bytes);
随后这些裸pcm数据将被送入bluez的a2dp_write(mdata, buffer, remaining);进行sbc_encode即sbc编码,
透过socket或者rfcomm送到bluetooth chip芯片最后发送到air等待a2dp设备接收.[luther.gliethttp]

audiohardwareinterface* audiohardwareinterface::create()
{
    ......
    hw = createaudiohardware(); // 调用alsa_sound/audiohardwarealsa.cpp构造函数
    ......
#ifdef with_a2dp
    hw = new a2dpaudiointerface(hw); // 使用a2dp作为默认hw,这样a2dp这个hw类发现device不是a2dp时
#endif                               // 它会调用alsa的hw打开设备,否则将自己打开该a2dp device[luther.gliethttp]
    ......
    return hw;
}

audiostreamout* a2dpaudiointerface::openoutputstream(
        uint32_t devices, int *format, uint32_t *channels, uint32_t *samplerate, status_t *status)
{
    if (!audiosystem::isa2dpdevice((audiosystem::audio_devices)devices)) {
        logv("a2dpaudiointerface::openoutputstream() open hw device: %x", devices);
        return mhardwareinterface->openoutputstream(devices, format, channels, samplerate, status);
    }

    status_t err = 0;

    // only one output stream allowed
    if (moutput) {
        if (status)
            *status = -1;
        return null;
    }

    // create new output stream
    a2dpaudiostreamout* out = new a2dpaudiostreamout();
    if ((err = out->set(devices, format, channels, samplerate)) == no_error) {
        moutput = out;
        moutput->setbluetoothenabled(mbluetoothenabled);
        moutput->setsuspended(msuspended);
    } else {
        delete out;
    }

    if (status)
        *status = err;
    return moutput;
}

frameworks/base/libs/audioflinger/a2dpaudiointerface.cpp
==> a2dpaudiointerface::a2dpaudiostreamout::init
==> 调用external/bluetooth/bluez/audio/liba2dp.c中的
==> a2dp_init(44100, 2, &mdata);

ssize_t a2dpaudiointerface::a2dpaudiostreamout::write(const void* buffer, size_t bytes)
{
    mutex::autolock lock(mlock);

    size_t remaining = bytes;
    status_t status = -1;

    if (!mbluetoothenabled || mclosing || msuspended) {
        logv("a2dpaudiostreamout::write(), but bluetooth disabled /
               mbluetoothenabled %d, mclosing %d, msuspended %d",
                mbluetoothenabled, mclosing, msuspended);
        goto error;
    }

    status = init();
    if (status < 0)
        goto error;

    while (remaining > 0) {
        status = a2dp_write(mdata, buffer, remaining);
        if (status <= 0) {
            loge("a2dp_write failed err: %d/n", status);
            goto error;
        }
        remaining -= status;
        buffer = ((char *)buffer) + status;
    }

    mstandby = false;

    return bytes;

error:
    // simulate audio output timing in case of error
    usleep(((bytes * 1000 )/ framesize() / samplerate()) * 1000);

    return status;
}

int a2dp_write(a2dpdata d, const void* buffer, int count)
{
    struct bluetooth_data* data = (struct bluetooth_data*)d;
    uint8_t* src = (uint8_t *)buffer;
    int codesize;
    int err, ret = 0;
    long frames_left = count;
    int encoded;
    unsigned int written;
    const char *buff;
    int did_configure = 0;
#ifdef enable_timing
    uint64_t begin, end;
    dbg("********** a2dp_write **********");
    begin = get_microseconds();
#endif

    err = wait_for_start(data, write_timeout);
    if (err < 0)
        return err;

    codesize = data->codesize;

    while (frames_left >= codesize) {
        /* enough data to encode (sbc wants 512 byte blocks) */
        encoded = sbc_encode(&(data->sbc), src, codesize,
                    data->buffer + data->count,
                    sizeof(data->buffer) - data->count,
                    &written);
        if (encoded <= 0) {
            err("encoding error %d", encoded);
            goto done;
        }
        vdbg("sbc_encode returned %d, codesize: %d, written: %d/n",
            encoded, codesize, written);

        src += encoded;
        data->count += written;
        data->frame_count++;
        data->samples += encoded;
        data->nsamples += encoded;

        /* no space left for another frame then send */
        if ((data->count + written >= data->link_mtu) ||
                (data->count + written >= buffer_size)) {
            vdbg("sending packet %d, count %d, link_mtu %u",
                    data->seq_num, data->count,
                    data->link_mtu);
            err = avdtp_write(data);
            if (err < 0)
                return err;
        }

        ret += encoded;
        frames_left -= encoded;
    }

    if (frames_left > 0)
        err("%ld bytes left at end of a2dp_write/n", frames_left);

done:
#ifdef enable_timing
    end = get_microseconds();
    print_time("a2dp_write total", begin, end);
#endif
    return ret;
}

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 股票退市股民的钱怎么办 美国股票退市股民怎么办 百度云字幕和视频不同步怎么办 百度云加载字幕有延迟怎么办 很难适应新环境怎么办 蜘蛛丝碰到嘴唇上起包有毒怎么办? 电瓶车在路上爆胎了怎么办 嘴被虫子咬肿了怎么办 高铁管家购票失败怎么办 高铁车厢空调冷怎么办 高铁票过了时间怎么办 网购火车票丢了怎么办 改签没有票了怎么办 火车票取了没赶上车怎么办 上车后车票丢了怎么办 晒了吗任务过期怎么办 坐火车买了站票怎么办 坐火车忘记带票怎么办 距离二本线差几分怎么办 行李包落火车候车厅怎么办 高铁票买错地点怎么办 高铁票买错日期怎么办 票买错时间了怎么办 上高铁了票丢了怎么办 上车前高铁票丢了怎么办 高铁安检没收的东西怎么办 高铁安检员老了怎么办 高铁安检喷雾拍照了怎么办 十个小时的高铁怎么办 华为开机需要激活码怎么办 高铁提前上车了出站怎么办 买火车票忘记带身份证怎么办 买高铁票没赶上怎么办 电脑放视频没有声音怎么办 内业计算中角度超限怎么办 遇到飞机出故障乘客怎么办 模拟城市5矿产满了怎么办 模拟城市5劳工短缺怎么办 模拟城市5土地价值低怎么办 考上研究生想二战研究生学籍怎么办 小米3屏幕花屏怎么办