Skip to Main Content

Invalid memory access Error - Speaker Volume for Vista & Windows 7 - JNA

896842Oct 31 2011
<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)
Comments
Post Details
Added on Oct 31 2011
0 comments
1,685 views