mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-18 15:18:20 +00:00
committed by
Christian Helmuth
parent
c814d13737
commit
72e1147cce
@ -19,6 +19,7 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <os/server.h>
|
#include <os/server.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
|
#include <util/retry.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <audio_out_session/connection.h>
|
#include <audio_out_session/connection.h>
|
||||||
#include <audio_out_session/rpc_object.h>
|
#include <audio_out_session/rpc_object.h>
|
||||||
@ -92,6 +93,9 @@ struct Audio_out::Session_elem : Audio_out::Session_rpc_object,
|
|||||||
|
|
||||||
Session_elem(char const *label, Genode::Signal_context_capability data_cap)
|
Session_elem(char const *label, Genode::Signal_context_capability data_cap)
|
||||||
: Session_rpc_object(data_cap), label(label) { }
|
: Session_rpc_object(data_cap), label(label) { }
|
||||||
|
|
||||||
|
Packet *get_packet(unsigned offset) {
|
||||||
|
return stream()->get(stream()->pos() + offset); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -108,6 +112,11 @@ class Audio_out::Mixer
|
|||||||
Connection _right; /* right output */
|
Connection _right; /* right output */
|
||||||
Connection *_out[MAX_CHANNELS];
|
Connection *_out[MAX_CHANNELS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remix all exception
|
||||||
|
*/
|
||||||
|
struct Remix_all { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A channel contains multiple session components
|
* A channel contains multiple session components
|
||||||
*/
|
*/
|
||||||
@ -115,12 +124,11 @@ class Audio_out::Mixer
|
|||||||
{
|
{
|
||||||
void insert(Session_elem *session) { List<Session_elem>::insert(session); }
|
void insert(Session_elem *session) { List<Session_elem>::insert(session); }
|
||||||
void remove(Session_elem *session) { List<Session_elem>::remove(session); }
|
void remove(Session_elem *session) { List<Session_elem>::remove(session); }
|
||||||
Session_elem* first() { return List<Session_elem>::first(); }
|
|
||||||
|
|
||||||
template <typename FUNC> void for_each_session(FUNC const &func)
|
template <typename FUNC> void for_each_session(FUNC const &func)
|
||||||
{
|
{
|
||||||
for (Session_elem *elem = first(); elem; elem = elem->next())
|
for (Session_elem *elem = List<Session_elem>::first(); elem;
|
||||||
func(*elem);
|
elem = elem->next()) func(*elem);
|
||||||
}
|
}
|
||||||
} _channels[MAX_CHANNELS];
|
} _channels[MAX_CHANNELS];
|
||||||
|
|
||||||
@ -128,7 +136,7 @@ class Audio_out::Mixer
|
|||||||
* Helper method for walking over session in a channel
|
* Helper method for walking over session in a channel
|
||||||
*/
|
*/
|
||||||
template <typename FUNC> void _for_each_channel(FUNC const &func) {
|
template <typename FUNC> void _for_each_channel(FUNC const &func) {
|
||||||
for (int i = 0; i < MAX_CHANNELS; i++) func(&_channels[i]); }
|
for (int i = LEFT; i < MAX_CHANNELS; i++) func(&_channels[i]); }
|
||||||
|
|
||||||
bool _check_active()
|
bool _check_active()
|
||||||
{
|
{
|
||||||
@ -154,10 +162,8 @@ class Audio_out::Mixer
|
|||||||
stream->increment_position();
|
stream->increment_position();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send 'progress' sginal */
|
|
||||||
session->progress_submit();
|
session->progress_submit();
|
||||||
|
|
||||||
/* send 'alloc' signal */
|
|
||||||
if (full) session->alloc_submit();
|
if (full) session->alloc_submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,11 +179,9 @@ class Audio_out::Mixer
|
|||||||
|
|
||||||
void _mix_packet(Packet *out, Packet *in, bool clear)
|
void _mix_packet(Packet *out, Packet *in, bool clear)
|
||||||
{
|
{
|
||||||
/* when clear is set, set input an zero out remainder */
|
|
||||||
if (clear) {
|
if (clear) {
|
||||||
out->content(in->content(), PERIOD);
|
out->content(in->content(), Audio_out::PERIOD);
|
||||||
} else {
|
} else {
|
||||||
/* mix */
|
|
||||||
for_each_index(Audio_out::PERIOD, [&] (int const i) {
|
for_each_index(Audio_out::PERIOD, [&] (int const i) {
|
||||||
out->content()[i] += in->content()[i];
|
out->content()[i] += in->content()[i];
|
||||||
|
|
||||||
@ -185,14 +189,11 @@ class Audio_out::Mixer
|
|||||||
if (out->content()[i] < -1) out->content()[i] = -1;
|
if (out->content()[i] < -1) out->content()[i] = -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* mark packet as processed */
|
|
||||||
in->invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
Packet *_session_packet(Session *session, unsigned offset)
|
/*
|
||||||
{
|
* Mark the packet as processed by invalidating it
|
||||||
Stream *s = session->stream();
|
*/
|
||||||
return s->get(s->pos() + offset);
|
in->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _mix_channel(Channel_number nr, unsigned out_pos, unsigned offset)
|
bool _mix_channel(Channel_number nr, unsigned out_pos, unsigned offset)
|
||||||
@ -205,37 +206,36 @@ class Audio_out::Mixer
|
|||||||
bool mix_all = false;
|
bool mix_all = false;
|
||||||
bool const out_valid = out->valid();
|
bool const out_valid = out->valid();
|
||||||
|
|
||||||
for (Session_elem *session = channel->first();
|
Genode::retry<Remix_all>(
|
||||||
session;
|
[&] () {
|
||||||
session = session->next()) {
|
channel->for_each_session([&] (Session_elem &session) {
|
||||||
|
if (session.stopped()) return;
|
||||||
|
|
||||||
if (session->stopped()) continue;
|
Packet *in = session.get_packet(offset);
|
||||||
|
|
||||||
Packet *in = _session_packet(session, offset);
|
/*
|
||||||
|
* When there already is an out packet, start over and mix
|
||||||
|
* everything.
|
||||||
|
*/
|
||||||
|
if (in->valid() && out_valid && !mix_all) throw Remix_all();
|
||||||
|
|
||||||
/*
|
/* skip if packet has been processed or was already played */
|
||||||
* When there already is an out packet, start over and mix
|
if ((!in->valid() && !mix_all) || in->played()) return;
|
||||||
* everything.
|
|
||||||
*/
|
_mix_packet(out, in, clear);
|
||||||
if (in->valid() && out_valid && !mix_all) {
|
|
||||||
|
if (verbose)
|
||||||
|
PLOG("mix: ch %u in %u -> out %u all %d o: %u",
|
||||||
|
nr, session.stream()->packet_position(in),
|
||||||
|
stream->packet_position(out), mix_all, offset);
|
||||||
|
|
||||||
|
clear = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[&] () {
|
||||||
clear = true;
|
clear = true;
|
||||||
mix_all = true;
|
mix_all = true;
|
||||||
session = channel->first();
|
});
|
||||||
in = _session_packet(session, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip if packet has been processed or was already played */
|
|
||||||
if ((!in->valid() && !mix_all) || in->played()) continue;
|
|
||||||
|
|
||||||
_mix_packet(out, in, clear);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
PLOG("mix: ch %u in %u -> out %u all %d o: %u",
|
|
||||||
nr, session->stream()->packet_position(in),
|
|
||||||
stream->packet_position(out), mix_all, offset);
|
|
||||||
|
|
||||||
clear = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !clear;
|
return !clear;
|
||||||
}
|
}
|
||||||
@ -250,10 +250,11 @@ class Audio_out::Mixer
|
|||||||
* Look for packets that are valid, mix channels in an alternating
|
* Look for packets that are valid, mix channels in an alternating
|
||||||
* way.
|
* way.
|
||||||
*/
|
*/
|
||||||
for_each_index(QUEUE_SIZE, [&] (int const i) {
|
for_each_index(Audio_out::QUEUE_SIZE, [&] (int const i) {
|
||||||
bool mix_one = true;
|
bool mix_one = true;
|
||||||
for (int j = LEFT; j < MAX_CHANNELS; j++)
|
for_each_index(MAX_CHANNELS, [&] (int const j) {
|
||||||
mix_one &= _mix_channel((Channel_number)j, pos[j], i);
|
mix_one = _mix_channel((Channel_number)j, pos[j], i);
|
||||||
|
});
|
||||||
|
|
||||||
if (mix_one) {
|
if (mix_one) {
|
||||||
_out[LEFT]->submit(_out[LEFT]->stream()->get(pos[LEFT] + i));
|
_out[LEFT]->submit(_out[LEFT]->stream()->get(pos[LEFT] + i));
|
||||||
|
Reference in New Issue
Block a user