📄 source.c
字号:
if (!success) {
debug_msg("Failed to allocate codec state storage\n");
goto fail_create_states;
}
success = pktbuf_create(&psrc->pktbuf, 8);
if (!success) {
debug_msg("Failed to allocate packet buffer\n");
goto fail_pktbuf;
}
/* List maintenance */
psrc->next = plist->sentinel.next;
psrc->prev = &plist->sentinel;
psrc->next->prev = psrc;
psrc->prev->next = psrc;
plist->nsrcs++;
debug_msg("Created source decode path\n");
source_validate(psrc);
return psrc;
/* Failure fall throughs */
fail_pktbuf:
codec_state_store_destroy(&psrc->codec_states);
fail_create_states:
pb_iterator_destroy(psrc->media, &psrc->media_pos);
fail_create_iterator:
pb_destroy(&psrc->media);
fail_create_media:
pb_destroy(&psrc->channel);
fail_create_channel:
block_free(psrc, sizeof(source));
return NULL;
}
/* All sources need to be reconfigured when anything changes in
* audio path. These include change of device frequency, change of
* the number of channels, etc..
*/
static void
source_reconfigure(source *src,
cc_id_t ccid,
uint8_t codec_pt,
uint16_t units_per_packet,
converter_id_t conv_id,
int render_3d,
uint16_t out_rate,
uint16_t out_channels)
{
uint16_t src_rate, src_channels;
codec_id_t src_cid;
const codec_format_t *src_cf;
codec_id_t cid;
uint32_t samples_per_frame;
source_validate(src);
cid = codec_get_by_payload(codec_pt);
src_cf = codec_get_format(cid);
/* Fix details... */
src->pdbe->enc = codec_pt;
src->pdbe->units_per_packet = units_per_packet;
src->pdbe->channel_coder_id = ccid;
if (src->channel_state != NULL) {
channel_decoder_destroy(&(src->channel_state));
pb_flush(src->channel);
}
channel_decoder_create(src->pdbe->channel_coder_id, &(src->channel_state));
samples_per_frame = codec_get_samples_per_frame(cid);
debug_msg("Reconfiguring source:\n");
debug_msg(" samples per frame = %d\n", samples_per_frame);
debug_msg(" frames per packet = %d\n", units_per_packet);
debug_msg(" audio sample rate = %d\n", src_cf->format.sample_rate);
src->pdbe->sample_rate = src_cf->format.sample_rate;
src->pdbe->inter_pkt_gap = src->pdbe->units_per_packet * (uint16_t)samples_per_frame;
src->pdbe->frame_dur = ts_map32(src_cf->format.sample_rate, samples_per_frame);
/* Set age to zero and flush existing media
* so that repair mechanism does not attempt
* to patch across different block sizes.
*/
src->age = 0;
pb_flush(src->media);
/* Get rate and channels of incoming media so we know
* what we have to change.
*/
src_cid = codec_get_by_payload(src->pdbe->enc);
src_cf = codec_get_format(src_cid);
src_rate = (uint32_t)src_cf->format.sample_rate;
src_channels = (uint16_t)src_cf->format.channels;
if (render_3d) {
assert(out_channels == 2);
/* Rejig 3d renderer if there, else create */
if (src->pdbe->render_3D_data) {
int azi3d, fil3d, len3d;
render_3D_get_parameters(src->pdbe->render_3D_data, &azi3d, &fil3d, &len3d);
render_3D_set_parameters(src->pdbe->render_3D_data, (int)src_rate, azi3d, fil3d, len3d);
} else {
src->pdbe->render_3D_data = render_3D_init((int)src_rate);
}
assert(src->pdbe->render_3D_data);
/* Render 3d is before sample rate/channel conversion, and */
/* output 2 channels. */
src_channels = 2;
} else {
/* Rendering is switched off so destroy info. */
if (src->pdbe->render_3D_data != NULL) {
render_3D_free(&src->pdbe->render_3D_data);
}
}
/* Now destroy converter if it is already there. */
if (src->converter) {
converter_destroy(&src->converter);
}
if (src_rate != out_rate || src_channels != out_channels) {
converter_fmt_t c;
c.src_freq = src_rate;
c.src_channels = src_channels;
c.dst_freq = out_rate;
c.dst_channels = out_channels;
converter_create(conv_id, &c, &src->converter);
}
src->byte_count = 0;
src->bps = 0.0;
source_validate(src);
}
void
source_remove(source_list *plist, source *psrc)
{
source_validate(psrc);
assert(plist);
assert(psrc);
assert(source_get_by_ssrc(plist, psrc->pdbe->ssrc) != NULL);
psrc->next->prev = psrc->prev;
psrc->prev->next = psrc->next;
if (psrc->channel_state) {
channel_decoder_destroy(&psrc->channel_state);
}
if (psrc->converter) {
converter_destroy(&psrc->converter);
}
pb_iterator_destroy(psrc->media, &psrc->media_pos);
pb_destroy(&psrc->channel);
pb_destroy(&psrc->media);
codec_state_store_destroy(&psrc->codec_states);
pktbuf_destroy(&psrc->pktbuf);
plist->nsrcs--;
debug_msg("Destroying source decode path\n");
block_free(psrc, sizeof(source));
assert(source_get_by_ssrc(plist, psrc->pdbe->ssrc) == NULL);
}
/* Source Processing Routines ************************************************/
/* Returns true if fn takes ownership responsibility for data */
static int
source_process_packet (source *src,
u_char *pckt,
uint32_t pckt_len,
uint8_t payload,
timestamp_t playout)
{
channel_data *cd;
channel_unit *cu;
cc_id_t cid;
uint8_t clayers;
source_validate(src);
assert(src != NULL);
assert(pckt != NULL);
/* Need to check:
* (i) if layering is enabled
* (ii) if channel_data exists for this playout point (if pb_iterator_get_at...)
* Then need to:
* (i) create cd if doesn't exist
* (ii) add packet to cd->elem[layer]
* We work out layer number by deducting the base port
* no from the port no this packet came from
* But what if layering on one port?
*/
/* Or we could:
* (i) check if cd exists for this playout point
* (ii) if so, memcmp() to see if this packet already exists (ugh!)
*/
cid = channel_coder_get_by_payload(payload);
clayers = channel_coder_get_layers(cid);
if (clayers > 1) {
struct s_pb_iterator *pi;
uint8_t i;
uint32_t clen;
int dup;
timestamp_t lplayout;
pb_iterator_create(src->channel, &pi);
while(pb_iterator_advance(pi)) {
pb_iterator_get_at(pi, (u_char**)&cd, &clen, &lplayout);
/* if lplayout==playout there is already
channel_data for this playout point */
if (!ts_eq(playout, lplayout)) {
continue;
}
pb_iterator_detach_at(pi, (u_char**)&cd, &clen, &lplayout);
assert(cd->nelem >= 1);
/* if this channel_data is full, this new packet must *
* be a duplicate, so we don't need to check */
if (cd->nelem >= clayers) {
debug_msg("source_process_packet failed - duplicate layer\n");
src->pdbe->duplicates++;
pb_iterator_destroy(src->channel, &pi);
goto done;
}
cu = (channel_unit*)block_alloc(sizeof(channel_unit));
cu->data = pckt;
cu->data_len = pckt_len;
cu->pt = payload;
dup = 0;
/* compare existing channel_units to this one */
for (i=0; i<cd->nelem; i++) {
if(cu->data_len!=cd->elem[i]->data_len) break;
/* This memcmp arbitrarily only checks
* 20 bytes, otherwise it takes too
* long */
if (memcmp(cu->data, cd->elem[i]->data, 20) == 0) {
dup=1;
}
}
/* duplicate, so stick the channel_data back on *
* the playout buffer and swiftly depart */
if (dup) {
debug_msg("source_process_packet failed - duplicate layer\n");
src->pdbe->duplicates++;
/* destroy temporary channel_unit */
block_free(cu->data, cu->data_len);
cu->data_len = 0;
block_free(cu, sizeof(channel_unit));
pb_iterator_destroy(src->channel, &pi);
goto done;
}
/* add this layer if not a duplicate *
* NB: layers are not added in order, and thus *
* have to be reorganised in the layered *
* channel coder */
cd->elem[cd->nelem] = cu;
cd->nelem++;
pb_iterator_destroy(src->channel, &pi);
goto done;
}
pb_iterator_destroy(src->channel, &pi);
}
if (channel_data_create(&cd, 1) == 0) {
return FALSE;
}
cu = cd->elem[0];
cu->data = pckt;
cu->data_len = pckt_len;
cu->pt = payload;
src->age++;
done:
if (pb_add(src->channel, (u_char*)cd, sizeof(channel_data), playout) == FALSE) {
src->pdbe->duplicates++;
channel_data_destroy(&cd, sizeof(channel_data));
}
source_validate(src);
return TRUE;
}
#ifdef SOURCE_LOG_PLAYOUT
static FILE *psf; /* Playout stats file */
static uint32_t t0;
static void
source_close_log(void)
{
if (psf) {
fclose(psf);
psf = NULL;
}
}
static void
source_playout_log(source *src, uint32_t ts, timestamp_t now)
{
source_validate(src);
if (psf == NULL) {
psf = fopen("playout.log", "w");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -