
/**
@page smpl_audio NiAudioSample.cpp - sample program

	<b>Source file:</b> Click the following link to view the source code file:
		- NiAudioSample.cpp 
		
	This section describes an OpenNI sample program for using the Audio interface.

	The documentation describes the sample program's code from the top of the program file(s) to bottom.
	
	This documentation item describes only OpenNI code features. Third party features, e.g., GL code, may be ignored. However, place holders as section headings appear in place of complete functions or large code blocks that are not OpenNI specific or key to understanding the logic of the sample program. These place holders are section headings with minimal text to enable the reader to identify the original program structure when studying the documentation.
	
	Every OpenNI feature is described the first time it appears in this sample program. Further appearances of the same feature are not described again.	
	
	
	@section bkrec_macros Macro Declarations	
	
		At the top of the program is a macro utility declaration, which calls OpenNI methods. It is described below. However, for the sake of conciseness, the rest of this documentation skips calls to this macro.
		
		The CHECK_RC() macro checks whether the most recent OpenNI operation was successful or returned an error result. On error, the @ref xn::xnGetStatusString "xnGetStatusString()" method converts the OpenNI error return code to the corresponding error string for printing, and the current function exits.
		@code
			#define CHECK_RC(rc, what) \
				if (rc != XN_STATUS_OK)										\
				{															\
					printf("%s failed: %s\n", what, xnGetStatusString(rc));	\
					return rc;												\
				}
		@endcode	
	
	
	@section rec_syn_sample_xml_path Declaration of File Path
	
		In the following definitions, SAMPLE_XML_PATH is for the path to an OpenNI XML script input file for building a production graph. The <i>production graph</i> is a network of <i>production nodes</i> and is the principal OpenNI object model. See @ref prod_graph for more about the production graph.
		@code
			#define SAMPLE_XML_PATH "../../../../Data/SamplesConfig.xml"
		@endcode
		

	@section aud_glb_dcl_blk_ref "Declaration Block" section		
	
		The reader may find it convenient to study the global declaration block before continuing to study the code statements. The global declaration block is documented later in this section, corresponding to its position in the program file &ndash; see @ref aud_glb_dcl_blk.
		
	
	@section aud_decl_mode enum Mode
	
		The following declaration defines the  program mode, whether whether it is recording an OpenNI data generation session or whether  it is playing a recording.
		@code
			enum Mode
			{
				MODE_PLAY,
				MODE_RECORD,
			};
		@endcode

		This declaration is not OpenNI specific.
		
		
	@section aud_printusage printUsage() method
	
		This function is not OpenNI specific.		
	
	
	@section aud_play play() method - Play Audio
	
		This routine gets an array of AudioGenerators, takes the first one, and constantly reads data from it and sends it to be played.
		
		The following code block gets the first AudioGenerator node's wave output mode. It is received in an xn::XnWaveOutputMode, which comprises: bits per sample, channel, and sample rate. This information is then used for setting up the audio output buffers for collecting the generated play data and for setting up the hardware audio output channel.
		@code
			XnWaveOutputMode waveMode;
			nRetVal = aGens[0].GetWaveOutputMode(waveMode);
			CHECK_RC(nRetVal, "Failed getting wave output mode");
		@endcode

		The above completes the initialization. The following code is the main program loop.
		
		The application calls an 'Update Data()' method, in this case the node's @ref xn::Generator::WaitAndUpdateData "WaitAndUpdateData", to make a new frame available for getting. The application can then get the data (for example, using a metadata GetData() method).
		@code
			nRetVal = aGens[0].WaitAndUpdateData();
		@endcode

		Assuming the above call succeeded, the application then gets the size of the audio data that was generated by the AudioGenerator node.
		@code
			XnUInt32 nBufferSize = aGens[0].GetDataSize();
		@endcode
		
		The next OpenNI statements copy the AudioGenerator node's data into a prepared buffer to be sent to the machine sound card. <code>xnOSMemCopy</code> is OpenNI memory copy routine.
		@code	
			xnOSMemCopy(pHeader->lpData, aGens[0].GetAudioBuffer(), nBufferSize);
			pHeader->dwBufferLength = nBufferSize;
		@endcode
		
		
	@section aud_record record() method - Record Audio		
	
		This method gets a list of audio generators, and records to a separate file the data generated by each generator .	
		The following code block creates files named with the names of the AudioGenerator nodes.
		@code			
			XN_FILE_HANDLE aFiles[nSupportedNodes];
			for (XnUInt32 i = 0; i < nNodes; ++i)
			{
				XnChar strFileName[XN_FILE_MAX_PATH];
				sprintf(strFileName, "audio.%s.pcm", aGens[i].GetName());
				nRetVal = xnOSOpenFile(strFileName, XN_OS_FILE_WRITE, &aFiles[i]);
				CHECK_RC(nRetVal, "Open file");
			}
		@endcode		
	
		The application then calls an @ref conc_updating_data "'Update Data'" method, in this case xn::Context.WaitAnyUpdateAll(), to update all generator nodes in the context to the latest available data, first waiting for any of the nodes to have new data available. The first call is used just to flush the node. 
		@code			
			context.WaitAnyUpdateAll();
		@endcode
		
		The following loop checks which node has new data and writes it to a file. The IsDataNew() method returns whether a node's frame data was updated by the most recent call to the WaitAnyUpdateAll() method.
		@code	
			XN_FILE_HANDLE aFiles[nSupportedNodes];
			   ...
			   ...
			for (XnUInt32 i = 0; i < nNodes; ++i)
			{
				if (aGens[i].IsDataNew())
				{
					nRetVal = xnOSWriteFile(aFiles[i], aGens[i].GetAudioBuffer(), aGens[i].GetDataSize());
					CHECK_RC(nRetVal, "Write to file");
				}
			}
		@endcode	
		

		
		
	@section aud_mainprg Main Program
	

		@subsection aud_glb_dcl_blk "Declaration Block" section		
	
			The declaration block at the top of the main program declares a @ref xn::Context object, an @ref xn::EnumerationErrors object, and an xn::ScriptNode object. The Context object is a workspace in which the application builds an OpenNI production graph. the @ref xn::EnumerationErrors object is for collecting errors from any of the OpenNI functions. Also declared is an OpenNI status flag for collecting return values from method calls. the @ref xn::ScriptNode object loads an XML script from a file or string, and then runs the XML script to build a production graph.		

			@code	
				XnStatus nRetVal = XN_STATUS_OK;
				Context context;
				EnumerationErrors errors;
				  ...
				ScriptNode scriptNode;
			@endcode
		
		@subsection aud_main_code Main Code Section		

			In the following, the InitFromXmlFile() method is a shorthand combination of two other initialization methods &ndash; Init() and then RunXmlScriptFromFile() &ndash; which initializes the context object and then creates a production graph from an XML file.	
			@code		
				nRetVal = context.InitFromXmlFile(SAMPLE_XML_PATH, scriptNode);			
			@endcode
			
			The following code block tests whether a production graph was created. If not, the reason is reported as a list of one or more errors in the <code>errors</code> object.
			@code		
				if (nRetVal == XN_STATUS_NO_NODE_PRESENT)
				{
					XnChar strError[1024];
					errors.ToString(strError, 1024);
					printf("%s\n", strError);
					return (nRetVal);
				}
			@endcode
		
			The following code block searches for xn::AudioGenerator nodes in the production graph. The nodes are returned in the @ref xn::NodeInfoList object. This object is a list xn::NodeInfo objects, each containing information about a node found in the above  EnumerateExistingNodes() call. 
			
			@code
				NodeInfoList list;
				nRetVal = context.EnumerateExistingNodes(list, XN_NODE_TYPE_AUDIO);
				CHECK_RC(nRetVal, "Enumerate audio nodes");	
				AudioGenerator gens[nSupportedNodes];
				XnUInt32 nNodes = 0;
			@endcode
			
			The following declarations and statements get all the @ref xn::AudioGenerator nodes that were found by the EnumerateExistingNodes() call. The <code>gens</code> array receives all the nodes, and they are counted by the <code>nNodes</code> variable. (Currently, only a single AudioGenerator node is supported for playing at at once.)
			@code		
				AudioGenerator gens[nSupportedNodes];
				XnUInt32 nNodes = 0;
				   ...
				for (NodeInfoList::Iterator it = list.Begin(); it != list.End(); ++it)
				{
					NodeInfo info = *it;
					nRetVal = info.GetInstance(gens[nNodes]);
					CHECK_RC(nRetVal, "Get audio node");
					nNodes++;
				}
			@endcode

*/


