mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-10-29 05:40:23 -04:00 
			
		
		
		
	bluetooth: Handle fragmented faststream frames
Incoming frames can span multiple packets, add support for this. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/628>
This commit is contained in:
		
							parent
							
								
									697a1a309a
								
							
						
					
					
						commit
						76e01b25f5
					
				
					 1 changed files with 61 additions and 13 deletions
				
			
		|  | @ -39,6 +39,8 @@ | |||
| #define SBC_BITPOOL_DEC_STEP 5 | ||||
| #define SBC_BITPOOL_INC_STEP 1 | ||||
| 
 | ||||
| #define SBC_SYNCWORD    0x9C | ||||
| 
 | ||||
| struct sbc_info { | ||||
|     sbc_t sbc;                           /* Codec data */ | ||||
|     size_t codesize, frame_length;       /* SBC Codesize, frame_length. We simply cache those values here */ | ||||
|  | @ -54,6 +56,11 @@ struct sbc_info { | |||
| 
 | ||||
|     uint8_t nr_blocks; | ||||
|     uint8_t nr_subbands; | ||||
| 
 | ||||
|     /* Size of SBC frame fragment left over from previous decoding iteration */ | ||||
|     size_t frame_fragment_size; | ||||
|     /* Maximum SBC frame size is 512 bytes when SBC compression ratio > 1 */ | ||||
|     uint8_t frame_fragment[512]; | ||||
| }; | ||||
| 
 | ||||
| static bool can_be_supported(bool for_encoding) { | ||||
|  | @ -936,6 +943,9 @@ static int reset(void *codec_info) { | |||
|     struct sbc_info *sbc_info = (struct sbc_info *) codec_info; | ||||
|     int ret; | ||||
| 
 | ||||
|     /* forget last saved frame fragment */ | ||||
|     sbc_info->frame_fragment_size = 0; | ||||
| 
 | ||||
|     ret = sbc_reinit(&sbc_info->sbc, 0); | ||||
|     if (ret != 0) { | ||||
|         pa_log_error("SBC reinitialization failed: %d", ret); | ||||
|  | @ -1279,27 +1289,60 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu | |||
|             .rate = 16000U | ||||
|     }; | ||||
|     uint8_t decode_buffer[4096]; | ||||
|     uint8_t frame_buffer[4096]; | ||||
| 
 | ||||
|     p = input_buffer; | ||||
|     to_decode = input_size; | ||||
| 
 | ||||
|     /* append input buffer to fragment left from previous decode call */ | ||||
|     if (sbc_info->frame_fragment_size) { | ||||
| 
 | ||||
|         if (sbc_info->frame_fragment_size + to_decode > sizeof(frame_buffer)) { | ||||
|             pa_log_debug("FastStream SBC input (saved + incoming) size %lu larger than buffer size %lu, input truncated to fit", | ||||
|                     sbc_info->frame_fragment_size + to_decode, sizeof(frame_buffer)); | ||||
|             to_decode = sizeof(frame_buffer) - sbc_info->frame_fragment_size; | ||||
|         } | ||||
| 
 | ||||
|         memcpy(frame_buffer, sbc_info->frame_fragment, sbc_info->frame_fragment_size); | ||||
|         memcpy(frame_buffer + sbc_info->frame_fragment_size, input_buffer, to_decode); | ||||
| 
 | ||||
|         to_decode += sbc_info->frame_fragment_size; | ||||
|         p = frame_buffer; | ||||
| 
 | ||||
|         /* clear saved fragment */ | ||||
|         sbc_info->frame_fragment_size = 0; | ||||
|     } else | ||||
|         p = input_buffer; | ||||
| 
 | ||||
|     d = output_buffer; | ||||
|     to_write = output_size; | ||||
| 
 | ||||
|     while (PA_LIKELY(to_decode > 0 && to_write > 0)) { | ||||
|         size_t written; | ||||
|         size_t written = 0; | ||||
|         ssize_t decoded; | ||||
| 
 | ||||
|         /* skip to SBC sync word before attempting decode */ | ||||
|         if (*p != SBC_SYNCWORD) { | ||||
|             ++p; | ||||
|             --to_decode; | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         decoded = sbc_decode(&sbc_info->sbc, | ||||
|                              p, to_decode, | ||||
|                              decode_buffer, sizeof(decode_buffer), | ||||
|                              &written); | ||||
| 
 | ||||
|         if (PA_UNLIKELY(decoded <= 0)) { | ||||
|             /* sbc_decode returns -1 if input too short,
 | ||||
|              * break from loop to save this frame fragment for next decode iteration */ | ||||
|             if (decoded == -1) { | ||||
|                 pa_log_debug("FastStream SBC decoding error (%li) input %lu is too short", (long) decoded, to_decode); | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             /* otherwise failed to decode frame, skip to next SBC sync word */ | ||||
|             pa_log_error("FastStream SBC decoding error (%li)", (long) decoded); | ||||
|             decoded = PA_MIN(sbc_info->frame_length, to_decode); | ||||
|             written = PA_MIN(sbc_info->codesize, to_write); | ||||
|             pa_silence_memory(decode_buffer, written, &decoded_sample_spec); | ||||
|             decoded = 1; | ||||
|         } else { | ||||
|             /* Reset codesize and frame_length to values found by decoder */ | ||||
|             sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); | ||||
|  | @ -1325,14 +1368,7 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu | |||
|                 memcpy(d, decode_buffer, written); | ||||
|         } | ||||
| 
 | ||||
|         if ((sbc_info->frame_length & 1) && decoded < to_decode) { | ||||
|             ++decoded; | ||||
|             ++sbc_info->frame_length; | ||||
|         } | ||||
| 
 | ||||
|         pa_assert_fp((size_t) decoded <= to_decode); | ||||
|         pa_assert_fp((size_t) decoded == PA_MIN(sbc_info->frame_length, to_decode)); | ||||
| 
 | ||||
|         pa_assert_fp((size_t) written <= to_write); | ||||
| 
 | ||||
|         p += decoded; | ||||
|  | @ -1342,7 +1378,19 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu | |||
|         to_write -= written; | ||||
|     } | ||||
| 
 | ||||
|     /* XXX eat remainder, may need to fix this if input frames are split across packets */ | ||||
|     if (to_decode) { | ||||
|         if (to_decode > sizeof(sbc_info->frame_fragment)) { | ||||
|             pa_log_debug("FastStream remaining SBC fragment size %lu larger than buffer size %lu, remainder truncated to fit", | ||||
|                     to_decode, sizeof(sbc_info->frame_fragment)); | ||||
|             p += to_decode - sizeof(sbc_info->frame_fragment); | ||||
|             to_decode = sizeof(sbc_info->frame_fragment); | ||||
|         } | ||||
| 
 | ||||
|         pa_log_debug("FastStream saving SBC fragment size %lu for next decoding iteration", to_decode); | ||||
|         memcpy(sbc_info->frame_fragment, p, to_decode); | ||||
|         sbc_info->frame_fragment_size = to_decode; | ||||
|     } | ||||
| 
 | ||||
|     *processed = input_size; | ||||
| 
 | ||||
|     return d - output_buffer; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Igor V. Kovalenko
						Igor V. Kovalenko