+++ /dev/null
-/*
-* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <signal.h>
-
-#include <alsa/asoundlib.h>
-#include <dbus/dbus.h>
-#include <dlog.h>
-#include <unistd.h>
-#include <glib.h>
-#include <gio/gio.h>
-
-#include "loopback.h"
-#include "algo_speex.h"
-
-#define LOOPBACK_BUFFER_COUNT 40
-#define FIXME_DEFAULT_FORMAT_SIZE 2
-
-/* AEC daemon interfaceis */
-#define AEC_BUS_NAME "org.tizen.AudioAec"
-#define AEC_OBJECT "/org/tizen/AudioAec"
-#define AEC_INTERFACE "org.tizen.AudioAec"
-
-/* pulseaudio aec-manager interfaces */
-#define PA_BUS_NAME "org.pulseaudio.Server"
-#define PA_AEC_MANAGER_OBJECT_PATH "/org/pulseaudio/AecManager"
-#define PA_AEC_MANAGER_INTERFACE "org.pulseaudio.AecManager"
-#define PA_AEC_MANAGER_METHOD_NAME_ON "On"
-#define PA_AEC_MANAGER_METHOD_NAME_OFF "Off"
-#define PA_AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS "GetSinkParam"
-#define PA_AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS "GetSourceParam"
-
-#define SOUNDCARD_LOOPBACK "Loopback"
-#define LOOPBACK_PLAYBACK_SOURCE "hw:Loopback,1,0"
-#define LOOPBACK_CAPTURE_SINK "hw:Loopback,0,1"
-
-#define DEVICE_NAME_MAX 64
-
-enum {
- CAPTURE_DEVICE,
- PLAYBACK_DEVICE,
- DEVICE_MAX
-};
-
-enum {
- THREAD_CAPTURE,
- THREAD_PLAYBACK,
- THREAD_MAX
-};
-
-static struct sigaction sigabt, sigsegv, sigterm;
-
-static DBusConnection *conn;
-static loopback_dev_t *reference[DEVICE_MAX];
-static loopback_dev_t *recording[DEVICE_MAX];
-static loopback_t *thread[THREAD_MAX];
-static int opt_ec;
-
-static struct aec_params {
- int rate;
- int channels;
- int format;
- int frag_size;
- int nfrags;
- char *card;
- char *device;
- char fullname[DEVICE_NAME_MAX];
-} aec_params[DEVICE_MAX];
-
-static int _get_devices_params(int dev, struct aec_params *params);
-static int __dbus_method_call(const char *method, GVariant *param, GVariant **reply);
-static void __register_signal_handler();
-
-loopback_t *__create_loopback_instance(const char *name, const char *c, const char *p,
- struct aec_params *params, loopback_dev_t **dev)
-{
- int i;
- const char *devs[DEVICE_MAX] = { c, p };
- loopback_dev_t *_dev[DEVICE_MAX] = { 0, 0 };
- loopback_t *ret = NULL;
-
- unsigned int buffer_frame, period_frame;
- const int BUFFER_COUNT = 60; /* refq needs a lot of nodes than others */
-
- if (!c || !p || !name) {
- LOGE("Invalid args capture(%s), playback(%s), thread name(%s)",
- c != NULL ? c : "", p != NULL ? p : "",
- name != NULL ? name : "");
- return NULL;
- }
-
- buffer_frame = params->nfrags * params->frag_size;
- buffer_frame /= FIXME_DEFAULT_FORMAT_SIZE * params->channels;
- period_frame = params->frag_size / FIXME_DEFAULT_FORMAT_SIZE / params->channels;
-
- for (i = 0; i < DEVICE_MAX; i++) {
- _dev[i] = loopback_alloc_device(devs[i], i, params->rate, params->channels,
- FIXME_DEFAULT_FORMAT_SIZE, buffer_frame);
- if (!_dev[i]) {
- LOGE("Failed to alloc device index(%d)", i);
- goto exit;
- }
- }
-
- ret = loopback_create(name, _dev[CAPTURE_DEVICE], _dev[PLAYBACK_DEVICE],
- period_frame, BUFFER_COUNT);
- if (!ret) {
- LOGE("Failed to create loopback. capture(%s) playback(%s)", c, p);
- goto exit;
- }
-
- dev[CAPTURE_DEVICE] = _dev[CAPTURE_DEVICE];
- dev[PLAYBACK_DEVICE] = _dev[PLAYBACK_DEVICE];
-
- return ret;
-
-exit:
- if (_dev[CAPTURE_DEVICE])
- loopback_free_device(_dev[CAPTURE_DEVICE]);
-
- if (_dev[PLAYBACK_DEVICE])
- loopback_free_device(_dev[PLAYBACK_DEVICE]);
-
- return NULL;
-}
-
-static void __send_success_reply(DBusConnection *conn, DBusMessage *msg)
-{
- DBusMessage *reply = NULL;
-
- if (!(reply = dbus_message_new_method_return(msg))) {
- LOGE("Failed to get reply.");
- return;
- }
-
- dbus_connection_send(conn, reply, NULL);
- dbus_message_unref(reply);
-}
-
-static void __send_error_reply(DBusConnection *conn, DBusMessage *msg,
- const char *name, const char *s)
-{
- DBusMessage *reply = NULL;
-
- if (!(reply = dbus_message_new_error(msg, name, s))) {
- LOGE("Failed to get reply.");
- return;
- }
-
- dbus_connection_send(conn, reply, NULL);
- dbus_message_unref(reply);
-}
-
-static int __run_thread_workers(struct aec_params *params)
-{
- int i;
-
- thread[THREAD_PLAYBACK] = __create_loopback_instance("playback",
- LOOPBACK_PLAYBACK_SOURCE,
- params[PLAYBACK_DEVICE].fullname,
- &aec_params[PLAYBACK_DEVICE], reference);
- if (!thread[THREAD_PLAYBACK]) {
- LOGE("Failed to create reference thread");
- goto fail;
- }
-
- thread[THREAD_CAPTURE] = __create_loopback_instance("capture",
- aec_params[CAPTURE_DEVICE].fullname,
- LOOPBACK_CAPTURE_SINK,
- &aec_params[CAPTURE_DEVICE], recording);
- if (!thread[THREAD_CAPTURE]) {
- LOGE("Failed to create recording thread");
- goto fail;
- }
-
- // FIXME
- if (opt_ec) {
- if (loopback_bind_reference(thread[THREAD_CAPTURE],
- thread[THREAD_PLAYBACK],
- get_speex_instance())) {
- LOGE("Failed to bind reference");
- goto fail;
- }
- }
-
- if (loopback_start(thread[THREAD_CAPTURE])) {
- LOGE("Failed to start reference thread");
- goto fail;
- }
-
- if (loopback_start(thread[THREAD_PLAYBACK])) {
- LOGE("Failed to start recording thread");
- goto fail;
- }
-
- return 0;
-
-fail:
- LOGE("Failed to Launch/Quit. Process will be terminated");
-
- for (i = 0; i < THREAD_MAX; i++) {
- loopback_stop(thread[i]);
- loopback_destroy(thread[i]);
- }
- for (i = 0; i < DEVICE_MAX; i++) {
- loopback_free_device(reference[i]);
- loopback_free_device(recording[i]);
- }
-
- return -1;
-}
-
-static int __stop_thread_workers() {
- int i;
- int ret = 0;
- loopback_dev_t **devs[THREAD_MAX] = { recording, reference };
-
- for (i = 0; i < THREAD_MAX; i++) {
- if (thread[i]) {
- ret = loopback_stop(thread[i]);
- ret |= loopback_destroy(thread[i]);
- thread[i] = NULL;
- }
- ret |= loopback_free_device(devs[i][CAPTURE_DEVICE]);
- ret |= loopback_free_device(devs[i][PLAYBACK_DEVICE]);
- recording[CAPTURE_DEVICE] = NULL;
- recording[PLAYBACK_DEVICE] = NULL;
-
- if (ret)
- LOGE("Failed to stop thread workers(%d)", i);
- }
-
- return 0;
-}
-
-static DBusHandlerResult __message_handler(DBusConnection *conn,
- DBusMessage *msg, void *userdata)
-{
- LOGD("type(%d) path(%s) member(%s) intf(%s), sig(%s)",
- dbus_message_get_type(msg), dbus_message_get_path(msg),
- dbus_message_get_member(msg), dbus_message_get_interface(msg),
- dbus_message_get_signature(msg));
-
- if (dbus_message_is_method_call(msg, AEC_INTERFACE, "Launch")) {
- if (thread[THREAD_PLAYBACK] || thread[THREAD_CAPTURE]) {
- LOGW("Already working");
- goto exit;
- }
-
- if (__run_thread_workers(aec_params)) {
- __send_error_reply(conn, msg, DBUS_ERROR_FAILED, "Process will be terminated");
- dbus_connection_unref(conn);
- raise(SIGTERM);
- }
- __dbus_method_call(PA_AEC_MANAGER_METHOD_NAME_ON, NULL, NULL);
-
- LOGI("Launched successfully");
-
- } else if (dbus_message_is_method_call(msg, AEC_INTERFACE, "Quit")) {
- if (!thread[THREAD_PLAYBACK] || !thread[THREAD_CAPTURE]) {
- LOGW("not working");
- goto exit;
- }
-
- if (__stop_thread_workers()) {
- __send_error_reply(conn, msg, DBUS_ERROR_FAILED, "Process will be terminated");
- dbus_connection_unref(conn);
- raise(SIGTERM);
- }
- __dbus_method_call(PA_AEC_MANAGER_METHOD_NAME_OFF, NULL, NULL);
-
- LOGE("Quit successfully");
- }
-
-exit:
- __send_success_reply(conn, msg);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-DBusConnection *register_service()
-{
- int rv;
- DBusError err;
- static DBusObjectPathVTable vtable = { .message_function = __message_handler };
-
- dbus_error_init(&err);
-
- conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- if (!conn) {
- LOGE("Failed to get a private DBus connection");
- goto exit;
- }
-
- rv = dbus_bus_request_name(conn, AEC_BUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
- if (rv != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- LOGE("Failed to request name on bus err(%s)\n", err.message);
- goto exit;
- }
-
- if (!dbus_connection_register_object_path(conn, AEC_OBJECT, &vtable, NULL)) {
- LOGE("Failed to register object path(%s)", AEC_OBJECT);
- goto exit;
- }
-
- return conn;
-
-exit:
- dbus_error_free(&err);
-
- return NULL;
-}
-
-void run_service(DBusConnection *conn)
-{
- while (dbus_connection_read_write_dispatch(conn, -1));
-}
-
-int main(int argc, char *argv[])
-{
- if (argc != 1 && argc != 2)
- exit(EXIT_FAILURE);
-
- if (snd_card_get_index(SOUNDCARD_LOOPBACK) < 0) {
- LOGE("Failed to get Loopback card");
- exit(EXIT_FAILURE);
- }
-
- __register_signal_handler();
-
- conn = register_service();
-
- if (getopt(argc, argv, "c") == 'c')
- opt_ec = 1;
-
- if (_get_devices_params(CAPTURE_DEVICE, &aec_params[CAPTURE_DEVICE])) {
- LOGE("Failed to get source params");
- exit(EXIT_FAILURE);
- }
-
- if (_get_devices_params(PLAYBACK_DEVICE, &aec_params[PLAYBACK_DEVICE])) {
- LOGE("Failed to get sink params");
- exit(EXIT_FAILURE);
- }
-
- run_service(conn);
-
- dbus_connection_flush(conn);
- dbus_connection_close(conn);
-
- return 0;
-}
-
-static int _get_devices_params(int dev, struct aec_params *params)
-{
- GVariant *reply = NULL;
-
- int rate, channels, format, frag_size, nfrags;
- char *card = NULL;
- char *device = NULL;
- char *msg;
-
- if (dev == PLAYBACK_DEVICE)
- msg = PA_AEC_MANAGER_METHOD_NAME_GET_SINK_PARAMS;
- else
- msg = PA_AEC_MANAGER_METHOD_NAME_GET_SOURCE_PARAMS;
-
- if (__dbus_method_call(msg, NULL, &reply)) {
- LOGE("Failed to get device params");
- return -1;
- }
-
- if (!reply) {
- LOGE("Failed to start aec daemon");
- return -1;
- }
-
- g_variant_get(reply, "(iiiii&s&s)", &rate, &channels, &format,
- &frag_size, &nfrags, &card, &device);
- if (!card || !device) {
- LOGE("Failed to get device and card names");
- g_variant_unref(reply);
- return -1;
- }
-
- LOGI("source param rate(%d), channels(%d), format(%d), "
- "frag_size(%d), nfrag(%d), card(%s), device(%s)",
- rate, channels, format, frag_size, nfrags, card, device);
-
- params->rate = rate;
- params->channels = channels;
- params->format = format;
- params->frag_size = frag_size;
- params->nfrags = nfrags;
- params->card = strdup(card);
- params->device = strdup(device);
- snprintf(params->fullname, DEVICE_NAME_MAX, "hw:%s,%s", params->card, params->device);
-
- g_variant_unref(reply);
-
- return 0;
-}
-
-static GDBusConnection *__get_dbus_connection(void)
-{
- GDBusConnection *conn = NULL;
- GError *err = NULL;
-
- conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
- if (!conn) {
- LOGE("g_bus_get_sync() error (%s)", err->message);
- g_error_free(err);
- }
-
- return conn;
-}
-
-static int __dbus_method_call(const char *method, GVariant *param, GVariant **reply)
-{
- GDBusConnection *conn = NULL;
- GVariant *_reply = NULL;
- GError *err = NULL;
-
- if (!method) {
- LOGE("invalid parameter");
- goto error;
- }
-
- if (!(conn = __get_dbus_connection()))
- goto error;
-
- _reply = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
- PA_AEC_MANAGER_OBJECT_PATH,
- PA_AEC_MANAGER_INTERFACE,
- method, param, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
-
- g_object_unref(conn);
-
- if (!_reply) {
- LOGE("g_dbus_connection_call_sync() method(%s), err-msg(%s)", method, err->message);
- g_error_free(err);
- return -1;
- }
-
- if (reply)
- *reply = _reply;
- else
- g_variant_unref(_reply);
-
- return 0;
-
-error:
- if (param)
- g_variant_unref(param);
-
- return -1;
-}
-
-static void _signal_handler(int sig)
-{
- int i;
-
- __dbus_method_call(PA_AEC_MANAGER_METHOD_NAME_OFF, NULL, NULL);
-
- for (i = 0; i < 2; i++) {
- loopback_stop(thread[i]);
- loopback_destroy(thread[i]);
- loopback_free_device(reference[i]);
- loopback_free_device(recording[i]);
- }
-
- switch (sig) {
- case SIGABRT:
- sigaction(SIGABRT, &sigabt, NULL);
- break;
- case SIGSEGV:
- sigaction(SIGSEGV, &sigsegv, NULL);
- break;
- case SIGTERM:
- sigaction(SIGTERM, &sigterm, NULL);
- break;
- default:
- break;
- }
-
- raise(sig);
-}
-
-static void __register_signal_handler()
-{
- struct sigaction action;
-
- action.sa_handler = _signal_handler;
- action.sa_flags = 0;
- sigemptyset(&action.sa_mask);
-
- sigaction(SIGABRT, &action, &sigabt);
- sigaction(SIGSEGV, &action, &sigsegv);
- sigaction(SIGTERM, &action, &sigterm);
-}
-
+++ /dev/null
-/*
-* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <dlog.h>
-
-#include "static_queue.h"
-
-struct sqbuffer {
- unsigned char *buffer;
- struct static_queue *p;
- struct sqbuffer *n;
-};
-
-struct static_queue {
- struct sqbuffer *hold;
- struct sqbuffer *idle;
- struct sqbuffer *front, *rear;
-
- int count;
- int bytes;
- int inqueue;
-
- pthread_mutex_t lock;
-};
-
-sq *create_static_queue(int bytes, int count)
-{
- struct static_queue *sq;
- struct sqbuffer *sqb = NULL;
- int i;
-
- if (bytes != 0 && count == 0) {
- LOGE("invalid count(%d)", count);
- return NULL;
- }
-
- if (bytes == 0 && count != 0) {
- LOGE("invalid bytes(%d)", bytes);
- return NULL;
- }
-
- sq = (struct static_queue *)calloc(1, sizeof(struct static_queue));
- if (!sq) {
- LOGE("Failed to alloc sq");
- return NULL;
- }
-
- sq->bytes = bytes;
- sq->count = count;
- pthread_mutex_init(&sq->lock, NULL);
-
- /* for refq */
- if (bytes == 0 && count == 0)
- return sq;
-
- sqb = (struct sqbuffer *)calloc(count, sizeof(struct sqbuffer));
- if (!sqb) {
- LOGE("Failed to alloc sqb %d", count);
- goto fail;
- }
- sq->hold = sqb;
-
- for (i = 0; i < count; i++) {
- sqb[i].buffer = (unsigned char *)malloc(bytes);
- if (!sqb[i].buffer) {
- LOGE("Failed to alloc sqb buffer");
- goto fail;
- }
- sqb[i].p = sq;
- sqb[i].n = sq->idle;
- sq->idle = sqb + i;
- }
-
- return sq;
-
-fail:
- if (sqb) {
- for (i = 0; i < count; i++) {
- if (sqb[i].buffer)
- free(sqb[i].buffer);
- }
- free(sqb);
- }
- if (sq)
- free(sq);
-
- return NULL;
-}
-
-void destory_static_queue(sq *q)
-{
- int i;
-
- if (!q) {
- LOGE("invalid args");
- return;
- }
-
- for (i = 0; i < q->count; i++) {
- if (q->hold[i].buffer)
- free(q->hold[i].buffer);
- }
-
- pthread_mutex_destroy(&q->lock);
-
- if (q->hold)
- free(q->hold);
- if (q)
- free(q);
-}
-
-sqbuffer *sq_get_node(sq *q)
-{
- sqbuffer *sqb;
-
- if (!q) {
- LOGE("invalid args");
- return NULL;
- }
-
- if (!q->idle) {
- LOGE("Failed to get available node");
- return NULL;
- }
-
- sqb = q->idle;
- q->idle = sqb->n;
- sqb->n = NULL;
-
- return sqb;
-}
-
-sqbuffer *sq_get_node_lock(sq *q)
-{
- sqbuffer *ret;
-
- if (!q)
- return NULL;
-
- pthread_mutex_lock(&q->lock);
- ret = sq_get_node(q);
- pthread_mutex_unlock(&q->lock);
-
- return ret;
-}
-
-void sq_put_node(sqbuffer *b)
-{
- sq *q;
-
- if (!b) {
- LOGE("invalid args");
- return;
- }
-
- q = b->p;
- b->n = q->idle;
- q->idle = b;
-}
-
-void sq_put_node_lock(sqbuffer *b)
-{
- sq *q;
-
- if (!b) {
- LOGE("invalid args");
- return;
- }
-
- q = b->p;
-
- pthread_mutex_lock(&q->lock);
- sq_put_node(b);
- pthread_mutex_unlock(&q->lock);
-}
-
-unsigned char *sq_get_buffer(sqbuffer *sqb)
-{
- return sqb ? sqb->buffer : NULL;
-}
-
-int sq_enqueue_node(sq *q, sqbuffer *b)
-{
- if (!q || !b) {
- LOGE("invalid args");
- return -1;
- }
-
- if (!q->front)
- q->front = q->rear = b;
- else
- q->rear = q->rear->n = b;
-
- q->inqueue++;
-
- return q->inqueue;
-}
-
-int sq_enqueue_node_lock(sq *q, sqbuffer *b)
-{
- int ret;
-
- pthread_mutex_lock(&q->lock);
- ret = sq_enqueue_node(q, b);
- pthread_mutex_unlock(&q->lock);
-
- return ret;
-}
-
-sqbuffer *sq_dequeue_node(sq *q)
-{
- sqbuffer *sqb;
-
- if (!q) {
- LOGE("invalid args");
- return NULL;
- }
-
- if (!q->front)
- return NULL;
-
- sqb = q->front;
- q->front = sqb->n;
- sqb->n = NULL;
- q->inqueue--;
-
- return sqb;
-}
-
-sqbuffer *sq_dequeue_node_lock(sq *q)
-{
- sqbuffer *sqb;
-
- pthread_mutex_lock(&q->lock);
- sqb = sq_dequeue_node(q);
- pthread_mutex_unlock(&q->lock);
-
- return sqb;
-}
-
-void sq_flush(sq *q)
-{
- sqbuffer *i;
-
- if (!q)
- return;
-
- while ((i = sq_dequeue_node(q)) != NULL)
- sq_put_node(i);
-}
-
-void sq_flush_lock(sq *q)
-{
- sqbuffer *i;
-
- if (!q)
- return;
-
- pthread_mutex_lock(&q->lock);
-
- while ((i = sq_dequeue_node(q)) != NULL)
- sq_put_node_lock(i);
-
- pthread_mutex_unlock(&q->lock);
-}
-
-int sq_is_empty(sq *q)
-{
- if (!q)
- return -1;
-
- return q->front ? 0 : 1;
-}
-
-int sq_is_empty_lock(sq *q)
-{
- int ret;
-
- if (!q)
- return -1;
-
- pthread_mutex_lock(&q->lock);
- ret = sq_is_empty(q);
- pthread_mutex_unlock(&q->lock);
-
- return ret;
-}
-
-int sq_get_work_node_count(sq *q)
-{
- if (!q)
- return -1;
-
- return q->inqueue;
-}
-