From bb7868bd875257f4716ec61cb09d3a4bbbbbfc04 Mon Sep 17 00:00:00 2001 From: Brant Thomsen Date: Mon, 21 Aug 2017 16:20:00 -0600 Subject: AAF Integer Conversion Support Added When using AAF in 16-bit, 24-bit, or 32-bit integer mode, the incoming audio can be 16-bit, 24-bit, or 32-bit integer data. The incoming audio is converted to the desired internal format. Note that the conversion only works correctly if the incoming audio is big- endian, which IEEE 1722-2016 Clause 7.3.5 lists as a requirement for AAF. INI files updated to match IEEE 1722-2016 specification. --- .../map_aaf_audio/openavb_map_aaf_audio.c | 110 +++++++++++++++++---- .../map_aaf_audio/openavb_map_aaf_audio_pub.h | 2 +- .../platform/Linux/intf_alsa/aaf_file_talker.ini | 4 + .../platform/Linux/intf_alsa/aaf_listener.ini | 11 ++- .../platform/Linux/intf_alsa/aaf_listener_auto.ini | 11 ++- .../platform/Linux/intf_alsa/aaf_talker.ini | 10 +- 6 files changed, 116 insertions(+), 32 deletions(-) diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c index b29563d2..ef3b4a91 100755 --- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c +++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c @@ -32,7 +32,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175. /* * MODULE SUMMARY : Implementation for AAF mapping module * - * AAF is defined in IEEE 1722-rev1/D12 (still in draft as of Feb 2015). + * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7. */ #include @@ -141,6 +141,7 @@ typedef struct { aaf_sample_format_t aaf_format; U8 aaf_bit_depth; U32 payloadSize; + U32 payloadSizeMax; U8 aaf_event_field; @@ -273,13 +274,19 @@ static void x_calculateSizes(media_q_t *pMediaQ) // AAF packet size calculations pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels; - pPvtData->payloadSize = pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes; + pPvtData->payloadSize = pPvtData->payloadSizeMax = + pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes; AVB_LOGF_INFO("packet: sampleSz=%d * channels=%d => frameSz=%d * %d => payloadSz=%d", pPubMapInfo->packetSampleSizeBytes, pPubMapInfo->audioChannels, pPubMapInfo->packetFrameSizeBytes, pPubMapInfo->framesPerPacket, pPvtData->payloadSize); + if (pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) { + // Determine the largest size we could receive before adjustments. + pPvtData->payloadSizeMax = 4 * pPubMapInfo->audioChannels * pPubMapInfo->framesPerPacket; + AVB_LOGF_DEBUG("packet: payloadSizeMax=%d", pPvtData->payloadSizeMax); + } // MediaQ item size calculations pPubMapInfo->packingFactor = pPvtData->packingFactor; @@ -378,7 +385,7 @@ U16 openavbMapAVTPAudioMaxDataSizeCB(media_q_t *pMediaQ) } AVB_TRACE_EXIT(AVB_TRACE_MAP); - return pPvtData->payloadSize + TOTAL_HEADER_SIZE; + return pPvtData->payloadSizeMax + TOTAL_HEADER_SIZE; } AVB_TRACE_EXIT(AVB_TRACE_MAP); return 0; @@ -626,8 +633,11 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen) return FALSE; } + aaf_sample_format_t incoming_aaf_format; + U8 incoming_bit_depth; int tmp; bool dataValid = TRUE; + bool dataConversionEnabled = FALSE; U32 timestamp = ntohl(*pHdr++); U32 format_info = ntohl(*pHdr++); @@ -637,18 +647,26 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen) bool streamSparseMode = (pHdrV0[HIDX_AVTP_HIDE7_SP] & SP_M0_BIT) ? TRUE : FALSE; U16 payloadLen = ntohs(*(U16 *)(&pHdrV0[HIDX_STREAM_DATA_LEN16])); - if (payloadLen > dataLen - TOTAL_HEADER_SIZE) { + if (payloadLen > dataLen - TOTAL_HEADER_SIZE) { if (pPvtData->dataValid) AVB_LOGF_ERROR("header data len %d > actual data len %d", payloadLen, dataLen - TOTAL_HEADER_SIZE); dataValid = FALSE; } - if ((tmp = ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) { - if (pPvtData->dataValid) - AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)", - pPvtData->aaf_format, tmp); - dataValid = FALSE; + if ((incoming_aaf_format = (aaf_sample_format_t) ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) { + // Check if we can convert the incoming data. + if (incoming_aaf_format >= AAF_FORMAT_INT_32 && incoming_aaf_format <= AAF_FORMAT_INT_16 && + pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) { + // Integer conversion should be supported. + dataConversionEnabled = TRUE; + } + else { + if (pPvtData->dataValid) + AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)", + pPvtData->aaf_format, incoming_aaf_format); + dataValid = FALSE; + } } if ((tmp = ((format_info >> 20) & 0x0F)) != pPvtData->aaf_rate) { if (pPvtData->dataValid) @@ -662,17 +680,29 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen) pPubMapInfo->audioChannels, tmp); dataValid = FALSE; } - if ((tmp = (format_info & 0xFF)) != pPvtData->aaf_bit_depth) { + if ((incoming_bit_depth = (U8) (format_info & 0xFF)) == 0) { if (pPvtData->dataValid) - AVB_LOGF_ERROR("Listener bit depth (%d) doesn't match received data (%d)", - pPvtData->aaf_bit_depth, tmp); + AVB_LOGF_ERROR("Listener bit depth (%d) not valid", + incoming_bit_depth); dataValid = FALSE; } if ((tmp = ((packet_info >> 16) & 0xFFFF)) != pPvtData->payloadSize) { - if (pPvtData->dataValid) - AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)", - pPvtData->payloadSize, tmp); - dataValid = FALSE; + if (!dataConversionEnabled) { + if (pPvtData->dataValid) + AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)", + pPvtData->payloadSize, tmp); + dataValid = FALSE; + } + else { + int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received + int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want + if (tmp / nInSampleLength != pPvtData->payloadSize / nOutSampleLength) { + if (pPvtData->dataValid) + AVB_LOGF_ERROR("Listener payload samples (%d) doesn't match received data samples (%d)", + pPvtData->payloadSize / nOutSampleLength, tmp / nInSampleLength); + dataValid = FALSE; + } + } } if ((tmp = ((packet_info >> 8) & 0x0F)) != pPvtData->aaf_event_field) { if (pPvtData->dataValid) @@ -724,11 +754,53 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen) } } if (dataValid) { - if (pPubMapInfo->intf_rx_translate_cb) { - pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize); + if (!dataConversionEnabled) { + // Just use the raw incoming data, and ignore the incoming bit_depth. + if (pPubMapInfo->intf_rx_translate_cb) { + pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize); + } + + memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize); + } + else { + static U8 s_audioBuffer[1500]; + U8 *pInData = pPayload; + U8 *pInDataEnd = pPayload + payloadLen; + U8 *pOutData = s_audioBuffer; + int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received + int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want + int i; + if (nInSampleLength < nOutSampleLength) { + // We need to pad the data supplied. + while (pInData < pInDataEnd) { + for (i = 0; i < nInSampleLength; ++i) { + *pOutData++ = *pInData++; + } + for ( ; i < nOutSampleLength; ++i) { + *pOutData++ = 0; // Value specified in Clause 7.3.4. + } + } + } + else { + // We need to truncate the data supplied. + while (pInData < pInDataEnd) { + for (i = 0; i < nOutSampleLength; ++i) { + *pOutData++ = *pInData++; + } + pInData += (nInSampleLength - nOutSampleLength); + } + } + if (pOutData - s_audioBuffer != pPvtData->payloadSize) { + AVB_LOGF_ERROR("Output not expected size (%d instead of %d)", pOutData - s_audioBuffer, pPvtData->payloadSize); + } + + if (pPubMapInfo->intf_rx_translate_cb) { + pPubMapInfo->intf_rx_translate_cb(pMediaQ, s_audioBuffer, pPvtData->payloadSize); + } + + memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, s_audioBuffer, pPvtData->payloadSize); } - memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize); pMediaQItem->dataLen += pPvtData->payloadSize; } diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h index d8f82906..213f3bb6 100755 --- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h +++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h @@ -32,7 +32,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175. /* * HEADER SUMMARY : AVTP Audio Format mapping module public interface * - * AAF is defined in IEEE 1722a (still in draft as of Feb 2015). + * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7. * * map_nv_tx_rate must be set in the .ini file. */ diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini index 18535347..210ae966 100644 --- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini +++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini @@ -127,3 +127,7 @@ intf_fn = openavbIntfWavFileInitialize # intf_nv_file_name: The fully qualified file name. intf_nv_file_name = test.wav + +# AAF is defined to be big-endian. +intf_nv_audio_endian = big + diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini index 3ba10918..c7c799de 100644 --- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini +++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini @@ -115,15 +115,14 @@ intf_fn = openavbIntfAlsaInitialize intf_nv_device_name = default # intf_nv_audio_rate: Valid values that are supported by AAF are: -# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 +# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 intf_nv_audio_rate = 48000 # intf_nv_audio_bit_depth: Valid values that are supported by AAF are: -# 8, 16, 32 +# 16, 24, 32 intf_nv_audio_bit_depth = 32 -# intf_nv_audio_channels: Valid values that are supported by AAF are: -# 1 - 8 +# intf_nv_audio_channels intf_nv_audio_channels = 2 # intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable. @@ -137,3 +136,7 @@ intf_nv_start_threshold_periods = 3 # This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible. # Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used. # intf_nv_period_time = 31250 + +# AAF is defined to be big-endian. +intf_nv_audio_endian = big + diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini index 7c1f48b3..d3d064b1 100644 --- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini +++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini @@ -111,15 +111,14 @@ intf_fn = openavbIntfAlsaInitialize intf_nv_device_name = default # intf_nv_audio_rate: Valid values that are supported by AAF are: -# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 +# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 intf_nv_audio_rate = 48000 # intf_nv_audio_bit_depth: Valid values that are supported by AAF are: -# 8, 16, 32 +# 16, 24, 32 intf_nv_audio_bit_depth = 16 -# intf_nv_audio_channels: Valid values that are supported by AAF are: -# 1 - 8 +# intf_nv_audio_channels intf_nv_audio_channels = 2 # intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable. @@ -133,3 +132,7 @@ intf_nv_start_threshold_periods = 3 # This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible. # Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used. # intf_nv_period_time = 31250 + +# AAF is defined to be big-endian. +intf_nv_audio_endian = big + diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini index 5ff3d2d5..a6a85071 100644 --- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini +++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini @@ -152,17 +152,19 @@ intf_fn = openavbIntfAlsaInitialize intf_nv_device_name = default # intf_nv_audio_rate: Valid values that are supported by AAF are: -# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 +# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000 intf_nv_audio_rate = 48000 # intf_nv_audio_bit_depth: Valid values that are supported by AAF are: -# 8, 16, 32 +# 16, 24, 32 intf_nv_audio_bit_depth = 32 -# intf_nv_audio_channels: Valid values that are supported by AAF are: -# 1 - 8 +# intf_nv_audio_channels intf_nv_audio_channels = 2 # intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable. intf_nv_allow_resampling = 1 +# AAF is defined to be big-endian. +intf_nv_audio_endian = big + -- cgit v1.2.1