Reanimated 和 Expo 音频出现问题

问题描述

我正在构建一个具有两个视图的音频播放器,一个迷你播放器(底部选项卡)和一个全屏播放器。滑动或点击以在视图之间切换。当我重新加载我的应用程序时,一切正常,我的占位符封面艺术在播放器上,我可以上下滑动。但是当我加载播放实例时,所有功能都会停止。没有滑动,没有点击。我的 onPress 仍在接收点击,但没有动作。对此有何想法?我将一些控制台日志放入 useCode 中,看起来它仅在初始加载时被调用,我认为这是有道理的。

import React,{ useState,useEffect } from 'react';
import { StyleSheet,useWindowDimensions } from 'react-native';
import MiniPlayer,{ MINI_PLAYER_HEIGHT } from './MiniPlayer';
import Animated,{
  Clock,Value,cond,useCode,set,block,not,clockRunning,interpolate,Extrapolate,} from 'react-native-reanimated';
import {
  clamp,timing,onGestureEvent,withSpring,} from 'react-native-redash/lib/module/v1';
import FullPlayer from './FullPlayer';
import { PanGestureHandler,State } from 'react-native-gesture-handler';
import { Audio } from 'expo-av';
import { useSelector } from '../../customHooks/useSelector';
import { audioRoute } from '../../constants/apiConfigs';
import { useStateIfMounted } from 'use-state-if-mounted';
import { usedispatch } from 'react-redux';
import { updateSleepTimer,postIsLoading } from '../../redux/media/thunks';

const springConfig = {
  damping: 15,mass: 1,stiffness: 150,overshootClamping: true,restSpeedThreshold: 0.1,restdisplacementThreshold: 0.1,};

const Player = () => {
  const { height } = useWindowDimensions();
  const dispatch = usedispatch();
  const shouldLoad =
    useSelector((state) => state.media.audioInfo?.shouldLoad) || null;
  const audioPost = useSelector((state) => state.media.audioInfo?.post) || null;
  const storedTrackBySlug =
    useSelector((state) => state.media.storedTrackBySlug) || null;
  const [playbackInstance,setPlaybackInstance] = useState(null);
  const [isPlaying,setIsPlaying] = useStateIfMounted(false);
  const [currentPositionMillis,setCurrentPositionMillis] = useStateIfMounted(
    0
  );
  const [totalDurationMillis,setTotalDurationMillis] = useStateIfMounted(0);
  const [volume] = useStateIfMounted(1.0);
  const [isBuffering,setIsBuffering] = useStateIfMounted(false);
  const [rate,setRate] = useStateIfMounted(1.0);
  const timerRemainingInMillis = useSelector(
    (state) => state.media.audioTimer?.remainingMillis
  );
  const timerLastPositionInMillis = useSelector(
    (state) => state.media.audioTimer?.lastPositionMillis
  );

  const increaseRateByQuarter = async (): Promise<void> => {
    let playbackRate = rate + 0.25;
    if (playbackRate > 2.0) {
      playbackRate = 0.5;
    }

    await playbackInstance.setRateAsync(
      playbackRate,true,Audio.PitchCorrectionQuality.Medium
    );
  };

  const seekPositionBySeconds = async (position: number): Promise<void> => {
    await playbackInstance.setPositionAsync(position * 1000);

    if (timerRemainingInMillis > 0) {
      dispatch(
        updateSleepTimer(
          Math.round(
            (timerRemainingInMillis -
              (currentPositionMillis - timerLastPositionInMillis)) /
              1000
          ) *
            1000 -
            10,position * 1000
        )
      );
    }
  };

  const handlePlayPause = async (): Promise<void> => {
    isPlaying
      ? await playbackInstance.pauseAsync()
      : await playbackInstance.playAsync();
    setIsPlaying(!isPlaying);
  };

  const handleSkipBack = async (): Promise<void> => {
    seekPositionBySeconds(currentPositionMillis / 1000 - 15);
  };

  const handleSkipForward = async (): Promise<void> => {
    seekPositionBySeconds(currentPositionMillis / 1000 + 15);
  };

  const translationY = new Value(0);
  const veLocityY = new Value(0);
  const state = new Value(State.UNDETERmineD);
  const gestureHandler = onGestureEvent({ translationY,state,veLocityY });

  const [] = useState(true);
  const SNAP_TOP = 0;
  const SNAP_BottOM = height - MINI_PLAYER_HEIGHT;

  const offset = new Value(SNAP_BottOM);
  const goUp: Value<0 | 1> = new Animated.Value(0);
  const godown: Value<0 | 1> = new Animated.Value(0);

  const translateY = clamp(
    withSpring({
      state,offset,value: translationY,veLocity: veLocityY,snapPoints: [SNAP_TOP,SNAP_BottOM],config: springConfig,}),SNAP_TOP,SNAP_BottOM
  );

  const miniPlayerOpacity = interpolate(translateY,{
    inputRange: [SNAP_BottOM - MINI_PLAYER_HEIGHT,outputRange: [0,1],extrapolate: Extrapolate.CLAMP,});

  const overlayOpacity = interpolate(translateY,{
    inputRange: [
      SNAP_BottOM - MINI_PLAYER_HEIGHT * 2,SNAP_BottOM - MINI_PLAYER_HEIGHT,],});

  const clock = new Clock();

  useEffect(() => {
    if (audioPost && shouldLoad) {
      initPlaybackInstance();
      dispatch(postIsLoading());
    }
  },[shouldLoad]);

  const initPlaybackInstance = async () => {
    if (playbackInstance != null) {
      playbackInstance.unloadAsync();
    }

    await Audio.setAudioModeAsync({
      allowsRecordingIOS: false,interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,playsInSilentModeIOS: true,interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,shouldDuckAndroid: false,staysActiveInBackground: true,playThroughEarpieceAndroid: true,});
    await loadAudio();
  };

  const loadAudio = async () => {
    const audioInstance = new Audio.sound();
    const source = {
      uri: storedTrackBySlug[audioPost.slug]?.uri ?? audioRoute(audioPost.slug),};
    const status = {
      shouldplay: true,volume: volume,};

    audioInstance.setonPlaybackStatusUpdate(onPlaybackStatusUpdate);
    await audioInstance.loadAsync(source,status,false);
    setPlaybackInstance(audioInstance);
  };

  const onPlaybackStatusUpdate = (status): void => {
    setIsBuffering(status.isBuffering);
    setIsPlaying(status.isPlaying);
    setCurrentPositionMillis(status.positionMillis);
    setTotalDurationMillis(status.durationMillis);
    setRate(status.rate);
  };

  // PERHAPS REMOVE USE CODE AND ONLY USE CLICK FROM SNACK EXAMPLE AND SWIPE FROM SPOTIFY EXAMPLE

  useCode(() => {
    console.log('useCode CALLED');
    console.log(JSON.stringify(goUp));
    return block([
      cond(goUp,[
        set(
          offset,timing({
            clock,from: offset,to: SNAP_TOP,})
        ),cond(not(clockRunning(clock)),[set(goUp,0)]),]),cond(godown,to: SNAP_BottOM,[set(godown,]);
  },[]);

  return (
    <PanGestureHandler {...gestureHandler}>
      <Animated.View
        style={[styles.playerSheet,{ transform: [{ translateY }] }]}
      >
        <FullPlayer
          post={audioPost}
          isPlaying={isPlaying}
          isBuffering={isBuffering}
          currentPositionMillis={currentPositionMillis}
          totalDurationMillis={totalDurationMillis}
          rate={rate}
          handleSkipBack={handleSkipBack}
          handleSkipForward={handleSkipForward}
          handlePlayPause={handlePlayPause}
          seekPositionBySeconds={seekPositionBySeconds}
          increaseRateByQuarter={increaseRateByQuarter}
          onPress={() => {
            console.log('AUdioPLAYER CLICKED');
            godown.setValue(1);
          }}
        />
        <Animated.View
          style={{
            ...StyleSheet.absoluteFillObject,opacity: overlayOpacity,}}
          pointerEvents='none'
        />
        <Animated.View
          style={{
            opacity: miniPlayerOpacity,position: 'absolute',top: 0,left: 0,right: 0,height: MINI_PLAYER_HEIGHT,}}
        >
          <MiniPlayer
            postTitle={audioPost?.title}
            isPlaying={isPlaying}
            isBuffering={isBuffering}
            handlePlayPause={handlePlayPause}
            onPress={() => {
              console.log('MINIAUdioPLAYER CLICKED');
              goUp.setValue(1);
              //setIsPlayerUp(!isPlayerUp);
            }}
          />
        </Animated.View>
      </Animated.View>
    </PanGestureHandler>
  );
};

const styles = StyleSheet.create({
  thumbnailoverlay: {
    ...StyleSheet.absoluteFillObject,padding: 16,},scroll: {
    flex: 1,marginHorizontal: 10,overflow: 'hidden',playerSheet: {
    ...StyleSheet.absoluteFillObject,backgroundColor: 'cyan',});

export default Player;

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...