android+WM9714(AC97)调试

来源:互联网 发布:gif调色软件 编辑:程序博客网 时间:2024/05/06 01:50
 

s3c6410平台,codec为WM9714(驱动可使用WM9713的),使用ALSA,android版本1.5. MID上移植android以来一直没有声音。

 

首先确认AC97的硬件连接,AC-LINK通讯是否正常,这里使用到wince中的init寄存器组,在

sound/soc/codecs/wm9713.c中替换static const u16 wm9713_reg[]相应的寄存器,以适配硬件

配置。

做完这部分工作后,应该启动时就会有噗噗声,如果能听到,说明硬件连接正常,软件读写CODEC正常. 

在网上查了很多资料,很多说要配置/system/etc/asound.conf,可我也不知道怎么去配,找了一堆的资料学习,然后对照wm9713.c中

 

的参数和别人的asound.conf,终于弄了一份上去,不过似乎不起说明作用,用alsa_aplay z.wav还是提示错误"Unable to install 

 

hw params:",以下函数出错:

err = snd_pcm_hw_params(handle, params);

也就是说真正要和硬件交互的时候错了。。 终端里用logcat命令查看log信息,发现还是一直打印消息:

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

W/AudioSystem( 1185): AudioFlinger not published, waiting...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

W/AudioSystem( 1185): AudioFlinger not published, waiting...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

 

这说明audio服务还是没有正常启动起来! 于是查android源代码,在frameworks/base/libs/audioflinger/AudioFlinger.cpp中,

void AudioFlinger::instantiate() {

LOGD("*******++AudioFlinger::instantiate()/n");

    defaultServiceManager()->addService(

            String16("media.audio_flinger"), new AudioFlinger());

LOGD("*******--AudioFlinger::instantiate()/n");

}

有调用此函数将自己添加到服务管理器,但是不知道什么原因,系统的服务管理器并没有

得到media.audio_flinger的管理权,所以就会出现上面的一直等待的情况。

跟进new AudioFlinger()

先创建一个audio硬件对象 mAudioHardware = AudioHardwareInterface::create();

AudioHardwareInterface* AudioHardwareInterface::create()

{

    /*

     * FIXME: This code needs to instantiate the correct audio device

     * interface. For now - we use compile-time switches.

     */

    AudioHardwareInterface* hw = 0;

    char value[PROPERTY_VALUE_MAX];

 

#ifdef GENERIC_AUDIO

    hw = new AudioHardwareGeneric();

#else

    // if running in emulation - use the emulator driver

    if (property_get("ro.kernel.qemu", value, 0)) {

        LOGD("Running in emulation - using generic audio driver");

        hw = new AudioHardwareGeneric();

    }

    else {

        LOGV("Creating Vendor Specific AudioHardware");

        hw = createAudioHardware();

    }

#endif

    if (hw->initCheck() != NO_ERROR) {

        LOGW("Using stubbed audio hardware. No sound will be produced.");

        delete hw;

        hw = new AudioHardwareStub();

    }

 

#ifdef DUMP_FLINGER_OUT

    // This code adds a record of buffers in a file to write calls made by AudioFlinger.

    // It replaces the current AudioHardwareInterface object by an intermediate one which

    // will record buffers in a file (after sending them to hardware) for testing purpose.

    // This feature is enabled by defining symbol DUMP_FLINGER_OUT.

    // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.

 

    hw = new AudioDumpInterface(hw);    // replace interface

#endif

    return hw;

}

 

这里hw = createAudioHardware();才是真正的初始化主体:

    android::AudioHardwareInterface *createAudioHardware(void) {

        return new android::AudioHardwareALSA();

    }

也就是AudioHardwareInterface::create()返回的是实际的硬件初始化对象AudioHardwareALSA的指针。

接着跟进:

AudioHardwareALSA::AudioHardwareALSA() :

    mOutput(0),

    mInput(0),

    mIPC(0) // sangsu fix : for IPC

{

    snd_lib_error_set_handler(&ALSAErrorHandler);

    mMixer = new ALSAMixer;  //创建混合器对象

    mIPC = new AudioHardwareIPC; // sangsu fix : IPC init

}

再看mIPC = new AudioHardwareIPC;

AudioHardwareIPC::AudioHardwareIPC() :

    mClient(NULL)

{

LOGD("### %s", __func__);

    int err = 0;

 

    mClient = OpenClient_RILD();

    if (mClient == NULL){

        LOGE("[*] OpenClient_RILD() error/n");

        err = 1;

    }

 

    if (RegisterRequestCompleteHandler(mClient, RIL_REQUEST_OEM_HOOK_RAW, 

onRawReqComplete) != RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] RegisterRequestCompleteHandler() error/n");

        err = 1;

    }

 

    if (RegisterUnsolicitedHandler(mClient, 11004, onUnsol) != 

RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] RegisterUnsolicitedHandler() error/n");

        err = 1;

    }

 

    if (Connect_RILD(mClient) != RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] Connect_RILD() error/n");

        err = 1;

    }

 

    if (!err) LOGD("Success Initializing IPC");

    else LOGE("Failed Initializing IPC");

}

在logcat里也确实有打印出这些出错信息,说明RIL服务没有运行。

 

再次回到AudioFlinger::AudioFlinger(),创建音频接口对象后,接着打开OutputStream

AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);

实际调用函数:

AudioStreamOut *

AudioHardwareALSA::openOutputStream(int format,

                                    int channelCount,

                                    uint32_t sampleRate,

                                    status_t *status)

{

AutoMutex lock(mLock);

 

LOGD("++AudioHardwareALSA::openOutputStream()/n");

 

    // only one output stream allowed

    if (mOutput) {

        *status = ALREADY_EXISTS;

        return 0;

    }

 

    AudioStreamOutALSA *out = new AudioStreamOutALSA(this);

    *status = out->set(format, channelCount, sampleRate);

    if (*status == NO_ERROR) {

        mOutput = out;

        // Some information is expected to be available immediately after

        // the device is open.

        uint32_t routes = mRoutes[mMode];

        mOutput->setDevice(mMode, routes);

    }

    else {

        delete out;

    }

LOGD("--AudioHardwareALSA::openOutputStream()/n");

    return mOutput;

}

进入new AudioStreamOutALSA(this)

AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent) :

    mParent(parent),

    mPowerLock(false)

{

    static StreamDefaults _defaults = {

        devicePrefix   : "AndroidPlayback",

        direction      : SND_PCM_STREAM_PLAYBACK,

        format         : SND_PCM_FORMAT_S16_LE,   // AudioSystem::PCM_16_BIT

        channels       : 2,

        sampleRate     : DEFAULT_SAMPLE_RATE,

        latency        : 250000,                  // Desired Delay in usec

        // sangsu fix : optimizing output buffer size

        bufferSize     : 2048,                   // Desired Number of samples

        };

 

    setStreamDefaults(&_defaults);

}

这里就是设置的默认OutStream参数了。。 再看out->set(format, channelCount, sampleRate);

            status_t                set(int format          = 0,

                                        int channelCount    = 0,

                                        uint32_t sampleRate = 0) {

                return ALSAStreamOps::set(format, channelCount, sampleRate);

            }

 

status_t ALSAStreamOps::set(int      format,

                            int      channels,

                            uint32_t rate)

{

    if (channels != 0)

        mDefaults->channels = channels;

 

    if (rate != 0)

        mDefaults->sampleRate = rate;

 

    switch(format) {

      // format == 0

        case AudioSystem::DEFAULT:

            break;

 

        case AudioSystem::PCM_16_BIT:

            mDefaults->format = SND_PCM_FORMAT_S16_LE;

            break;

 

        case AudioSystem::PCM_8_BIT:

            mDefaults->format = SND_PCM_FORMAT_S8;

            break;

 

        default:

            LOGE("Unknown PCM format %i. Forcing default", format);

            break;

    }

 

    return NO_ERROR;

}

也就是继续设置default参数。 然后调用mOutput->setDevice(mMode, routes);

status_t AudioStreamOutALSA::setDevice(int mode, uint32_t newDevice)

{

    AutoMutex lock(mLock);

 

    return ALSAStreamOps::setDevice(mode, newDevice);

}

 

status_t ALSAStreamOps::setDevice(int mode, uint32_t device)

{

    // Close off previously opened device.

    // It would be nice to determine if the underlying device actually

    // changes, but we might be manipulating mixer settings (see asound.conf).

    //

    close();

 

    const char *stream = streamName();

    status_t    status = open (mode, device);

    int     err;

 

    if (status != NO_ERROR)

        return status;

 

    err = snd_pcm_hw_params_any(mHandle, mHardwareParams);

    if (err < 0) {

        LOGE("Unable to configure hardware: %s", snd_strerror(err));

        return NO_INIT;

    }

 

    status = setPCMFormat(mDefaults->format);

 

    // Set the interleaved read and write format.

    err = snd_pcm_hw_params_set_access(mHandle, mHardwareParams,

                                       SND_PCM_ACCESS_RW_INTERLEAVED);

    if (err < 0) {

        LOGE("Unable to configure PCM read/write format: %s",

            snd_strerror(err));

        return NO_INIT;

    }

 

    //

    // Some devices do not have the default two channels.  Force an error to

    // prevent AudioMixer from crashing and taking the whole system down.

    //

    // Note that some devices will return an -EINVAL if the channel count

    // is queried before it has been set.  i.e. calling channelCount()

    // before channelCount(channels) may return -EINVAL.

    //

    status = channelCount(mDefaults->channels);

    if (status != NO_ERROR)

        return status;

 

    // Don't check for failure; some devices do not support the default

    // sample rate.

    sampleRate(mDefaults->sampleRate);

 

    // Disable hardware resampling.

    status = setHardwareResample(false);

    if (status != NO_ERROR)

        return status;

 

    snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;

    unsigned int latency = mDefaults->latency;

 

    // Make sure we have at least the size we originally wanted

    err = snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, bufferSize);

    if (err < 0) {

        LOGE("Unable to set buffer size to %d:  %s",

             (int)bufferSize, snd_strerror(err));

        return NO_INIT;

    }

 

    // Setup buffers for latency

    err = snd_pcm_hw_params_set_buffer_time_near (mHandle, mHardwareParams,

                                                  &latency, NULL);

    if (err < 0) {

        /* That didn't work, set the period instead */

        unsigned int periodTime = latency / 4;

        err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,

                                                      &periodTime, NULL);

        if (err < 0) {

            LOGE("Unable to set the period time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        snd_pcm_uframes_t periodSize;

        err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);

        if (err < 0) {

            LOGE("Unable to get the period size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        bufferSize = periodSize * 4;

        if (bufferSize < mDefaults->bufferSize)

            bufferSize = mDefaults->bufferSize;

        err = snd_pcm_hw_params_set_buffer_size_near (mHandle, mHardwareParams, &bufferSize);

        if (err < 0) {

            LOGE("Unable to set the buffer size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

    } else {

        // OK, we got buffer time near what we expect. See what that did for bufferSize.

        err = snd_pcm_hw_params_get_buffer_size (mHardwareParams, &bufferSize);

        if (err < 0) {

            LOGE("Unable to get the buffer size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        // Does set_buffer_time_near change the passed value? It should.

        err = snd_pcm_hw_params_get_buffer_time (mHardwareParams, &latency, NULL);

        if (err < 0) {

            LOGE("Unable to get the buffer time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        unsigned int periodTime = latency / 4;

        err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,

                                                      &periodTime, NULL);

        if (err < 0) {

            LOGE("Unable to set the period time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

    }

 

    LOGD("Buffer size: %d", (int)bufferSize);

    LOGD("Latency: %d", (int)latency);

 

    mDefaults->bufferSize = bufferSize;

    mDefaults->latency = latency;

 

    // Commit the hardware parameters back to the device.

    err = snd_pcm_hw_params(mHandle, mHardwareParams);

    if (err < 0) {

        LOGE("Unable to set hardware parameters: %s", snd_strerror(err));

        return NO_INIT;

    }

 

    status = setSoftwareParams();

 

    return status;

}

 

在调用了一系列设置参数的函数后,最后调用err = snd_pcm_hw_params(mHandle, mHardwareParams);

将参数写入到硬件。

 

完成这个过程后,接着创建 MixerThread ,AudioRecordThread ,至此media.audio_flinger服务初始化完毕。

 

在我们的MID上,wince6.0下有调试WM9714通过,可正常发声和录音。可android下使用alsa_aplay测试总是出现问题。

一气之下重新解压android包,编译,烧写ramdisk-uboot.img,system.img,userdata.img,偶然在android界面点开music player,找

 

到SD卡上的音乐,竟然能发出不连续的声音,欣喜若狂!  赶紧在kernel中关掉打印信息,再次进入播放,悠扬的声音出来了!

 

 

晕~~~  竟然不用动什么东西! 也不需要配asound.conf,所需要注意的是测试在android界面里用music player播放就好,

 

alsa_aplay还是在这种场合不合适,因为android加载,占用了音频设备。每次烧写也应该带上ramdisk-uboot.img,这个很重要。

 

我的alsa_aplay版本:

# alsa_aplay --version

aplay: version 1.0.19 by Jaroslav Kysela <perex@perex.cz>