Windows NT Systems Programming

[ Home | Syllabus |Course Notes]


RPC Audio Message Server


(source code here)

Objectives


Context Handles (chapter 8 pp. 451-461)

Problem: How to keep state of client/server connection between RPC calls?

WIN32 RPC use the later approach.


An RPC File Server

 

[
  uuid(c262dfb0-54af-11d1-a98f-00609752bfb9), // Used uuidgen -i to generate this number
  version(1.0),
  endpoint ("ncacn_ip_tcp:[44533]")
]
interface audioRPC // Provides a set of RPC calls
{
	typedef [context_handle] void *audioContext; // This is a 32 bit pointer to the client state in the server

	void openRecord([in , string] char*, [out, ref] audioContext * ac);
	void saveAudio([in] audioContext ac, [in] int size, [in, size_is(size)] char* buf);
	void closeRecord([in, out,ref] audioContext *ac);
	void openPlayBack([in, string] char*, [out, ref] audioContext * ac);
	void closePlayBack([in, out,ref] audioContext *ac);
	int getAudio([in] audioContext ac, [in] int size, [out, size_is(size)] char buf[]); 
}

rainbow.gif (2243 bytes)


Server (AudioRPC.cpp)


#include <windows.h>
#include "audMsg.h" // generated by the IDL file - contains the stubs

typedef struct
{
  HANDLE audioFile;
} audioContextStruct;

// function to initialize sum context
void openRecord(unsigned char* fileName, audioContext *contextHandle)
{
  audioContextStruct *tmp;

  tmp=(audioContextStruct *) midl_user_allocate(sizeof(audioContextStruct));

  	tmp->audioFile = CreateFile((const char*)fileName, GENERIC_WRITE,
		0,0, CREATE_ALWAYS, 0, 0);
  

  *contextHandle=(audioContext)tmp;
}

void openPlayBack(unsigned char* fileName, audioContext *contextHandle)
{
  audioContextStruct *tmp;

  tmp=(audioContextStruct *)
    midl_user_allocate(sizeof(audioContextStruct));

  	tmp->audioFile = CreateFile((const char*)fileName, GENERIC_READ,
		0,0, OPEN_EXISTING, 0, 0);
  

  *contextHandle=(audioContext)tmp;
}


void saveAudio(audioContext contextHandle, int size, unsigned char* buf)
{
	DWORD numWrite;

	WriteFile(((audioContextStruct *) contextHandle)->audioFile, buf, size, &numWrite, 0);
  
}

int getAudio(audioContext contextHandle,
  int size, unsigned char* buf)
{
	DWORD numWrite;

	ReadFile(((audioContextStruct *) contextHandle)->audioFile, buf, size, &numWrite, 0);
	return numWrite;
  
}
// function to uninitialize sum context
void closeRecord(audioContext *contextHandle)
{
 	CloseHandle(((audioContextStruct *) *contextHandle)->audioFile);
 	 midl_user_free(*contextHandle);

  	*contextHandle=NULL;
}

void closePlayBack(audioContext *contextHandle)
{
	CloseHandle(((audioContextStruct *) *contextHandle)->audioFile);
  midl_user_free(*contextHandle);

  *contextHandle=NULL;
}

// function which gets called if client
// looses contact with server
void __RPC_USER audioContext_rundown
  (audioContext contextHandle)
{
	midl_user_free(*contextHandle);
}

rainbow.gif (2243 bytes)


Server.cpp

 if (RpcServerUseAllProtseqsIf(1,
    audioRPC_v1_0_s_ifspec,
    NULL))
  if (RpcServerRegisterIf(audioRPC_v1_0_s_ifspec,
    NULL, NULL))
  if (RpcServerListen(1, 5, FALSE))
 

Client.h

// Main Window is a dialog box

class CMsgApp : public CWinApp
{
public:
	virtual BOOL InitInstance(); // everybody overrides this one
};

Client.cpp

 

CMsgApp msgApp;  

// Init the application and the main window
BOOL CMsgApp::InitInstance()
{
	CMsgDlg dlg;
	m_pMainWnd = &dlg;
	dlg.DoModal();
	
	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;

}

CMsgDlg.h

 

class CMsgDlg : public CDialog
{
public:
	CMsgDlg(CWnd* pParentWnd = NULL) :
	  CDialog(IDD_MSGDLG, pParentWnd) {}
	  virtual BOOL OnInitDialog();

private:
	HANDLE audioThread;
protected:
	afx_msg void OnRecord();
	afx_msg void OnPlay();
	afx_msg void OnStop();
	DECLARE_MESSAGE_MAP()
};

CMsgDlg.cpp

BOOL CMsgDlg::OnInitDialog()
{
	UCHAR *stringBinding;
	
	CDialog::OnInitDialog();
	RpcStringBindingCompose(NULL,
		(UCHAR *) "ncacn_ip_tcp", (UCHAR *) "localhost",
		(UCHAR *) "44533", NULL,
		&stringBinding);
	
	RpcBindingFromStringBinding(stringBinding,
		&audioRPCHandle);
	
	RpcStringFree(&stringBinding);
	stopRecord = CreateEvent(0, FALSE, FALSE, 0); // so that Record/Stop buttons can control recording
	ResetEvent(stopRecord);
	return TRUE;
}


void CMsgDlg::OnRecord()
// Saves the message
{
	DWORD threadid;
	void record(void*);
	CString msgName;
	char* msgName2;
	
	GetDlgItem(IDC_STOP)->EnableWindow(true);
	GetDlgItem(IDC_RECORD)->EnableWindow(false);
	GetDlgItem(IDC_PLAY)->EnableWindow(false);
	GetDlgItemText(IDC_MSG_ID, msgName);
	msgName2 = new char[sizeof(msgName)]+1;
	strcpy(msgName2, msgName);
	
	audioThread = CreateThread(NULL, 0,
		(LPTHREAD_START_ROUTINE) record, msgName2, 0,
		&threadid);   
	
}

void CMsgDlg::OnStop()
{
	GetDlgItem(IDC_STOP)->EnableWindow(false);
	GetDlgItem(IDC_RECORD)->EnableWindow(true);
	GetDlgItem(IDC_PLAY)->EnableWindow(true);
	SetEvent(stopRecord);
	GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
}

void CMsgDlg::OnPlay()
// Saves the message
{
	DWORD threadid;
	void playBack(void*);
	int i = 0;
	CString msgName;
	char* msgName2;
	
	GetDlgItem(IDC_STOP)->EnableWindow(true);
	GetDlgItem(IDC_RECORD)->EnableWindow(false);
	GetDlgItem(IDC_PLAY)->EnableWindow(false);
	GetDlgItemText(IDC_MSG_ID, msgName);
	msgName2 = new char[sizeof(msgName)]+1;
	strcpy(msgName2, msgName);
	
	audioThread = CreateThread(NULL, 0,
		(LPTHREAD_START_ROUTINE) playBack, msgName2, 0,
		&threadid);   
}

rainbow.gif (2243 bytes)


Recording Thread

void record(void * msgName) // this is a thread function which is passed a pointer to a string
{
	DWORD threadid;
	HANDLE recordHandle;
	openRecord((unsigned char*)msgName,&ac);
	msgApp.m_pMainWnd->SetWindowText("Start Recording");
	calledBack = CreateEvent(0, FALSE, FALSE, 0);
	ResetEvent(calledBack);
	recordHandle = CreateThread(NULL, 0,
		(LPTHREAD_START_ROUTINE) Recorder, NULL, 0,
		&threadid);
	openWaveInDev();
	WaitForSingleObject(recordHandle, INFINITE);
	waveInClose(hWaveIn);
	CloseHandle(calledBack);
	CloseHandle(recordHandle);
	closeRecord(&ac);
	msgApp.m_pMainWnd->SetWindowText("Done Recording");
	
}

rainbow.gif (2243 bytes)


Record Thread

UINT Recorder(void *p)
{
	
	while (true)
	{
		WaitForSingleObject(calledBack, INFINITE); // wait till device has called back
		if (!(WaveHeader.dwFlags & WHDR_DONE))
		{
			continue;
		}
		saveAudio(ac, WaveHeader.dwBytesRecorded, (unsigned char*) WaveHeader.lpData);
		if (waveInUnprepareHeader(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
			break;
		}
		WaveHeader.dwFlags = 0;
		
		if (waveInPrepareHeader(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
			break;
		}
		if (waveInAddBuffer(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
			break;
		}
		if(WaitForSingleObject(stopRecord, 0) != WAIT_TIMEOUT)
			break;
		
		
	}
	waveInReset(hWaveIn);
	return 0;
}

rainbow.gif (2243 bytes)


What Next?


Copyright chris wild 1997.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: November 05, 1997.