I have a program I'm writing which has a Server and a Client to communicate with each other to stream a microphone in real-time.
This is how it works
The user opens the client.exe, and their computer appears on the server, which is where I can operate the microphone (I'm NOT using this on other people).
When I press "listen" I can hear the clients microphone.
This is the code I'm using to listen to the clients microphone
CLIENT APPLICATION
Private Declare Function mmciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Case "scream1"
mmciSendString("open new Type waveaudio Alias recsound", "", 0, 0)
mmciSendString("record recsound", "", 0, 0)
Case "scream1stop"
mmciSendString("save recsound " + screamx, "", 0, 0)
mmciSendString("close recsound", "", 0, 0)
Dim n As New IO.FileInfo(screamx)
Comet.Send("scream2" & Yy & n.Name & Yy & Convert.ToBase64String(IO.File.ReadAllBytes(screamx)))
Comet.Send("screamf" & Yy & n.Name & Yy & Convert.ToBase64String(IO.File.ReadAllBytes(screamx)))
My.Computer.Audio.Stop()
SERVER APPLICATION
Timer2.Enabled = True
Timer3.Enabled = True
Private Sub Timer3_Tick(sender As Object, e As EventArgs) Handles Timer3.Tick
Form1.S.Send(xxx, "scream1")
Timer1.Enabled = True
Timer3.Enabled = False
Timer3.Enabled = True
End Sub
Private Sub BunifuFlatButton3_Click(sender As Object, e As EventArgs) Handles BunifuFlatButton3.Click
BunifuFlatButton2.Show()
BunifuFlatButton3.Hide()
Form1.S.Send(xxx, "scream1stop")
Timer1.Enabled = False
Timer2.Enabled = False
Timer3.Enabled = False
End Sub
Of course, there is other code which communicates with the server, but I don't think it's necessary at this point in time.
So, that code I provided you with, it listens for the microphone, but doesn't stream my own microphone. So, how can I do this?
Are there any good .dll add-ons for Visual Basic to do this task?
If I haven't made this clear enough, please comment below.
Thanks!
Related
I'm trying to write an app to perform some basic process automation by sending keyboard events (i.e. simulating single key presses as well as holding keys down) to a window in focus (any window, such as Notepad). I can get single key presses to work just fine, but I can't get it to hold a key down. Even if I do a key down event, followed by a lengthy delay, followed by a key up... all I get is a single keypress.
I've read so many tutorials, and many of them multiple times over to ensure I haven't missed something. Every single time however, all I get is a single key press, it fails to hold the key down.
The following is a code sample I found from:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/bad5b1f3-cf59-4a2b-889b-257ee590bf99/vb-advanced-key-bot?forum=vbgeneral
What I'm expecting to have happen is that it would send a keyboard event that tells the system to hold down a key (e.g. aaaaaaaaaaaaaaaaaaaa), but all I get is a single character. I've tried spamming the system with repeat keypresses, but the receiving app sees the different keyboard code for keydowns and keyups, as opposed to a key in a held status, and thus is not responding as though the key were actually held key down.
What am I doing wrong? Did they maybe change this dll?
A huge thanks to anyone who can help me get this working.
Public Class Form1
Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Integer, ByVal wMapType As Integer) As Integer
' flag to indicate completion
Dim finished As Boolean = True
' how long to 'press' the Space key
Dim delay As Integer = 3
' how many times to repeat Q and Space
Dim Repeats As Integer
' User closes application during processing
Dim UserInterupt As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
KeyPreview = True
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
If Not finished Then
TextBox1.AppendText("USER closing" & vbCrLf)
UserInterupt = True
e.Cancel = True
End If
End Sub
Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
Select Case e.KeyChar
Case "z", "Z"
e.Handled = True
Repeats = 12
finished = False
Do While Not finished
TextBox1.AppendText("Pressing SPACE" & vbCrLf)
HoldKeyDown(Keys.Space, delay)
Loop
Case "x", "X"
e.Handled = True
TextBox1.AppendText("USER stopping" & vbCrLf)
finished = True
End Select
End Sub
Private Sub HoldKeyDown(ByVal k As Keys, ByVal Hold As Integer)
Dim HoldFor As DateTime = DateTime.Now().AddSeconds(Hold)
keybd_event(k, MapVirtualKey(k, 0), 0, 0)
While HoldFor.Subtract(DateTime.Now()).TotalSeconds > 0
Application.DoEvents()
End While
keybd_event(k, MapVirtualKey(k, 0), 2, 0)
TextBox1.AppendText("SPACE released" & vbCrLf)
Repeats -= 1
If Repeats = 0 Then
finished = True
TextBox1.AppendText("REPEATS completed" & vbCrLf)
End If
If UserInterupt Then End
End Sub
End Class
Answering my own question after going right down the rabbit hole on this one.
Basically put, the only way to do this is with SendKeys. The other methods are all deprecated and so will not work in this way anymore.
However this isn't a dead-end for you. If you want to use SendKeys to "hold down" a key, then spam the key at 10ms intervals and this should trigger the receiving app to think the key is held down.
I'm trying to create an audio recorder using VB.Net.
This is how I'm doing it:
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
mciSendString("open new Type waveaudio Alias recsound", "", 0, 0)
mciSendString("set recsound samplespersec 11025 channels 2 bitspersample 16 alignment 4 bytespersec 44100", vbNullString, 0, 0)
mciSendString("record capture", vbNullString, 0, 0)
Label1.Text = "Recording..."
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
mciSendString("save recsound c:\recsound.wav", "", 0, 0)
mciSendString("close recsound", "", 0, 0)
Label1.Text = "Stopped."
End Sub
It works fine, the only problem is that I have two mics, one of them is built-in and the other one is connected via USB. The second one has a way better recording quality but this application always records from the built-in mic.
I've searched all over the internet and I can't find a way to select the recording device. The only thing I was able to find was:
Dim DeviceId As Integer = 2
mciSendString("set recsound input " & DeviceId.ToString())
I've tried different values to no avail.
I have also tried the following code that successfully listed all the properties of all the recording devices found in my computer but I couldn't find anything that could help:
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim objSearcher As New System.Management.ManagementObjectSearcher("SELECT * FROM Win32_SoundDevice")
Dim objCollection As System.Management.ManagementObjectCollection = objSearcher.Get()
Me.TextBox1.Text = ""
For Each obj As ManagementObject In objCollection
Me.TextBox1.Text &= "---------------------------------" & vbCrLf
For Each myProperty As PropertyData In obj.Properties
Me.TextBox1.Text &= myProperty.Name & " - " & myProperty.Value & vbCrLf
Next
Next
End Sub
Any suggestions will be appreciated.
I realize that you asked this question almost two years ago and so you may never see this answer. Perhaps you have notifications turned on and this may help you.
I have switched to Naudio (available through Nuget) for my recording applications and have had much better luck with it. I can specify the recording device as follows:
waveIn = New WaveIn
waveIn.DeviceNumber = 0 '0 - Stereo Mix, 1 - Microphone, 2 - Line In
Figure out what device number your USB microphone is and use that. Do a search on "Naudio" and you will find example code.
I'm writing a program for a handheld barcode scanner which uses Windows Embedded Handheld 6.5 Classic.
I have added a LinkLabel on my form and have coded it so that when you press Shift and click the link it brings up an input box for you to enter a password (I'll be replacing this with an actual form eventually but it is an InputBox for the time being)
When I let go of shift and begin to type my password using the physical keys (it is currently a 4 digit number) it treats the first character as though I am still holding shift.
Is there any way, in code, to revert it back so that shift isn't pressed?
I have tried to use the keybd_event api and it doesn't seem to work
This is what I've tried but I can't seem to find anything else to try.
Public Declare Sub keybd_event Lib "coredll.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)
Private Sub lblTitle_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lblTitle.Click
Try
If GetKeyState(Keys.ShiftKey) = 0 Then Exit Sub
Dim StaffPassword as String = "1234"
Dim _Continue As Boolean = False
keybd_event(VK_Shift, 0, KEYEVENTF_KEYDOWN, 0)
keybd_event(VK_Shift, 0, KEYEVENTF_KEYUP, 0)
Do Until _Continue
Dim _Password As String = InputBox("Please enter the staff password to go into the Admin Screen.", "Enter Password", "", True)
If Not _Password = StaffPassword Then
Dim _Ans As MsgBoxResult = MsgBox("You entered an incorrect password!" & vbNewLine & vbNewLine & "Would you like to try again?", MsgBoxStyle.Exclamation + MsgBoxStyle.YesNo, "Incorrect Password")
If _Ans = MsgBoxResult.No Then Exit Sub
Else
_Continue = True
End If
Loop
frmAdmin.ShowDialog()
Catch ex As Exception
MsgBox(ex.ToString, MsgBoxStyle.Critical, "Error")
End Try
End Sub
Please could someone help?
I know you want to revert the shift effect but maybe a simple workaround could do it. I'm only suggesting this approach because windows ce devices often have non-standard (hardware) keyboards whose drivers are not always perfect.
Since you are only expecting numbers you could try to detect a non-number char and map it to the corresponding number on the keyboard.
I have a problem about a game. I want to play a background sound and another sound when you click a button. When this happens, the background sound stops and the 2nd sound starts. When the 2nd sound finishes, no sound will be played.
You can see my code below:
Imports System.Media.SoundPlayer
Public Class GamePlaying
Dim mainmenusndplayer As New System.Media.SoundPlayer
Private Sub GamePlaying_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
MainMenu.Show()
mainmenusndplayer.Stop()
End Sub
Private Sub btn_Fire_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Fire.Click
btn_Fire.Enabled = False
Dim shotsound As New System.Media.SoundPlayer
shotsound.Stream = My.Resources.TankShoot
shotsound.Play()
End Sub
Private Sub GamePlaying_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
mainmenusndplayer.Stream = My.Resources.WoT_Roll_Out
mainmenusndplayer.Load()
mainmenusndplayer.PlayLooping()
End Sub
End Class
I had been struggling with the same issue.....
The short answer is you can't. The system will only permit one channel to the sound interface within any given process. As such, when you start a new sound, the previous one terminates.
There are a number of work-arounds which mostly use either Direct-X or Media-Player. However, I found neither of those solutions to be either easy or robust in that you are depending on the users machine to have the right things installed.
However, I found a quick and simple solution to the problem.
I added a special "hook" to my application so that when I run it with an appropriate command line argument, all it does is play a particular sound and quit. I then use the process object to start another instance of the application with the appropriate argument.. and hey presto.. multiple sounds.
If your application is configured to automatically be be a single instance, you need to disable that and replace it with a little code to detect another instance and quit.
Another alternative is to add a small exe to your application package that simply does the sound part.
I know it does not sound very "pure", but really, all you are doing is starting a process to play a sound in the background. It doesn't really matter if that process is a windows native function or one of your own making.
you can use winmm.dll with mciSendString :
Imports System.Text
Imports System.Runtime.InteropServices
<DllImport("winmm.dll")>
Private Shared Function mciSendString(ByVal command As String, ByVal buffer As
StringBuilder, ByVal bufferSize As Integer, ByVal hwndCallback As IntPtr) As Integer
End Function
Private Sub MyForm_Click(sender As Object, e As EventArgs) Handles Me.Click
mciSendString("open " & Chr(34) & "C:\myFile1.wav" & Chr(34) " type waveaudio alias Sound1" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("open " & Chr(34) & "C:\myFile2.wav" & Chr(34) " type waveaudio alias Sound2" & internalName, Nothing, 0, IntPtr.Zero)
mciSendString("play Sound1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("play Sound2", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound1 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
mciSendString("setaudio Sound2 volume to 1000", Nothing, 0, Me.Handle.ToInt64())
End Sub
and to stop the sounds you have to :
mciSendString("close Name1", Nothing, 0, Me.Handle.ToInt64())
mciSendString("close Name2", Nothing, 0, Me.Handle.ToInt64())
Download winmm.dll at https://www.dll-files.com/winmm.dll.html
i have the following code:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Const WM_SYSCOMMAND As Integer = &H112
Const SC_SCREENSAVE As Integer = &HF140
MyBase.WndProc(m)
If bloqueado = 0 Then
If m.Msg = WM_SYSCOMMAND AndAlso m.WParam.ToInt32 = SC_SCREENSAVE Then
Timer2.Start()
inicio = Now
pausa = pausa + 1
AddHandler Application.Idle, AddressOf Application_Idle
End If
End If
End Sub
Private Sub Application_Idle(ByVal sender As Object, ByVal e As EventArgs)
Dim newitem As ListViewItem
Dim diferença As TimeSpan
'MsgBox(Now.ToString)'
Debug.Print(Now.ToString)
fim = Now
diferença = fim - inicio
Timer2.Stop()
newitem = New ListViewItem
newitem.Text = pausa
newitem.SubItems.Add(inicio.ToLongTimeString)
newitem.SubItems.Add(fim.ToLongTimeString)
newitem.SubItems.Add(diferença.ToString.Substring(0, 8))
ListView1.Items.Add(newitem)
parcial = parcial & pausa & vbTab & vbTab & inicio.ToLongTimeString & vbTab & vbTab & fim.ToLongTimeString _
& vbTab & vbTab & diferença.ToString.Substring(0, 8) & vbTab & vbTab & " screensaver" & System.Environment.NewLine
RemoveHandler Application.Idle, AddressOf Application_Idle
End Sub
Basically the first part detect when screensaver activates and creates a application.idle event handler and the second part, when activity is detected a bunch of code is run and the handler removed.
It's all works fine except for one point:
As you can see i have inicio = now when screensaver becomes active and fim = now when activity is detected (when screensaver becomes inactive), so i should have 2 differente times, but if i have it like i posted the 2 datetime will be the same. If you notice i have a msgbox displaying the now (when screensaver stops) in comment, if i take it out of comment the 2 datetimes will be differente and correct (i used a cronometer to make sure of the results)
Now my questions:
Why does it need the messagebox for the now to be updated and why doesn't it work it debug.print?
Is there a way to solve this problem/update the now var, without having to use a messagebox (i wouldn't like for the app to have pop-up messages)
If i really have to use msgbox for this purpose is there a way for it not to send the pop-up or to autoclick ok right after so it disappears instantly?
EDIT:
I have been searching and i found this code:
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Function IsSNRunning() As Boolean
IsSNRunning = (FindWindow("WindowsScreenSaverClass", vbNullString) <> 0)
End Function
Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
If IsSNRunning() Then
'Screen Saver Is Running
Else
Timer3.Stop()
code
End If
End Sub
i used Timer3.Start() when in the part that captures the start of the screensaver, my idea being if i start the timer when i know the screensaver if on, then when i get IsSNRunning as false is when the screensaver stops running, but it doesn't work, any ideas why?
Doing anything with Application.Idle is a lost cause. Not only does your app go idle immediately after the screen saver activates, you also never stop being idle while it is running. The screen saver switches the active desktop to a dedicated secure desktop, none of the running programs will ever get any input, not until it de-activates.
You can observe the desktop switch, the SystemEvents.SessionSwitch event fires.
Do note the considerable lack of practical usefulness of code like this. Curiosity is okay but there are always a lot of things to learn. The screen saver should be at the bottom of your list.
First i'll thank you guys for the help, like you said application.idle doesn't work, with you help i got this solution i VB:
Imports System
Imports Microsoft.Win32
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
<DllImport("user32.dll", CharSet:=CharSet.Auto)> Public Shared Function SystemParametersInfo(uAction As UInteger, _
uParam As UInteger, ByRef lpvParam As Boolean, fWinIni As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
' Check if the screensaver is busy running.'
Public Shared Function IsScreensaverRunning() As Boolean
Const SPI_GETSCREENSAVERRUNNING As Integer = 114
Dim isRunning As Boolean = False
If Not SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, isRunning, 0) Then
' Could not detect screen saver status...'
Return False
End If
If isRunning Then
' Screen saver is ON.'
Return True
End If
' Screen saver is OFF.'
Return False
End Function
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Const WM_SYSCOMMAND As Integer = &H112
Const SC_SCREENSAVE As Integer = &HF140
MyBase.WndProc(m)
If bloqueado = 0 Then
If m.Msg = WM_SYSCOMMAND AndAlso m.WParam.ToInt32 = SC_SCREENSAVE Then
Timer2.Start()
Timer3.Enabled = True
Timer3.Start()
'here we that that the screensaver started running so we start a timer'
End If
End If
End Sub
Private Sub Timer3_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer3.Tick
If IsScreensaverRunning() Then
'Screen Saver Is Running'
Else
Timer3.Stop()
Timer3.Enabled = False
'Screen Saver Is not Running'
End If
End Sub
Because the timer only starts running when the screensaver is running we know that when you get timer3.stop is when the screensaver stopped running
Important, don't put a msgbox before the timer stop because it wont work, the pop-up will show and it wont get to the stop so innumerous pop-up will appear (yeah... i made that mistake :S)
Again, thanks for helping me and hope it will help someone in the future