俗话说,巧妇难为无米之炊,现在我们已经有了所有的配料,那就赶紧下锅吧。
接下来的代码,才是SpyDroid自己写的代码,让我们来研究下:
~~~~~~~~~~~~~接下来执行:
this.session = this.sessionbuilderaac.build();
进入build函数,让我们来执行下:
~~~~~~~~~~~~~接下来执行:
Session session;
session = new Session();
我们看public Session()
{
的第一行代码是:this(null, null);
表明调用了另外一个构造器,进入this(null, null);来执行看看。
~~~~~~~~~~~~~
long uptime = System.currentTimeMillis();
MainActivity.singleInstane.dispatch("uptime="+uptime+"\r\n");
//当前时间与1970年1月1日0点之差。
mDestination = destination;
//设置mDestination为null
mOrigin = origin;
//设置mOrigin为null
mTimestamp = (uptime/1000)<<32 & (((uptime-((uptime/1000)*1000))>>32)/1000); // NTP timestamp
MainActivity.singleInstane.dispatch("mTimestamp="+uptime+"\r\n");
//设置NTP时间戳
~~~~~~~~~~~~~这里插一句:
mTimeStamp的计算方法中,
(
uptime -(
(uptime/1000)*1000
)
)>>32
肯定为0,所以整个计算结果也肯定为0
~~~~~~~接下来执行:
try
{
mOrigin = InetAddress.getLocalHost();
} catch (Exception ignore)
{
MainActivity.singleInstane.dispatch("构造session出错了");
mOrigin = null;
}
这个我通过打印消息的方式表明这段代码是一般情况下是会出现异常的,
我之所以说一般,是因为可以通过别的方式保证这段代码不发生异常且可顺利执行,
不过我之前已经给过了另外一个通用函数。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~回到build函数来:
session.setContext(mContext);
作用:
private Context mContext = null;
//--->上下文的引用
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~接下来执行:
session.setOrigin(mOrigin);
作用:
private InetAddress mOrigin;
//--->null-->null--> //--->192.168.2.132
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~接下来执行:
session.setDestination(mDestination);
作用:
private InetAddress mDestination;
//--->null //--->192.168.1.100
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~接下来执行:
session.setTimeToLive(mTimeToLive);
private int mTimeToLive = 64;
// //-->64
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~接下来执行:
switch (mAudioEncoder)
{
case AUDIO_AAC:
AACStream stream = new AACStream();
session.addAudioTrack(stream);
if (mContext!=null)
stream.setPreferences(PreferenceManager.getDefaultSharedPreferences(mContext));
break;
case AUDIO_AMRNB:
session.addAudioTrack(new AMRNBStream());
break;
}
这段代码是根据音频格式的不同,构造不同的流对象。
这里是AAC格式,构造一个AACStream stream = new AACStream();
那下面来看看AACStream的初始化过程。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
先看看涉及到哪几个类:
public abstract class MediaStream implements Stream {
public abstract class AudioStream extends MediaStream {
public class AACStream extends AudioStream {
涉及到三个类,1个接口。
下面开始分析过程,这部分挺重要:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
注意:执行的顺序是先从MediaStream开始,到AudioStream,再到AACStream,下面为了方便,没有
按照这个顺序讲解。
AACStream的初始化函数第一行是:super();
也就是初始化AudioStream.
public AudioStream()
{
setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
}
可见核心代码就一行: setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
作用:
protected int mAudioSource;
//--->MediaRecorder.AudioSource.CAMCORDER
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
关于MediaStream的初始化,这里有一个代码块。
static
{
// We determine wether or not the MediaCodec API should be used
try {
Class.forName("android.media.MediaCodec");
// Will be set to MODE_MEDIACODEC_API at some point...
sSuggestedMode = MODE_MEDIACODEC_API;
Log.i(TAG,"Phone supports the MediaCoded API");
} catch (ClassNotFoundException e) {
sSuggestedMode = MODE_MEDIARECORDER_API;
Log.i(TAG,"Phone does not support the MediaCodec API");
}
}
用来确定录制音频的模式,根据手机来判断。
我的手机表明:采用MODE_MEDIACODEC_API方式。
protected int mMode = MODE_MEDIARECORDER_API;
//--->MODE_MEDIACODEC_API
protected static int sSuggestedMode = MODE_MEDIARECORDER_API;
//--->MODE_MEDIACODEC_API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
回到AACStream的初始化函数。
if (!AACStreamingSupported())
{
Log.e(TAG,"AAC not supported on this phone");
throw new AACNotSupportedException();
} else {
Log.d(TAG,"AAC supported on this phone");
}
检验AAC是否支持,我的手机自然是支持的。
~~~~~~~~~~~~~~~~~~~~~~~~~接下来执行:
if (mMode == MODE_MEDIARECORDER_API)
{
mPacketizer = new AACADTSPacketizer();
}
else
{
mPacketizer = new AACLATMPacketizer();
}
我的手机显示执行下面一个选择 mPacketizer = new AACLATMPacketizer();。
接下来看AACLATMPacketizer的初始化。
看,JAVA代码就是各种对象的错综复杂。