[libuac] add pulse audio on linux, unfinished

This commit is contained in:
gozfree
2020-05-30 21:56:02 +08:00
parent e06d08d06d
commit c6e326dbcc
9 changed files with 632 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libuac
ifeq ($(MODE), release)
LOCAL_CFLAGS += -O2
endif
LIBRARIES_DIR := $(LOCAL_PATH)/../
LOCAL_C_INCLUDES := $(LOCAL_PATH)
# Add your application source files here...
LOCAL_SRC_FILES := libuac.c
include $(BUILD_SHARED_LIBRARY)
+112
View File
@@ -0,0 +1,112 @@
###############################################################################
# common
###############################################################################
#ARCH: linux/pi/android/ios/
ARCH ?= linux
CROSS_PREFIX ?=
OUTPUT ?= /usr/local
BUILD_DIR := $(shell pwd)/../../build/
ARCH_INC := $(BUILD_DIR)/$(ARCH).inc
COLOR_INC := $(BUILD_DIR)/color.inc
ifeq ($(ARCH_INC), $(wildcard $(ARCH_INC)))
include $(ARCH_INC)
endif
CC = $(CROSS_PREFIX)gcc
CXX = $(CROSS_PREFIX)g++
LD = $(CROSS_PREFIX)ld
AR = $(CROSS_PREFIX)ar
STRIP = $(CROSS_PREFIX)strip
ifeq ($(COLOR_INC), $(wildcard $(COLOR_INC)))
include $(COLOR_INC)
else
CC_V = $(CC)
CXX_V = $(CXX)
LD_V = $(LD)
AR_V = $(AR)
CP_V = $(CP)
RM_V = $(RM)
endif
###############################################################################
# target and object
###############################################################################
LIBNAME = libuac
VERSION_SH = $(shell pwd)/version.sh $(LIBNAME)
VER = $(shell $(VERSION_SH); awk '/define\ $(LIBNAME)_version/{print $$3}' version.h)
TGT_LIB_H = $(LIBNAME).h
TGT_LIB_A = $(LIBNAME).a
TGT_LIB_SO = $(LIBNAME).so
TGT_LIB_SO_VER = $(TGT_LIB_SO).${VER}
TGT_UNIT_TEST = test_$(LIBNAME)
OBJS_LIB = $(LIBNAME).o pulseaudio.o
OBJS_UNIT_TEST = test_$(LIBNAME).o
###############################################################################
# cflags and ldflags
###############################################################################
ifeq ($(MODE), release)
CFLAGS := -O2 -Wall -Werror -fPIC
LTYPE := release
else
CFLAGS := -g -Wall -Werror -fPIC
LTYPE := debug
endif
CFLAGS += $($(ARCH)_CFLAGS)
CFLAGS += -I$(OUTPUT)/include
SHARED := -shared
LDFLAGS := $($(ARCH)_LDFLAGS)
LDFLAGS += -pthread -lpulse
###############################################################################
# target
###############################################################################
.PHONY : all clean
TGT := $(TGT_LIB_A)
TGT += $(TGT_LIB_SO)
TGT += $(TGT_UNIT_TEST)
OBJS := $(OBJS_LIB) $(OBJS_UNIT_TEST)
all: $(TGT)
%.o:%.c
$(CC_V) -c $(CFLAGS) $< -o $@
$(TGT_LIB_A): $(OBJS_LIB)
$(AR_V) rcs $@ $^
$(TGT_LIB_SO): $(OBJS_LIB)
$(CC_V) -o $@ $^ $(SHARED)
@mv $(TGT_LIB_SO) $(TGT_LIB_SO_VER)
@ln -sf $(TGT_LIB_SO_VER) $(TGT_LIB_SO)
$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST) $(ANDROID_MAIN_OBJ)
$(CC_V) -o $@ $^ $(TGT_LIB_A) $(LDFLAGS)
clean:
$(RM_V) -f $(OBJS)
$(RM_V) -f $(TGT)
$(RM_V) -f version.h
$(RM_V) -f $(TGT_LIB_SO)*
$(RM_V) -f $(TGT_LIB_SO_VER)
install:
$(MAKEDIR_OUTPUT)
@if [ "$(MODE)" = "release" ];then $(STRIP) $(TGT); fi
$(CP_V) -r $(TGT_LIB_H) $(OUTPUT)/include/gear-lib
$(CP_V) -r $(TGT_LIB_A) $(OUTLIBPATH)/lib/gear-lib
$(CP_V) -r $(TGT_LIB_SO) $(OUTLIBPATH)/lib/gear-lib
$(CP_V) -r $(TGT_LIB_SO_VER) $(OUTLIBPATH)/lib/gear-lib
uninstall:
cd $(OUTPUT)/include/gear-lib/ && rm -f $(TGT_LIB_H)
$(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_A)
$(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO)
$(RM_V) -f $(OUTLIBPATH)/lib/gear-lib/$(TGT_LIB_SO_VER)
+54
View File
@@ -0,0 +1,54 @@
###############################################################################
# common
###############################################################################
#ARCH: linux/pi/android/ios/win
LD = link
AR = lib
RM = del
###############################################################################
# target and object
###############################################################################
LIBNAME = libuac
TGT_LIB_A = $(LIBNAME).lib
TGT_LIB_SO = $(LIBNAME).dll
TGT_UNIT_TEST = test_$(LIBNAME).exe
OBJS_LIB = $(LIBNAME).obj
OBJS_UNIT_TEST = test_$(LIBNAME).obj
###############################################################################
# cflags and ldflags
###############################################################################
CFLAGS = /Iinclude /I.
!IF "$(MODE)"=="release"
CFLAGS = $(CFLAGS) /O2 /GF
!ELSE
CFLAGS = $(CFLAGS) /Od /W3 /Zi
!ENDIF
LDFLAGS = /NOLOGO
LIBS = ws2_32.lib
###############################################################################
# target
###############################################################################
TGT = $(TGT_LIB_A) $(TGT_LIB_SO) $(TGT_UNIT_TEST)
OBJS = $(OBJS_LIB) $(OBJS_UNIT_TEST)
all: $(TGT)
$(TGT_LIB_A): $(OBJS_LIB)
$(AR) $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_A)
$(TGT_LIB_SO): $(OBJS_LIB)
$(LD) $(LDFLAGS) /Dll $(OBJS_LIB) $(LIBS) /o:$(TGT_LIB_SO)
$(TGT_UNIT_TEST): $(OBJS_UNIT_TEST)
$(CC) $(TGT_LIB_A) $(OBJS_UNIT_TEST) /o $(TGT_UNIT_TEST)
clean:
$(RM) $(OBJS)
$(RM) $(TGT)
$(RM) $(TGT_LIB_SO)*
+3
View File
@@ -0,0 +1,3 @@
## libuac
This is a simple libuac library.
+102
View File
@@ -0,0 +1,102 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#include "libuac.h"
#include <stdio.h>
#include <stdlib.h>
#if defined (OS_LINUX)
extern struct uac_ops pa_ops;
#elif defined (OS_WINDOWS)
#endif
static struct uac_ops *uac_ops[] = {
#if defined (OS_LINUX)
&pa_ops,
#elif defined (OS_WINDOWS)
#endif
NULL
};
struct uac_ctx *uac_open(const char *dev, struct uac_config *conf)
{
struct uac_ctx *uac;
if (!dev || !conf) {
printf("invalid paraments!\n");
return NULL;
}
uac = (struct uac_ctx *)calloc(1, sizeof(struct uac_ctx));
if (!uac) {
printf("malloc failed!\n");
return NULL;
}
uac->ops = uac_ops[0];
uac->opaque = uac->ops->open(uac, dev, conf);
if (!uac->opaque) {
printf("open %s failed!\n", dev);
goto failed;
}
return uac;
failed:
free(uac);
return NULL;
}
void uac_close(struct uac_ctx *uac)
{
if (!uac) {
printf("invalid paraments!\n");
return;
}
uac->ops->close(uac);
free(uac);
}
int uac_query_frame(struct uac_ctx *uac, struct audio_frame *frame)
{
if (!uac || !frame) {
printf("invalid paraments!\n");
return -1;
}
return uac->ops->query_frame(uac, frame);
}
int uac_start_stream(struct uac_ctx *uac, audio_frame_cb *cb)
{
if (!uac) {
printf("invalid paraments!\n");
return -1;
}
uac->on_audio_frame = cb;
return uac->ops->start_stream(uac);
}
int uac_stop_stream(struct uac_ctx *uac)
{
if (!uac) {
printf("invalid paraments!\n");
return -1;
}
return uac->ops->stop_stream(uac);
}
+79
View File
@@ -0,0 +1,79 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#ifndef LIBUAC_H
#define LIBUAC_H
#include <gear-lib/libposix.h>
#include <gear-lib/libmedia-io.h>
#include <stdio.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct uac_ctx;
struct uac_ops;
typedef int (audio_frame_cb)(struct uac_ctx *c, struct audio_frame *frame);
struct uac_config {
};
struct uac_ctx {
int fd;
struct uac_config conf;
struct uac_ops *ops;
audio_frame_cb *on_audio_frame;
void *opaque;
};
struct uac_ops {
void *(*open)(struct uac_ctx *uac, const char *dev, struct uac_config *conf);
void (*close)(struct uac_ctx *c);
int (*ioctl)(struct uac_ctx *c, unsigned long int cmd, ...);
int (*start_stream)(struct uac_ctx *c);
int (*stop_stream)(struct uac_ctx *c);
int (*query_frame)(struct uac_ctx *c, struct audio_frame *frame);
};
struct uac_ctx *uac_open(const char *dev, struct uac_config *conf);
int uac_ioctl(struct uac_ctx *c, unsigned long int cmd, ...);
void uac_close(struct uac_ctx *c);
/*
* active query frame one by one
*/
int uac_query_frame(struct uac_ctx *c, struct audio_frame *frame);
/*
* passive get frame when cb is set, otherwise need query frame one by one
*/
int uac_start_stream(struct uac_ctx *uac, audio_frame_cb *cb);
int uac_stop_stream(struct uac_ctx *uac);
#ifdef __cplusplus
}
#endif
#endif
+194
View File
@@ -0,0 +1,194 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#include "libuac.h"
#include <gear-lib/libthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <sys/epoll.h>
#include <pulse/pulseaudio.h>
struct pulse_ctx {
int fd;
struct uac_ctx *parent;
bool is_streaming;
pa_threaded_mainloop *mainloop;
pa_context *ctx;
pa_context_state_t state;
};
#define timeval2ns(tv) \
(((uint64_t)tv.tv_sec * 1000000000) + ((uint64_t)tv.tv_usec * 1000))
static void on_pulse_state(pa_context *ctx, void *userdata)
{
struct pulse_ctx *c = userdata;
if (c->ctx != ctx) {
printf("c->ctx=%p, ctx=%p\n", c->ctx, ctx);
return;
}
switch (pa_context_get_state(ctx)) {
case PA_CONTEXT_UNCONNECTED:
printf("%s:%d PA_CONTEXT_UNCONNECTED\n", __func__, __LINE__);
break;
case PA_CONTEXT_CONNECTING:
printf("%s:%d PA_CONTEXT_CONNECTING\n", __func__, __LINE__);
break;
case PA_CONTEXT_AUTHORIZING:
printf("%s:%d PA_CONTEXT_AUTHORIZING\n", __func__, __LINE__);
break;
case PA_CONTEXT_SETTING_NAME:
printf("%s:%d PA_CONTEXT_SETTING_NAME\n", __func__, __LINE__);
break;
case PA_CONTEXT_READY:
printf("%s:%d PA_CONTEXT_READY\n", __func__, __LINE__);
break;
case PA_CONTEXT_FAILED:
printf("%s:%d PA_CONTEXT_FAILED\n", __func__, __LINE__);
break;
case PA_CONTEXT_TERMINATED:
printf("%s:%d PA_CONTEXT_TERMINATED\n", __func__, __LINE__);
break;
default:
printf("%s:%d xxxx\n", __func__, __LINE__);
break;
}
pa_threaded_mainloop_signal(c->mainloop, 0);
}
static void pa_server_info_cb(pa_context *ctx, const pa_server_info *info, void *data)
{
struct pulse_ctx *c = data;
if (c->ctx != ctx) {
printf("c->ctx=%p, ctx=%p\n", c->ctx, ctx);
return;
}
printf("========pulse audio information========\n");
printf(" Server Version: %s\n", info->server_version);
printf(" Server Name: %s\n", info->server_name);
printf(" Default Source Name: %s\n", info->default_source_name);
printf(" Default Sink Name: %s\n", info->default_sink_name);
printf(" Host Name: %s\n", info->host_name);
printf(" User Name: %s\n", info->user_name);
printf(" Channels: %hhu\n", info->sample_spec.channels);
printf(" Rate: %u\n", info->sample_spec.rate);
printf(" Frame Size: %lu\n", pa_frame_size(&info->sample_spec));
printf(" Sample Size: %lu\n", pa_sample_size(&info->sample_spec));
printf(" ChannelMap Channels: %hhu\n", info->channel_map.channels);
pa_threaded_mainloop_signal(c->mainloop, 0);
}
static void *uac_pa_open(struct uac_ctx *uac, const char *dev, struct uac_config *conf)
{
pa_mainloop_api *mainloop_api;
struct pulse_ctx *c = calloc(1, sizeof(struct pulse_ctx));
c->mainloop = pa_threaded_mainloop_new();
if (!c->mainloop) {
printf("pa_threaded_mainloop_new failed!\n");
}
mainloop_api = pa_threaded_mainloop_get_api(c->mainloop);
if (!mainloop_api) {
printf("pa_threaded_mainloop_get_api failed!\n");
}
c->ctx = pa_context_new(mainloop_api, "libuac");
if (!c->ctx) {
printf("pa_context_new failed!\n");
}
pa_context_set_state_callback(c->ctx, on_pulse_state, c);
pa_context_connect(c->ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);
pa_threaded_mainloop_start(c->mainloop);
pa_threaded_mainloop_lock(c->mainloop);
while ((c->state = pa_context_get_state(c->ctx)) != PA_CONTEXT_READY) {
if (c->state == PA_CONTEXT_FAILED || c->state == PA_CONTEXT_TERMINATED) {
printf("pa_context_state is invalid!\n");
break;
}
pa_threaded_mainloop_wait(c->mainloop);
}
pa_threaded_mainloop_unlock(c->mainloop);
pa_context_set_state_callback(c->ctx, NULL, c);
pa_operation *op = NULL;
pa_operation_state_t op_state;
pa_threaded_mainloop_lock(c->mainloop);
op = pa_context_get_server_info(c->ctx, pa_server_info_cb, c);
while ((op_state = pa_operation_get_state(op)) != PA_OPERATION_DONE) {
if (op_state == PA_OPERATION_CANCELLED) {
printf("Get server info operation cancelled!");
break;
}
printf("%s:%d xxxx\n", __func__, __LINE__);
pa_threaded_mainloop_wait(c->mainloop);
}
pa_operation_unref(op);
pa_threaded_mainloop_unlock(c->mainloop);
c->parent = uac;
return c;
}
static int uac_pa_start_stream(struct uac_ctx *uac)
{
return 0;
}
static int uac_pa_stop_stream(struct uac_ctx *uac)
{
return 0;
}
static int uac_pa_query_frame(struct uac_ctx *uac, struct audio_frame *frame)
{
return 0;
}
static void uac_pa_close(struct uac_ctx *uac)
{
}
struct uac_ops pa_ops = {
.open = uac_pa_open,
.close = uac_pa_close,
.ioctl = NULL,
.start_stream = uac_pa_start_stream,
.stop_stream = uac_pa_stop_stream,
.query_frame = uac_pa_query_frame,
};
+43
View File
@@ -0,0 +1,43 @@
/******************************************************************************
* Copyright (C) 2014-2020 Zhifeng Gong <gozfree@163.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
******************************************************************************/
#include "libuac.h"
#include <stdio.h>
#include <stdlib.h>
static int foo()
{
struct uac_config conf = {
};
struct uac_ctx *uac = uac_open("xxx", &conf);
if (!uac) {
printf("uac_open failed!\n");
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
foo();
return 0;
}
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
major=0
minor=1
patch=0
libname=$1
output=version.h
LIBNAME=`echo ${libname} | tr 'a-z' 'A-Z'`
export version=${major}.${minor}.${patch}
export buildid=`git log -1 --pretty=format:"git-%cd-%h" --date=short 2>/dev/null`
autogen_version_h()
{
cat > version.h <<!
/* Automatically generated by version.sh - do not modify! */
#ifndef ${LIBNAME}_VERSION_H
#define ${LIBNAME}_VERSION_H
#define ${libname}_version ${version}
#define ${libname}_buildid ${buildid}
#endif
!
}
autogen_version_h