I'm working on a React Native mobile radio application (testing on Android API 28 as target and 26 as check, both emulator and physical device), and the idea is to enable the radio channel host to talk into the phone microphone and have that audio overlayed on the radio music.
I'm using IceCast 2 and Liquidsoap to (successfully) stream music to the listeners, and mix in a microphone stream (liquidsoap input.harbor, at URL:PORT/ICECAST_ENDPOINT) which I am currently able to stream microphone to using butt.
Now my question is how to capture mic input from the mobile device and then stream it to the same URL endpoint from the React Native app?
I've tried using react-native-microphone-stream, but the listener lambda is never called:
import React, { useState, useEffect } from 'react';
import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import MicStream from 'react-native-microphone-stream';
/**
* STYLING
*/
const styles = StyleSheet.create({
container: {
flex: 0.1,
height: 5,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
paddingVertical: 4,
paddingHorizontal: 16,
backgroundColor: 'black',
paddingHorizontal: 32,
},
autoFadeButton: {
color: 'white',
textAlignVertical: 'center',
alignSelf: 'center',
},
microphoneButton: {
flexDirection: 'row',
color: '#B52C55',
},
});
/**
* Navigational function for choosing the channel and searching for new channels
*/
export default function ActionBar() {
const [auto, setAuto] = useState(false);
const [recording, setRecording] = useState(false);
const listener = MicStream.addListener((data) => console.log('data', data)); // This never occurs
MicStream.init({
bufferSize: 4096,
sampleRate: 44100,
bitsPerChannel: 16,
channelsPerFrame: 1,
});
function toggleRecord() {
if (recording) {
console.log('starting mic');
MicStream.start();
} else {
console.log('stopping mic');
MicStream.stop();
}
}
useEffect(() => {
return () => listener.remove();
}, []);
useEffect(() => {
toggleRecord();
}, [recording]);
return (
<View style={styles.container}><TouchableOpacity onPress={() => setAuto(!auto)}><Text style={styles.autoFadeButton}>Auto.</Text></TouchableOpacity><TouchableOpacity
style={styles.microphoneButtonBroadcasting}
onPress={() => setRecording(!recording)}><Icon
name="microphone-outline"
size={40}
color={recording ? '#B52C55' : 'grey'}
/></TouchableOpacity><TouchableOpacity><Icon
style={[{ transform: [{ scaleX: 2 }, { scaleY: 0.8 }] }]}
name="chevron-down"
size={40}
color="white"
/></TouchableOpacity></View>
);
}