前几天,躺在床上玩MX2,电脑放着歌,有点大声。突然想睡觉,但又懒得起床关掉电脑的音乐,无奈之下,就想,要是手机能控制电脑的声音就好了。于是就有了下面的故事:做一个android客户端,用来控制电脑的音量。
大概的思想如下:通过socket来通信,手机客户端通过socket绑定到PC,然后通过发送消失到PC,再由PC进行解析,并进行音量的控制。主要有以下两个阶段。
第一阶段:
PC端,由C++代码来实现,主要考虑到有些电脑不一定能运行java程序。之前很少接触过C++,虽然我现在的工作主要是用C的,但感觉还是差挺多。
之前并没有用C++来控制windows的系统音量,于是在网上查了挺久的资料,才发现需要用mixer来控制。控制的音量的代码如下,封装成一个函数:
void SetVolume(int volume)
{
DWORD vol;
HMIXER hMixer;
MIXERLINE mixerline;
MIXERLINECONTROLS mcls;
MIXERCONTROL mc;
MIXERCONTROLDETAILS mcd;
MIXERCONTROLDETAILS_UNSIGNED mcd_u;
vol = volume*70000/100;
mcd_u.dwValue = vol;
try
{
if(MMSYSERR_NOERROR == mixerOpen(&hMixer, 0, 0, 0, 0))
{
RtlZeroMemory(&mixerline, sizeof(mixerline));
mixerline.cbStruct = sizeof(MIXERLINE);
mixerline.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
if(MMSYSERR_NOERROR == mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerline, MIXER_GETLINEINFOF_COMPONENTTYPE))
{
RtlZeroMemory(&mcls, sizeof(mcls));
mcls.cbStruct = sizeof(MIXERLINECONTROLS);
mcls.dwLineID = mixerline.dwLineID;
mcls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mcls.cControls = 1;
mcls.cbmxctrl = sizeof(MIXERCONTROL);
mcls.pamxctrl = &mc;
// mixerGetControlDetails((HMIXEROBJ)hMixer, (MIXERCONTROLDETAILS *)&mc, MIXER_GETCONTROLDETAILSF_VALUE);
// printf("mcd.bound.maxvolume:0x%x\n", mc.Bounds.lMaximum);
// printf("mcd.bound.minvolume:0x%x\n", mc.Bounds.lMinimum);
if(MMSYSERR_NOERROR == mixerGetLineControls((HMIXEROBJ)hMixer, &mcls, MIXER_GETLINECONTROLSF_ONEBYTYPE))
{
RtlZeroMemory(&mcd, sizeof(MIXERCONTROLDETAILS));
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.dwControlID = mc.dwControlID;
mcd.cChannels = 1;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.paDetails = &mcd_u;
if(MMSYSERR_NOERROR == mixerSetControlDetails((HMIXEROBJ)hMixer,&mcd, MIXER_SETCONTROLDETAILSF_VALUE))
{
return;
}
}
}
}
}
catch(...)
{
}
}
然后只要在main函数的socket中,在接收到客户端的数据后,解析出要设置的音量值,然后调用接口进行设置,就可以了。系统的音量有一个范围,大概是0~7000。如果你要设置的音量是30的话,那就要转换一下了,公式是:客户端传的音量值*7000/100,这样设置的结果才是你想要的效果。
第二阶段:android客户端实现
android刚接触没多少。不过由于之前接触过C#,感觉还是有些类似的。界面布局的话,差不多就一个配置文件。界面主要由一个输入IP的文本框,一个进行创建socket的按钮,以及一个拖动条组成。在创建socket的过程中,有一个问题困扰了我好久,创建socket进行连接的主要代码如下:
sock = new Socket(tv_ip.getText().toString(), port);
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
sock.getOutputStream())), true);
当我一点连接的时候,就异常了,也就是在一运行到sock = new Socket(tv_ip.getText().toString(), port);的时候,程序就异常了,虽然用try进行了捕获,但根本没有,让我好不郁闷,当时又还不怎么熟悉android的调试,也很少看调试信息。最后问了一个编程很牛的同学,在他的指教下,在网上查了下异常信息,才算解决了。具体可以看
http://k-beta.com/android-os-networkonmainthreadexception.html。
终于创建socket是OK了。接下来就是组织数据并发送数据的过程了,这个并没有遇到多大困难。后来又增加了两个按钮,一个是关闭电脑的,一个是重启电脑的。后期的话,还需要将C++的程序完善一下,让它在开机的时候就运行,这样就不用每次都手动去运行了。另外,android客户端也有很多要完善的地方。由于最近工作的原因,时间不够,就暂时搁了。