Expo:实时获取音频数据并通过Socket.IO发送

问题描述 投票:0回答:2

我想做的应用程序

我想制作像Shazam这样的音频识别移动应用程序

我想通过Socket.IO每秒或每个样本将记录数据发送到基于机器学习的识别服务器(也许每秒发送数据采样率次数太多),然后移动应用程序接收并显示预测结果。

问题

如何在录制时从

recordingInstance
获取数据?我读了世博音频文档,但我不知道该怎么做。

到目前为止

我运行了两个示例:

现在我想混合两个例子。感谢您的阅读。如果我可以

console.log
记录数据,那就会有很大帮助了。

相关问题

react-native socket.io expo sound-recognition expo-av
2个回答
0
投票

我想我找到了解决这个问题的好方法。

await recordingInstance.prepareToRecordAsync(recordingOptions);
recordingInstance.setOnRecordingStatusUpdate(checkStatus);
recordingInstance.setProgressUpdateInterval(10000);
await recordingInstance.startAsync();
setRecording(recordingInstance);

在上面创建并准备录制之后,我添加了一个每 10 秒运行一次的回调函数。

const duration = status.durationMillis / 1000;
const info = await FileSystem.getInfoAsync(recording.getURI());
const uri = info.uri;
console.log(`Recording Status: ${status.isRecording}, Duration: ${duration}, Meterring: ${status.metering}, Uri: ${uri}`)
if(duration >10 && duration - prevDuration > 0){
            sendBlob(uri);
        }
 setPrevDuration(duration);

回调函数检查持续时间是否大于10秒且与上次持续时间的差值大于0,然后通过WebSocket发送数据。

目前唯一的问题,第一次不运行回调,但第二次运行。


0
投票

App.js:

import React, {useEffect, useState} from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { Audio } from 'expo-av';
import * as FileSystem from 'expo-file-system';
import {socket, uploadChunksToServer} from './socket';




export default function App() {
  const [recording, setRecording] = React.useState();
  const [recordings, setRecordings] = React.useState([]);
  const [sending, setSending] = useState(false);
  const [recordingBackLog, setRecordingBackLog] = useState([]);

  const [isRecording, setIsRecording] = React.useState(false);
  const [prevLen, setPrevLen] = useState(0);
  const [isConnected, setIsConnected] = useState(false);
  const [transport, setTransport] = useState('N/A');
  let sum = 0;
  let p_len = 0;

  useEffect(() => {
    if (socket.connected) {
      onConnect();
    }

    function onConnect() {
      setIsConnected(true);
      setTransport(socket.io.engine.transport.name);

      socket.io.engine.on('upgrade', (transport) => {
        setTransport(transport.name);
      });
    }

    function onDisconnect() {
      setIsConnected(false);
      setTransport('N/A');
    }

    socket.on('connect', onConnect);
    socket.on('disconnect', onDisconnect);

    return () => {
      socket.off('connect', onConnect);
      socket.off('disconnect', onDisconnect);
    };
  }, []);

const convertMP4ToBase64 = async (uri, delay = 0) => {
  try {
    // Read the file
    const fileContent = await FileSystem.readAsStringAsync(uri, {
      encoding: FileSystem.EncodingType.Base64,
      position: 0,
      length: 100
    });

    // Introduce optional delay (if delay is a positive number)
    if (delay > 0) {
      await new Promise((resolve) => setTimeout(resolve, delay));
    }

    return fileContent;
  } catch (error) {
    console.error('Error converting MP4 to base64:', error);
    return null;
  }
};

async function startRecording() {

  try {
    const perm = await Audio.requestPermissionsAsync();
    if (perm.status === "granted") {
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        playsInSilentModeIOS: true
      });

      const recordingInstance = new Audio.Recording();
      await recordingInstance.prepareToRecordAsync({
        android:{
          extension: '.wav',
          linearPCMIsBigEndian:false,

        },
        ios:{
          extension: '.wav',
          linearPCMIsBigEndian:false,
          },
      });

      await recordingInstance.startAsync();

      setRecording(recordingInstance);
      setRecordingBackLog(prevBackLog => [...prevBackLog, recordingInstance]);

      await uploadChunksToServer(recordingInstance, 96000, 950);

      recordingInstance.setOnRecordingStatusUpdate(async (status) => {
      });

    }
  } catch (err) {
    console.error('Failed to start recording', err);
  }
}

  async function stopRecording() {
    setPrevLen(0);
    try {
      if (!recording) return;

      await recording.stopAndUnloadAsync();
      let allRecordings = [...recordings];
      const { sound, status } = await recording.createNewLoadedSoundAsync();
      allRecordings.push({
        sound: sound,
        duration: getDurationFormatted(status.durationMillis),
        file: recording.getURI()
      });
      setRecordings(allRecordings);
    } catch (err) {
      console.error('Failed to stop recording', err);
    } finally {
      setRecording(undefined);
    }
  }

  function getDurationFormatted(milliseconds) {
    const minutes = milliseconds / 1000 / 60;
    const seconds = Math.round((minutes - Math.floor(minutes)) * 60);
    return seconds < 10 ? `${Math.floor(minutes)}:0${seconds}` : `${Math.floor(minutes)}:${seconds}`;
  }

  function toggleRecording() {
    setIsRecording(prevState => !prevState);
  }

  function getRecordingLines() {
    return recordings.map((recordingLine, index) => {
      return (
        <View key={index} style={styles.row}>
          <Text style={styles.fill}>
            Recording #{index + 1} | {recordingLine.duration}
          </Text>
          <Button onPress={() => recordingLine.sound.replayAsync()} title="Play"></Button>
          <Button title="Send Recording to Backend"/>
        </View>
      );
    });
  }

  function clearRecordings() {
    setRecordings([]);
  }

  return (
    <View style={styles.container}>
      <Button title={recording ? 'Stop Recording' : 'Start Recording\n\n\n'} onPress={recording ? stopRecording : startRecording} />
      {getRecordingLines()}
      <Button title={recordings.length > 0 ? 'Clear Recordings' : ''} onPress={clearRecordings} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    marginLeft: 10,
    marginRight: 40
  },
  fill: {
    flex: 1,
    margin: 15
  }
});

socket.js

import { io } from 'socket.io-client';
import * as FileSystem from "expo-file-system";

export const socket = io('URL'); // use the IP address of your machine


const sleep = (ms) => {
  return new Promise((resolve) => setTimeout(resolve, ms));
};


export async function uploadChunksToServer(recordingInstance, chunkSize, delayBetweenChunks) {
  console.log('calling sending');
  await sleep(4000);

  let info = await FileSystem.getInfoAsync(recordingInstance.getURI());
  let uri = info.uri;
  let currentPosition = 0;

  let current_file_size = info.size;
  let prev_pos = 0;

  do{

    try{

      let info = await FileSystem.getInfoAsync(recordingInstance.getURI());
      current_file_size = info.size;

        if (currentPosition + chunkSize >= current_file_size &&  currentPosition === prev_pos && prev_pos !== 0){
          console.log('blocked')
          continue;

        }
        else{
          console.log(currentPosition, current_file_size);
          const fileChunk = await FileSystem.readAsStringAsync(uri, {
              encoding: FileSystem.EncodingType.Base64,
              position: currentPosition,
              length: chunkSize
            })
            currentPosition += chunkSize;
            socket.emit('audioData', fileChunk);
          }
          prev_pos = currentPosition;


    }
    catch (e) {
      console.log(e);
    }
    if (recordingInstance._isDoneRecording && current_file_size - currentPosition < chunkSize){
          const fileChunk = await FileSystem.readAsStringAsync(uri, {
          encoding: FileSystem.EncodingType.Base64,
          position: currentPosition,
          length: current_file_size - currentPosition
        })
        currentPosition += current_file_size - currentPosition;
        socket.emit('audioData', fileChunk);
        break
      }
      await sleep(delayBetweenChunks);

  }


  while(currentPosition < current_file_size)
  console.log("final report >> ", currentPosition, current_file_size)
  console.log('exiting')

   const fileChunk = await FileSystem.readAsStringAsync(uri, {
    encoding: FileSystem.EncodingType.Base64,
  })
  socket.emit('data', fileChunk);

}

© www.soinside.com 2019 - 2024. All rights reserved.