mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Improved workaround (v3): adapt processing of mSBC to handle bogus 'all-zero' packets (see #549)
This commit is contained in:
		
							parent
							
								
									540011f1e3
								
							
						
					
					
						commit
						cbea225abd
					
				
					 1 changed files with 111 additions and 38 deletions
				
			
		| 
						 | 
					@ -339,6 +339,116 @@ static void msbc_buffer_append_byte(struct impl *this, uint8_t byte)
 | 
				
			||||||
        ++this->msbc_buffer_pos;
 | 
					        ++this->msbc_buffer_pos;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					   Helper function for easier debugging
 | 
				
			||||||
 | 
					   Caveat: If size_read is not a multiple of 16, then the last bytes
 | 
				
			||||||
 | 
					   will not be printed / logged
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					static void hexdump_to_log(void *log, uint8_t *read_data, int size_read)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int rowsize = 16*3;
 | 
				
			||||||
 | 
						int line_idx = 0;
 | 
				
			||||||
 | 
						char hexline[16*3] = "";
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < size_read; ++i) {
 | 
				
			||||||
 | 
							snprintf(&hexline[line_idx], 4, "%02X ", read_data[i]);
 | 
				
			||||||
 | 
							line_idx += 3;
 | 
				
			||||||
 | 
							if (line_idx == rowsize) {
 | 
				
			||||||
 | 
								spa_log_trace(log, "Processing read data: read_data %02i: %s", i-15, hexline);
 | 
				
			||||||
 | 
								line_idx = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* helper function to detect if a packet consists only of zeros */
 | 
				
			||||||
 | 
					static bool is_zero_packet(uint8_t *data, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for (int i = 0; i < size; ++i) {
 | 
				
			||||||
 | 
							if (data[i] != 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void preprocess_and_decode_msbc_data(void *userdata, uint8_t *read_data, int size_read)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *this = userdata;
 | 
				
			||||||
 | 
						struct port *port = &this->port;
 | 
				
			||||||
 | 
						struct spa_data *datas = port->current_buffer->buf->datas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_log_trace(this->log, "handling mSBC data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* print hexdump of package  */
 | 
				
			||||||
 | 
						bool flag_hexdump_to_log = false;
 | 
				
			||||||
 | 
						if (flag_hexdump_to_log) {
 | 
				
			||||||
 | 
							hexdump_to_log(this->log, read_data, size_read);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check if the packet contains only zeros - if so ignore the packet.
 | 
				
			||||||
 | 
						   This is necessary, because some kernels insert bogus "all-zero" packets
 | 
				
			||||||
 | 
						   into the datastream.
 | 
				
			||||||
 | 
						   See https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/549 */
 | 
				
			||||||
 | 
						if (is_zero_packet(read_data, size_read)) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						for (i = 0; i < size_read; ++i) {
 | 
				
			||||||
 | 
							msbc_buffer_append_byte(this, read_data[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Handle found mSBC packets.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * XXX: if there's no space for the decoded audio in
 | 
				
			||||||
 | 
							 * XXX: the current buffer, we'll drop data.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (this->msbc_buffer_pos == MSBC_ENCODED_SIZE) {
 | 
				
			||||||
 | 
								spa_log_trace(this->log, "Received full mSBC packet, start processing it");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (port->ready_offset + MSBC_DECODED_SIZE <= datas[0].maxsize) {
 | 
				
			||||||
 | 
									int seq, processed;
 | 
				
			||||||
 | 
									size_t written;
 | 
				
			||||||
 | 
									spa_log_trace(this->log,
 | 
				
			||||||
 | 
										"Output buffer has space, processing mSBC packet");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* Check sequence number */
 | 
				
			||||||
 | 
									seq = ((this->msbc_buffer[1] >> 4) & 1) |
 | 
				
			||||||
 | 
									      ((this->msbc_buffer[1] >> 6) & 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									spa_log_trace(this->log, "mSBC packet seq=%u", seq);
 | 
				
			||||||
 | 
									if (!this->msbc_seq_initialized) {
 | 
				
			||||||
 | 
										this->msbc_seq_initialized = true;
 | 
				
			||||||
 | 
										this->msbc_seq = seq;
 | 
				
			||||||
 | 
									} else if (seq != this->msbc_seq) {
 | 
				
			||||||
 | 
										spa_log_info(this->log,
 | 
				
			||||||
 | 
											"missing mSBC packet: %u != %u", seq, this->msbc_seq);
 | 
				
			||||||
 | 
										this->msbc_seq = seq;
 | 
				
			||||||
 | 
										/* TODO: Implement PLC. */
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									this->msbc_seq = (this->msbc_seq + 1) % 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* decode frame */
 | 
				
			||||||
 | 
									processed = sbc_decode(
 | 
				
			||||||
 | 
										&this->msbc, this->msbc_buffer + 2, MSBC_ENCODED_SIZE - 3,
 | 
				
			||||||
 | 
										(uint8_t *)datas[0].data + port->ready_offset, MSBC_DECODED_SIZE,
 | 
				
			||||||
 | 
										&written);
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
									if (processed < 0) {
 | 
				
			||||||
 | 
										spa_log_warn(this->log, "sbc_decode failed: %d", processed);
 | 
				
			||||||
 | 
										/* TODO: manage errors */
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									port->ready_offset += written;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									spa_log_warn(this->log, "Output buffer full, dropping mSBC packet");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int sco_source_cb(void *userdata, uint8_t *read_data, int size_read)
 | 
					static int sco_source_cb(void *userdata, uint8_t *read_data, int size_read)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *this = userdata;
 | 
						struct impl *this = userdata;
 | 
				
			||||||
| 
						 | 
					@ -377,45 +487,8 @@ static int sco_source_cb(void *userdata, uint8_t *read_data, int size_read)
 | 
				
			||||||
	spa_log_debug(this->log, "read socket data %d", size_read);
 | 
						spa_log_debug(this->log, "read socket data %d", size_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->transport->codec == HFP_AUDIO_CODEC_MSBC) {
 | 
						if (this->transport->codec == HFP_AUDIO_CODEC_MSBC) {
 | 
				
			||||||
		int i;
 | 
							preprocess_and_decode_msbc_data(userdata, read_data, size_read);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < size_read; ++i) {
 | 
					 | 
				
			||||||
			msbc_buffer_append_byte(this, read_data[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* Handle found mSBC packets.
 | 
					 | 
				
			||||||
			 *
 | 
					 | 
				
			||||||
			 * XXX: if there's no space for the decoded audio in
 | 
					 | 
				
			||||||
			 * XXX: the current buffer, we'll drop data.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			if (this->msbc_buffer_pos == MSBC_ENCODED_SIZE &&
 | 
					 | 
				
			||||||
			    port->ready_offset + MSBC_DECODED_SIZE <= datas[0].maxsize) {
 | 
					 | 
				
			||||||
				int seq, processed;
 | 
					 | 
				
			||||||
				size_t written;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* Check sequence number */
 | 
					 | 
				
			||||||
				seq = ((this->msbc_buffer[1] >> 4) & 1) | ((this->msbc_buffer[1] >> 6) & 2);
 | 
					 | 
				
			||||||
				if (!this->msbc_seq_initialized) {
 | 
					 | 
				
			||||||
					this->msbc_seq_initialized = true;
 | 
					 | 
				
			||||||
					this->msbc_seq = seq;
 | 
					 | 
				
			||||||
				} else if (seq != this->msbc_seq) {
 | 
					 | 
				
			||||||
					spa_log_info(this->log, "missing mSBC packet: %u != %u", seq, this->msbc_seq);
 | 
					 | 
				
			||||||
					this->msbc_seq = seq;
 | 
					 | 
				
			||||||
					/* TODO: Implement PLC. */
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				this->msbc_seq = (this->msbc_seq + 1) % 4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* decode frame */
 | 
					 | 
				
			||||||
				processed = sbc_decode(&this->msbc, this->msbc_buffer + 2, MSBC_ENCODED_SIZE - 3,
 | 
					 | 
				
			||||||
						       (uint8_t *)datas[0].data + port->ready_offset, MSBC_DECODED_SIZE, &written);
 | 
					 | 
				
			||||||
				if (processed < 0) {
 | 
					 | 
				
			||||||
					spa_log_warn(this->log, "sbc_decode failed: %d", processed);
 | 
					 | 
				
			||||||
					/* TODO: manage errors */
 | 
					 | 
				
			||||||
					continue;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				port->ready_offset += written;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		uint8_t *packet;
 | 
							uint8_t *packet;
 | 
				
			||||||
		packet = (uint8_t *)datas[0].data + port->ready_offset;
 | 
							packet = (uint8_t *)datas[0].data + port->ready_offset;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue