我们有一个Android设备,我们希望microphone同时使用2应用程序.
实际上,我们有一个在后台运行的声音命令服务(我们正在使用该CMU Sphinx库).问题是当我们启动录像机(相机应用程序)时,我们无法启动录制,因为2个应用程序无法同时访问麦克风.
错误
08-20 12:20:14.601: I/MediaRecorderJNI(7261): prepare: surface=0x59590668
08-20 12:20:15.916: E/MediaRecorder(7261): start failed: -38
08-20 12:20:15.916: E/com.example.CamcorderView(7261): Failed to start recorder.
08-20 12:20:15.916: E/com.example.CamcorderView(7261): java.lang.IllegalStateException
08-20 12:20:15.916: E/com.example.CamcorderView(7261): at android.media.MediaRecorder.start(Native Method)
Run Code Online (Sandbox Code Playgroud)
请注意,当人声服务关闭时,相机可以正常工作.
而且,我确切地说我已经读过这个帖子了:
Android:同时访问麦克风(RecognizerIntent +自己的应用)
但这里的不同之处在于我们可以在O/S和内核上进行操作.所以我们可以根据需要应用补丁.
这是一个SDK/OS/Kernel限制吗?有没有解决方法?
经过对Stackoverflow和google的大量研究后,似乎很难使用它的句柄将击键组合发送到后台窗口.例如,我想发送CTRL + F.似乎Sendmessage不起作用,并且sendinput无效,因为窗口需要焦点.
所以我最后的想法是关于挂钩:无论如何使用这种方式发送组合?
目前,我正在制作一个拦截特定键盘击键的程序(使用其HID进行过滤).因此,为了知道特定设备发送了哪些击键,我使用了RawInput技术,受到这个伟大教程的启发:
http://www.codeproject.com/Articles/17123/Using-Raw-Input-from-C-to-handle-multiple-keyboard
现在,它工作得很好:我可以获得击键并知道哪个键盘生成了它.
我的项目的难点在于拦截和阻止来自这个特定键盘的击键,以避免这些击键到达聚焦应用程序(聚焦意味着操作系统带来的前景窗口).
因此,在具有窗口句柄的所有当前线程上,自然解决方案是低级全局钩子.
我使用并调整了此页面中的代码来执行此操作:
http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
我在visual studio中创建了一个新项目,以避免在我的工作中乱七八糟.经过一些研究,我能够通过在回调函数中返回值(-1)来阻止所有应用程序的击键:
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
//Check if we have a key to pass
if (
nCode >= 0 && (
(wParam == (IntPtr)WM_KEYDOWN) || (wParam == (IntPtr)WM_KEYUP) )
)
{
int vkCode = Marshal.ReadInt32(lParam);
if ((Keys)vkCode == Form1.KeysToIgnore)
{
return (IntPtr)(-1);
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)
为了将所有内容(钩子程序和击键检测)放在一起,我在最终项目中创建了两个线程:
1st:使用RawInput识别每个键击并将其附加到设备
第二:用于挂钩所有窗口并阻止某些击键
线程1被设计为发送键击以阻止线程2,线程2读取发送到所有窗口应用程序的所有消息和来自特定键盘的垃圾键击.我确切地知道这两个线程是同步的.
问题是钩子似乎是在执行Rawinput之前执行的,所以我无法识别发送击键的键盘.我不知道怎么做,也许改变钩子的类型(避免使用低级键盘钩,但使用用户空间级键盘钩).
或者也许有人知道一种聪明的方式来做我想做的事情?
我知道这个请求真的很复杂,请不要犹豫,询问更多细节.