Эх сурвалжийг харах

Z991239-1812 #comment fix: 增加使用pulseaudio库获取音频设备信息功能

陈礼鹏80274480 4 жил өмнө
parent
commit
8231e3853b

+ 70 - 0
Other/libaudiomgr/CMakeLists.txt

@@ -0,0 +1,70 @@
+set(MODULE_NAME "audiomgr")
+set(MODULE_PREFIX "LIB_AUDIOMGR_FUNC")
+
+
+if(RVC_DEBUG_MODE)
+    set(SPBASE_LIB spbased)
+else()
+    set(SPBASE_LIB spbase)
+endif(RVC_DEBUG_MODE)
+
+
+set(${MODULE_PREFIX}_SRCS
+    iaudiomgrinterface.h
+	iaudiomgrinterface.cpp
+	libaudiomgr.h
+	libaudiomgr.cpp
+)
+
+add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+
+if(WIN32)
+else(WIN32)
+conan_cmake_run(REQUIRES pulseaudio/14.0.1@LR04.02_ThirdParty/dynamic
+BASIC_SETUP CMAKE_TARGETS
+BUILD missing)
+endif(WIN32)
+
+
+target_include_directories(${MODULE_NAME} PRIVATE
+	${CONAN_INCLUDE_DIRS_PULSEAUDIO}
+	)
+
+target_link_directories(${MODULE_NAME} PRIVATE
+	${CONAN_LIB_DIRS_PULSEAUDIO}
+	)
+
+
+# 添加实体需要依赖的其他共享库(包括系统库)
+if(WIN32)
+set(${MODULE_PREFIX}_LIBS  ${MODULE_BASE_LIBS} 
+)
+else(WIN32)
+message(STATUS "CONAN_LIB_DIRS_PULSEAUDIO ${CONAN_LIB_DIRS_PULSEAUDIO}")
+message(STATUS "CONAN_PKG_LIBS_PULSEAUDIO ${CONAN_PKG_LIBS_PULSEAUDIO}")
+set(${MODULE_PREFIX}_LIBS  ${MODULE_BASE_LIBS}
+${CONAN_PKG_LIBS_PULSEAUDIO}
+pulse
+pthread
+m
+)
+endif(WIN32)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+
+target_compile_definitions(${MODULE_NAME} PUBLIC "LIBAUDIOMGR_EXPORTS")
+
+if(MSVC)
+	install(TARGETS ${MODULE_NAME} 
+    RUNTIME DESTINATION "${RVC_RUNTIME_PATH}" COMPONENT libraries
+    ARCHIVE DESTINATION "${RVC_LIBRARY_PATH}" COMPONENT develops EXCLUDE_FROM_ALL
+    LIBRARY DESTINATION "${RVC_LIBRARY_PATH}" COMPONENT libraries
+    )
+else()
+install(TARGETS ${MODULE_NAME} 
+    RUNTIME DESTINATION "${RVC_RUNTIME_PATH}"
+    ARCHIVE DESTINATION "${RVC_LIBRARY_PATH}"
+    LIBRARY DESTINATION "${RVC_RUNTIME_PATH}"
+    COMPONENT libraries)
+endif(MSVC)

+ 14 - 0
Other/libaudiomgr/iaudiomgrinterface.cpp

@@ -0,0 +1,14 @@
+#include "iaudiomgrinterface.h"
+#include "libaudiomgr.h"
+
+
+IAudioMgr* CreateAudioMgrObj(IAudioMgrCallback* pCallback)
+{
+	return new AudioMgrImpl(pCallback);
+}
+
+
+void DestroyIAudioMgrObj(IAudioMgr* pIAudioMgr)
+{
+	pIAudioMgr->audio_mgr_destroy();
+}

+ 41 - 0
Other/libaudiomgr/iaudiomgrinterface.h

@@ -0,0 +1,41 @@
+#pragma  once
+
+#ifdef _WIN32
+#ifdef LIBAUDIOMGR_EXPORTS
+#define LIBAUDIOMGR_API __declspec(dllexport)
+#else
+#define LIBAUDIOMGR_API __declspec(dllimport)
+#endif
+# elif ( defined(__GNUC__) &&  __GNUC__ >= 4 )
+#define LIBAUDIOMGR_API __attribute__((visibility("default")))
+#else // RVC_OS_WIN
+#define LIBAUDIOMGR_API
+#endif // RVC_OS_WIN
+
+#include <stddef.h>
+
+struct IAudioMgrCallback
+{
+	virtual void debug(const char* fmt, ...) = 0;
+	virtual void on_audio_mgr_failed() = 0;
+	virtual void on_audio_mgr_excption() = 0;
+};
+
+class IAudioMgr 
+{
+public:
+	virtual int audio_mgr_initialize() = 0;
+	virtual int audio_mgr_terminate() = 0;
+	virtual int audio_get_device_count(bool binput) = 0;
+	virtual int audio_get_device_name(char* pstrbuf, size_t ulen, bool binput, int index) = 0;
+
+	virtual int set_audio_capture_params() = 0;
+	virtual int start_audio_capture() = 0;
+	virtual int stop_audio_capture() = 0;
+	virtual int audio_mgr_destroy() = 0;
+};
+
+
+extern "C" LIBAUDIOMGR_API IAudioMgr* CreateAudioMgrObj(IAudioMgrCallback* pCallback);
+extern "C" LIBAUDIOMGR_API void DestroyIAudioMgrObj(IAudioMgr* pIAudioMgr);
+

+ 651 - 0
Other/libaudiomgr/libaudiomgr.cpp

@@ -0,0 +1,651 @@
+#include"libaudiomgr.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static uint32_t latency_ms = 15; // requested initial latency in milisec: 0 use max
+static pa_usec_t latency = 0; //real latency in usec (for timestamping)
+
+static int sink_index = 0;
+static int source_index = 0;
+
+AudioMgrImpl::AudioMgrImpl(IAudioMgrCallback* pCallback)
+{
+	m_audio_context = NULL;
+	m_callback = pCallback;
+}
+
+AudioMgrImpl::~AudioMgrImpl()
+{
+	if (NULL != m_audio_context){
+		if (NULL != m_audio_context->list_input_devices) {
+			free(m_audio_context->list_input_devices);
+			m_audio_context->list_input_devices = NULL;
+		}
+
+		if (NULL != m_audio_context->list_output_devices) {
+			free(m_audio_context->list_output_devices);
+			m_audio_context->list_output_devices = NULL;
+		}
+
+		if (NULL != m_audio_context->capture_buff) {
+			free(m_audio_context->capture_buff);
+			m_audio_context->capture_buff = NULL;
+		}
+
+		free(m_audio_context);
+		m_audio_context = NULL;
+	}
+	m_callback = NULL;
+}
+
+int AudioMgrImpl::audio_mgr_destroy()
+{
+	delete this;
+	return 0;
+}
+
+/*
+ * init pulseaudio api
+ * args:
+ *    audio_ctx - pointer to audio context data
+ *
+ * asserts:
+ *    audio_ctx is not null
+ *
+ * returns: error code (0 = E_OK)
+ */
+int AudioMgrImpl::audio_init_pulseaudio()
+{
+	/*assertions*/
+	assert(NULL != m_audio_context);
+
+	if (pa_get_devicelist() < 0)
+	{
+		m_callback->debug( "pulse audio failed to get audio device list from pulse server\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+ * pa_mainloop will call this function when it's ready to tell us
+ *  about a source (input).
+ *  Since we're not threading when listing devices,
+ *  there's no need for mutexes on the devicelist structure
+ * args:
+ *    c - pointer to pulse context
+ *    l - pointer to source info
+ *    eol - end of list
+ *    data - pointer to user data (audio context)
+ *
+ * asserts:
+ *    none
+ *
+ * returns: none
+ */
+static void pa_sourcelist_cb(pa_context* c, const pa_source_info* l, int eol, void* data)
+{
+	rvc_audio_context_t* audio_ctx = (rvc_audio_context_t*)data;
+
+	int channels = 1;
+
+	/*
+	* If eol is set to a positive number,
+	* you're at the end of the list
+	*/
+	if (eol > 0)
+		return;
+
+	source_index++;
+
+	if (l->sample_spec.channels < 1)
+		channels = 1;
+	else
+		channels = l->sample_spec.channels;
+
+	double my_latency = 0.0;
+	int verbosity = 1;
+
+	if (verbosity > 0)
+	{
+		printf("AUDIO: =======[ Input Device #%d ]=======\n", source_index);
+		printf("       Description: %s\n", l->description);
+		printf("       Name: %s\n", l->name);
+		printf("       Index: %d\n", l->index);
+		printf("       Channels: %d (default to: %d)\n", l->sample_spec.channels, channels);
+		printf("       SampleRate: %d\n", l->sample_spec.rate);
+		printf("       Latency: %llu (usec)\n", (long long unsigned) l->latency);
+		printf("       Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
+		printf("       Card: %d\n", l->card);
+		printf("\n");
+	}
+
+	if (my_latency <= 0.0)
+		my_latency = (double)latency_ms / 1000;
+
+	if (l->monitor_of_sink == PA_INVALID_INDEX)
+	{
+		audio_ctx->num_input_dev++;
+		/*add device to list*/
+		audio_ctx->list_input_devices = (rvc_audio_device_t*)realloc(audio_ctx->list_input_devices, audio_ctx->num_input_dev * sizeof(rvc_audio_device_t));
+		if (audio_ctx->list_input_devices == NULL)
+		{
+			printf("AUDIO: FATAL memory allocation failure (pa_sourcelist_cb): %s\n", strerror(errno));
+			exit(-1);
+		}
+		/*fill device data*/
+		audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].id = l->index; /*saves dev id*/
+		strncpy(audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].name, l->name, MAX_PATH_EX-1);
+		strncpy(audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].description, l->description, MAX_PATH-1);
+		audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].channels = channels;
+		audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].samprate = l->sample_spec.rate;
+		audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].low_latency = my_latency; /*in seconds*/
+		audio_ctx->list_input_devices[audio_ctx->num_input_dev - 1].high_latency = my_latency; /*in seconds*/
+
+	}
+}
+
+/*
+ * pa_mainloop will call this function when it's ready to tell us
+ *  about a source (input).
+ *  This callback is pretty much identical to the previous
+ *  but it will only print the output devices
+ * args:
+ *    c - pointer to pulse context
+ *    l - pointer to sink info
+ *    eol - end of list
+ *    data - pointer to user data (audio context)
+ *
+ * asserts:
+ *    none
+ *
+ * returns: none
+ */
+static void pa_sinklist_cb(pa_context* c, const pa_sink_info* l, int eol, void* userdata)
+{
+	rvc_audio_context_t* audio_ctx = (rvc_audio_context_t*)userdata;
+
+	/*
+	 * If eol is set to a positive number,
+	 * you're at the end of the list
+	 */
+	if (eol > 0)
+		return;
+
+	sink_index++;
+
+	double my_latency = 0.0;
+	int verbosity = 1;
+
+	if (verbosity > 0)
+	{
+		printf("AUDIO: =======[ Output Device #%d ]=======\n", sink_index);
+		printf("       Description: %s\n", l->description);
+		printf("       Name: %s\n", l->name);
+		printf("       Index: %d\n", l->index);
+		printf("       Channels: %d\n", l->channel_map.channels);
+		printf("       SampleRate: %d\n", l->sample_spec.rate);
+		printf("       Latency: %llu (usec)\n", (long long unsigned) l->latency);
+		printf("       Configured Latency: %llu (usec)\n", (long long unsigned) l->configured_latency);
+		printf("       Card: %d\n", l->card);
+		printf("\n");
+	}
+
+	if (my_latency <= 0.0)
+		my_latency = (double)latency_ms / 1000;
+
+	audio_ctx->num_output_dev++;
+	/*add device to list*/
+	audio_ctx->list_output_devices = (rvc_audio_device_t*)realloc(audio_ctx->list_output_devices, audio_ctx->num_output_dev * sizeof(rvc_audio_device_t));
+	if (audio_ctx->list_output_devices == NULL)
+	{
+		printf("AUDIO: FATAL memory allocation failure (pa_sinklist_cb): %s\n", strerror(errno));
+		exit(-1);
+	}
+	/*fill device data*/
+	audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].id = l->index; /*saves dev id*/
+	strncpy(audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].name, l->name, MAX_PATH_EX-1);
+	strncpy(audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].description, l->description, MAX_PATH-1);
+	audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].channels = l->channel_map.channels;
+	audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].samprate = l->sample_spec.rate;
+	audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].low_latency = my_latency; /*in seconds*/
+	audio_ctx->list_output_devices[audio_ctx->num_output_dev - 1].high_latency = my_latency; /*in seconds*/
+}
+
+
+
+/*
+ * This callback gets called when our context changes state.
+ *  We really only care about when it's ready or if it has failed
+ * args:
+ *    c -pointer to pulse context
+ *    data - pointer to user data
+ *
+ * asserts:
+ *    none
+ *
+ * retuns: none
+ */
+static void pa_state_cb(pa_context* c, void* data)
+{
+	pa_context_state_t state;
+	int* pa_ready = (int*)data;
+	state = pa_context_get_state(c);
+	switch (state)
+	{
+		// These are just here for reference
+	case PA_CONTEXT_UNCONNECTED:
+	case PA_CONTEXT_CONNECTING:
+	case PA_CONTEXT_AUTHORIZING:
+	case PA_CONTEXT_SETTING_NAME:
+	default:
+		break;
+	case PA_CONTEXT_FAILED:
+	case PA_CONTEXT_TERMINATED:
+		*pa_ready = 2;
+		break;
+	case PA_CONTEXT_READY:
+		*pa_ready = 1;
+		break;
+	}
+}
+
+
+
+/*
+ * clean up and disconnect
+ * args:
+ *    pa_ctx - pointer to pulse context
+ *    pa_ml - pointer to pulse mainloop
+ *
+ * asserts:
+ *    none
+ *
+ * returns:
+ *    none
+ */
+static void finish(pa_context* pa_ctx, pa_mainloop* pa_ml)
+{
+	/* clean up and disconnect */
+	pa_context_disconnect(pa_ctx);
+	pa_context_unref(pa_ctx);
+	pa_mainloop_free(pa_ml);
+}
+
+/*
+ * iterate the main loop until all devices are listed
+ * args:
+ *    audio_ctx - pointer to audio context
+ *
+ * asserts:
+ *    audio_ctx is not null
+ *
+ * returns: error code
+ */
+int AudioMgrImpl::pa_get_devicelist()
+{
+	/*assertions*/
+	assert(m_audio_context != NULL);
+
+	/* Define our pulse audio loop and connection variables */
+	pa_mainloop* pa_ml;
+	pa_mainloop_api* pa_mlapi;
+	pa_operation* pa_op = NULL;
+	pa_context* pa_ctx;
+
+	/* We'll need these state variables to keep track of our requests */
+	int state = 0;
+	int pa_ready = 0;
+
+	/* Create a mainloop API and connection to the default server */
+	pa_ml = pa_mainloop_new();
+	pa_mlapi = pa_mainloop_get_api(pa_ml);
+	pa_ctx = pa_context_new(pa_mlapi, "getDevices");
+
+	/* This function connects to the pulse server */
+	if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
+	{
+		m_callback->debug("AUDIO: PULSE - unable to connect to server: pa_context_connect failed");
+		finish(pa_ctx, pa_ml);
+		return -1;
+	}
+
+	/*
+	 * This function defines a callback so the server will tell us
+	 * it's state.
+	 * Our callback will wait for the state to be ready.
+	 * The callback will modify the variable to 1 so we know when we
+	 * have a connection and it's ready.
+	 * If there's an error, the callback will set pa_ready to 2
+	 */
+	pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
+
+	/*
+	 * Now we'll enter into an infinite loop until we get the data
+	 * we receive or if there's an error
+	 */
+	for (;;)
+	{
+		/*
+		 * We can't do anything until PA is ready,
+		 * so just iterate the mainloop and continue
+		 */
+		if (pa_ready == 0)
+		{
+			pa_mainloop_iterate(pa_ml, 1, NULL);
+			continue;
+		}
+		/* We couldn't get a connection to the server, so exit out */
+		if (pa_ready == 2)
+		{
+			finish(pa_ctx, pa_ml);
+			return -1;
+		}
+		/*
+		 * At this point, we're connected to the server and ready
+		 * to make requests
+		 */
+		switch (state)
+		{
+			/* State 0: we haven't done anything yet */
+		case 0:
+			/*
+			 * This sends an operation to the server.
+			 * pa_sinklist_cb is our callback function and a pointer
+			 * o our devicelist will be passed to the callback
+			 * (audio_ctx) The operation ID is stored in the
+			 * pa_op variable
+			 */
+			pa_op = pa_context_get_sink_info_list(
+				pa_ctx,
+				pa_sinklist_cb,
+				(void*)m_audio_context);
+
+			/* Update state for next iteration through the loop */
+			state++;
+			break;
+		case 1:
+			/*
+			 * Now we wait for our operation to complete.
+			 * When it's complete our pa_output_devicelist is
+			 * filled out, and we move along to the next state
+			 */
+			if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
+			{
+				pa_operation_unref(pa_op);
+
+				/*
+				 * Now we perform another operation to get the
+				 * source(input device) list just like before.
+				 * This time we pass a pointer to our input structure
+				 */
+				pa_op = pa_context_get_source_info_list(
+					pa_ctx,
+					pa_sourcelist_cb,
+					(void*)m_audio_context);
+				/* Update the state so we know what to do next */
+				state++;
+			}
+			break;
+		case 2:
+			if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
+			{
+				/*
+				 * Now we're done,
+				 * clean up and disconnect and return
+				 */
+				pa_operation_unref(pa_op);
+				finish(pa_ctx, pa_ml);
+				return 0;
+			}
+			break;
+		default:
+			/* We should never see this state */
+			printf("AUDIO: Pulseaudio in state %d\n", state);
+			return -1;
+		}
+		/*
+		 * Iterate the main loop and go again.  The second argument is whether
+		 * or not the iteration should block until something is ready to be
+		 * done.  Set it to zero for non-blocking.
+		 */
+		pa_mainloop_iterate(pa_ml, 1, NULL);
+	}
+
+	return 0;
+}
+
+
+/*
+ * get the number of available audio devices
+ *
+  * args:
+ *    binput - is input device
+ * asserts:
+ *   audio_ctx is not null
+ *
+ * returns: number of listed audio devices
+ */
+int AudioMgrImpl::audio_get_device_count(bool binput)
+{
+	/*assertions*/
+	assert(m_audio_context != NULL);
+	if (binput){
+		return m_audio_context->num_input_dev;
+	}
+	else {
+		return m_audio_context->num_output_dev;
+	}
+
+	
+}
+
+
+/*
+ * get the audio device referenced by index
+ * args:
+ *   index - index of audio device
+ *
+ * asserts:
+ *   audio_ctx is not null
+ *
+ * returns: audio device referenced by index
+ */
+rvc_audio_device_t* AudioMgrImpl::audio_get_input_device(int index)
+{
+	/*assertions*/
+	assert(m_audio_context != NULL);
+
+	if (index >= m_audio_context->num_input_dev){
+		printf("AUDIO: (audio_get_input_device) bad index %i using %i\n",index, m_audio_context->num_input_dev - 1);
+		index = m_audio_context->num_input_dev - 1;
+	}
+
+	if (index < 0){
+		printf("AUDIO: (audio_get_input_device) bad index %i using 0\n", index);
+		index = 0;
+	}
+
+	return &m_audio_context->list_input_devices[index];
+}
+
+
+/*
+ * get the output audio device referenced by index
+ * args:
+ *   index - index of output audio device
+ *
+ * asserts:
+ *   audio_ctx is not null
+ *
+ * returns: output audio device referenced by index
+ */
+rvc_audio_device_t* AudioMgrImpl::audio_get_output_device( int index)
+{
+	/*assertions*/
+	assert(m_audio_context != NULL);
+
+	if (index >= m_audio_context->num_output_dev)
+	{
+		printf("AUDIO: (audio_get_output_device) bad index %i using %i\n",
+			index, m_audio_context->num_output_dev - 1);
+		index = m_audio_context->num_output_dev - 1;
+	}
+
+	if (index < 0)
+	{
+		printf("AUDIO: (audio_get_output_device) bad index %i using 0\n", index);
+		index = 0;
+	}
+
+	return &m_audio_context->list_output_devices[index];
+}
+
+
+int AudioMgrImpl::audio_get_device_name(char* pstrbuf, size_t ulen, bool binput, int index)
+{
+	int iret = -1;
+
+	rvc_audio_device_t* audio_device = NULL;
+	if (binput){
+		audio_device = audio_get_input_device(index);
+	}
+	else{
+		audio_device = audio_get_output_device(index);
+	}
+		
+	size_t unamelen = strlen(audio_device->description);
+	if (ulen > unamelen){
+		snprintf(pstrbuf, ulen, "%s", audio_device->description);
+		iret = 0;
+	}
+
+	return iret;
+}
+
+
+int AudioMgrImpl::audio_mgr_initialize()
+{
+	int iret = -1;
+	m_audio_context = (rvc_audio_context_t*)calloc(1, sizeof(rvc_audio_context_t));
+
+	if (NULL == m_audio_context){
+		m_callback->debug("%s:%d couldn't allocate audio context.", __FUNCTION__, __LINE__);
+		return iret;
+	}
+
+	/*initialize the mutex*/
+	__INIT_MUTEX(&(m_audio_context->mutex));
+
+	iret = audio_init_pulseaudio();
+
+	/*force a valid number of channels*/
+	if (m_audio_context->channels > 2) {
+		m_audio_context->channels = 2;
+	}
+		
+	return iret;
+}
+
+/*
+ * close and clean audio context for pulse audio api
+ *
+ * asserts:
+ *   none
+ *
+ * returns: none
+ */
+int AudioMgrImpl::audio_close_pulseaudio()
+{
+	int iret = -1;
+	if (m_audio_context == NULL){
+		return iret;
+	}
+
+	if (m_audio_context->stream_flag == AUDIO_STRM_ON) {
+		stop_audio_capture();
+	}
+		
+	if (NULL != m_audio_context->list_input_devices) {
+		free(m_audio_context->list_input_devices);
+		m_audio_context->list_input_devices = NULL;
+	}
+
+	if (NULL != m_audio_context->list_output_devices){
+		free(m_audio_context->list_output_devices);
+		m_audio_context->list_output_devices = NULL;
+	}
+
+	if (NULL != m_audio_context->capture_buff) {
+		free(m_audio_context->capture_buff);
+		m_audio_context->capture_buff = NULL;
+	}
+	
+	free(m_audio_context);
+	m_audio_context = NULL;
+
+	iret = 0;
+
+	return iret;
+}
+
+/*
+ * stop and join the main loop iteration thread
+ *
+ * asserts:
+ *   audio_ctx is not null
+ *
+ * returns: error code
+ */
+int AudioMgrImpl::stop_audio_capture()
+{
+	/*assertions*/
+	assert(m_audio_context != NULL);
+
+	m_audio_context->stream_flag = AUDIO_STRM_OFF;
+
+	if (0 == __THREAD_JOIN(m_readthread)){
+		m_callback->debug("read thread join success!");
+	}
+	else{
+		m_callback->debug("read thread join failed!");
+	}
+
+	return 0;
+}
+
+int AudioMgrImpl::audio_mgr_terminate()
+{
+	int iret = -1;
+	/*assertions*/
+	assert(m_audio_context != NULL);
+
+	/* thread must be joined before destroying the mutex
+		 * so no need to unlock before destroying it
+	*/
+
+		 /*destroy the mutex*/
+	__CLOSE_MUTEX(&(m_audio_context->mutex));
+
+	iret = audio_close_pulseaudio();
+
+	//if (audio_buffers != NULL)
+	//	audio_free_buffers();
+
+	return iret;
+}
+
+
+int AudioMgrImpl::set_audio_capture_params()
+{
+	return 0;
+}
+
+int AudioMgrImpl::start_audio_capture()
+{
+	return 0;
+}

+ 114 - 0
Other/libaudiomgr/libaudiomgr.h

@@ -0,0 +1,114 @@
+#pragma once
+
+#include "iaudiomgrinterface.h"
+#include <pthread.h>
+#include <stdint.h>
+#include <assert.h>
+#include <pulse/pulseaudio.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifndef MAX_PATH_EX
+#define MAX_PATH_EX 512
+#endif
+
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+
+/*Audio stream flag*/
+#define AUDIO_STRM_ON       (1)
+#define AUDIO_STRM_OFF      (0)
+
+#define __THREAD_TYPE pthread_t
+#define __THREAD_CREATE(t,f,d) (pthread_create(t,NULL,f,d))
+#define __THREAD_CREATE_ATTRIB(t,a,f,d) (pthread_create(t,a,f,d))
+#define __THREAD_JOIN(t) (pthread_join(t, NULL))
+
+#define __ATTRIB_TYPE pthread_attr_t
+#define __INIT_ATTRIB(t) (pthread_attr_init(t))
+#define __ATTRIB_JOINABLE(t) (pthread_attr_setdetachstate(t, PTHREAD_CREATE_JOINABLE))
+#define __CLOSE_ATTRIB(t) (pthread_attr_destroy(t))
+
+#define __MUTEX_TYPE pthread_mutex_t
+#define __STATIC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
+#define __INIT_MUTEX(m) ( pthread_mutex_init(m, NULL) )
+#define __CLOSE_MUTEX(m) ( pthread_mutex_destroy(m) )
+#define __LOCK_MUTEX(m) ( pthread_mutex_lock(m) )
+#define __UNLOCK_MUTEX(m) ( pthread_mutex_unlock(m) )
+
+#define __COND_TYPE pthread_cond_t
+#define __INIT_COND(c)  ( pthread_cond_init (c, NULL) )
+#define __CLOSE_COND(c) ( pthread_cond_destroy(c) )
+#define __COND_BCAST(c) ( pthread_cond_broadcast(c) )
+#define __COND_SIGNAL(c) ( pthread_cond_signal(c) )
+#define __COND_TIMED_WAIT(c,m,t) ( pthread_cond_timedwait(c,m,t) )
+
+typedef struct rvc_audio_device_s
+{
+	int id;							/*audo device id*/
+	int channels;					/*max channels*/
+	int samprate;					/*default samplerate*/
+	double low_latency;				/*default low latency*/
+	double high_latency;			/*default high latency*/
+	char name[MAX_PATH_EX];         /*device name*/
+	char description[MAX_PATH];		/*device description*/
+} rvc_audio_device_t;
+
+typedef struct rvc_audio_context_s
+{
+	int num_input_dev;            /*number of audio input devices in list*/
+	rvc_audio_device_t* list_input_devices; /*audio input devices list*/
+
+	int num_output_dev;
+	rvc_audio_device_t* list_output_devices; /*audio output devices list*/
+
+	int device;                   /*current device list index*/
+	int channels;                 /*channels*/
+	int samprate;                 /*sample rate*/
+	double latency;               /*current sugested latency*/
+
+	/*all ts are monotonic based: both real and generated*/
+	int64_t current_ts;           /*current buffer generated timestamp*/
+	int64_t last_ts;              /*last real timestamp (in nanosec)*/
+	int64_t snd_begintime;        /*sound capture start ref time*/
+	int64_t ts_drift;             /*drift between real and generated ts*/
+
+	int16_t* capture_buff;       /*pointer to capture data*/
+	int capture_buff_size;        /*capture buffer size (bytes)*/
+	float capture_buff_level[2];  /*capture buffer channels level*/
+
+	int stream_flag;              /*stream flag*/
+
+	pthread_mutex_t mutex;       /*audio mutex*/
+
+}rvc_audio_context_t;
+
+class AudioMgrImpl : public IAudioMgr
+{
+public:
+	AudioMgrImpl(IAudioMgrCallback* pCallback);
+	~AudioMgrImpl();
+
+	int audio_mgr_initialize();
+	int audio_mgr_terminate();
+	int audio_get_device_count(bool binput);
+	int audio_get_device_name(char* pstrbuf, size_t ulen, bool binput, int index);
+
+	int set_audio_capture_params();
+	int start_audio_capture();
+	int stop_audio_capture();
+	int audio_mgr_destroy();
+
+private:
+	int audio_init_pulseaudio();
+	int pa_get_devicelist();
+	int audio_close_pulseaudio();
+	rvc_audio_device_t* audio_get_input_device(int index);
+	rvc_audio_device_t* audio_get_output_device(int index);
+
+private:
+	rvc_audio_context_t* m_audio_context;
+	IAudioMgrCallback* m_callback;
+	__THREAD_TYPE m_readthread;
+};

+ 43 - 0
Other/rvcaudiomgr/CMakeLists.txt

@@ -0,0 +1,43 @@
+
+set(MODULE_NAME "rvcaudiomgr")
+set(MODULE_PREFIX "RVCAUDIOMGR_FUNC")
+
+
+set(${MODULE_PREFIX}_SRCS
+	audiomgr.h
+	audiomgr.cpp	
+	rvcaudiomgr.cpp
+	)
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_include_directories(${MODULE_NAME} PRIVATE
+	
+)
+
+target_link_directories(${MODULE_NAME} PRIVATE
+
+)
+
+# 添加实体需要依赖的其他共享库(包括系统库)
+
+set(${MODULE_PREFIX}_LIBS  ${MODULE_BASE_LIBS}
+	audiomgr
+)
+
+target_link_libraries(${MODULE_NAME} PRIVATE ${${MODULE_PREFIX}_LIBS})
+
+
+if(MSVC)
+	install(TARGETS ${MODULE_NAME} 
+    RUNTIME DESTINATION "${RVC_RUNTIME_PATH}" COMPONENT libraries
+    ARCHIVE DESTINATION "${RVC_LIBRARY_PATH}" COMPONENT develops EXCLUDE_FROM_ALL
+    LIBRARY DESTINATION "${RVC_LIBRARY_PATH}" COMPONENT libraries
+    )
+else()
+install(TARGETS ${MODULE_NAME} 
+    RUNTIME DESTINATION "${RVC_RUNTIME_PATH}"
+    ARCHIVE DESTINATION "${RVC_LIBRARY_PATH}"
+    LIBRARY DESTINATION "${RVC_RUNTIME_PATH}"
+    COMPONENT libraries)
+endif(MSVC)

+ 75 - 0
Other/rvcaudiomgr/audiomgr.cpp

@@ -0,0 +1,75 @@
+#include"audiomgr.h"
+#include<stdlib.h>
+#include<string.h>
+#include<stdarg.h>
+#include <time.h>
+#include <stdio.h>
+
+AudioMgrEntity::AudioMgrEntity()
+{
+	m_pAudioMgr = NULL;
+}
+
+AudioMgrEntity::~AudioMgrEntity()
+{
+	if (NULL != m_pAudioMgr){
+		DestroyIAudioMgrObj(m_pAudioMgr);
+	}
+}
+
+int AudioMgrEntity::Init()
+{
+	int iRet = -1;
+	m_pAudioMgr = CreateAudioMgrObj(this);
+	if (NULL != m_pAudioMgr){
+		iRet = 0;
+	}
+
+	return iRet;
+}
+
+
+
+int AudioMgrEntity::AudioMgrInitialize()
+{
+	return m_pAudioMgr->audio_mgr_initialize();
+}
+
+int AudioMgrEntity::AudioMgrTerminate()
+{
+	return m_pAudioMgr->audio_mgr_terminate();
+}
+
+int AudioMgrEntity::audio_get_device_count(bool binput)
+{
+	return m_pAudioMgr->audio_get_device_count(binput);
+}
+
+
+int AudioMgrEntity::audio_get_device_name(char* strbuf, size_t ulen, bool binput, int index)
+{
+	return m_pAudioMgr->audio_get_device_name(strbuf, ulen, binput, index);
+}
+
+
+void AudioMgrEntity::debug(const char* fmt, ...)
+{
+	char strfmt[512] = { 0 };
+	va_list args;
+	va_start(args, fmt);
+	vsprintf(strfmt, fmt, args);
+	printf("%s\n", strfmt);
+	va_end(args);
+	fflush(stdout);
+}
+
+
+void AudioMgrEntity::on_audio_mgr_failed()
+{
+
+}
+
+void AudioMgrEntity::on_audio_mgr_excption()
+{
+
+}

+ 24 - 0
Other/rvcaudiomgr/audiomgr.h

@@ -0,0 +1,24 @@
+
+
+#include "../libaudiomgr/iaudiomgrinterface.h"
+
+
+class AudioMgrEntity : public IAudioMgrCallback
+{
+public:
+	AudioMgrEntity();
+	virtual ~AudioMgrEntity();
+
+	void debug(const char* fmt, ...);
+	void on_audio_mgr_failed();
+	void on_audio_mgr_excption();
+
+	int Init();
+	int AudioMgrInitialize();
+	int AudioMgrTerminate();
+	int audio_get_device_count(bool binput);
+	int audio_get_device_name(char* strbuf, size_t ulen, bool binput, int index);
+	
+private:
+	IAudioMgr* m_pAudioMgr;
+};

+ 37 - 0
Other/rvcaudiomgr/rvcaudiomgr.cpp

@@ -0,0 +1,37 @@
+#include "audiomgr.h"
+#include<unistd.h>
+#include <stdio.h>
+
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+
+int main()
+{
+	AudioMgrEntity* pAudioMgr = new AudioMgrEntity();
+	if (0 == pAudioMgr->Init()) {
+		if (0 == pAudioMgr->AudioMgrInitialize()){
+			int icountmic = pAudioMgr->audio_get_device_count(true);
+			printf("audio input device(%d):\n", icountmic);
+			for (int i = 0; i < icountmic; i++){
+				char strname[MAX_PATH] = { 0 };
+				pAudioMgr->audio_get_device_name(strname, MAX_PATH,true, i);
+				printf("%d = %s\n",i, strname);
+			}
+			int icountspeaker = pAudioMgr->audio_get_device_count(false);
+			printf("audio output device(%d):\n", icountspeaker);
+			for (int i = 0; i < icountspeaker; i++) {
+				char strname[MAX_PATH] = { 0 };
+				pAudioMgr->audio_get_device_name(strname, MAX_PATH, false, i);
+				printf("%d = %s\n", i, strname);
+			}
+		}
+
+		if (0 != pAudioMgr->AudioMgrTerminate()){
+			printf("audio manager terminate failed!\n");
+		}
+	}
+
+	delete pAudioMgr;
+	pAudioMgr = NULL;
+}