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>