1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
#ifdef WITH_TRANSCODING
#include "audio_player.h"
#include "call.h"
#include "media_player.h"
#include "mix_buffer.h"
#include "codec.h"
struct audio_player {
struct media_player *mp;
struct mix_buffer mb;
int64_t last_run;
unsigned int ptime_us;
unsigned int ptime; // in samples
unsigned long long pts;
};
// call is locked in R and mp is locked
static bool audio_player_run(struct media_player *mp) {
if (!mp || !mp->media)
return false;
struct audio_player *ap = mp->media->audio_player;
if (!ap || !ap->ptime_us)
return false;
ap->last_run = rtpe_now; // equals mp->next_run
unsigned int size;
void *buf = mix_buffer_read_fast(&ap->mb, ap->ptime, &size);
if (!buf) {
if (!size) {
// error or not active: just reschedule
mp->next_run += ap->ptime_us;
timerthread_obj_schedule_abs(&mp->tt_obj, mp->next_run);
return false;
}
buf = g_alloca(size);
mix_buffer_read_slow(&ap->mb, buf, ap->ptime);
}
media_player_add_packet(mp, buf, size, ap->ptime_us, ap->pts);
ap->pts += ap->ptime;
return false;
}
// call locked in W
bool audio_player_setup(struct call_media *m, const rtp_payload_type *dst_pt,
unsigned int size_ms, unsigned int delay_ms, str_case_value_ht codec_set)
{
if (!dst_pt)
return false;
unsigned int bufsize_ms = size_ms;
if (!bufsize_ms)
bufsize_ms = rtpe_config.audio_buffer_length;
if (!bufsize_ms)
return false;
unsigned int clockrate = fraction_mult(dst_pt->clock_rate, &dst_pt->codec_def->default_clockrate_fact);
unsigned int ptime_ms = m->ptime;
if (!ptime_ms)
ptime_ms = 20;
unsigned int ptime_us = ptime_ms * 1000;
unsigned int ptime_smp = ptime_ms * clockrate / 1000; // in samples
// TODO: shortcut this to avoid the detour of avframe -> avpacket -> avframe (all in s16)
rtp_payload_type src_pt = {
.payload_type = -1,
.encoding = STR_CONST("X-L16"), // XXX support flp
.channels = dst_pt->channels,
.clock_rate = clockrate,
.ptime = ptime_ms,
};
struct audio_player *ap;
struct media_player *mp = NULL;
// check if objects exists and parameters are still the same
if ((ap = m->audio_player) && (mp = ap->mp)) {
if (!media_player_pt_match(mp, &src_pt, dst_pt))
{ /* do reset below */ }
if (ap->ptime != ptime_smp || ap->ptime_us != ptime_us)
{ /* do reset below */ }
else // everything matched
return true;
ilogs(transcoding, LOG_DEBUG, "Resetting audio player for new parameters");
}
else
ilogs(transcoding, LOG_DEBUG, "Creating new audio player");
// create ap and mp objects, or reset them if needed
if (ap) {
mix_buffer_destroy(&ap->mb);
ZERO(ap->mb);
}
else
ap = m->audio_player = g_new0(__typeof(*m->audio_player), 1);
if (mp)
media_player_stop(mp);
else {
media_player_new(&mp, m->monologue, NULL, NULL);
ap->mp = mp;
}
if (!mp)
goto error;
// set everything up
src_pt.codec_def = codec_find_by_av(AV_CODEC_ID_PCM_S16LE), // XXX shortcut this?
mp->run_func = audio_player_run;
ap->ptime_us = ptime_us;
ap->ptime = ptime_smp;
if (media_player_setup(mp, &src_pt, dst_pt, codec_set))
goto error;
bufsize_ms = MAX(bufsize_ms, ptime_ms * 2); // make sure the buf size is at least 2 frames
mix_buffer_init_active(&ap->mb, AV_SAMPLE_FMT_S16, clockrate, dst_pt->channels, bufsize_ms, delay_ms,
false);
return true;
error:
audio_player_free(m);
return false;
}
void audio_player_activate(struct call_media *m) {
if (!m)
return;
struct audio_player *ap = m->audio_player;
if (!ap)
return;
mix_buffer_activate(&ap->mb);
}
// call locked in W
void audio_player_start(struct call_media *m) {
struct audio_player *ap;
if (!m || !(ap = m->audio_player))
return;
struct media_player *mp = ap->mp;
if (!mp)
return;
media_player_set_media(mp, m);
if (mp->next_run) // already running?
return;
ilogs(transcoding, LOG_DEBUG, "Starting audio player");
ap->last_run = rtpe_now;
mp->next_run = rtpe_now;
mp->next_run += ap->ptime_us;
timerthread_obj_schedule_abs(&mp->tt_obj, mp->next_run);
}
void audio_player_add_frame(struct audio_player *ap, uint32_t ssrc, AVFrame *frame) {
bool ret = mix_buffer_write(&ap->mb, ssrc, frame->extended_data[0], frame->nb_samples);
if (!ret)
ilogs(transcoding, LOG_WARN | LOG_FLAG_LIMIT, "Failed to add samples to mix buffer");
av_frame_free(&frame);
}
void audio_player_stop(struct call_media *m) {
struct audio_player *ap = m->audio_player;
if (!ap)
return;
ilogs(transcoding, LOG_DEBUG, "Stopping audio player");
media_player_stop(ap->mp);
media_player_put(&ap->mp);
}
bool audio_player_is_active(struct call_media *m) {
if (!m->audio_player)
return false;
if (!m->audio_player->mp)
return false;
if (!m->audio_player->mp->next_run)
return false;
return true;
}
bool audio_player_pt_match(struct call_media *m, const rtp_payload_type *pt) {
return rtp_payload_type_eq_exact(&m->audio_player->mp->coder.handler->dest_pt, pt);
}
void audio_player_free(struct call_media *m) {
struct audio_player *ap = m->audio_player;
if (!ap)
return;
mix_buffer_destroy(&ap->mb);
media_player_put(&ap->mp);
g_free(ap);
m->audio_player = NULL;
}
#endif
|