<font size="2"><p>
To get speaker volume in Vista and Windows 7 computers I've written Java-JNA code using JNA 3.3.0 jar.
While invoking winapi (windows API from winmm.dll) mixerGetLineControlsA(..) I got "Invalid memory access" error in both 32 bit Vista and 64 bit windows 7 machines.
Somehow I feel I'm not allocating memory properly while defining the structures
MIXERLINECONTROLS and
MIXERLINECONTROL, but I'm not able to figure it out.
Appreciate your help in resolving this.
</font>
package com.mytest.jna;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.Union;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
public class SystemSpeakerTest {
private static Winmm winmmLib=Winmm.INSTANCE;
private static final int STRUCTURE_ALLIGNMENT=Structure.ALIGN_NONE;
static {
Native.setProtected(true);
}
public static class MixerConstants{
//Refer to -> http://source.winehq.org/source/include/mmsystem.h
public static int MMSYSERR_NOERROR = 0;
public static int MAXPNAMELEN = 32;
public static int MIXER_LONG_NAME_CHARS = 64;
public static int MIXER_SHORT_NAME_CHARS = 16;
public static int MIXER_OBJECTF_HANDLE=0x80000000;
public static int MIXER_OBJECTF_MIXER=0x00000000;
public static int MIXER_OBJECTF_HMIXER=(MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIXER);
public static int MIXER_GETLINECONTROLSF_ALL=0x00000000;
public static int MIXER_GETLINECONTROLSF_ONEBYID=0x00000001;
public static int MIXER_GETLINECONTROLSF_ONEBYTYPE=0x00000002;
public static int MIXER_GETLINECONTROLSF_QUERYMASK=0x0000000F;
//Possible values of MIXERLINE.fdwLine
public static int MIXERLINE_LINEF_ACTIVE=0x00000001;
public static int MIXERLINE_LINEF_DISCONNECTED=0x00008000;
public static int MIXERLINE_LINEF_SOURCE=0x80000000;
public static int MIXER_GETLINEINFOF_DESTINATION=0x00000000;
public static int MIXER_GETLINEINFOF_SOURCE=0x00000001;
public static int MIXER_GETLINEINFOF_LINEID=0x00000002;
public static int MIXER_GETLINEINFOF_COMPONENTTYPE =0x00000003;
public static int MIXER_GETLINEINFOF_TARGETTYPE=0x00000004;
public static int MIXER_GETLINEINFOF_QUERYMASK=0x0000000F;
public static int MIXERCONTROL_CT_CLASS_SWITCH =0x20000000;
public static int MIXERCONTROL_CT_CLASS_FADER =0x50000000;
public static int MIXERCONTROL_CT_SC_SWITCH_BOOLEAN =0x00000000;
public static int MIXERCONTROL_CT_UNITS_BOOLEAN =0x00010000;
public static int MIXERCONTROL_CT_UNITS_UNSIGNED =0x00030000;
public static int MIXERCONTROL_CONTROLTYPE_BOOLEAN =(MIXERCONTROL_CT_CLASS_SWITCH | MIXERCONTROL_CT_SC_SWITCH_BOOLEAN | MIXERCONTROL_CT_UNITS_BOOLEAN);
public static int MIXERCONTROL_CONTROLTYPE_ONOFF =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1);
public static int MIXERCONTROL_CONTROLTYPE_MUTE =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2);
public static int MIXERCONTROL_CONTROLTYPE_MONO =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3);
public static int MIXERCONTROL_CONTROLTYPE_LOUDNESS =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4);
public static int MIXERCONTROL_CONTROLTYPE_STEREOENH =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5);
public static int MIXERCONTROL_CONTROLTYPE_BASS_BOOST =(MIXERCONTROL_CONTROLTYPE_BOOLEAN + 0x00002277);
public static int MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED);
public static int MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1);
public static int MIXERCONTROL_CONTROLTYPE_BASS =(MIXERCONTROL_CONTROLTYPE_FADER + 2);
public static int MIXERCONTROL_CONTROLTYPE_TREBLE =(MIXERCONTROL_CONTROLTYPE_FADER + 3);
public static int MIXERCONTROL_CONTROLTYPE_EQUALIZER =(MIXERCONTROL_CONTROLTYPE_FADER + 4);
}
public interface Winmm extends StdCallLibrary {
Winmm INSTANCE = (Winmm)Native.loadLibrary("winmm", Winmm.class);
//Ref: http://msdn.microsoft.com/en-us/library/aa910078.aspx
int mixerGetNumDevs();
//Ref: http://msdn.microsoft.com/en-us/library/ms932053.aspx
int mixerOpen(IntByReference phmx, int pMxId, int dwCallback, int dwInstance, int fdwOpen);
//Ref: http://msdn.microsoft.com/en-us/library/ms932045.aspx
int mixerGetDevCapsA(int uMxId, MIXERCAPS pmxcaps,int cbmxcaps);
//Ref: http://msdn.microsoft.com/en-us/library/dd757303(VS.85).aspx
int mixerGetLineInfoA(int hmxobj,MIXERLINE pmxl, int fdwInfo);
//Ref: http://msdn.microsoft.com/en-us/library/aa909824.aspx
int mixerGetLineControlsA(int hmxobj,MIXERLINECONTROLS pmxlc, int fdwControls );
//Ref: http://msdn.microsoft.com/en-us/library/aa909818.aspx
int mixerClose(int hmx);
}
public static class MIXERCAPS extends Structure{
public short wMid;
public short wPid;
public int vDriverVersion;
public byte[] szPname=new byte[MixerConstants.MAXPNAMELEN];
public int fdwSupport;
public int cDestinations;
}
public static class MIXERLINE extends Structure {
public int cbStruct;
public int dwDestination;
public int dwSource;
public int dwLineID;
public int fdwLine;
/**
* by http://msdn.microsoft.com/en-us/library/aa909791.aspx
* the field dwUser is int
* by http://msdn.microsoft.com/en-us/library/dd757305(v=VS.85).aspx
* the field dwUser is IntByReference
*/
public int dwUser;
public int dwComponentType;
public int cChannels;
public int cConnections;
public int cControls;
public byte[] szShortName=new byte [MixerConstants.MIXER_SHORT_NAME_CHARS];
public byte[] szName=new byte[MixerConstants.MIXER_LONG_NAME_CHARS];
public Target target;
}
public static class Target extends Structure{
public int dwType;
public int dwDeviceID;
public short wMid;
public short wPid;
public long vDriverVersion;
public byte[] szPname=new byte[MixerConstants.MAXPNAMELEN];
}
public static class MIXERLINECONTROLS extends Structure{
public int cbStruct;
public int dwLineID;
public int dwControlIdType;
public int cControls;
public int cbmxctrl;
public MIXERCONTROL pamxctrl;
public MIXERLINECONTROLS(int cControls){//right now only cControls=1 is supported in the code
super.setAlignType(STRUCTURE_ALLIGNMENT);
this.cControls=cControls;
this.pamxctrl=new MIXERCONTROL();
this.cbmxctrl=this.pamxctrl.size();
allocateMemory();
}
}
public static class MIXERCONTROL extends Structure{
public int cbStruct;
public int dwControlID;
public int dwControlType;
public int fdwControl;
public int cMultipleItems;
public byte[] szShortName=new byte[MixerConstants.MIXER_SHORT_NAME_CHARS];
public byte[] szName=new byte[MixerConstants.MIXER_LONG_NAME_CHARS];
public Bounds.ByValue bounds;
public Metrics.ByValue metrics;
public MIXERCONTROL(){
super.setAlignType(STRUCTURE_ALLIGNMENT);
allocateMemory();
}
}
public static class Bounds extends Union{
public static class ByValue extends Bounds implements Structure.ByValue {}
public LMaxMin.ByValue lMaxMin;
public DwMaxMin.ByValue dwMaxMin;
public int[] dwReserved=new int[6];
public Bounds(){
super.setAlignType(STRUCTURE_ALLIGNMENT);
}
}
public static class Metrics extends Union{
public static class ByValue extends Metrics implements Structure.ByValue {}
public int cSteps;
public int cbCustomData;
public int[] dwReserved=new int[6];
public Metrics(){
super.setAlignType(STRUCTURE_ALLIGNMENT);
}
}
public static class LMaxMin extends Structure{
public static class ByValue extends LMaxMin implements Structure.ByValue {}
public long lMinimum;
public long lMaximum;
public LMaxMin(){
super.setAlignType(STRUCTURE_ALLIGNMENT);
}
}
public static class DwMaxMin extends Structure{
public static class ByValue extends DwMaxMin implements Structure.ByValue {}
public int dwMinimum;
public int dwMaximum;
public DwMaxMin(){
super.setAlignType(STRUCTURE_ALLIGNMENT);
}
}
private static int getNumberOfMixerInSystem(){
int numOfMixer=-1;
numOfMixer=winmmLib.mixerGetNumDevs();
System.out.println("Number Of Mixer :"+numOfMixer);
System.out.println();
return numOfMixer;
}
private static IntByReference openMixerByMixerId(int pMxId){
int dwCallback=0;
int dwInstance=0;
int fdwOpen=MixerConstants.MIXER_OBJECTF_MIXER;//0;
IntByReference phmx=new IntByReference();
int rc=winmmLib.mixerOpen( phmx, pMxId, dwCallback, dwInstance, fdwOpen);
System.out.println("RC mixerOpen ="+rc);
System.out.println("Mixer Id ="+pMxId);
System.out.println("Mixer Handle value ="+phmx.getValue());
System.out.println();
return rc== MixerConstants.MMSYSERR_NOERROR? phmx: null;
}
private static void closeMixerByHanlde(IntByReference mixerHandle){
int rc=winmmLib.mixerClose( mixerHandle.getValue());
System.out.println("RC mixerClose ="+rc);
System.out.println();
}
private static void getMixerCapabilitiesByMixerId(int pMxId){
MIXERCAPS pmxcaps=new MIXERCAPS();
int cbmxcaps =pmxcaps.size();
int rc=winmmLib.mixerGetDevCapsA(pMxId,pmxcaps,cbmxcaps);
System.out.println("RC mixerGetDevCaps ="+rc);
System.out.println("Mixer Id ="+pMxId);
System.out.println("Manufacturer identifier for the mixer device driver ="+pmxcaps.wMid);
System.out.println("Product Name of the Mixer="+new String(pmxcaps.szPname));
System.out.println("Destination Line Count="+pmxcaps.cDestinations);
System.out.println();
}
/**
* If VolumeConstants.MIXER_GETLINEINFOF_DESTINATION
* pmxl.dwDestination= [0,MIXERCAPS.cDestinations)
*
*
* If VolumeConstants.MIXER_GETLINEINFOF_SOURCE
* pmxl.dwDestination= [0,MIXERCAPS.cDestinations)
* pmxl.dwSource=[0, MIXERLINE.cConnections) for each pmxl.dwDestination;
*
* If VolumeConstants.MIXER_GETLINEINFOF_LINEID
* pmxl.dwLineID=MIXERLINE.dwLineID;
*
* @param mixerHandle
* @return
*/
private static MIXERLINE getLineInfoOfMixer(IntByReference mixerHandle){
MIXERLINE pmxl=new MIXERLINE ();
pmxl.cbStruct=pmxl.size();
pmxl.dwDestination=0;
int rc=winmmLib.mixerGetLineInfoA(mixerHandle.getValue(),pmxl,MixerConstants.MIXER_GETLINEINFOF_DESTINATION);
System.out.println("RC mixerGetLineInfoA ="+rc);
System.out.println("dwLineID="+getUnsignedIntValue(pmxl.dwLineID)+" [Signed value="+pmxl.dwLineID+"]");
String shortName=new String(pmxl.szShortName);
System.out.println("szShortName =["+shortName+"]\nszName =["+new String(pmxl.szName)+"]");
System.out.println("Mixer Line State ="+(pmxl.fdwLine==MixerConstants.MIXERLINE_LINEF_ACTIVE?"Active":
pmxl.fdwLine==MixerConstants.MIXERLINE_LINEF_SOURCE?"Source":"Disconnected")+" [fdwLine="+pmxl.fdwLine+"]");
System.out.println("No of Audio Channels for this line that can be manipulated ="+pmxl.cChannels);
System.out.println("No of Source Line associated ="+pmxl.cConnections);
System.out.println("Number of Audio Controls for this line ="+pmxl.cControls);
System.out.println("Component Type ="+pmxl.dwComponentType);
System.out.println();
return rc==MixerConstants.MMSYSERR_NOERROR?pmxl:null;
}
private static void getLineControlOfMixer(IntByReference mixerHandle, MIXERLINE pmxl){
if(pmxl==null){
System.out.println("pmxl is null. mixerGetLineControlsA will not be dispatched.");
return;
}
MIXERLINECONTROLS pmxlc=new MIXERLINECONTROLS(1);
pmxlc.cbStruct=pmxlc.size();
pmxlc.dwControlIdType=MixerConstants.MIXERCONTROL_CONTROLTYPE_MUTE;
int rc=winmmLib.mixerGetLineControlsA(mixerHandle.getValue(), pmxlc, MixerConstants.MIXER_GETLINECONTROLSF_ONEBYTYPE);
System.out.println("RC mixerGetLineControlsA ="+rc);
}
public static long getUnsignedIntValue(int valueOfUnsignedInt){
long MASK=0x00000000FFFFFFFFL;
return MASK&valueOfUnsignedInt;
}
//An unsigned short of bit pattern 0xC000 [1100 0000 0000 0000] decimal value 49152 when assigned to java short becomes signed short
//having a decimal value= -ve of (NOT (1100 0000 0000 0000 -1) ) = -16384
//This method takes a short value of -16384 and return 49152 which of course requires higher bit data type i.e. int in this case
public static int getUnsignedShortValue(short valueOfUnsignedShort){
int MASK=0x0000FFFF;
return MASK&valueOfUnsignedShort;
}
public static void main(String[] args) {
int numOfMixer=getNumberOfMixerInSystem();
for(int mixerId=0; mixerId<numOfMixer; mixerId++){
IntByReference mixerHandle=openMixerByMixerId(mixerId);
if(mixerHandle==null){continue;}
getMixerCapabilitiesByMixerId(mixerId);
MIXERLINE pmxl=getLineInfoOfMixer(mixerHandle);
getLineControlOfMixer(mixerHandle,pmxl);
closeMixerByHanlde(mixerHandle);
//Not interested about mixerId=1 so exit.
if(mixerId==0)System.exit(0);
}
}
}
The error & output:
Number Of Mixer :2
RC mixerOpen =0
Mixer Id =0
Mixer Handle value =2919296
RC mixerGetDevCaps =0
Mixer Id =0
Manufacturer identifier for the mixer device driver =1
Product Name of the Mixer=Speakers (Conexant 20672 SmartA
Destination Line Count=1
RC mixerGetLineInfoA =0
dwLineID=4294901760 [Signed value=-65536]
szShortName =[Volume]
szName =[Master Volume]
Mixer Line State =Active [fdwLine=1]
No of Audio Channels for this line that can be manipulated =4
No of Source Line associated =1
Number of Audio Controls for this line =2
Component Type =0
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:344)
at com.sun.jna.Function.invoke(Function.java:276)
at com.sun.jna.Library$Handler.invoke(Library.java:216)
at $Proxy0.mixerGetLineControlsA(Unknown Source)
at com.kausik.jna.SystemSpeakerTest.getLineControlOfMixer(SystemSpeakerTest.java:293)
at com.kausik.jna.SystemSpeakerTest.main(SystemSpeakerTest.java:323)