Skip to content

Commit

Permalink
Support playing audio files on AOS and LOS. Issue 187.
Browse files Browse the repository at this point in the history
Allow elevation for AOS and LOS to be set to something other than 0 degrees. Issue 167.
Signal LOS when autotrack is enabled. Issue 193.
Update Windows makefile to work with latest version of msys2. Issue 110.
  • Loading branch information
srcejon committed Feb 18, 2020
1 parent 01e2d1e commit d391ce9
Show file tree
Hide file tree
Showing 18 changed files with 578 additions and 74 deletions.
16 changes: 16 additions & 0 deletions configure.ac
Expand Up @@ -52,6 +52,16 @@ else
AC_MSG_ERROR(Gpredict requires libgoocanvas-2.0-dev)
fi

# check for gstreamer (optional)
if pkg-config --atleast-version=1.0 gstreamer-1.0; then
CFLAGS="$CFLAGS `pkg-config --cflags gstreamer-1.0`"
LIBS="$LIBS `pkg-config --libs gstreamer-1.0`"
havelibgstreamer=true;
AC_DEFINE(HAS_LIBGSTREAMER, 1, [Define if libgstreamer is available])
else
havelibgstreamer=false;
fi

# check for libgps (optional)
if pkg-config --atleast-version=2.90 libgps; then
CFLAGS="$CFLAGS `pkg-config --cflags libgps`"
Expand Down Expand Up @@ -94,6 +104,11 @@ GTHR_V=`pkg-config --modversion gthread-2.0`
GDK_V=`pkg-config --modversion gdk-3.0`
GTK_V=`pkg-config --modversion gtk+-3.0`
GOOC_V=`pkg-config --modversion goocanvas-2.0`
if test "$havelibgstreamer" = true ; then
GST_V=`pkg-config --modversion gstreamer-1.0`
else
GST_V='Not found'
fi
CURL_V=`pkg-config --modversion libcurl`
if test "$havelibgps" = true ; then
GPS_V=`pkg-config --modversion libgps`
Expand Down Expand Up @@ -132,6 +147,7 @@ echo Gthread version.... : $GTHR_V
echo Gdk version........ : $GDK_V
echo Gtk+ version....... : $GTK_V
echo GooCanvas version.. : $GOOC_V
echo gstreamer version.. : $GST_V
echo Libcurl version.... : $CURL_V
if test "$havelibgps" = true ; then
echo Libgps version..... : $GPS_V
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Expand Up @@ -37,6 +37,7 @@ gpredict_SOURCES = \
first-time.c first-time.h \
gpredict-help.c gpredict-help.h \
gpredict-utils.c gpredict-utils.h \
gtk-audio.c gtk-audio.h \
gtk-azel-plot.c gtk-azel-plot.h \
gtk-event-list.c gtk-event-list.h \
gtk-event-list-popup.c gtk-event-list-popup.h \
Expand Down
81 changes: 81 additions & 0 deletions src/gtk-audio.c
@@ -0,0 +1,81 @@
/* Functions to play audio files (.wav etc).
*
* This uses the gstreamer library & requires the playbin and wav plugins.
* On Windows/msys2, these can be installed with:
* pacman -S mingw-w64-i686-gstreamer mingw-w64-i686-gst-plugins-base mingw-w64-i686-gst-plugins-good
* On Centos 8:
* yum install gstreamer1 streamer1-plugins-good gstreamer1-devel
*/

#ifdef HAVE_CONFIG_H
#include <build-config.h>
#endif

#include <glib.h>
#include <glib/gi18n.h>
#ifdef HAS_LIBGSTREAMER
#include <gst/gst.h>
#endif

#include "gtk-audio.h"
#include "sat-log.h"

/* Convert path to absolute path */
gchar *
absolute_path (const gchar *filename)
{
gchar *abs_path;

if (!g_path_is_absolute (filename))
{
gchar *cwd = NULL;

cwd = g_get_current_dir();
abs_path = g_build_filename(cwd, filename, NULL);
g_free(cwd);
}
else
abs_path = g_strdup(filename);

return abs_path;
}

#ifdef HAS_LIBGSTREAMER
void audio_play_uri(gchar *uri)
{
GstElement *pipeline;

/* playbin requires an absolute URI. E.g. file:///absolute/path.
We try to see if the input uri is actually a file path. If so, we make it
into a uri.
*/
if (g_file_test(uri, G_FILE_TEST_EXISTS))
{
gchar *filename;
GError *error = NULL;

filename = absolute_path(uri);
uri = g_filename_to_uri(filename, NULL, &error);
g_free(filename);
}

/* Play audio using playbin plugin. */
pipeline = gst_element_factory_make("playbin", NULL);
if (!pipeline) {
/* This will fail if the playbin plugin isn't found. */
sat_log_log(SAT_LOG_LEVEL_ERROR,
_("%s: Failed to create playbin pipeline. Are gst plugins installed?"),
__func__);
return;
}
g_object_set(pipeline, "uri", uri, NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
}
#else
void audio_play_uri(gchar *uri)
{
sat_log_log(SAT_LOG_LEVEL_WARN,
_("%s: Request to play audio \"%s\", but gpredict was compiled without libgstreamer"),
__func__, uri);
}
#endif
21 changes: 21 additions & 0 deletions src/gtk-audio.h
@@ -0,0 +1,21 @@
#ifndef __GTK_AUDIO_H
#define __GTK_AUDIO_H 1

#include <glib.h>

#ifdef __cplusplus
extern "C" {
#endif

/**< Play audio file. E.g. .wav
uri can be a relative pathname or URI.
E.g. ../path/file.wav, file:///path/something.wav or http://server/file.wav
Supported file formats depend on which plugins are installed.
*/
void audio_play_uri(gchar *uri);

#ifdef __cplusplus
}
#endif

#endif
36 changes: 28 additions & 8 deletions src/gtk-rig-ctrl.c
Expand Up @@ -60,6 +60,7 @@
#include "sat-log.h"
#include "sat-cfg.h"
#include "trsp-conf.h"
#include "gtk-audio.h"


#define AZEL_FMTSTR "%7.2f\302\260"
Expand Down Expand Up @@ -215,7 +216,7 @@ static void update_count_down(GtkRigCtrl * ctrl, gdouble t)
gchar *aoslos;

/* select AOS or LOS time depending on target elevation */
if (ctrl->target->el < 0.0)
if (ctrl->target->el < ctrl->conf->aos_el)
{
targettime = ctrl->target->aos;
aoslos = g_strdup_printf(_("AOS in"));
Expand Down Expand Up @@ -323,13 +324,15 @@ void gtk_rig_ctrl_update(GtkRigCtrl * ctrl, gdouble t)
if (ctrl->target->aos > ctrl->pass->aos)
{
free_pass(ctrl->pass);
ctrl->pass = get_next_pass(ctrl->target, ctrl->qth, 3.0);
ctrl->pass = get_next_pass_el(ctrl->target, ctrl->qth, 3.0,
ctrl->conf->aos_el);
}
}
else
{
/* we don't have any current pass; store the current one */
ctrl->pass = get_next_pass(ctrl->target, ctrl->qth, 3.0);
ctrl->pass = get_next_pass_el(ctrl->target, ctrl->qth, 3.0,
ctrl->conf->aos_el);
}
}

Expand Down Expand Up @@ -394,6 +397,12 @@ void gtk_rig_ctrl_select_sat(GtkRigCtrl * ctrl, gint catnum)
sat_t *sat;
int i, n;

/* This is called indirectly by update_autotrack, when a satellite goes
below the horizon. So we need to call check_aos_los here, to give it a
chance to signal LOS, otherwise it will be missed, as the current sat
will have changed on the next call. */
check_aos_los(ctrl);

/* find index in satellite list */
n = g_slist_length(ctrl->sats);
for (i = 0; i < n; i++)
Expand Down Expand Up @@ -667,7 +676,8 @@ static void sat_selected_cb(GtkComboBox * satsel, gpointer data)
/* update next pass */
if (ctrl->pass != NULL)
free_pass(ctrl->pass);
ctrl->pass = get_next_pass(ctrl->target, ctrl->qth, 3.0);
ctrl->pass = get_next_pass_el(ctrl->target, ctrl->qth, 3.0,
ctrl->conf->aos_el);

/* read transponders for new target */
load_trsp_list(ctrl);
Expand Down Expand Up @@ -2370,9 +2380,12 @@ static gboolean check_aos_los(GtkRigCtrl * ctrl)
adjusting for doppler, which we may not want to do for some demodulators */
if (ctrl->engaged)
{
if (ctrl->prev_ele < 0.0 && ctrl->target->el >= 0.0)
if (ctrl->prev_ele < ctrl->conf->aos_el
&& ctrl->target->el >= ctrl->conf->aos_el)
{
/* AOS has occurred */
if (ctrl->conf->signal_aos && ctrl->conf->aos_wav)
audio_play_uri(ctrl->conf->aos_wav);
if (ctrl->conf->signal_aos && ctrl->conf->aos_command)
{
retcode &= send_rigctld_commands(ctrl, ctrl->sock,
Expand All @@ -2389,9 +2402,12 @@ static gboolean check_aos_los(GtkRigCtrl * ctrl)
}
}
}
else if (ctrl->prev_ele >= 0.0 && ctrl->target->el < 0.0)
else if (ctrl->prev_ele >= ctrl->conf->los_el
&& ctrl->target->el < ctrl->conf->los_el)
{
/* LOS has occurred */
if (ctrl->conf->signal_los && ctrl->conf->los_wav)
audio_play_uri(ctrl->conf->los_wav);
if (ctrl->conf->signal_los && ctrl->conf->los_command)
{
retcode &= send_rigctld_commands(ctrl, ctrl->sock,
Expand Down Expand Up @@ -3010,8 +3026,12 @@ GtkWidget *gtk_rig_ctrl_new(GtkSatModule * module)
if (rigctrl->target != NULL)
{
/* get next pass for target satellite */
GTK_RIG_CTRL(widget)->pass = get_next_pass(rigctrl->target,
rigctrl->qth, 3.0);
GTK_RIG_CTRL(widget)->pass = get_next_pass_el(rigctrl->target,
rigctrl->qth,
3.0,
rigctrl->conf
? rigctrl->conf->aos_el
: 0.0);
}

/* create contents */
Expand Down
44 changes: 40 additions & 4 deletions src/gtk-sat-module.c
Expand Up @@ -80,12 +80,28 @@ static void update_autotrack(GtkSatModule * module)
guint i, n;
double next_aos;
gint next_sat;
double aos_el;
double los_el;
gdouble maxdt;

/* Get AOS/LOS elevation for rig */
aos_el = 0.0;
los_el = 0.0;
if (module->rigctrl != NULL)
{
GtkRigCtrl *ctrl = GTK_RIG_CTRL(module->rigctrl);
if ((ctrl != NULL) && (ctrl->conf != NULL))
{
aos_el = ctrl->conf->aos_el;
los_el = ctrl->conf->los_el;
}
}

if (module->target > 0)
sat = g_hash_table_lookup(module->satellites, &module->target);

/* do nothing if current target is still above horizon */
if (sat != NULL && sat->el > 0.0)
if (sat != NULL && sat->el > los_el)
return;

/* set target to satellite with next AOS */
Expand All @@ -98,13 +114,15 @@ static void update_autotrack(GtkSatModule * module)
next_aos = module->tmgCdnum + 10.f; /* hope there is AOS within 10 days */
next_sat = module->target;

maxdt = (gdouble) sat_cfg_get_int(SAT_CFG_INT_PRED_LOOK_AHEAD);

i = 0;
while (i++ < n)
{
sat = (sat_t *) iter->data;

/* if sat is above horizon, select it and we are done */
if (sat->el > 0.0)
if (sat->el > aos_el)
{
next_sat = sat->tle.catnr;
break;
Expand All @@ -113,8 +131,26 @@ static void update_autotrack(GtkSatModule * module)
/* we have a candidate if AOS is in the future */
if (sat->aos > module->tmgCdnum && sat->aos < next_aos)
{
next_aos = sat->aos;
next_sat = sat->tle.catnr;
/* sat->aos is at the horizon, not rigs desired elevation for AOS,
so we calculate when the next pass at the desired elevation is */
if (aos_el != 0.0)
{
pass_t *pass;

/* Should we avoid recalculating this? */
pass = get_next_pass_el(sat, module->qth, maxdt, aos_el);
if ((pass != NULL) && (pass->aos < next_aos))
{
next_aos = pass->aos;
next_sat = sat->tle.catnr;
free_pass (pass);
}
}
else
{
next_aos = sat->aos;
next_sat = sat->tle.catnr;
}
}

iter = iter->next;
Expand Down
6 changes: 6 additions & 0 deletions src/main.c
Expand Up @@ -23,6 +23,9 @@
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#ifdef HAS_LIBGSTREAMER
#include <gst/gst.h>
#endif
#include <signal.h>
#include <stdlib.h>
#ifdef WIN32
Expand Down Expand Up @@ -101,6 +104,9 @@ int main(int argc, char *argv[])
textdomain(PACKAGE);
#endif
gtk_init(&argc, &argv);
#ifdef HAS_LIBGSTREAMER
gst_init(&argc, &argv);
#endif

context = g_option_context_new("");
g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
Expand Down
28 changes: 28 additions & 0 deletions src/predict-tools.c
Expand Up @@ -369,6 +369,33 @@ pass_t *get_next_pass(sat_t * sat, qth_t * qth, gdouble maxdt)
return get_pass(sat, qth, now, maxdt);
}

/**
* \brief Predict the next pass that has a minimum elevation.
* \param sat Pointer to the satellite data.
* \param qth Pointer to the observer data.
* \param maxdt The maximum number of days to look ahead.
* \param min_ele Minimum elevation.
* \return Pointer newly allocated pass_t structure that should be freed
* with free_pass when no longer needed, or NULL if no pass can be
* found.
*
* This function simply wraps the get_pass function using the current time
* as parameter.
*
* \note the data in sat will be corrupt (future) and must be refreshed
* by the caller, if the caller will need it later on (eg. if the caller
* is GtkSatList).
*/
pass_t *get_next_pass_el(sat_t * sat, qth_t * qth, gdouble maxdt, gdouble min_ele)
{
gdouble now;

/* get the current time and call the get_pass function */
now = get_current_daynum();

return get_pass_engine(sat, qth, now, maxdt, min_ele);
}

/**
* \brief Predict upcoming passes starting now
* \param sat Pointer to the satellite data.
Expand Down Expand Up @@ -441,6 +468,7 @@ pass_t *get_pass_no_min_el(sat_t * sat_in, qth_t * qth, gdouble start,
* \param qth Pointer to the location data.
* \param start Starting time.
* \param maxdt The maximum number of days to look ahead (0 for no limit).
* \param min_el Minimum elevation for the pass.
* \return Pointer to a newly allocated pass_t structure or NULL if
* there was an error.
*
Expand Down
1 change: 1 addition & 0 deletions src/predict-tools.h
Expand Up @@ -92,6 +92,7 @@ gdouble find_prev_aos (sat_t *sat, qth_t *qth, gdouble start);

/* next events */
pass_t *get_next_pass (sat_t *sat, qth_t *qth, gdouble maxdt);
pass_t *get_next_pass_el (sat_t *sat, qth_t *qth, gdouble maxdt, gdouble min_el);
GSList *get_next_passes (sat_t *sat, qth_t *qth, gdouble maxdt, guint num);

/* future events */
Expand Down

0 comments on commit d391ce9

Please sign in to comment.