文章目录
本文以MixerThread为例
1. threadloop到streamout的write函数
start执行下来的broadcast_l(),唤醒了MixerThread::threadloop
MixerThread线程环接收到广播信号,开始处理。
注意:我这版本的代码没有重新编写MixerThread::threadloop,故执行在AudioFlinger::PlaybackThread::threadLoop中。此版本的线程环包含了其他线程的判断。
AudioFlinger::PlaybackThread::threadLoop
|- AudioFlinger::MixerThread::threadLoop_write
|- AudioFlinger::PlaybackThread::threadLoop_write
|- write
//Threads.cpp
bool AudioFlinger::PlaybackThread::threadLoop()
{
//处理配置
processConfigEvents_l();
if (mNormalSink != 0) {
//······
}
//准备数据
// mMixerStatusIgnoringFastTracks is also updated internally
mMixerStatus = prepareTracks_l(&tracksToRemove);
//写到hal
ret = threadLoop_write();
}
//Threads.cpp
ssize_t AudioFlinger::MixerThread::threadLoop_write()
{
// FIXME workaround for first HAL write being CPU bound on some devices
mOutput->write((char *)mSinkBuffer, 0);
//调到playback thread类定义的write,这里是实际的赋值
return PlaybackThread::threadLoop_write();
}
//Threads.cpp
ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{
mInWrite = true;
ssize_t bytesWritten;
const size_t offset = mCurrentWriteLength - mBytesRemaining;
// If an NBAIO sink is present, use it to write the normal mixer's submix
if (mNormalSink != 0) {
//······
//mNormalSink的write操作,具体看下mNormalSink的定义
ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
// otherwise use the HAL / AudioStreamOut directly
} else {
// Direct output and offload threads
//
bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
}
}
到这里可以看出来,从线程环执行到具体的write函数,不过这个write函数有两种:
- mNormalSink->write
- mOutput->write
2. streamout的write函数
我们来分别看下这两种调用的flow
2.1 mNormalSink->write
2.1.1 mNormalSink定义
//-----------------------------mNormalSink-------------------------
//@Threads.h
class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
public VolumeInterface {
sp<NBAIO_Sink> mNormalSink;
}
//@NBAIO.h
class NBAIO_Sink : public NBAIO_Port {
virtual ssize_t write(const void *buffer, size_t count) = 0;
}
mNormalSink变量是PlaybackThread 类中的变量
其类型是NBAIO_Sink类的强指针
mNormalSink->write是NBAIO_Sink类中定义的一个纯虚函数,需要查找这个write的具体执行函数
2.1.2 mNormalSink创建
mNormalSink是PlaybackThread 类中的变量,所以在PlaybackThread的初始化中看下是否对它进行赋值。
查看PlaybackThread的构造函数,没有找到mNormalSink变量的初始化,那就去mixerthread中找找看(因为mixerthread继承自PlaybackThread,所以mixerthread也有mNormalSink变量)。
//threads.cpp
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
audio_devices_t device,
type_t type,
bool systemReady)
: ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
mNormalFrameCount(0), mSinkBuffer(NULL),
mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
mMixerBuffer(NULL),
mMixerBufferSize(0),
mMixerBufferFormat(AUDIO_FORMAT_INVALID),
mMixerBufferValid(false),
mEffectBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
mEffectBuffer(NULL),
mEffectBufferSize(0),
mEffectBufferFormat(AUDIO_FORMAT_INVALID),
mEffectBufferValid(false),
mSuspended(0), mBytesWritten(0),
mFramesWritten(0),
mSuspendedFrames(0),
mActiveTracks(&this->mLocalLog),
// mStreamTypes[] initialized in constructor body
mOutput(output),
mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
mMixerStatus(MIXER_IDLE),
mMixerStatusIgnoringFastTracks(MIXER_IDLE),
mStandbyDelayNs(AudioFlinger::mStandbyTimeInNsecs),
mBytesRemaining(0),
mCurrentWriteLength(0),
mUseAsyncWrite(false),
mWriteAckSequence(0),
mDrainSequence(0),
mScreenState(AudioFlinger::mScreenState),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
mLeftVolFloat(-1.0), mRightVolFloat(-1.0), mHwSupportsSuspend(false)
{
snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
// Assumes constructor is called by AudioFlinger with it's mLock held, but
// it would be safer to explicitly pass initial masterVolume/masterMute as
// parameter.
//
// If the HAL we are using has support for master volume or master mute,
// then do not attenuate or mute during mixing (just leave the volume at 1.0
// and the mute set to false).
mMasterVolume = audioFlinger->masterVolume_l();
mMasterMute = audioFlinger->masterMute_l();
if (mOutput && mOutput->audioHwDev) {
if (mOutput->audioHwDev->canSetMasterVolume()) {
mMasterVolume = 1.0;
}
if (mOutput->audioHwDev->canSetMasterMute()) {
mMasterMute = false;
}
}
readOutputParameters_l();
// ++ operator does not compile
for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
}
}
//threads.cpp
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
// mAudioMixer below
// mFastMixer below
mFastMixerFutex(0),
mMasterMono(false)
// mOutputSink below
// mPipeSink below
// mNormalSink below
{
mOutputSink = new AudioStreamOutSink(output->stream);
mOutputSink->negotiate(offers, 1, NULL, numCounterOffers);
NBAIO_Format format = mOutputSink->format();
state->mOutputSink = mOutputSink.get();
switch (kUseFastMixer) {
case FastMixer_Never:
case FastMixer_Dynamic:
mNormalSink = mOutputSink;
break;
case FastMixer_Always:
mNormalSink = mPipeSink;
break;
case FastMixer_Static:
mNormalSink = initFastMixer ? mPipeSink : mOutputSink;
break;
}
}
在MixerThread构造函数中发现了mNormalSink 的初始化,这里分为两种情况
- mNormalSink = mOutputSink
- mNormalSink = mPipeSink
这里简单介绍第一种情况
在MixerThread构造函数中,为AudioStreamOutSink类分配了空间,并把mOutputSink(后面赋值给mNormalSink)指向该空间。
接下来查看两点
1.入参output->stream的由来
2.AudioStreamOutSink的构造函数
2.1.2.1 new AudioStreamOutSink的入参
MixerThread构造函数中将output->stream作为AudioStreamOutSink的入参,而output又是MixerThread的入参,查看下创建MixerThread的函数
//AudioFlinger.cpp
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
}
可以看到,AudioStreamOutSink的入参output == MixerThread的入参outputStream,而outputStream又是在outHwDev->openOutputStream()函数中进行初始化的,openOutputStream函数是初始化这个outputStream参数的流程参见这篇文章。
2.1.2.2 AudioStreamOutSink的构造函数
//AudioStreamOutSink.h
class AudioStreamOutSink : public NBAIO_Sink {
sp<StreamOutHalInterface> mStream;
}
//AudioStreamOutSink.cpp
AudioStreamOutSink::AudioStreamOutSink(sp<StreamOutHalInterface> stream) :
NBAIO_Sink(),
mStream(stream),
mStreamBufferSizeBytes(0)
{
ALOG_ASSERT(stream != 0);
}
//@threads.cpp
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady)
{
// create an NBAIO sink for the HAL output stream, and negotiate
mOutputSink = new AudioStreamOutSink(output->stream);
}
AudioStreamOutSink的构造函数将入参stream(即output->stream)赋值给AudioStreamOutSink类中的变量mStream。之后在AudioStreamOutSink的ops中就可以直接获取mStream进行处理。
需要注意的是mStream类型,它是一个强指针,而且是一个hal接口,具体的操作定义后面遇到了讨论。
2.1.2.3 AudioStreamOutSink的ops
mNormalSink->write执行的是AudioStreamOutSink::write()函数
看下定义
//AudioStreamOutSink.h
class AudioStreamOutSink : public NBAIO_Sink
virtual ssize_t write(const void *buffer, size_t count);
}
这里可以发现,AudioStreamOutSink类型继承自NBAIO_Sink,又重新定义了write函数,看下write函数的具体实现
//AudioStreamOutSink.cpp
ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
{
status_t ret = mStream->write(buffer, count * mFrameSize, &written);
}
//AudioStreamOutSink.h
class AudioStreamOutSink : public NBAIO_Sink {
sp<StreamOutHalInterface> mStream;
}
//AudioStreamOutSink.cpp
AudioStreamOutSink::AudioStreamOutSink(sp<StreamOutHalInterface> stream) :
NBAIO_Sink(),
mStream(stream),
mStreamBufferSizeBytes(0)
{
ALOG_ASSERT(stream != 0);
}
NBAIO_Sink的实现类是:AudioStreamOutSink
mStream是AudioStreamOutSink类中的变量,其类型是StreamOutHalInterface的指针。
就是传入的那个output->stream参数,接下来查看下这个变量的操作。
output->stream变量的初始化在openoutput()中实现,具体调用内容参考这篇文章。
直接看下mStream的write操作
//@audio_hw.c
//初始化输出流的操作
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address __unused)
{
out->stream.write = out_write;
}
这里进行了初始化,所以AudioStreamOutSink::write执行的write就是out_write函数。
out_write的调用在第三章,接下来分析另一种情况,使用mOutput->write。
总结下:这里我以mNormalSink == mOutputSink为例,理一下流程
- openOutputStream中创建并初始化了outputStream (注意这里初始化了mNormalSink->write)
- 创建MixerThread,这里进行了情况判断,具体mNormalSink是用哪一个变量mPipeSink还是mOutputSink
- MixerThread的播放线程环内打开流,使用到了mNormalSink。
至此使用NBAIO的情况就结束了,接下来介绍下另一种方式,直接运用HAL或者AudioStreamOut进行写操作
2.2 mOutput->write
2.2.1 mOutput定义
首先查看下moutput参数的定义
//threads.cpp
class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
public VolumeInterface {
AudioStreamOut *mOutput;
}
mOutput在playbackthread类中定义,并且类型是AudioStreamOut。
2.2.2 mOutput创建
2.2.2.1 mOutput来源
接下来看下它的初始化
mOutput是playbackthread的变量,查看playbackthread的构造函数
//threads.cpp
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
audio_io_handle_t id,
audio_devices_t device,
type_t type,
bool systemReady)
mOutput(output),
{
}
PlaybackThread的入参output赋值给PlaybackThread->mOutput变量。
看下PlaybackThread是哪里创建的,一般PlaybackThread是由播放线程实例(如mixerthread)的构造函数中继承过来,查看下mixerthread的构造函数。
//threads.cpp
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
// mAudioMixer below
// mFastMixer below
mFastMixerFutex(0),
mMasterMono(false)
// mOutputSink below
// mPipeSink below
// mNormalSink below
{
}
看到了,mixerthread的构造函数中先执行PlaybackThread构造函数,同时把output传入,那查看下mixerthread的入参是从哪里来的
//AudioStreamOut.h
class AudioStreamOut {
sp<StreamOutHalInterface> stream;
}
//AudioFlinger.cpp
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
//这里outputStream的初始化
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
//创建MixerThread线程
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
}
MixerThread的构造函数的第二个入参outputStream就是我们要的mOutput变量。
outputStream变量的初始化在openoutput()中实现,具体调用内容参考这篇文章。
```cpp
//@AudioHwDevice.cpp
//打开输出流
status_t AudioHwDevice::openOutputStream(
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
const char *address)
{
//创建AudioStreamOut音频输出流
AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
//创建成功后就打开这个输出流,这里是是outputStream的操作初始化
status_t status = outputStream->open(handle, devices, config, address);
//将这个指针赋值给传入的参数,实现参数的传出
*ppStreamOut = outputStream;
return status;
}
这里创建了AudioStreamOut对象,并传出,作为mixerthread的第二个入参。
对比一下mNormalSink,这两种情况都是传入outputStream,同一个参数
区别:mNormalSink情况下,在mixerthread的构造函数中利用outputStream创建了AudioStreamOutSink,之后就是针对这个类的对象进行操作
mOutput情况下,直接利用传入的outputStream参数(AudioStreamOut 类型)进行处理。
待整理
moutput是在PlaybackThread的构造函数中赋初值的,所以要看下PlaybackThread的初始化传入参数哪来的。查看下前文openoutput中创建的线程。需要注意的是PlaybackThread构造函数的第二个参数才是我们需要的,看下new mixerhthread中的第二个参数outputStream。
注意:传入函数的时候使用的参数名可能更改了,要注意区别,可能会和之后的参数同名(比如outputStream和output)
好的,至此我们知道了mOutput->write的初始化是在openoutput()函数中调用了openOutputStream创建的。具体看下openOutputStream函数
2.2.2.1 mOutput的ops
write操作定义
//AudioHwDevice.cpp
status_t AudioHwDevice::openOutputStream(
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
const char *address)
{
//创建一个AudioStreamOut对象,并给到AudioStreamOut指针
AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
//创建成功后就打开这个输出流,这里是是outputStream的操作初始化
status_t status = outputStream->open(handle, devices, config, address);
//将这个指针赋值给传入的参数,实现参数的传出
*ppStreamOut = outputStream;
return status;
}
//AudioStreamOut.cpp
status_t AudioStreamOut::open(
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
const char *address)
{
sp<StreamOutHalInterface> outStream;
int status = hwDev()->openOutputStream(
handle,
devices,
customFlags,
config,
address,
&outStream);
return status;
}
//中间还有调用,具体细节查看openoutput文章
//@audio_hw.c
//初始化输出流的操作
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address __unused)
{
out->stream.write = out_write;
}
openOutputStream()函数中会对stream进行初始化,moutput->write执行的函数就是这里定义的,该write操作就是执行的out_write()函数。之后就和第一种情况一样。
待处理
总结:这种直接调用方法和上一种的区别在于,上一种中间创建了audiostreamsink类,重新封装了write函数,但是最终都调用到audiohw.cpp中的操作。
3. out_write
这里介绍下上面都调到的部分,out_write()函数,这里开始两种方式执行的都一样。
//@audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
struct stream_out *out = (struct stream_out *)stream;
ret = start_output_stream(out);
}
int start_output_stream(struct stream_out *out)
{
out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
flags, &out->config);
}
//\external\tinyalsa\pcm.c
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config)
{
char fn[256];
//初始化fn,打开设备路径
snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
flags & PCM_IN ? 'c' : 'p');
pcm->flags = flags;
pcm->fd = open(fn, O_RDWR|O_NONBLOCK);
}
注意:这里就是打开内核中文件系统的pcm设备,open(),打开设备会执行设备定义的操作,来看下pcm字符设备定义的操作。
到这里就有点进行不下去了,因为这要具体的pcm字符设备号。
查看sound.c文件,可以发现打开设备的函数
static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
const struct file_operations *new_fops;
int err = 0;
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
mutex_lock(&sound_mutex);
mptr = snd_minors[minor];
if (mptr == NULL) {
mptr = autoload_device(minor);
if (!mptr) {
mutex_unlock(&sound_mutex);
return -ENODEV;
}
}
//获取文件的操作函数,具体要看这个pcm设备的声卡号等
new_fops = fops_get(mptr->f_ops);
mutex_unlock(&sound_mutex);
if (!new_fops)
return -ENODEV;
replace_fops(file, new_fops);
//这里执行pcmC0D00的具体操作
if (file->f_op->open)
err = file->f_op->open(inode, file);
return err;
}
这里的open函数执行到我的Xmind文件alsa创建流程中的pcm使用部分,具体的调用之后再写。只要知道这句open语句执行之后,就进入到了pcm设备的打开,可以先参考这篇文章,很详细地讲解了pcm的创建和使用,可以直接看使用部分,图4.3.2.1中的file system就是open这个环节。
至此,就成功地从native到了kernel的driver中。超nice
结合之前看到ALSA,可以看到之后的调用。
从应用层到内核驱动的线路就此打通了一条小路,还有很多其他知识点需要再梳理。先这样吧,哈哈哈哈。
以下仅作参考
这里是我往下挖的变量类型定义,而上面是从调用的角度找函数的初始化,上面那个效率更高
这里有两个文件,一个是hidl下的,一个是local下的,具体调用到哪一个还不确定。这两个类都是由StreamOutHalInterface继承而来
//StreamHalHidl.h
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
virtual status_t write(const void *buffer, size_t bytes, size_t *written);
}
//StreamOutHalLocal.h
class StreamOutHalLocal : public StreamOutHalInterface, public StreamHalLocal {
virtual status_t write(const void *buffer, size_t bytes, size_t *written);
}
//------------------------local---------------------------------
//StreamOutHalLocal.cpp
status_t StreamOutHalLocal::write(const void *buffer, size_t bytes, size_t *written) {
ssize_t writeResult = mStream->write(mStream, buffer, bytes);
if (writeResult > 0) {
*written = writeResult;
mStreamPowerLog.log(buffer, *written);
return OK;
} else {
*written = 0;
return writeResult;
}
}
//------------------------hidl---------------------------------
status_t StreamOutHalHidl::write(const void *buffer, size_t bytes, size_t *written) {
if (mStream == 0) return NO_INIT;
*written = 0;
if (bytes == 0 && !mDataMQ) {
// Can't determine the size for the MQ buffer. Wait for a non-empty write request.
ALOGW_IF(mCallback.unsafe_get(), "First call to async write with 0 bytes");
return OK;
}
status_t status;
if (!mDataMQ) {
// In case if playback starts close to the end of a compressed track, the bytes
// that need to be written is less than the actual buffer size. Need to use
// full buffer size for the MQ since otherwise after seeking back to the middle
// data will be truncated.
size_t bufferSize;
if ((status = getCachedBufferSize(&bufferSize)) != OK) {
return status;
}
if (bytes > bufferSize) bufferSize = bytes;
if ((status = prepareForWriting(bufferSize)) != OK) {
return status;
}
}
status = callWriterThread(
WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
[&] (const WriteStatus& writeStatus) {
*written = writeStatus.reply.written;
// Diagnostics of the cause of b/35813113.
ALOGE_IF(*written > bytes,
"hal reports more bytes written than asked for: %lld > %lld",
(long long)*written, (long long)bytes);
});
mStreamPowerLog.log(buffer, *written);
return status;
hidl中创建线程,具体调用看参考的文档
local中的
//StreamOutHalLocal.h
class StreamOutHalLocal : public StreamOutHalInterface, public StreamHalLocal {
audio_stream_out_t *mStream;
}
//audio.h
typedef struct audio_stream_out audio_stream_out_t;
struct audio_stream_out {
ssize_t (*write)(struct audio_stream_out *stream, const void* buffer,
size_t bytes);
}
local代码中最终调用到audio_stream_out结构体中的write函数。
mOutput->write
NBAIO_Sink的class中查看到了write(),这是一个纯虚函数,所以看其实现在哪里。
AudioStreamOutSink类继承自NBAIO_Sink类,所以NBAIO_Sink的write函数的具体实现是在AudioStreamOutSink::write()中。
上面代码可以看到
//-----------------------------mOutput-------------------------
//Threads.h
AudioStreamOut *mOutput;
//@AudioStreamOutSink.h
class AudioStreamOutSink : public NBAIO_Sink {
virtual ssize_t write(const void *buffer, size_t count);
}
AudioStreamOutSink::AudioStreamOutSink(sp<StreamOutHalInterface> stream) :
NBAIO_Sink(),
mStream(stream),
mStreamBufferSizeBytes(0)
{
ALOG_ASSERT(stream != 0);
}
//Threads.h
AudioStreamOut *mOutput;
sp<NBAIO_Sink> mNormalSink;
//Threads.cpp
ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{
if (mNormalSink != 0) {
ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
} else {
bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
}
}
先看下AudioStreamOutSink::write
//@AudioStreamOutSink.h
class AudioStreamOutSink : public NBAIO_Sink {
sp<StreamOutHalInterface> mStream;
}
//StreamHalInterface.h
class StreamHalInterface : public virtual RefBase
//AudioStreamOutSink.cpp
ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
{
status_t ret = mStream->write(buffer, count * mFrameSize, &written);
}
这里执行到流输出槽接口类StreamHalInterface ,看了下文件,推测是在StreamOutHalLocal.cpp中实现的具体函数。
找到了mStream的类型是audio_stream_out,现在要找它在哪里进行初始化。
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address __unused)
{
out->stream.write = out_write;
}
目前就先查到这,具体是否在这里初始化等明天看
来源:CSDN
作者:飞鸟厌雨
链接:https://blog.csdn.net/qq_38091632/article/details/103410850