Loading system/stack/btm/btm_sco.cc +112 −44 Original line number Diff line number Diff line Loading @@ -204,12 +204,83 @@ void tSCO_CB::Free() { /* Buffer used for reading PCM data from audio server that will be encoded into * mSBC packet. The BTM_SCO_DATA_SIZE_MAX should be set to a number divisible by * BTM_MSBC_CODE_SIZE(240) */ static int16_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; static uint8_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; static uint8_t packet_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; /* The read and write offset for btm_pcm_buf. * They are only used for WBS and the unit is byte. */ static size_t btm_pcm_buf_read_offset = 0; static size_t btm_pcm_buf_write_offset = 0; static bool btm_pcm_buf_write_mirror = false; static bool btm_pcm_buf_read_mirror = false; enum btm_pcm_buf_state { DECODE_BUF_EMPTY, DECODE_BUF_FULL, // Neither empty nor full. DECODE_BUF_PARTIAL, }; void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) { size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - offset; if (bytes_remaining > amount) { offset += amount; return; } mirror = !mirror; offset = amount - bytes_remaining; } btm_pcm_buf_state btm_pcm_buf_status() { if (btm_pcm_buf_read_offset == btm_pcm_buf_write_offset) { if (btm_pcm_buf_read_mirror == btm_pcm_buf_write_mirror) return DECODE_BUF_EMPTY; return DECODE_BUF_FULL; } return DECODE_BUF_PARTIAL; } size_t btm_pcm_buf_data_len() { switch (btm_pcm_buf_status()) { case DECODE_BUF_EMPTY: return 0; case DECODE_BUF_FULL: return BTM_SCO_DATA_SIZE_MAX; case DECODE_BUF_PARTIAL: default: if (btm_pcm_buf_write_offset > btm_pcm_buf_read_offset) return btm_pcm_buf_write_offset - btm_pcm_buf_read_offset; return BTM_SCO_DATA_SIZE_MAX - (btm_pcm_buf_read_offset - btm_pcm_buf_write_offset); }; } size_t btm_pcm_buf_avail_len() { return BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_data_len(); } size_t write_btm_pcm_buf(uint8_t* source, size_t amount) { if (btm_pcm_buf_avail_len() < amount) { return 0; } size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; if (bytes_remaining > amount) { std::copy(source, source + amount, btm_pcm_buf + btm_pcm_buf_write_offset); } else { std::copy(source, source + bytes_remaining, btm_pcm_buf + btm_pcm_buf_write_offset); std::copy(source + bytes_remaining, source + amount, btm_pcm_buf); } incr_btm_pcm_buf_offset(btm_pcm_buf_write_offset, btm_pcm_buf_write_mirror, amount); return amount; } /******************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /******************************************************************************/ Loading Loading @@ -341,6 +412,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { auto rx_data = data.data(); const uint8_t* decoded = nullptr; size_t written = 0, rc = 0; if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { auto status = valid_packet.GetPacketStatusFlag(); Loading Loading @@ -370,24 +442,21 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { /* For Chrome OS, we send the outgoing data after receiving an incoming one. * server, so that we can keep the data read/write rate balanced */ size_t read = 0, avail = 0; size_t read = 0; const uint8_t* encoded = nullptr; if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { while (written) { avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; size_t avail = btm_pcm_buf_avail_len(); if (avail) { size_t to_read = written < avail ? written : avail; read = bluetooth::audio::sco::read( (uint8_t*)btm_pcm_buf + btm_pcm_buf_write_offset, to_read); if (read != to_read) { log::assert_that( btm_pcm_buf_write_offset + read <= BTM_SCO_DATA_SIZE_MAX, "Read more {} data ({}) than available buffer ({}) guarded by " "read", codec, (unsigned long)read, (unsigned long)(BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset)); // Read to the packet_buf first and then copy to the btm_pcm_buf. read = bluetooth::audio::sco::read(packet_buf, to_read); write_btm_pcm_buf(packet_buf, read); if (read != to_read) { log::info( "Requested to read {} bytes of {} data but got {} bytes of PCM " "data from audio server: WriteOffset:{} ReadOffset:{}", Loading @@ -404,25 +473,33 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { log::warn( "Buffer is full when we try to read {} packet from audio server", codec); log::assert_that( btm_pcm_buf_write_offset - btm_pcm_buf_read_offset >= (codec_type == BTM_SCO_CODEC_MSBC ? BTM_MSBC_CODE_SIZE : BTM_LC3_CODE_SIZE), "PCM buffer is full but fails to encode an {} packet. This is " "abnormal and can cause busy loop: WriteOffset:{}, ReadOffset:{}, " "BufferSize:{}", codec, (unsigned long)btm_pcm_buf_write_offset, (unsigned long)btm_pcm_buf_read_offset, (unsigned long)sizeof(btm_pcm_buf)); } btm_pcm_buf_write_offset += read; auto encode = codec_type == BTM_SCO_CODEC_LC3 ? &bluetooth::audio::sco::swb::encode : &bluetooth::audio::sco::wbs::encode; rc = encode(&btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); size_t data_len = btm_pcm_buf_data_len(); if (data_len) { // Copy all data to the packet_buf first and then call encode. size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_read_offset; if (bytes_remaining > data_len) { std::copy(btm_pcm_buf + btm_pcm_buf_read_offset, btm_pcm_buf + btm_pcm_buf_read_offset + data_len, packet_buf); } else { std::copy(btm_pcm_buf + btm_pcm_buf_read_offset, btm_pcm_buf + BTM_SCO_DATA_SIZE_MAX, packet_buf); std::copy(btm_pcm_buf, btm_pcm_buf + data_len - bytes_remaining, packet_buf + bytes_remaining); } rc = encode((int16_t*)packet_buf, data_len); incr_btm_pcm_buf_offset(btm_pcm_buf_read_offset, btm_pcm_buf_read_mirror, rc); if (!rc) log::debug( Loading @@ -430,14 +507,6 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { "WriteOffset:{}", codec, (unsigned long)btm_pcm_buf_read_offset, (unsigned long)btm_pcm_buf_write_offset); /* The offsets should reset some time as the buffer length should always * divisible by 480 and `encode` only returns 480(LC3), 240(MSBC), or 0. */ btm_pcm_buf_read_offset += rc; if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) { btm_pcm_buf_write_offset = 0; btm_pcm_buf_read_offset = 0; } /* Send all of the available SCO packets buffered in the queue */ Loading @@ -455,7 +524,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { } else { while (written) { read = bluetooth::audio::sco::read( (uint8_t*)btm_pcm_buf, btm_pcm_buf, written < BTM_SCO_DATA_SIZE_MAX ? written : BTM_SCO_DATA_SIZE_MAX); if (read == 0) { log::info("Failed to read {} bytes of PCM data from audio server", Loading @@ -470,8 +539,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { * send PCM data directly to SCO. * We don't maintain buffer read/write offset for NB as we send all data * that we read from the audio server. */ auto data = std::vector<uint8_t>((uint8_t*)btm_pcm_buf, (uint8_t*)btm_pcm_buf + read); auto data = std::vector<uint8_t>(btm_pcm_buf, btm_pcm_buf + read); btm_send_sco_packet(std::move(data)); } } Loading Loading
system/stack/btm/btm_sco.cc +112 −44 Original line number Diff line number Diff line Loading @@ -204,12 +204,83 @@ void tSCO_CB::Free() { /* Buffer used for reading PCM data from audio server that will be encoded into * mSBC packet. The BTM_SCO_DATA_SIZE_MAX should be set to a number divisible by * BTM_MSBC_CODE_SIZE(240) */ static int16_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; static uint8_t btm_pcm_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; static uint8_t packet_buf[BTM_SCO_DATA_SIZE_MAX] = {0}; /* The read and write offset for btm_pcm_buf. * They are only used for WBS and the unit is byte. */ static size_t btm_pcm_buf_read_offset = 0; static size_t btm_pcm_buf_write_offset = 0; static bool btm_pcm_buf_write_mirror = false; static bool btm_pcm_buf_read_mirror = false; enum btm_pcm_buf_state { DECODE_BUF_EMPTY, DECODE_BUF_FULL, // Neither empty nor full. DECODE_BUF_PARTIAL, }; void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) { size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - offset; if (bytes_remaining > amount) { offset += amount; return; } mirror = !mirror; offset = amount - bytes_remaining; } btm_pcm_buf_state btm_pcm_buf_status() { if (btm_pcm_buf_read_offset == btm_pcm_buf_write_offset) { if (btm_pcm_buf_read_mirror == btm_pcm_buf_write_mirror) return DECODE_BUF_EMPTY; return DECODE_BUF_FULL; } return DECODE_BUF_PARTIAL; } size_t btm_pcm_buf_data_len() { switch (btm_pcm_buf_status()) { case DECODE_BUF_EMPTY: return 0; case DECODE_BUF_FULL: return BTM_SCO_DATA_SIZE_MAX; case DECODE_BUF_PARTIAL: default: if (btm_pcm_buf_write_offset > btm_pcm_buf_read_offset) return btm_pcm_buf_write_offset - btm_pcm_buf_read_offset; return BTM_SCO_DATA_SIZE_MAX - (btm_pcm_buf_read_offset - btm_pcm_buf_write_offset); }; } size_t btm_pcm_buf_avail_len() { return BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_data_len(); } size_t write_btm_pcm_buf(uint8_t* source, size_t amount) { if (btm_pcm_buf_avail_len() < amount) { return 0; } size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; if (bytes_remaining > amount) { std::copy(source, source + amount, btm_pcm_buf + btm_pcm_buf_write_offset); } else { std::copy(source, source + bytes_remaining, btm_pcm_buf + btm_pcm_buf_write_offset); std::copy(source + bytes_remaining, source + amount, btm_pcm_buf); } incr_btm_pcm_buf_offset(btm_pcm_buf_write_offset, btm_pcm_buf_write_mirror, amount); return amount; } /******************************************************************************/ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /******************************************************************************/ Loading Loading @@ -341,6 +412,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { auto rx_data = data.data(); const uint8_t* decoded = nullptr; size_t written = 0, rc = 0; if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { auto status = valid_packet.GetPacketStatusFlag(); Loading Loading @@ -370,24 +442,21 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { /* For Chrome OS, we send the outgoing data after receiving an incoming one. * server, so that we can keep the data read/write rate balanced */ size_t read = 0, avail = 0; size_t read = 0; const uint8_t* encoded = nullptr; if (codec_type == BTM_SCO_CODEC_MSBC || codec_type == BTM_SCO_CODEC_LC3) { while (written) { avail = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset; size_t avail = btm_pcm_buf_avail_len(); if (avail) { size_t to_read = written < avail ? written : avail; read = bluetooth::audio::sco::read( (uint8_t*)btm_pcm_buf + btm_pcm_buf_write_offset, to_read); if (read != to_read) { log::assert_that( btm_pcm_buf_write_offset + read <= BTM_SCO_DATA_SIZE_MAX, "Read more {} data ({}) than available buffer ({}) guarded by " "read", codec, (unsigned long)read, (unsigned long)(BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_write_offset)); // Read to the packet_buf first and then copy to the btm_pcm_buf. read = bluetooth::audio::sco::read(packet_buf, to_read); write_btm_pcm_buf(packet_buf, read); if (read != to_read) { log::info( "Requested to read {} bytes of {} data but got {} bytes of PCM " "data from audio server: WriteOffset:{} ReadOffset:{}", Loading @@ -404,25 +473,33 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { log::warn( "Buffer is full when we try to read {} packet from audio server", codec); log::assert_that( btm_pcm_buf_write_offset - btm_pcm_buf_read_offset >= (codec_type == BTM_SCO_CODEC_MSBC ? BTM_MSBC_CODE_SIZE : BTM_LC3_CODE_SIZE), "PCM buffer is full but fails to encode an {} packet. This is " "abnormal and can cause busy loop: WriteOffset:{}, ReadOffset:{}, " "BufferSize:{}", codec, (unsigned long)btm_pcm_buf_write_offset, (unsigned long)btm_pcm_buf_read_offset, (unsigned long)sizeof(btm_pcm_buf)); } btm_pcm_buf_write_offset += read; auto encode = codec_type == BTM_SCO_CODEC_LC3 ? &bluetooth::audio::sco::swb::encode : &bluetooth::audio::sco::wbs::encode; rc = encode(&btm_pcm_buf[btm_pcm_buf_read_offset / sizeof(*btm_pcm_buf)], btm_pcm_buf_write_offset - btm_pcm_buf_read_offset); size_t data_len = btm_pcm_buf_data_len(); if (data_len) { // Copy all data to the packet_buf first and then call encode. size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_read_offset; if (bytes_remaining > data_len) { std::copy(btm_pcm_buf + btm_pcm_buf_read_offset, btm_pcm_buf + btm_pcm_buf_read_offset + data_len, packet_buf); } else { std::copy(btm_pcm_buf + btm_pcm_buf_read_offset, btm_pcm_buf + BTM_SCO_DATA_SIZE_MAX, packet_buf); std::copy(btm_pcm_buf, btm_pcm_buf + data_len - bytes_remaining, packet_buf + bytes_remaining); } rc = encode((int16_t*)packet_buf, data_len); incr_btm_pcm_buf_offset(btm_pcm_buf_read_offset, btm_pcm_buf_read_mirror, rc); if (!rc) log::debug( Loading @@ -430,14 +507,6 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { "WriteOffset:{}", codec, (unsigned long)btm_pcm_buf_read_offset, (unsigned long)btm_pcm_buf_write_offset); /* The offsets should reset some time as the buffer length should always * divisible by 480 and `encode` only returns 480(LC3), 240(MSBC), or 0. */ btm_pcm_buf_read_offset += rc; if (btm_pcm_buf_write_offset == btm_pcm_buf_read_offset) { btm_pcm_buf_write_offset = 0; btm_pcm_buf_read_offset = 0; } /* Send all of the available SCO packets buffered in the queue */ Loading @@ -455,7 +524,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { } else { while (written) { read = bluetooth::audio::sco::read( (uint8_t*)btm_pcm_buf, btm_pcm_buf, written < BTM_SCO_DATA_SIZE_MAX ? written : BTM_SCO_DATA_SIZE_MAX); if (read == 0) { log::info("Failed to read {} bytes of PCM data from audio server", Loading @@ -470,8 +539,7 @@ static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet) { * send PCM data directly to SCO. * We don't maintain buffer read/write offset for NB as we send all data * that we read from the audio server. */ auto data = std::vector<uint8_t>((uint8_t*)btm_pcm_buf, (uint8_t*)btm_pcm_buf + read); auto data = std::vector<uint8_t>(btm_pcm_buf, btm_pcm_buf + read); btm_send_sco_packet(std::move(data)); } } Loading