ryanheise / audio_session

MIT License
107 stars 68 forks source link

Android detects the headset as if it is connected even if it is not #121

Closed yagizdo closed 6 months ago

yagizdo commented 6 months ago

I check the page when it is first opened on Android devices. Even if no device is connected and BT is turned off, the 'connect' section in the if-else section works. I don't know if it's an Android error or if I'm doing something wrong.

It works fine on iOS, only Android has this problem.

Pubspec :

 # Audio
  audio_video_progress_bar: ^2.0.1
  just_audio: ^0.9.35
  just_audio_background: ^0.0.1-beta.10
  rxdart: ^0.27.7
  audio_session: ^0.1.18

Audio Progress Controls widget :


class AudioProgressControls extends StatefulWidget {
  const AudioProgressControls({super.key});

  @override
  State<AudioProgressControls> createState() => _AudioProgressControlsState();
}

class _AudioProgressControlsState extends State<AudioProgressControls> {
  late final NowPlayingViewModel nowPlayingViewModel;
  late final AudioSession session;

  bool is90PercentListenedChecked = false;

  @override
  void initState() {
    super.initState();
    nowPlayingViewModel = getIt<NowPlayingViewModel>();
    _initSession();
  }

  Future<void> _initSession() async {
    session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration.music());
    final connectedDevicesList = await session.getDevices();
    final connectedDevicesTypes =
        connectedDevicesList.map((device) => device.type).toList();
    // First time check
    if (connectedDevicesTypes.contains(AudioDeviceType.builtInEarpiece) ||
        connectedDevicesTypes.contains(AudioDeviceType.bluetoothA2dp) ||
        connectedDevicesTypes.contains(AudioDeviceType.wiredHeadphones) ||
        connectedDevicesTypes.contains(AudioDeviceType.wiredHeadset)) {
      nowPlayingViewModel.setHeadsetState(HeadsetStatus.connect);
    } else {
      nowPlayingViewModel.setHeadsetState(HeadsetStatus.disconnect);
    }
    session.devicesChangedEventStream.listen((event) {
      final connectedDevices =
      event.devicesAdded.map((device) => device.type).toList();

      print("connectedDevices: $connectedDevices");
      if (connectedDevices.contains(AudioDeviceType.builtInEarpiece) ||
          connectedDevices.contains(AudioDeviceType.bluetoothA2dp) ||
          connectedDevices.contains(AudioDeviceType.wiredHeadphones) ||
          connectedDevices.contains(AudioDeviceType.wiredHeadset)) {
        nowPlayingViewModel.setHeadsetState(HeadsetStatus.connect);
      } else {
        nowPlayingViewModel.setHeadsetState(HeadsetStatus.disconnect);
      }
    });
    session.devicesStream.listen((devices) {

    });
  }

  @override
  Widget build(BuildContext context) {
    return _buildBody(context);
  }

  Widget _buildBody(BuildContext context) {
    return StreamBuilder<PositionData>(
        stream: nowPlayingViewModel.positionDataStream,
        builder: (context, state) {
          nowPlayingViewModel
              .saveAudioCache(state.data?.position.inSeconds ?? 0);

          if (!is90PercentListenedChecked &&
              state.hasData &&
              state.data!.position.inSeconds >=
                  0.9 * state.data!.duration.inSeconds) {

            nowPlayingViewModel.checkNinetyPercentListened(
                state.data!.position.inSeconds);

            is90PercentListenedChecked = true;
          }

          // if song complete
          if (state.hasData &&
              state.data!.position.inSeconds >=
                  state.data!.duration.inSeconds) {
            nowPlayingViewModel.completeAudio();
          }
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              AudioControls(
                currentPosition: state.data?.position ?? Duration.zero,
                totalDuration: state.data?.duration ?? Duration.zero,
              ),
              height5Per(context: context),
              Observer(
                builder: (context) {
                  return NowPlayingSvgBtn(
                      iconPath: nowPlayingViewModel.isMuted ? AppAssets.voiceMuteIcon : AppAssets.voiceUpIcon,
                      size: context.screenWidth * 0.08,
                      onTap: () {
                        nowPlayingViewModel.mute();
                        nowPlayingViewModel.setMute();
                      });
                }
              ),
              height5Per(context: context),
              _buildProgressBar(state),
            ],
          );
        });
  }

  Widget _buildProgressBar(AsyncSnapshot<PositionData> state) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: context.screenWidth * 0.02),
      child: ProgressBar(
        progress: state.hasData ? state.data!.position : Duration.zero,
        buffered: state.hasData ? state.data!.bufferedPosition : Duration.zero,
        total: state.hasData ? state.data!.duration : Duration.zero,
        onSeek: (duration) {
          if (duration.inSeconds == state.data!.duration.inSeconds) {
            nowPlayingViewModel.completeAudio();
          } else {
            nowPlayingViewModel.seekTo(duration);
          }
        },
        timeLabelTextStyle: AppTextStyle.nowPlayingTime(context),
        timeLabelLocation: TimeLabelLocation.below,
        timeLabelType: TimeLabelType.totalTime,
        timeLabelPadding: context.screenWidth * 0.02,
        barHeight: context.screenWidth * 0.01,
        thumbRadius: context.screenWidth * 0.015,
        baseBarColor: AppColors.nowPlayingProgressbarBgColor.withOpacity(0.4),
        bufferedBarColor: AppColors.white.withOpacity(0.5),
        progressBarColor: AppColors.blue,
      ),
    );
  }
} ```
yagizdo commented 6 months ago

Solved.

The problem was in the connectedDevices.contains(AudioDeviceType.builtInEarpiece) control inside the if-else. Although it is not visible in the emulator, I think it is one of the parameters that come by default in the real device. It was fixed when I removed it from the if else statement.