mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-30 09:03:23 -05:00
ce4ef0aa23
- Added custom checks for libraries and pkgconfig modules that test library presence with additional checks for use of headers and functions with given options. Also support correct additional feature library checks using provided flags. - Added custom enable/disable feature macros to simplify their use. - Use custom CFLAGS and LIBS variables for Makefiles to simplify maintenance. - Update many feature checks from platform to function. - Streamline many function checks. - Correctly check gnutls, gcrypt and gpg-error libraries. - Fix chromecast and spotify config and compile on FreeBSD - Added inotify, signalfd and kqueue, and byte swap checks. - Many clarifications of error messages. - Correct json-c checks to properly use supplied CFLAGS. - Correct many quoting inconsistencies - Use __DATE__ in place of BUILDDATE - Use full path for gperf and antlr3 - Remove unnecessary CFLAGS - Added tests for pthread_setname_np parameters - Added tests for clock_gettime and timer_settime - Added tests for time.h - Test if pthread, dl and rt libs are required/available. - Updated checks for libunistring
375 lines
6.9 KiB
C
375 lines
6.9 KiB
C
/*
|
|
* Copyright (C) 2016 Espen Jürgensen <espenjurgensen@gmail.com>
|
|
*
|
|
* This program 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "logger.h"
|
|
#include "outputs.h"
|
|
|
|
extern struct output_definition output_raop;
|
|
extern struct output_definition output_streaming;
|
|
extern struct output_definition output_dummy;
|
|
extern struct output_definition output_fifo;
|
|
#ifdef HAVE_ALSA
|
|
extern struct output_definition output_alsa;
|
|
#endif
|
|
#ifdef HAVE_LIBPULSE
|
|
extern struct output_definition output_pulse;
|
|
#endif
|
|
#ifdef CHROMECAST
|
|
extern struct output_definition output_cast;
|
|
#endif
|
|
|
|
// Must be in sync with enum output_types
|
|
static struct output_definition *outputs[] = {
|
|
&output_raop,
|
|
&output_streaming,
|
|
&output_dummy,
|
|
&output_fifo,
|
|
#ifdef HAVE_ALSA
|
|
&output_alsa,
|
|
#endif
|
|
#ifdef HAVE_LIBPULSE
|
|
&output_pulse,
|
|
#endif
|
|
#ifdef CHROMECAST
|
|
&output_cast,
|
|
#endif
|
|
NULL
|
|
};
|
|
|
|
int
|
|
outputs_device_start(struct output_device *device, output_status_cb cb, uint64_t rtptime)
|
|
{
|
|
if (outputs[device->type]->disabled)
|
|
return -1;
|
|
|
|
if (outputs[device->type]->device_start)
|
|
return outputs[device->type]->device_start(device, cb, rtptime);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
outputs_device_stop(struct output_session *session)
|
|
{
|
|
if (outputs[session->type]->disabled)
|
|
return;
|
|
|
|
if (outputs[session->type]->device_stop)
|
|
outputs[session->type]->device_stop(session);
|
|
}
|
|
|
|
int
|
|
outputs_device_probe(struct output_device *device, output_status_cb cb)
|
|
{
|
|
if (outputs[device->type]->disabled)
|
|
return -1;
|
|
|
|
if (outputs[device->type]->device_probe)
|
|
return outputs[device->type]->device_probe(device, cb);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
outputs_device_free(struct output_device *device)
|
|
{
|
|
if (outputs[device->type]->disabled)
|
|
DPRINTF(E_LOG, L_PLAYER, "BUG! Freeing device from a disabled output?\n");
|
|
|
|
if (outputs[device->type]->device_free_extra)
|
|
outputs[device->type]->device_free_extra(device);
|
|
|
|
if (device->name)
|
|
free(device->name);
|
|
|
|
if (device->v4_address)
|
|
free(device->v4_address);
|
|
|
|
if (device->v6_address)
|
|
free(device->v6_address);
|
|
|
|
if (device->session)
|
|
DPRINTF(E_LOG, L_PLAYER, "BUG! Freeing device with active session?\n");
|
|
|
|
free(device);
|
|
}
|
|
|
|
int
|
|
outputs_device_volume_set(struct output_device *device, output_status_cb cb)
|
|
{
|
|
if (outputs[device->type]->disabled)
|
|
return -1;
|
|
|
|
if (outputs[device->type]->device_volume_set)
|
|
return outputs[device->type]->device_volume_set(device, cb);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
outputs_playback_start(uint64_t next_pkt, struct timespec *ts)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->playback_start)
|
|
outputs[i]->playback_start(next_pkt, ts);
|
|
}
|
|
}
|
|
|
|
void
|
|
outputs_playback_stop(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->playback_stop)
|
|
outputs[i]->playback_stop();
|
|
}
|
|
}
|
|
|
|
void
|
|
outputs_write(uint8_t *buf, uint64_t rtptime)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->write)
|
|
outputs[i]->write(buf, rtptime);
|
|
}
|
|
}
|
|
|
|
int
|
|
outputs_flush(output_status_cb cb, uint64_t rtptime)
|
|
{
|
|
int ret;
|
|
int i;
|
|
|
|
ret = 0;
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->flush)
|
|
ret += outputs[i]->flush(cb, rtptime);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
outputs_status_cb(struct output_session *session, output_status_cb cb)
|
|
{
|
|
if (outputs[session->type]->disabled)
|
|
return;
|
|
|
|
if (outputs[session->type]->status_cb)
|
|
outputs[session->type]->status_cb(session, cb);
|
|
}
|
|
|
|
struct output_metadata *
|
|
outputs_metadata_prepare(int id)
|
|
{
|
|
struct output_metadata *omd;
|
|
struct output_metadata *new;
|
|
void *metadata;
|
|
int i;
|
|
|
|
omd = NULL;
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (!outputs[i]->metadata_prepare)
|
|
continue;
|
|
|
|
metadata = outputs[i]->metadata_prepare(id);
|
|
if (!metadata)
|
|
continue;
|
|
|
|
new = calloc(1, sizeof(struct output_metadata));
|
|
if (!new)
|
|
return omd;
|
|
|
|
if (omd)
|
|
new->next = omd;
|
|
omd = new;
|
|
omd->type = i;
|
|
omd->metadata = metadata;
|
|
}
|
|
|
|
return omd;
|
|
}
|
|
|
|
void
|
|
outputs_metadata_send(struct output_metadata *omd, uint64_t rtptime, uint64_t offset, int startup)
|
|
{
|
|
struct output_metadata *ptr;
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (!outputs[i]->metadata_send)
|
|
continue;
|
|
|
|
// Go through linked list to find appropriate metadata for type
|
|
for (ptr = omd; ptr; ptr = ptr->next)
|
|
if (ptr->type == i)
|
|
break;
|
|
|
|
if (!ptr)
|
|
continue;
|
|
|
|
outputs[i]->metadata_send(ptr->metadata, rtptime, offset, startup);
|
|
}
|
|
}
|
|
|
|
void
|
|
outputs_metadata_purge(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->metadata_purge)
|
|
outputs[i]->metadata_purge();
|
|
}
|
|
}
|
|
|
|
void
|
|
outputs_metadata_prune(uint64_t rtptime)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->metadata_prune)
|
|
outputs[i]->metadata_prune(rtptime);
|
|
}
|
|
}
|
|
|
|
void
|
|
outputs_metadata_free(struct output_metadata *omd)
|
|
{
|
|
struct output_metadata *ptr;
|
|
|
|
if (!omd)
|
|
return;
|
|
|
|
for (ptr = omd; omd; ptr = omd)
|
|
{
|
|
omd = ptr->next;
|
|
free(ptr);
|
|
}
|
|
}
|
|
|
|
int
|
|
outputs_priority(struct output_device *device)
|
|
{
|
|
return outputs[device->type]->priority;
|
|
}
|
|
|
|
const char *
|
|
outputs_name(enum output_types type)
|
|
{
|
|
return outputs[type]->name;
|
|
}
|
|
|
|
int
|
|
outputs_init(void)
|
|
{
|
|
int no_output;
|
|
int ret;
|
|
int i;
|
|
|
|
no_output = 1;
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->type != i)
|
|
{
|
|
DPRINTF(E_FATAL, L_PLAYER, "BUG! Output definitions are misaligned with output enum\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!outputs[i]->init)
|
|
continue;
|
|
|
|
ret = outputs[i]->init();
|
|
if (ret < 0)
|
|
outputs[i]->disabled = 1;
|
|
else
|
|
no_output = 0;
|
|
}
|
|
|
|
if (no_output)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
outputs_deinit(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; outputs[i]; i++)
|
|
{
|
|
if (outputs[i]->disabled)
|
|
continue;
|
|
|
|
if (outputs[i]->deinit)
|
|
outputs[i]->deinit();
|
|
}
|
|
}
|
|
|