Commit 766ad500 authored by Bob Ham's avatar Bob Ham

Initial commit

parents
((nil . ((indent-tabs-mode . nil))))
# Hægtesse
A daemon to transfer call audio data between a modem and PulseAudio.
Hægtesse was written solely for the SIMCom SIM7100 modem but may be
useful for other modems. The sample format is hard-coded.
Probably the best place for this functionality would be a PulseAudio
plugin which listens to ModemManager over D-Bus and configures itself
according to ModemManager call audio meta-data. This functionality is
still under deverlopment, however.
## License
Hægtesse is licensed under the GPLv3+.
## Dependencies
sudo apt-get install libpulse-dev libglib2.0-dev
A development version of ModemManager is required in order to send
appropriate AT commands to the SIM7100 for enabling call audio. Our
development tree is here:
https://source.puri.sm/Librem5/ModemManager
## Building
We use the meson and thereby Ninja. The quickest way to get going is
to do the following:
meson ../haegtesse-build
ninja -C ../haegtesse-build
ninja -C ../haegtesse-build install
## Running
Hægtesse is usually run as a systemd user service. To run it by hand,
you must pass the name of the TTY port to be used for audio. On the
SIM7100, this is ttyUSB4:
$ haegtesse -p /dev/ttyUSB4
haegtesse (0.0.0) UNRELEASED; urgency=medium
* Initial release.
-- Bob Ham <bob.ham@puri.sm> Thu, 06 Sep 2018 13:40:57 +0000
Source: haegtesse
Section: comm
Priority: optional
Maintainer: Bob Ham <rah@settrans.net>
Build-Depends:
debhelper (>= 9),
dh-exec,
libpulse-dev,
libglib2.0-dev,
meson,
Standards-Version: 4.1.3
Homepage: https://source.puri.sm/Librem5/haegtesse
Package: haegtesse
Architecture: any
Depends:
${misc:Depends},
${shlibs:Depends},
pulseaudio,
Recommends:
modemmanager
Description: A daemon to transfer audio data betwem a modem and PulseAudio
Some modems, like the SIMCom SIM7100 series, support transfer of
voice call audio over serial TTY devices. This daemon will sit on a
modem TTY port, wait for data and when it appears, transfer it to and
from PulseAudio streams.
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: haegtesse
Source: https://source.puri.sm/Librem5/haegtesse
Files: *
Copyright: 2018 Purism SPC
License: GPL-3+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
#!/usr/bin/dh-exec
[linux-any] debian/haegtesse.user-service => /usr/lib/systemd/user/haegtesse.service
[Unit]
Description=Hægtesse, a deamon for voice call audio
# We need PulseAudio
Requires=pulseaudio.service
# We can wait for the modem
Wants=sys-devices-soc0-soc-2100000.aips\x2dbus-2184200.usb-ci_hdrc.1-usb1-1\x2d1-1\x2d1.1-1\x2d1.1.4-1\x2d1.1.4:1.4-ttyUSB4-tty-ttyUSB4.device
[Service]
ExecStart=/usr/bin/haegtesse -p /dev/ttyUSB4
Restart=always
RestartSec=500ms
[Install]
WantedBy=default.target
#!/usr/bin/make -f
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
%:
dh $@ --builddirectory=_build
override_dh_link:
dh_link
ifeq ($(DEB_HOST_ARCH_OS),linux)
dh_link usr/lib/systemd/user/haegtesse.service usr/lib/systemd/user/default.target.wants/haegtesse.service
endif
<?xml version="1.0" encoding="UTF-8"?>
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:gnome="http://api.gnome.org/doap-extensions#"
xmlns="http://usefulinc.com/ns/doap#">
<name>Hægtesse</name>
<shortname>Hægtesse</shortname>
<shortdesc>A daemon to transfer audio data between a modem and PulseAudio</shortdesc>
<description>Some modems, like the SIMCom SIM7100 series, support
transfer of voice call audio over serial TTY devices. This daemon
will sit on a modem TTY port, wait for data and when it appears,
transfer it to and from PulseAudio streams.</description>
<homepage rdf:resource="https://source.puri.sm/Librem5/haegtesse" />
<license rdf:resource="http://usefulinc.com/doap/licenses/gpl" />
<programming-language>C</programming-language>
<maintainer>
<foaf:Person>
<foaf:name>Bob Ham</foaf:name>
<foaf:mbox rdf:resource="mailto:bob.ham@puri.sm" />
<foaf:mbox rdf:resource="mailto:rah@settrans.net" />
</foaf:Person>
</maintainer>
</Project>
#
# Copyright (C) 2018 Purism SPC
#
# This file is part of Hægtesse.
#
# Hægtesse is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Hægtesse is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Hægtesse. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
project('haegtesse', 'c',
version: '0.0.0',
license: 'GPLv3+',
meson_version: '>= 0.42.0',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
)
subdir('src')
/*
* Copyright (C) 2018 Purism SPC
*
* This file is part of Hægtesse.
*
* Hægtesse is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Hægtesse is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Hægtesse. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Bob Ham <bob.ham@puri.sm>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "haeg-sample-buffer.h"
#include <glib/gi18n.h>
#include <gmodule.h>
#include <unistd.h>
#include <errno.h>
/**
* SECTION:haeg-sample-buffer
* @short_description: Buffer data sample data from a TTY port and
* deliver it efficiently.
* @Title: HaegSampleBuffer
*/
struct _HaegSampleBuffer
{
GObject parent_instance;
gint fd;
gsize sample_len;
GByteArray *partial;
};
G_DEFINE_TYPE (HaegSampleBuffer, haeg_sample_buffer, G_TYPE_OBJECT);
enum {
PROP_0,
PROP_FILE_DES,
PROP_SAMPLE_LEN,
PROP_LAST_PROP,
};
static GParamSpec *props[PROP_LAST_PROP];
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
HaegSampleBuffer *self = HAEG_SAMPLE_BUFFER (object);
switch (property_id) {
case PROP_FILE_DES:
self->fd = g_value_get_int (value);
break;
case PROP_SAMPLE_LEN:
self->sample_len = g_value_get_ulong (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
haeg_sample_buffer_init (HaegSampleBuffer *self)
{
self->partial = g_byte_array_new ();
}
static void
dispose (GObject *object)
{
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
HaegSampleBuffer *self = HAEG_SAMPLE_BUFFER (object);
g_byte_array_unref (self->partial);
parent_class->dispose (object);
}
static void
haeg_sample_buffer_class_init (HaegSampleBufferClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = set_property;
object_class->dispose = dispose;
props[PROP_FILE_DES] =
g_param_spec_int ("file-des",
_("File descriptor"),
_("The file descriptor to read samples from"),
G_MININT, G_MAXINT, 0,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
props[PROP_SAMPLE_LEN] =
g_param_spec_ulong ("sample-len",
_("Sample len"),
_("The size, in bytes, of a sample"),
0, G_MAXULONG, 0,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
}
HaegSampleBuffer *
haeg_sample_buffer_new (gint fd, gsize sample_len)
{
return g_object_new (HAEG_TYPE_SAMPLE_BUFFER,
"file-des", fd,
"sample-len", sample_len,
NULL);
}
gsize
haeg_sample_buffer_read (HaegSampleBuffer *self,
gchar *buf, gsize buf_len)
{
guint partial_len = self->partial->len;
gsize total;
int bytes_read;
if (partial_len > 0)
{
// Copy partial frame
const gboolean partial_only = buf_len <= partial_len;
const gsize copy_len = partial_only ? buf_len : partial_len;
g_debug ("Using %" G_GSIZE_FORMAT
" bytes out of partial sample of length %" G_GSIZE_FORMAT,
copy_len, partial_len);
memcpy (buf, self->partial->data, copy_len);
if (buf_len < partial_len)
{
g_byte_array_remove_range (self->partial, 0, copy_len);
}
else
{
g_byte_array_set_size (self->partial, 0);
}
if (partial_only)
{
return copy_len;
}
total = copy_len;
}
else
{
total = 0;
}
// Read more samples
bytes_read = read (self->fd, buf + total, buf_len - total);
if (bytes_read == -1)
{
g_error ("Error reading from TTY port: %s",
g_strerror (errno));
}
g_debug ("Read %i bytes from TTY port", bytes_read);
total += bytes_read;
partial_len = total % self->sample_len;
if (partial_len != 0)
{
// Store partial
g_assert (self->partial->len == 0);
g_debug ("Storing partial sample of length %u"
" from buffer with total length %" G_GSIZE_FORMAT,
partial_len, total);
total -= partial_len;
g_byte_array_append (self->partial,
(const guint8 *)(buf + total),
partial_len);
}
g_debug ("Returning buffer of %" G_GSIZE_FORMAT " bytes", total);
return total;
}
/*
* Copyright (C) 2018 Purism SPC
*
* This file is part of Hægtesse.
*
* Hægtesse is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Hægtesse is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Hægtesse. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Bob Ham <bob.ham@puri.sm>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef HAEG_SAMPLE_BUFFER_H__
#define HAEG_SAMPLE_BUFFER_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define HAEG_TYPE_SAMPLE_BUFFER (haeg_sample_buffer_get_type ())
G_DECLARE_FINAL_TYPE (HaegSampleBuffer, haeg_sample_buffer, HAEG, SAMPLE_BUFFER, GObject);
HaegSampleBuffer *haeg_sample_buffer_new (gint fd, gsize sample_len);
gsize haeg_sample_buffer_read (HaegSampleBuffer *buffer,
gchar *buf, gsize buf_len);
G_END_DECLS
#endif /* HAEG_SAMPLE_BUFFER_H__ */
This diff is collapsed.
#
# Copyright (C) 2018 Purism SPC
#
# This file is part of Hægtesse.
#
# Hægtesse is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Hægtesse is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Hægtesse. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
haegtesse_deps = [ dependency('gobject-2.0'),
dependency('libpulse'),
dependency('libpulse-mainloop-glib'),
]
executable('haegtesse',
['main.c', 'haeg-sample-buffer.h', 'haeg-sample-buffer.c'],
dependencies : haegtesse_deps,
include_directories : include_directories('..'),
install : true)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment