| 1649 | } |
| 1650 | |
| 1651 | void audioBroadcastThread(udp::socket &sock) { |
| 1652 | auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown); |
| 1653 | auto packets = mail::man->queue<audio::packet_t>(mail::audio_packets); |
| 1654 | |
| 1655 | audio_packet_t audio_packet; |
| 1656 | fec::rs_t rs {reed_solomon_new(RTPA_DATA_SHARDS, RTPA_FEC_SHARDS)}; |
| 1657 | crypto::aes_t iv(16); |
| 1658 | |
| 1659 | // For unknown reasons, the RS parity matrix computed by our RS implementation |
| 1660 | // doesn't match the one Nvidia uses for audio data. I'm not exactly sure why, |
| 1661 | // but we can simply replace it with the matrix generated by OpenFEC which |
| 1662 | // works correctly. This is possible because the data and FEC shard count is |
| 1663 | // constant and known in advance. |
| 1664 | const unsigned char parity[] = {0x77, 0x40, 0x38, 0x0e, 0xc7, 0xa7, 0x0d, 0x6c}; |
| 1665 | memcpy(rs.get()->p, parity, sizeof(parity)); |
| 1666 | |
| 1667 | audio_packet.rtp.header = 0x80; |
| 1668 | audio_packet.rtp.packetType = 97; |
| 1669 | audio_packet.rtp.ssrc = 0; |
| 1670 | |
| 1671 | // Audio traffic is sent on this thread |
| 1672 | platf::adjust_thread_priority(platf::thread_priority_e::high); |
| 1673 | |
| 1674 | while (auto packet = packets->pop()) { |
| 1675 | if (shutdown_event->peek()) { |
| 1676 | break; |
| 1677 | } |
| 1678 | |
| 1679 | TUPLE_2D_REF(channel_data, packet_data, *packet); |
| 1680 | auto session = (session_t *) channel_data; |
| 1681 | |
| 1682 | auto sequenceNumber = session->audio.sequenceNumber; |
| 1683 | auto timestamp = session->audio.timestamp; |
| 1684 | |
| 1685 | *(std::uint32_t *) iv.data() = util::endian::big<std::uint32_t>(session->audio.avRiKeyId + sequenceNumber); |
| 1686 | |
| 1687 | auto &shards_p = session->audio.shards_p; |
| 1688 | |
| 1689 | auto bytes = encode_audio(session->config.encryptionFlagsEnabled & SS_ENC_AUDIO, packet_data, shards_p[sequenceNumber % RTPA_DATA_SHARDS], iv, session->audio.cipher); |
| 1690 | if (bytes < 0) { |
| 1691 | BOOST_LOG(error) << "Couldn't encode audio packet"sv; |
| 1692 | break; |
| 1693 | } |
| 1694 | |
| 1695 | BOOST_LOG(verbose) << "Audio [seq "sv << sequenceNumber << ", pts "sv << timestamp << "] :: send..."sv; |
| 1696 | |
| 1697 | audio_packet.rtp.sequenceNumber = util::endian::big(sequenceNumber); |
| 1698 | audio_packet.rtp.timestamp = util::endian::big(timestamp); |
| 1699 | |
| 1700 | session->audio.sequenceNumber++; |
| 1701 | session->audio.timestamp += session->config.audio.packetDuration; |
| 1702 | |
| 1703 | auto peer_address = session->audio.peer.address(); |
| 1704 | try { |
| 1705 | auto send_info = platf::send_info_t { |
| 1706 | (const char *) &audio_packet, |
| 1707 | sizeof(audio_packet), |
| 1708 | (const char *) shards_p[sequenceNumber % RTPA_DATA_SHARDS], |
nothing calls this directly
no test coverage detected