Suppress source radio playback only while viewing audible streams
This commit is contained in:
1 parent
d14f9233ed
commit
db7264e271
3 files changed
+57
-9
No files matched your search
@@ -1173,7 +1173,7 @@ void radio_audio_on_frame(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
|||||||
if (!fin && (!opus || len <= 0)) return;
|
if (!fin && (!opus || len <= 0)) return;
|
||||||
|
|
||||||
uint64_t now = get_time_tb();
|
uint64_t now = get_time_tb();
|
||||||
int muted = radio_member_muted(inst, group_id, src_node_id);
|
int muted = radio_member_silenced(inst, group_id, src_node_id);
|
||||||
pthread_mutex_lock(&g_mtx);
|
pthread_mutex_lock(&g_mtx);
|
||||||
if (g_active && group_id == g_group_id) {
|
if (g_active && group_id == g_group_id) {
|
||||||
if (len > 0) { g_last_rx_tb = now; g_last_rx_node = src_node_id; } /* busy-сигнал: чужой аудио-кадр */
|
if (len > 0) { g_last_rx_tb = now; g_last_rx_node = src_node_id; } /* busy-сигнал: чужой аудио-кадр */
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ static void rh_frame_cb(struct UTUN_INSTANCE* inst, uint64_t group_id,
|
|||||||
/* активный канал: первый кадр фиксирует group_id (узел слушает один канал) */
|
/* активный канал: первый кадр фиксирует group_id (узел слушает один канал) */
|
||||||
if (rh->group_id == 0) rh->group_id = group_id;
|
if (rh->group_id == 0) rh->group_id = group_id;
|
||||||
if (group_id != rh->group_id) return;
|
if (group_id != rh->group_id) return;
|
||||||
if (radio_member_muted(inst, group_id, src_node_id)) {
|
if (radio_member_silenced(inst, group_id, src_node_id)) {
|
||||||
if (seq == 0) DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "%s: muted burst grp=%016llx src=%016llx stream=%u",
|
if (seq == 0) DEBUG_DEBUG(DEBUG_CATEGORY_RADIO, "%s: muted burst grp=%016llx src=%016llx stream=%u",
|
||||||
RH_ID, (unsigned long long)group_id, (unsigned long long)src_node_id, stream_id);
|
RH_ID, (unsigned long long)group_id, (unsigned long long)src_node_id, stream_id);
|
||||||
return;
|
return;
|
||||||
|
|||||||
+55
-7
@@ -11,6 +11,7 @@
|
|||||||
#include "../utun_instance.h"
|
#include "../utun_instance.h"
|
||||||
#include "../chat/chat_core.h"
|
#include "../chat/chat_core.h"
|
||||||
#include "../chat/chat_event.h"
|
#include "../chat/chat_event.h"
|
||||||
|
#include "../radio/radio.h"
|
||||||
#include "stream_member.h"
|
#include "stream_member.h"
|
||||||
#include "stream_source.h"
|
#include "stream_source.h"
|
||||||
#include "stream_priv.h"
|
#include "stream_priv.h"
|
||||||
@@ -39,6 +40,7 @@ struct stream_session {
|
|||||||
unsigned owners, relay_owners, holds;
|
unsigned owners, relay_owners, holds;
|
||||||
int anchored, decoded, closing, invalidated, finished, end_delivered, reason;
|
int anchored, decoded, closing, invalidated, finished, end_delivered, reason;
|
||||||
int restarting, restart_gap, notify_close;
|
int restarting, restart_gap, notify_close;
|
||||||
|
int audio_enabled, radio_muted;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct STREAM_HANDLE {
|
struct STREAM_HANDLE {
|
||||||
@@ -193,6 +195,25 @@ static struct stream_session *session_find(struct stream_service *service, uint6
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int stream_radio_muted(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id) {
|
||||||
|
struct stream_session *s = inst && inst->stream ? session_find(inst->stream, group_id, source_id) : NULL;
|
||||||
|
return s && s->radio_muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Курсор означает просмотр. Raw readers, publisher и relay не отключают рацию. */
|
||||||
|
static void session_radio_update(struct stream_session *s) {
|
||||||
|
int muted = 0;
|
||||||
|
if (!s->closing && !s->invalidated && !s->finished && !s->source && s->audio_enabled)
|
||||||
|
for (struct STREAM_HANDLE *h = s->service->handles; h; h = h->next)
|
||||||
|
if (h->session == s && h->media_cursor && !h->relay && !h->publisher) { muted = 1; break; }
|
||||||
|
if (muted == s->radio_muted) return;
|
||||||
|
s->radio_muted = muted;
|
||||||
|
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "stream viewer mute group=%llx source=%llx epoch=%llx muted=%d audio=%d",
|
||||||
|
(unsigned long long)s->descriptor.group_id, (unsigned long long)s->descriptor.source_node_id,
|
||||||
|
(unsigned long long)s->descriptor.source_epoch, muted, s->audio_enabled);
|
||||||
|
radio_refresh_member_mute(s->service->inst, s->descriptor.group_id, s->descriptor.source_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Две опции заменяются одной подписанной записью; список отражает экземпляры, не отдельные handles. */
|
/* Две опции заменяются одной подписанной записью; список отражает экземпляры, не отдельные handles. */
|
||||||
static int service_publish_options(struct stream_service *service, struct TOPO_GROUP *group) {
|
static int service_publish_options(struct stream_service *service, struct TOPO_GROUP *group) {
|
||||||
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream options group missing"); return STREAM_ERR_STATE; }
|
if (!group) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream options group missing"); return STREAM_ERR_STATE; }
|
||||||
@@ -212,7 +233,7 @@ static int service_publish_options(struct stream_service *service, struct TOPO_G
|
|||||||
state.subscriptions[at] = state.subscriptions[at - 1]; at--;
|
state.subscriptions[at] = state.subscriptions[at - 1]; at--;
|
||||||
}
|
}
|
||||||
state.subscriptions[at] = entry;
|
state.subscriptions[at] = entry;
|
||||||
if (s->source && !s->finished) { state.source = s->descriptor; state.published = 1; }
|
if (s->source && !s->finished) { state.source = s->descriptor; state.published = 1; state.audio_enabled = s->audio_enabled; }
|
||||||
}
|
}
|
||||||
char source[MS_USERINFO_MAX + 1], subscriptions[MS_USERINFO_MAX + 1];
|
char source[MS_USERINFO_MAX + 1], subscriptions[MS_USERINFO_MAX + 1];
|
||||||
int result = stream_member_format(&state, source, subscriptions);
|
int result = stream_member_format(&state, source, subscriptions);
|
||||||
@@ -263,6 +284,7 @@ static void session_close(struct stream_session *s, int reason, int update_profi
|
|||||||
if (s->closing) return;
|
if (s->closing) return;
|
||||||
s->notify_close = notify && s->owners > s->relay_owners;
|
s->notify_close = notify && s->owners > s->relay_owners;
|
||||||
s->closing = 1; s->reason = reason; s->owners = 0;
|
s->closing = 1; s->reason = reason; s->owners = 0;
|
||||||
|
session_radio_update(s);
|
||||||
stream_optimizer_destroy(s->optimizer); s->optimizer = NULL;
|
stream_optimizer_destroy(s->optimizer); s->optimizer = NULL;
|
||||||
stream_network_cancel(s->service->network, &s->descriptor);
|
stream_network_cancel(s->service->network, &s->descriptor);
|
||||||
for (struct STREAM_HANDLE *h = s->service->handles; h; h = h->next)
|
for (struct STREAM_HANDLE *h = s->service->handles; h; h = h->next)
|
||||||
@@ -501,6 +523,8 @@ static void member_changed(uint64_t node_id, const char *tags, const char *chann
|
|||||||
|| state.source.block_size != s->descriptor.block_size)))) {
|
|| state.source.block_size != s->descriptor.block_size)))) {
|
||||||
s->invalidated = 1; s->reason = STREAM_CLOSE_SOURCE_CHANGED;
|
s->invalidated = 1; s->reason = STREAM_CLOSE_SOURCE_CHANGED;
|
||||||
}
|
}
|
||||||
|
if (!own && result == STREAM_OK) s->audio_enabled = state.published && state.audio_enabled;
|
||||||
|
session_radio_update(s);
|
||||||
}
|
}
|
||||||
if (!changed || service->reconcile) return;
|
if (!changed || service->reconcile) return;
|
||||||
service->reconcile = uasync_call_soon(service->inst->ua, service, service_reconcile);
|
service->reconcile = uasync_call_soon(service->inst->ua, service, service_reconcile);
|
||||||
@@ -594,7 +618,7 @@ void stream_set_event_callback(struct UTUN_INSTANCE *inst, stream_event_fn callb
|
|||||||
|
|
||||||
/* Подготовить все ресурсы до публикации member-опций; rollback не оставляет видимую подписку. */
|
/* Подготовить все ресурсы до публикации member-опций; rollback не оставляет видимую подписку. */
|
||||||
static int session_open(struct UTUN_INSTANCE *inst, const struct stream_descriptor *d, const uint8_t key[32], int publisher, int automatic,
|
static int session_open(struct UTUN_INSTANCE *inst, const struct stream_descriptor *d, const uint8_t key[32], int publisher, int automatic,
|
||||||
int relay,
|
int relay, int audio_enabled,
|
||||||
struct STREAM_HANDLE **out) {
|
struct STREAM_HANDLE **out) {
|
||||||
struct stream_service *service = inst->stream;
|
struct stream_service *service = inst->stream;
|
||||||
struct stream_session *s = session_find(service, d->group_id, d->source_node_id);
|
struct stream_session *s = session_find(service, d->group_id, d->source_node_id);
|
||||||
@@ -609,6 +633,7 @@ static int session_open(struct UTUN_INSTANCE *inst, const struct stream_descript
|
|||||||
s = u_calloc(1, sizeof(*s));
|
s = u_calloc(1, sizeof(*s));
|
||||||
if (!s) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream session allocation failed"); u_free(h); return STREAM_ERR_MEMORY; }
|
if (!s) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream session allocation failed"); u_free(h); return STREAM_ERR_MEMORY; }
|
||||||
s->service = service; s->descriptor = *d; memcpy(s->public_key, key, 32);
|
s->service = service; s->descriptor = *d; memcpy(s->public_key, key, 32);
|
||||||
|
s->audio_enabled = audio_enabled;
|
||||||
s->output = u_malloc((uint32_t)stream_input_size(d));
|
s->output = u_malloc((uint32_t)stream_input_size(d));
|
||||||
s->metrics = u_calloc(d->n, sizeof(*s->metrics));
|
s->metrics = u_calloc(d->n, sizeof(*s->metrics));
|
||||||
int result = s->output && s->metrics ? STREAM_OK : STREAM_ERR_MEMORY;
|
int result = s->output && s->metrics ? STREAM_OK : STREAM_ERR_MEMORY;
|
||||||
@@ -688,14 +713,14 @@ int stream_publish_open(struct UTUN_INSTANCE *inst, uint64_t group_id, const str
|
|||||||
struct stream_session *previous = session_find(inst->stream, group_id, inst->node_id);
|
struct stream_session *previous = session_find(inst->stream, group_id, inst->node_id);
|
||||||
if (previous && previous->source && previous->end_valid)
|
if (previous && previous->source && previous->end_valid)
|
||||||
session_close(previous, STREAM_CLOSE_SOURCE_CHANGED, 0, 1);
|
session_close(previous, STREAM_CLOSE_SOURCE_CHANGED, 0, 1);
|
||||||
return session_open(inst, &d, inst->my_ed25519_pubkey, 1, 0, 0, out);
|
return session_open(inst, &d, inst->my_ed25519_pubkey, 1, 0, 0, 0, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, int automatic, struct STREAM_HANDLE **out) {
|
static int subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, int automatic, struct STREAM_HANDLE **out) {
|
||||||
int result = stream_open_check(inst, group_id, out);
|
int result = stream_open_check(inst, group_id, out);
|
||||||
if (result != STREAM_OK) return result;
|
if (result != STREAM_OK) return result;
|
||||||
struct stream_session *s = session_find(inst->stream, group_id, source_id);
|
struct stream_session *s = session_find(inst->stream, group_id, source_id);
|
||||||
if (s) return session_open(inst, &s->descriptor, s->public_key, 0, automatic, 0, out);
|
if (s) return session_open(inst, &s->descriptor, s->public_key, 0, automatic, 0, s->audio_enabled, out);
|
||||||
struct stream_member_state state; uint8_t key[32];
|
struct stream_member_state state; uint8_t key[32];
|
||||||
result = stream_member_load(inst, group_id, source_id, &state, key);
|
result = stream_member_load(inst, group_id, source_id, &state, key);
|
||||||
if (result != STREAM_OK) return result;
|
if (result != STREAM_OK) return result;
|
||||||
@@ -703,7 +728,7 @@ static int subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_
|
|||||||
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "source not yet published source=%llx", (unsigned long long)source_id);
|
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "source not yet published source=%llx", (unsigned long long)source_id);
|
||||||
return STREAM_WAIT;
|
return STREAM_WAIT;
|
||||||
}
|
}
|
||||||
return session_open(inst, &state.source, key, 0, automatic, 0, out);
|
return session_open(inst, &state.source, key, 0, automatic, 0, state.audio_enabled, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Запрос старой эпохи не может незаметно подписать суперузел на новый запуск. */
|
/* Запрос старой эпохи не может незаметно подписать суперузел на новый запуск. */
|
||||||
@@ -712,7 +737,7 @@ int stream_relay_open(struct UTUN_INSTANCE *inst, const struct stream_descriptor
|
|||||||
if (result != STREAM_OK) return result;
|
if (result != STREAM_OK) return result;
|
||||||
struct stream_session *s = session_find(inst->stream, key->group_id, key->source_node_id);
|
struct stream_session *s = session_find(inst->stream, key->group_id, key->source_node_id);
|
||||||
if (s && s->descriptor.source_epoch == key->source_epoch)
|
if (s && s->descriptor.source_epoch == key->source_epoch)
|
||||||
return session_open(inst, &s->descriptor, s->public_key, 0, 1, 1, out);
|
return session_open(inst, &s->descriptor, s->public_key, 0, 1, 1, s->audio_enabled, out);
|
||||||
struct stream_member_state state; uint8_t public_key[32];
|
struct stream_member_state state; uint8_t public_key[32];
|
||||||
result = stream_member_load(inst, key->group_id, key->source_node_id, &state, public_key);
|
result = stream_member_load(inst, key->group_id, key->source_node_id, &state, public_key);
|
||||||
if (result != STREAM_OK) return result;
|
if (result != STREAM_OK) return result;
|
||||||
@@ -721,7 +746,7 @@ int stream_relay_open(struct UTUN_INSTANCE *inst, const struct stream_descriptor
|
|||||||
(unsigned long long)key->source_node_id, (unsigned long long)key->source_epoch, state.published,
|
(unsigned long long)key->source_node_id, (unsigned long long)key->source_epoch, state.published,
|
||||||
(unsigned long long)state.source.source_epoch); return STREAM_ERR_STATE;
|
(unsigned long long)state.source.source_epoch); return STREAM_ERR_STATE;
|
||||||
}
|
}
|
||||||
return session_open(inst, &state.source, public_key, 0, 1, 1, out);
|
return session_open(inst, &state.source, public_key, 0, 1, 1, state.audio_enabled, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
int stream_subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out) {
|
int stream_subscribe_open(struct UTUN_INSTANCE *inst, uint64_t group_id, uint64_t source_id, struct STREAM_HANDLE **out) {
|
||||||
@@ -758,6 +783,7 @@ void stream_close(struct STREAM_HANDLE *h) {
|
|||||||
}
|
}
|
||||||
struct stream_session *s = h->session;
|
struct stream_session *s = h->session;
|
||||||
if (s) {
|
if (s) {
|
||||||
|
session_radio_update(s);
|
||||||
int was_relay = s->owners == s->relay_owners;
|
int was_relay = s->owners == s->relay_owners;
|
||||||
if ((h->publisher && !s->end_valid) || s->owners == 1) session_close(s, STREAM_CLOSE_STOPPED, 1, !h->relay);
|
if ((h->publisher && !s->end_valid) || s->owners == 1) session_close(s, STREAM_CLOSE_STOPPED, 1, !h->relay);
|
||||||
else {
|
else {
|
||||||
@@ -804,6 +830,7 @@ int stream_media_enable(struct STREAM_HANDLE *h, unsigned tracks) {
|
|||||||
if (tracks && !h->media_cursor) {
|
if (tracks && !h->media_cursor) {
|
||||||
int result = stream_media_cursor_create(&h->media_cursor, s->media, tracks);
|
int result = stream_media_cursor_create(&h->media_cursor, s->media, tracks);
|
||||||
if (result != STREAM_OK) return result;
|
if (result != STREAM_OK) return result;
|
||||||
|
session_radio_update(s);
|
||||||
}
|
}
|
||||||
session_media_schedule(s);
|
session_media_schedule(s);
|
||||||
return STREAM_OK;
|
return STREAM_OK;
|
||||||
@@ -898,6 +925,27 @@ int stream_publish_block(struct STREAM_HANDLE *h, const uint8_t *data, size_t le
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int stream_publish_set_audio_enabled(struct STREAM_HANDLE *h, int enabled) {
|
||||||
|
if (!stream_handle_active(h) || !h->publisher || h->session->finished || (enabled != 0 && enabled != 1)) {
|
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream audio change invalid publisher/state enabled=%d", enabled); return STREAM_ERR_STATE;
|
||||||
|
}
|
||||||
|
struct stream_session *s = h->session;
|
||||||
|
if (s->audio_enabled == enabled) return STREAM_OK;
|
||||||
|
s->holds++;
|
||||||
|
int previous = s->audio_enabled;
|
||||||
|
s->audio_enabled = enabled;
|
||||||
|
int result = service_publish_options(s->service, stream_group(s->service->inst, s->descriptor.group_id));
|
||||||
|
if (result != STREAM_OK || s->closing) {
|
||||||
|
s->audio_enabled = previous;
|
||||||
|
if (result == STREAM_OK) result = STREAM_ERR_STATE;
|
||||||
|
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream audio state publication failed result=%d", result);
|
||||||
|
} else DEBUG_INFO(DEBUG_CATEGORY_STREAM, "stream audio group=%llx epoch=%llx enabled=%d",
|
||||||
|
(unsigned long long)s->descriptor.group_id, (unsigned long long)s->descriptor.source_epoch, enabled);
|
||||||
|
s->holds--;
|
||||||
|
if (s->closing && !s->holds && !s->delivery) session_free(s);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int stream_publish_finish(struct STREAM_HANDLE *h) {
|
int stream_publish_finish(struct STREAM_HANDLE *h) {
|
||||||
if (!stream_handle_active(h) || !h->publisher) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream finish not a publisher"); return STREAM_ERR_STATE; }
|
if (!stream_handle_active(h) || !h->publisher) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream finish not a publisher"); return STREAM_ERR_STATE; }
|
||||||
struct stream_session *s = h->session;
|
struct stream_session *s = h->session;
|
||||||
|
|||||||
Reference in new issue
Block a user