From b60a83482f156cc5e88dd2a06e8c19dc53dbc4d7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Tue, 18 Aug 2020 18:45:39 +0200 Subject: [PATCH] Cleanup aptX sections and add new aptX codec IDs Also, this commit removes configuration warning stating that [open]aptx library is not able to perform encoding, because now it supports FFmpeg as an encoding back-end (with some limitations, though). --- configure.ac | 8 --- src/a2dp-audio.c | 12 ++--- src/a2dp-codecs.h | 11 ++++- src/a2dp.c | 116 +++++++++++++++++++++++--------------------- src/ba-transport.c | 20 ++++---- src/bluealsa-dbus.c | 8 +-- src/utils.c | 50 ++++++++++--------- utils/a2dpconf.c | 17 +++++-- 8 files changed, 129 insertions(+), 113 deletions(-) diff --git a/configure.ac b/configure.ac index 44250d8ff..0c894fbd2 100644 --- a/configure.ac +++ b/configure.ac @@ -256,11 +256,3 @@ AM_COND_IF([ALSA_1_1_2], [ AC_MSG_WARN([Either compile alsa-lib without this feature or export]) AC_MSG_WARN([LIBASOUND_THREAD_SAFE=0 while using bluealsa PCM.]) ]) - -# warn user that aptX support is not an open-source feature -AM_COND_IF([ENABLE_APTX], [ - AC_MSG_WARN([ *** aptX encoder support ***]) - AC_MSG_WARN([You have enabled support for aptX encoding. Note, that]) - AC_MSG_WARN([by default bluez-alsa will use openaptx library, which]) - AC_MSG_WARN([does NOT perform any encoding/decoding.]) -]) diff --git a/src/a2dp-audio.c b/src/a2dp-audio.c index 62a746125..df160f848 100644 --- a/src/a2dp-audio.c +++ b/src/a2dp-audio.c @@ -1734,12 +1734,12 @@ static void *a2dp_source_aptx_hd(struct ba_transport *t) { break; } - bt.tail[0] = ((uint8_t *)code)[2]; - bt.tail[1] = ((uint8_t *)code)[1]; - bt.tail[2] = ((uint8_t *)code)[0]; - bt.tail[3] = ((uint8_t *)code)[6]; - bt.tail[4] = ((uint8_t *)code)[5]; - bt.tail[5] = ((uint8_t *)code)[4]; + bt.tail[0] = code[0] >> 16; + bt.tail[1] = code[0] >> 8; + bt.tail[2] = code[0]; + bt.tail[3] = code[1] >> 16; + bt.tail[4] = code[1] >> 8; + bt.tail[5] = code[1]; input += 4 * channels; input_len -= 4 * channels; diff --git a/src/a2dp-codecs.h b/src/a2dp-codecs.h index c96910316..40dfd233b 100644 --- a/src/a2dp-codecs.h +++ b/src/a2dp-codecs.h @@ -40,8 +40,10 @@ /* Customized (BlueALSA) 16-bit vendor extension. */ #define A2DP_CODEC_VENDOR_APTX 0x4FFF +#define A2DP_CODEC_VENDOR_APTX_AD 0xADFF +#define A2DP_CODEC_VENDOR_APTX_HD 0x24FF #define A2DP_CODEC_VENDOR_APTX_LL 0xA2FF -#define A2DP_CODEC_VENDOR_APTX_HD 0xD7FF +#define A2DP_CODEC_VENDOR_APTX_TWS 0x25FF #define A2DP_CODEC_VENDOR_FASTSTREAM 0xA1FF #define A2DP_CODEC_VENDOR_LDAC 0x2DFF #define A2DP_CODEC_VENDOR_LHDC 0x4CFF @@ -245,6 +247,7 @@ #define APTX_CHANNEL_MODE_MONO 0x01 #define APTX_CHANNEL_MODE_STEREO 0x02 +#define APTX_CHANNEL_MODE_TWS 0x08 #define APTX_SAMPLING_FREQ_16000 0x08 #define APTX_SAMPLING_FREQ_32000 0x04 @@ -288,6 +291,12 @@ #define APTX_HD_VENDOR_ID BT_COMPID_QUALCOMM_TECH #define APTX_HD_CODEC_ID 0x0024 +#define APTX_TWS_VENDOR_ID BT_COMPID_QUALCOMM_TECH +#define APTX_TWS_CODEC_ID 0x0025 + +#define APTX_AD_VENDOR_ID BT_COMPID_QUALCOMM_TECH +#define APTX_AD_CODEC_ID 0x00ad + #define LDAC_VENDOR_ID BT_COMPID_SONY #define LDAC_CODEC_ID 0x00aa diff --git a/src/a2dp.c b/src/a2dp.c index 9adcd67e8..e3195f6c7 100644 --- a/src/a2dp.c +++ b/src/a2dp.c @@ -394,6 +394,28 @@ static const struct a2dp_codec a2dp_codec_sink_aptx = { .samplings_size[0] = ARRAYSIZE(a2dp_aptx_samplings), }; +static const struct a2dp_codec a2dp_codec_source_aptx_hd = { + .dir = A2DP_SOURCE, + .codec_id = A2DP_CODEC_VENDOR_APTX_HD, + .capabilities = &a2dp_aptx_hd, + .capabilities_size = sizeof(a2dp_aptx_hd), + .channels[0] = a2dp_aptx_hd_channels, + .channels_size[0] = ARRAYSIZE(a2dp_aptx_hd_channels), + .samplings[0] = a2dp_aptx_hd_samplings, + .samplings_size[0] = ARRAYSIZE(a2dp_aptx_hd_samplings), +}; + +static const struct a2dp_codec a2dp_codec_sink_aptx_hd = { + .dir = A2DP_SINK, + .codec_id = A2DP_CODEC_VENDOR_APTX_HD, + .capabilities = &a2dp_aptx_hd, + .capabilities_size = sizeof(a2dp_aptx_hd), + .channels[0] = a2dp_aptx_hd_channels, + .channels_size[0] = ARRAYSIZE(a2dp_aptx_hd_channels), + .samplings[0] = a2dp_aptx_hd_samplings, + .samplings_size[0] = ARRAYSIZE(a2dp_aptx_hd_samplings), +}; + static const struct a2dp_codec a2dp_codec_source_faststream = { .dir = A2DP_SOURCE, .codec_id = A2DP_CODEC_VENDOR_FASTSTREAM, @@ -418,28 +440,6 @@ static const struct a2dp_codec a2dp_codec_sink_faststream = { .samplings_size[1] = ARRAYSIZE(a2dp_faststream_samplings_voice), }; -static const struct a2dp_codec a2dp_codec_source_aptx_hd = { - .dir = A2DP_SOURCE, - .codec_id = A2DP_CODEC_VENDOR_APTX_HD, - .capabilities = &a2dp_aptx_hd, - .capabilities_size = sizeof(a2dp_aptx_hd), - .channels[0] = a2dp_aptx_hd_channels, - .channels_size[0] = ARRAYSIZE(a2dp_aptx_hd_channels), - .samplings[0] = a2dp_aptx_hd_samplings, - .samplings_size[0] = ARRAYSIZE(a2dp_aptx_hd_samplings), -}; - -static const struct a2dp_codec a2dp_codec_sink_aptx_hd = { - .dir = A2DP_SINK, - .codec_id = A2DP_CODEC_VENDOR_APTX_HD, - .capabilities = &a2dp_aptx_hd, - .capabilities_size = sizeof(a2dp_aptx_hd), - .channels[0] = a2dp_aptx_hd_channels, - .channels_size[0] = ARRAYSIZE(a2dp_aptx_hd_channels), - .samplings[0] = a2dp_aptx_hd_samplings, - .samplings_size[0] = ARRAYSIZE(a2dp_aptx_hd_samplings), -}; - static const struct a2dp_codec a2dp_codec_source_ldac = { .dir = A2DP_SOURCE, .codec_id = A2DP_CODEC_VENDOR_LDAC, @@ -469,13 +469,13 @@ const struct a2dp_codec *a2dp_codecs[] = { #if ENABLE_APTX_HD &a2dp_codec_source_aptx_hd, #endif +#if ENABLE_APTX + &a2dp_codec_source_aptx, +#endif #if ENABLE_FASTSTREAM &a2dp_codec_source_faststream, &a2dp_codec_sink_faststream, #endif -#if ENABLE_APTX - &a2dp_codec_source_aptx, -#endif #if ENABLE_AAC &a2dp_codec_source_aac, &a2dp_codec_sink_aac, @@ -550,6 +550,10 @@ uint16_t a2dp_get_vendor_codec_id(const void *capabilities, size_t size) { switch (codec_id) { case APTX_HD_CODEC_ID: return A2DP_CODEC_VENDOR_APTX_HD; + case APTX_TWS_CODEC_ID: + return A2DP_CODEC_VENDOR_APTX_TWS; + case APTX_AD_CODEC_ID: + return A2DP_CODEC_VENDOR_APTX_AD; } break; case BT_COMPID_SONY: switch (codec_id) { @@ -713,15 +717,6 @@ uint32_t a2dp_check_configuration( } #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: { - const a2dp_faststream_t *cap = configuration; - cap_freq = cap->frequency_music; - cap_freq_bc = cap->frequency_voice; - break; - } -#endif - #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: { const a2dp_aptx_hd_t *cap = configuration; @@ -731,6 +726,15 @@ uint32_t a2dp_check_configuration( } #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: { + const a2dp_faststream_t *cap = configuration; + cap_freq = cap->frequency_music; + cap_freq_bc = cap->frequency_voice; + break; + } +#endif + #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: { const a2dp_ldac_t *cap = configuration; @@ -810,14 +814,14 @@ int a2dp_filter_capabilities( case A2DP_CODEC_VENDOR_APTX: break; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - break; -#endif #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: break; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + break; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: break; @@ -1049,20 +1053,20 @@ int a2dp_select_configuration( } #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: { +#if ENABLE_APTX_HD + case A2DP_CODEC_VENDOR_APTX_HD: { - a2dp_faststream_t *cap = capabilities; - unsigned int cap_freq = cap->frequency_music; - unsigned int cap_freq_bc = cap->frequency_voice; + a2dp_aptx_hd_t *cap = capabilities; + unsigned int cap_chm = cap->aptx.channel_mode; + unsigned int cap_freq = cap->aptx.frequency; - if ((cap->frequency_music = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) { - error("FastStream: No supported sampling frequencies: %#x", cap_freq); + if ((cap->aptx.channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) { + error("apt-X HD: No supported channel modes: %#x", cap_chm); goto fail; } - if ((cap->frequency_voice = a2dp_codec_select_sampling_freq(codec, cap_freq_bc, true)) == 0) { - error("FastStream: No supported back-channel sampling frequencies: %#x", cap_freq_bc); + if ((cap->aptx.frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) { + error("apt-X HD: No supported sampling frequencies: %#x", cap_freq); goto fail; } @@ -1070,20 +1074,20 @@ int a2dp_select_configuration( } #endif -#if ENABLE_APTX_HD - case A2DP_CODEC_VENDOR_APTX_HD: { +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: { - a2dp_aptx_hd_t *cap = capabilities; - unsigned int cap_chm = cap->aptx.channel_mode; - unsigned int cap_freq = cap->aptx.frequency; + a2dp_faststream_t *cap = capabilities; + unsigned int cap_freq = cap->frequency_music; + unsigned int cap_freq_bc = cap->frequency_voice; - if ((cap->aptx.channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) { - error("apt-X HD: No supported channel modes: %#x", cap_chm); + if ((cap->frequency_music = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) { + error("FastStream: No supported sampling frequencies: %#x", cap_freq); goto fail; } - if ((cap->aptx.frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) { - error("apt-X HD: No supported sampling frequencies: %#x", cap_freq); + if ((cap->frequency_voice = a2dp_codec_select_sampling_freq(codec, cap_freq_bc, true)) == 0) { + error("FastStream: No supported back-channel sampling frequencies: %#x", cap_freq_bc); goto fail; } diff --git a/src/ba-transport.c b/src/ba-transport.c index cd447a53c..0578e8cdd 100644 --- a/src/ba-transport.c +++ b/src/ba-transport.c @@ -532,17 +532,17 @@ static void transport_update_channels(struct ba_transport *t) { cfg_value = ((a2dp_aptx_t *)t->a2dp.configuration)->channel_mode; break; #endif +#if ENABLE_APTX_HD + case A2DP_CODEC_VENDOR_APTX_HD: + cfg_value = ((a2dp_aptx_hd_t *)t->a2dp.configuration)->aptx.channel_mode; + break; +#endif #if ENABLE_FASTSTREAM case A2DP_CODEC_VENDOR_FASTSTREAM: t->a2dp.pcm.channels = 2; t->a2dp.pcm_bc.channels = 1; break; #endif -#if ENABLE_APTX_HD - case A2DP_CODEC_VENDOR_APTX_HD: - cfg_value = ((a2dp_aptx_hd_t *)t->a2dp.configuration)->aptx.channel_mode; - break; -#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: cfg_value = ((a2dp_ldac_t *)t->a2dp.configuration)->channel_mode; @@ -601,17 +601,17 @@ static void transport_update_sampling(struct ba_transport *t) { cfg_value = ((a2dp_aptx_t *)t->a2dp.configuration)->frequency; break; #endif +#if ENABLE_APTX_HD + case A2DP_CODEC_VENDOR_APTX_HD: + cfg_value = ((a2dp_aptx_hd_t *)t->a2dp.configuration)->aptx.frequency; + break; +#endif #if ENABLE_FASTSTREAM case A2DP_CODEC_VENDOR_FASTSTREAM: cfg_value = ((a2dp_faststream_t *)t->a2dp.configuration)->frequency_music; cfg_value_bc = ((a2dp_faststream_t *)t->a2dp.configuration)->frequency_voice; break; #endif -#if ENABLE_APTX_HD - case A2DP_CODEC_VENDOR_APTX_HD: - cfg_value = ((a2dp_aptx_hd_t *)t->a2dp.configuration)->aptx.frequency; - break; -#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: cfg_value = ((a2dp_ldac_t *)t->a2dp.configuration)->frequency; diff --git a/src/bluealsa-dbus.c b/src/bluealsa-dbus.c index 6b814338b..1c8e9e3aa 100644 --- a/src/bluealsa-dbus.c +++ b/src/bluealsa-dbus.c @@ -164,14 +164,14 @@ static bool ba_variant_populate_sep(GVariantBuilder *props, const struct a2dp_se case A2DP_CODEC_VENDOR_APTX: break; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - break; -#endif #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: break; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + break; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: break; diff --git a/src/utils.c b/src/utils.c index 5f6d98e17..3d72142b8 100644 --- a/src/utils.c +++ b/src/utils.c @@ -90,14 +90,14 @@ const char *g_dbus_transport_type_to_bluez_object_path(struct ba_transport_type case A2DP_CODEC_VENDOR_APTX: return "/A2DP/aptX/Source"; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - return "/A2DP/FastStream/Source"; -#endif #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: return "/A2DP/aptXHD/Source"; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + return "/A2DP/FastStream/Source"; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: return "/A2DP/LDAC/Source"; @@ -118,10 +118,6 @@ const char *g_dbus_transport_type_to_bluez_object_path(struct ba_transport_type case A2DP_CODEC_MPEG24: return "/A2DP/AAC/Sink"; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - return "/A2DP/FastStream/Sink"; -#endif #if ENABLE_APTX case A2DP_CODEC_VENDOR_APTX: return "/A2DP/aptX/Sink"; @@ -130,6 +126,10 @@ const char *g_dbus_transport_type_to_bluez_object_path(struct ba_transport_type case A2DP_CODEC_VENDOR_APTX_HD: return "/A2DP/aptXHD/Sink"; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + return "/A2DP/FastStream/Sink"; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: return "/A2DP/LDAC/Sink"; @@ -220,12 +220,12 @@ uint16_t ba_transport_codecs_a2dp_from_string(const char *str) { #if ENABLE_APTX A2DP_CODEC_VENDOR_APTX, #endif -#if ENABLE_FASTSTREAM - A2DP_CODEC_VENDOR_FASTSTREAM, -#endif #if ENABLE_APTX_HD A2DP_CODEC_VENDOR_APTX_HD, #endif +#if ENABLE_FASTSTREAM + A2DP_CODEC_VENDOR_FASTSTREAM, +#endif #if ENABLE_LDAC A2DP_CODEC_VENDOR_LDAC, #endif @@ -256,12 +256,16 @@ const char *ba_transport_codecs_a2dp_to_string(uint16_t codec) { return "ATRAC"; case A2DP_CODEC_VENDOR_APTX: return "aptX"; - case A2DP_CODEC_VENDOR_FASTSTREAM: - return "FastStream"; - case A2DP_CODEC_VENDOR_APTX_LL: - return "aptX-LL"; + case A2DP_CODEC_VENDOR_APTX_AD: + return "aptX-AD"; case A2DP_CODEC_VENDOR_APTX_HD: return "aptX-HD"; + case A2DP_CODEC_VENDOR_APTX_LL: + return "aptX-LL"; + case A2DP_CODEC_VENDOR_APTX_TWS: + return "aptX-TWS"; + case A2DP_CODEC_VENDOR_FASTSTREAM: + return "FastStream"; case A2DP_CODEC_VENDOR_LDAC: return "LDAC"; case A2DP_CODEC_VENDOR_LHDC: @@ -340,14 +344,14 @@ const char *ba_transport_type_to_string(struct ba_transport_type type) { case A2DP_CODEC_VENDOR_APTX: return "A2DP Source (aptX)"; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - return "A2DP Source (FastStream)"; -#endif #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: return "A2DP Source (aptX HD)"; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + return "A2DP Source (FastStream)"; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: return "A2DP Source (LDAC)"; @@ -371,14 +375,14 @@ const char *ba_transport_type_to_string(struct ba_transport_type type) { case A2DP_CODEC_VENDOR_APTX: return "A2DP Sink (aptX)"; #endif -#if ENABLE_FASTSTREAM - case A2DP_CODEC_VENDOR_FASTSTREAM: - return "A2DP Sink (FastStream)"; -#endif #if ENABLE_APTX_HD case A2DP_CODEC_VENDOR_APTX_HD: return "A2DP Sink (aptX HD)"; #endif +#if ENABLE_FASTSTREAM + case A2DP_CODEC_VENDOR_FASTSTREAM: + return "A2DP Sink (FastStream)"; +#endif #if ENABLE_LDAC case A2DP_CODEC_VENDOR_LDAC: return "A2DP Sink (LDAC)"; diff --git a/utils/a2dpconf.c b/utils/a2dpconf.c index 5ae962955..bd10b015b 100644 --- a/utils/a2dpconf.c +++ b/utils/a2dpconf.c @@ -40,9 +40,11 @@ static const struct { { A2DP_CODEC_MPEG24, "MPEG24" }, { A2DP_CODEC_ATRAC, "ATRAC" }, { A2DP_CODEC_VENDOR_APTX, "aptX" }, - { A2DP_CODEC_VENDOR_FASTSTREAM, "FastStream" }, - { A2DP_CODEC_VENDOR_APTX_LL, "aptX-LL" }, + { A2DP_CODEC_VENDOR_APTX_AD, "aptX-AD" }, { A2DP_CODEC_VENDOR_APTX_HD, "aptX-HD" }, + { A2DP_CODEC_VENDOR_APTX_LL, "aptX-LL" }, + { A2DP_CODEC_VENDOR_APTX_TWS, "aptX-TWS" }, + { A2DP_CODEC_VENDOR_FASTSTREAM, "FastStream" }, { A2DP_CODEC_VENDOR_LDAC, "LDAC" }, { A2DP_CODEC_VENDOR_LHDC, "LHDC" }, { A2DP_CODEC_VENDOR_LHDC_V1, "LHDCv1" }, @@ -214,13 +216,14 @@ static void dump_aptx(const a2dp_aptx_t *aptx) { printf("aptX {\n" " vendor-id:32 = %#x\n" " vendor-codec-id:16 = %#x\n" - " channel-mode:4 =%s%s\n" + " channel-mode:4 =%s%s%s\n" " sampling-frequency:4 =%s%s%s%s\n" "}\n", bintohex(aptx, sizeof(*aptx)), A2DP_GET_VENDOR_ID(aptx->info), A2DP_GET_CODEC_ID(aptx->info), aptx->channel_mode & APTX_CHANNEL_MODE_STEREO ? " Stereo" : "", + aptx->channel_mode & APTX_CHANNEL_MODE_TWS ? " DualChannel" : "", aptx->channel_mode & APTX_CHANNEL_MODE_MONO ? " Mono" : "", aptx->frequency & APTX_SAMPLING_FREQ_48000 ? " 48000" : "", aptx->frequency & APTX_SAMPLING_FREQ_44100 ? " 44100" : "", @@ -352,13 +355,14 @@ int main(int argc, char *argv[]) { dump_atrac(&atrac); } break; - case A2DP_CODEC_VENDOR_APTX: { + case A2DP_CODEC_VENDOR_APTX: + case A2DP_CODEC_VENDOR_APTX_TWS: { a2dp_aptx_t aptx = { 0 }; if (get_codec_blob(codec, &aptx, sizeof(aptx)) != -1) dump_aptx(&aptx); } break; - case A2DP_CODEC_VENDOR_APTX_LL: { + case A2DP_CODEC_VENDOR_APTX_AD: { } break; case A2DP_CODEC_VENDOR_APTX_HD: { @@ -367,6 +371,9 @@ int main(int argc, char *argv[]) { dump_aptx_hd(&aptx_hd); } break; + case A2DP_CODEC_VENDOR_APTX_LL: { + } break; + case A2DP_CODEC_VENDOR_FASTSTREAM: { a2dp_faststream_t faststream = { 0 }; if (get_codec_blob(codec, &faststream, sizeof(faststream)) != -1)