I have a program that outputs audio via Portaudio. It works for the most part, but there are some USB devices that use the built-in Windows USBAudio drivers that don't work.
I don't get any error and the program shows data being processed in my program, but when the audio stream is sent to portaudio, no sound is output from the USB device. It seems as if portaudio is not initializing the device and therefore can't send the data stream to it.
Some USB devices will work on one USB port, but when I move it to a different USB port on the same computer, it will not work.
Other USB devices will not work on any USB port.
However, all the USB devices work fine when outputting sound from other programs or when using the Windows test audio output.
I cannot figure out why some USB devices work and others don;t even though they are all using the same USB drivers.
Here's the part of my code that initiates the portaudio stream:
static int paPlayCallback( const void *inputBuffer, void *output,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData ){
if(Out2){
int sz= Out2->Size();
if(sz>QUEUE_SIZE)start=1;
if(sz==0){
for(int i=0;i<10;i++)
averagePower[i]= 0.0;
start=0;
}
if(start){
printf("Output queue size %d\n",sz);
while(sampleCount<OUT_BUF_SIZE)
sampleCount+= AddBuffer();
Resample((float*)output, l,r,framesPerBuffer,dev.parameters.channelCount);
DelBuffer();
return paContinue;
}
}
memset(output,0, framesPerBuffer*dev.parameters.channelCount*4);
return paContinue;
}
static void StreamFinished( void* userData )
{
// exit(-1);
}
BOOL Play(int device){
dev.info = Pa_GetDeviceInfo( device );
dev.parameters.device = device;
dev.parameters.channelCount = dev.info->maxOutputChannels;
dev.parameters.sampleFormat = paFloat32;
if((dev.sampleRate = GetSampleRate(&dev.parameters))<=0){
fprintf(stderr,"Error: Bad output device sample rate.\n");
goto error;
}
int frameSize= (int)floor(dev.sampleRate/FPS);
PaError err;
do{
err= Pa_OpenStream(
&dev.stream,
NULL,
&dev.parameters,
dev.sampleRate,
frameSize,
paClipOff,
paPlayCallback,
0);
if(err ){
fprintf(stderr,"Error: Can't open %s in WASAPI exclusive mode.\n",dev.info->name);
}
}while(err != paNoError );
error_check(Pa_SetStreamFinishedCallback( dev.stream, &StreamFinished ));
error_check(Pa_StartStream( dev.stream ));
return TRUE;
error:
return FALSE;
}
It looks like you are opening the steam in shared mode. You must explicitly set the steam to use exclusive mode with the API specific parameters.
This post should demonstrate the correct syntax.
You might verify this by modifying the windows device settings to match your stream settings. If the settings match you should be able to open the device and stream to it successfully.
You may leave the device in shared mode if you query the device to get the default sample rate and type. In shared mode you can only open the device with the default settings.
MSDN article on exclusive streams
Related
I've been having an issue reading from GPIO devices on an embedded device (usrp n310). i2cdetect gives "UU" for the particular devices that I'm trying to reach indicating that the devices are already being occupied by a chip. /sys/bus/i2c/drivers shows that the driver linked to these devices is the pca953x. Previously, I was able to read and write from a GPIO device (tca6416) on the zc706 platform, however, when doing a comparison of /sys/bus/i2c/drivers, I don't see any drivers associated with that chip. The code that I'm using is the following
#include "i2c_dev.hpp"
int main()
{
int i2cfd;
__s32 num;
// Opening i2c adapter 6
printf("Opening bus adapter\n");
i2cfd = open("/dev/i2c-6", O_RDWR);
if ( i2cfd < 0 ) {
printf("Failed to open /dev/i2c-6: %s\n", strerror(errno));
return 1;
}
// Instatiating three objects of IO_Expander class
IO_Expander dba;
// Reading data from the IO Expander
printf("Setting slave address of device\n");
if (ioctl(i2cfd, I2C_SLAVE, 0x20) < 0) {
printf("Error setting slave address:%s\n", strerror(errno));
return 1;
}
printf("Reading data from the IO Expander for DB-A Object\n");
num = dba.read_data(i2cfd, 0x00);
if (num < 0) {
printf("Error reading data: %s\n", strerror(errno));
} else {
printf("The input value is %d\n", num);
}
printf("Leaving DB-A Object\n\n\n");
// Closing the adapter
close(i2cfd);
}
So, am I unable to read from the GPIO devices on the n310 platform because of this pca953x driver? If so, would a correct approach be to "unbind" the pca953x driver the from the devices in order to read values from them?
I'm working on designing a USB peripheral which will occasionally connect to a Windows PC, and transfer a few KB of data in each direction. There will be a custom PC application that controls the data transfers, using a proprietary protocol (i.e. for the USB payloads).
I see at the following link that Microsoft describes how to write a driver for a USB device. But do I need one?
Developing Windows client drivers for USB devices
The PC application is the only application that we intend to know how to communicate with the device, so there's no need for a driver from an application sharing standpoint.
Can I just bake the custom protocol directly into the application, have the application speak "raw USB" to the device, and do without a separate driver?
"raw USB", no, you can't do that from an application.
But because you control the device also, you can make it appear as one of the device classes for which Windows provides a device driver that's generic enough to do just about anything you want.
Those device classes are HID (Human Interface Device) and "WinUSB". Of these, HID is cross-platform but more limited in capability, WinUSB allows high performance data transfers as well as interrupt endpoints.
Instructions for setting up your device's string descriptors so that Windows automatically binds it to the WinUSB driver are on MSDN
A WinUSB device is a Universal Serial Bus (USB) device whose firmware defines certain Microsoft operating system (OS) feature descriptors that report the compatible ID as "WINUSB".
The purpose of a WinUSB device is to enable Windows to load Winusb.sys as the device's function driver without a custom INF file. For a WinUSB device, you are not required to distribute INF files for your device, making the driver installation process simple for end users.
There is another way with no need to write driver to write what You want to device using WriteFile function:WinUSB, how to do this:
Include WinUsb.h
Add WinUsb.lib to the list of linked libraries.
in Usb100.h some macros.
Use the device interface GUID to obtain the device path. The correct GUID is the one that you specified in the INF that was used to install WinUsb.sys.
Get a handle to the device information set by passing the device interface GUID that you defined in the INF to SetupDiGetClassDevs. The function returns an HDEVINFO handle.
Call SetupDiEnumDeviceInterfaces to enumerate the system’s device interfaces and obtain information on your device interface.
Call SetupDiGetDeviceInterfaceDetail to get detailed data for the device interface.
Call the GetDevicePath function to obtain the device path.
Pass the device path to CreateFile to obtain a file handle for the device. Use ReadFile and Write File to communicate with device!
Pass the file handle to WinUsb_Initialize to initialize WinUSB and obtain a WinUSB handle. You use the device’s WinUSB handle to identify the device when you call WinUSB API functions, not the device’s file handle.
For more advanced solutions - use functions:
WinUsb_QueryDeviceInformation to obtain the device’s speed.
WinUsb_QueryInterfaceSettings to obtain the corresponding interface descriptors. The WinUSB handle corresponds to the first interface.
WinUsb_QueryPipe gets information about each endpoint.
WinUsb_WritePipe writes the buffer to the device - default behavior: zero-length writes are forwarded down the stack. If the transfer length is greater than a maximum transfer length, WinUSB divides the request into smaller requests of maximum transfer length and submits them serially.
more functions and info: http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/winusb_howto.docx
For debugging purposes You probably need:
winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;
Wireshark https://www.wireshark.org with USBPcap plugin.
Other Example:
http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html.
Sample template comes with Visual Studio.
You need also have knowledge of writing .inf files.
Another easy way to communicate with USB - libusb-win32 https://sourceforge.net/projects/libusb-win32/
My simple console app sends chunks to device (raw data write immediately to device bypassing the stack):
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h>
#include <devguid.h>
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h>
iString<char> DevicePath;
bool WinusbHandle_Open=false;
bool DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;
bool connectusb();
void disconnectusb();
int main()
{
DWORD n;
DWORD numEvents;
HANDLE rHnd;
WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;
ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);
WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);
timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.
while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;
bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}
bool connectusb()
{
BOOL bResult = FALSE;
HDEVINFO deviceInfo;
SP_DEVICE_INTERFACE_DATA interfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
DWORD n;
SP_DEVINFO_DATA devinfo;
BYTE devdetailbuffer[4096];
bool found;
deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }
found = false;
for (n = 0;; n++)
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
{
n = GetLastError();
break;
}
detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
{
if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
{
if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
{
DevicePath = detailData->DevicePath;
found = true;
break;
}
}
}
}
SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;
DeviceHandle = CreateFile(DevicePath.Buffer() ,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == DeviceHandle) {
n = GetLastError();
}
if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;
if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
{
n = GetLastError();
CloseHandle(DeviceHandle); DeviceHandle_Open = false;
return false;
}
WinusbHandle_Open = true;
return true;
}
void disconnectusb()
{
if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
Making your firmware to be enumerated as a WINUSB (winusb generic driver) device makes life easier.
I believe it'd be clear if you have a demo and code so I made one for you :)
My KEIL project using the STM32F4 Discovery board working with WINUSB as an USB CDC device. You can see more information and have the source code from my GitHub.
I'm learning how to build OSX applications, and I was wondering if there is a way to check if there is some audio being outputted by any application on the system? Thanks
I think this can be checked with the kAudioDevicePropertyDeviceIsRunningSomewhere property.
From the header doc:
A UInt32 where 1 means that the AudioDevice is running in at least one process on the system and 0 means that it isn't running at all.
Pseudo-y code:
bool isRunningSomewhere(AudioDeviceID deviceId) {
uint32 val;
uint32 size = sizeof(val);
AudioObjectPropertyAddress pa = { kAudioDevicePropertyDeviceIsRunningSomewhere, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
AudioObjectGetPropertyData(deviceId, &pa, 0, NULL, &size, &val);
return val == 1;
}
This should tell you if the device is being used (i.e. has an active IOProc.) But it won't tell you if that IOProc is just sending silence.
This can't be done at the user application level. It might be possible by installing an OS X kext (kernel extension) or a custom audio device driver, which requires sudo privileges and possibly a reboot.
Please can anyone give me direct for realization next functional for Windows.
I have USB device which connects to the PC (it is JTAG programmer.) I know VID and PID of this hardware. I need:
1 Check what type of driver this hardware use (detecting winusb driver or not will be enough. Maybe do I need to read registry?)
2 If driver is not winusb I need to install winusb driver for this USB device from my application.
The current driver assigned to the device is stored in the registry, so you could read it directly from there. However, it is probably better to use SetupAPI, an API provided by Microsoft. The function to call is SetupDiGetDeviceRegistryProperty, and the third argument should be SPDRP_SERVICE. This will return the name of the driver as a string. Note that you will need to call several other SetupAPI functions before you have all the pieces of info you need to call SetupDiGetDeviceRegistryProperty.
I have not tried it, but libwdi has features for installing WinUSB onto a device node. It might also have functions for getting the current driver, so you should try using it before you spend too much time learning SetupAPI. The devcon utility from Microsoft (which is open source now) might be another option.
Without knowing the details of what you are doing, I question whether you really need to do this. It might be simpler to provide a signed driver package to users and instruct them to use the "Update Driver Software..." option from the Device Manager to apply it to particular device.
I made first part of task.
#ifdef Q_OS_WIN
DEFINE_GUID(GUID_DEVCLASS_WINUSB,0x88BAE032,0x5A81,0x49f0,
0xBC,0x3D,0xA4,0xFF,0x13,0x82,0x16,0xD6);
#endif
bool WinUSB::isWinUsbDriver(quint16 vid, quint16 pid)
{
#ifndef Q_OS_WIN
Q_UNUSED(vid);
Q_UNUSED(pid);
return true;
#else
HDEVINFO deviceInfoSet;
GUID *guidDev = (GUID*) &GUID_DEVCLASS_WINUSB;
deviceInfoSet = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE);
DWORD buffersize =4000;
TCHAR buffer [buffersize];
int memberIndex = 0;
bool retval = false;
QString vidPid;
vidPid = "VID_" + QString("%1").arg(vid,4,16,QChar('0')) + "&";
vidPid += "PID_" + QString("%1").arg(pid,4,16,QChar('0'));
while (true)
{
SP_DEVINFO_DATA deviceInfoData;
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex, &deviceInfoData) == FALSE) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
}
}
DWORD nSize=0 ;
SetupDiGetDeviceInstanceId (deviceInfoSet, &deviceInfoData, buffer, sizeof(buffer), &nSize);
buffer [nSize] ='\0';
QString str = QString::fromWCharArray(buffer);
if (str.indexOf(vidPid) >= 0) {
retval = true;
break;
}
memberIndex++;
}
if (deviceInfoSet) {
SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
return retval;
#endif
}
I am using OpenCV in Visual Studio 2010 to track an object, and I am trying to send a value to the Arduino to rotate servos attached to the camera. I am using an Arduino Uno. I have completed the C++ code that tracks the object and determines which direction the camera needs to be rotated, but I am having trouble sending this data to the Arduino. I am currently trying to use an RS-232 cable for this. I am using a Type-B USB cable to program my Arduino and an RS-232 to try to send the data from Visual Studio to the Arduino. Here is my code for the Visual Studio serial communication:
int portspeed(int centerpix, int xmid)
{HANDLE hDevice = CreateFile(L"COM5",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0);
DCB lpTest;
GetCommState(hDevice,&lpTest);
lpTest.BaudRate = CBR_9600;
lpTest.ByteSize = 8;
lpTest.Parity = NOPARITY;
lpTest.StopBits = ONESTOPBIT;
SetCommState(hDevice,&lpTest);
DWORD btsIO;
if (centerpix<xmid)
{
char test[] = "2";
WriteFile(hDevice,test,strlen(test),&btsIO,NULL);
cout << "Turn right " << test << endl;
}
else
{
char test[] = "3";
WriteFile(hDevice,test,strlen(test),&btsIO,NULL);
cout << "Turn left " << test << endl;
}
return 0;
}
On the Arduino code side I have this, which I am using to attempt to light two different LEDS to see if the program is able to correctly communicate which direction it needs to rotate:
int incomingByte = 0; // For incoming serial data
void setup()
{
Serial.begin(9600); // Opens serial port, sets data rate to 9600 bit/s
}
void loop()
{
// Send data only when you receive data:
if (Serial.available() > 0)
{
incomingByte = Serial.read();
if (incomingByte==50) //if =2
analogWrite(9,100);
else
analogWrite(9,0);
if (incomingByte==51) //if =3
analogWrite(10,50);
else analogWrite(10,0);
delay(3000);
}
else
analogWrite(9,255);
}
My interpretation is that I need to start the C++ program (which continuously sends the data over the serial communication), and then attach the TX pin from the RS-232 into the RX pin (digital 0) on the Arduino. When I try to upload the program to the Arduino I am given an error,
avrdude: stk500_getsync(): not in sync: resp=0x00
This only occurs when I have a wire going into the RX pin, even if this wire is not connected to anything. I believe that this error occurs because the RX is looking for an input with a baud rate of 9600, but it still gives me this error when the C++ program is running and sending the data with a rate of 9600.
How can I send a value from a Visual Studio project doing real time image processing on a laptop to an Arduino via serial communication?
Speaking as someone with limited Win32 experience (more of a .NET guy, really), I think your problem may be in write buffering.
By default, writes to a file or port are buffered in memory. Perhaps the write is never getting sent to the port as you are never closing the file handle nor calling [FlushFileBuffers][3].
Try adding this prior to return 0;:
//After a time, sensitive write
FlushFileBuffers(hDevice);
//or, more properly for the end of the program.
CloseHandle(hDevice);