मुझे ब्राउज़र पर पीसीएम ऑडियो चलाने में कुछ समस्याएँ आई हैं। पीसीएम ऑडियो udp-प्रोटोकॉल के साथ एक एंड्रॉइड डिवाइस से आता है और सर्वर पर *.raw . के रूप में सहेजा जाता है

मैं webaudioapi की मदद से इस सहेजी गई फ़ाइल को चलाने का असफल प्रयास कर रहा हूँ। निम्नलिखित कोड का उपयोग करते हुए, मुझे सफेद शोर के साथ कुछ खौफनाक ध्वनि बजाता है:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
audioCtx.sampleRate = 16000;


// Stereo
var channels = 1;
// Create an empty two second stereo buffer at the
// sample rate of the AudioContext
var frameCount = audioCtx.sampleRate * 10.0;

var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, audioCtx.sampleRate);


var req = new XMLHttpRequest();
req.open('GET', "example.raw", false);
req.overrideMimeType('text\/plain; charset=x-user-defined');
req.send(null);

function play(){
    for (var channel = 0; channel < channels; channel++) {

        var nowBuffering = myAudioBuffer.getChannelData(channel,16,16000);
        for (var i = 0; i < frameCount; i++) {
            // audio needs to be in [-1.0; 1.0]
            // for this reason I also tried to divide it by 32767
            // as my pcm sample is in 16-Bit. It plays still the
            // same creepy sound less noisy.
            nowBuffering[i] = (req.responseText.charCodeAt(i) & 0xff;

        }
    }
    // Get an AudioBufferSourceNode.
    // This is the AudioNode to use when we want to play an AudioBuffer
    var source = audioCtx.createBufferSource();
    // set the buffer in the AudioBufferSourceNode
    source.buffer = myAudioBuffer;
    // connect the AudioBufferSourceNode to the
    // destination so we can hear the sound
    source.connect(audioCtx.destination);
    // start the source playing
    source.start();
}

यह एक ऐसी अज्ञात ध्वनि बजा रहा है कि मुझे यकीन नहीं है कि यह पीसीएम फ़ाइल चला रहा है जो मुझे लगता है कि इसे करना है।

मुझे लगता है कि इसे पीसीएम फ़ाइल के साथ कुछ करना है। पीसीएम फ़ाइल में 16 kHz नमूना दर, प्रति नमूना 16 बिट और केवल एक चैनल या मोनो-चैनल है।

किसी को भी यहां एक ही समस्या है या किसी के पास मेरी समस्या को ठीक करने के लिए सुझाव हैं?

मैं समाधान के लिए कुछ दिनों से देख रहा हूं और किसी भी मदद की सराहना करता हूं।

7
Sercan Savran 21 अप्रैल 2017, 23:26

2 जवाब

सबसे बढ़िया उत्तर

सबसे पहले:

audioCtx.sampleRate = 16000; काम नहीं करता। आप audioCtx.sampleRate को संशोधित नहीं कर सकते। इसके बजाय, आपको निम्न कार्य करने की आवश्यकता है:

var frameCount = req.responseText.length / 2;
var myAudioBuffer = audioCtx.createBuffer(channels, frameCount, 16000);

क्योंकि आपकी फ़ाइल 16-बिट है, इसकी बाइट्स में लंबाई आपके लिए आवश्यक फ़्रेमों की संख्या से दोगुनी है।

(req.responseText.charCodeAt(i) & 0xff) 0 और 255 के बीच एक मान देगा, जो एक 8-बिट बाइट का प्रतिनिधित्व करता है। आपको 16 बिट्स चाहिए।

आपको अपने नमूने के बाइट क्रम को जानना होगा, और हर बार दो बाइट्स को संसाधित करना होगा

लिटिल एंडियन (LSB फर्स्ट) के लिए:

var word = (req.responseText.charCodeAt(i * 2) & 0xff) + ((req.responseText.charCodeAt(i * 2 + 1) & 0xff) << 8);

बड़े एंडियन के लिए (MSB पहले):

var unsignedWord = ((req.responseText.charCodeAt(i * 2) & 0xff) << 8) + (req.responseText.charCodeAt(i * 2 + 1) & 0xff);

यह एक अहस्ताक्षरित 16-बिट पूर्णांक का प्रतिनिधित्व करते हुए, 0 और 65535 के बीच एक संख्या देगा। हस्ताक्षरित पूर्णांक में बदलने के लिए, आपको निम्नलिखित करने की आवश्यकता है (X को उपरोक्त कोड से बदलें)

var signedWord = (unsignedWord + 32768) % 65536 - 32768;

यह -32768 और 32767 के बीच एक संख्या देगा, जिसे आप अपना वांछित परिणाम प्राप्त करने के लिए 32768.0 से विभाजित कर सकते हैं।

nowBuffering[i] = signedWord / 32768.0;

संपादित करें: कार्य उदाहरण https://o.lgm.cl/example.html (16-बिट एलएसबी)

11
Locoluis 22 अप्रैल 2017, 19:35
मैंने Javacv के FfmpegGrabber का उपयोग करके आरटीएसपी स्ट्रीम से ऑडियो पकड़ा, पकड़े गए सॉकेट को वेब पेज पर धक्का दिया, और ऑडियो चलाने में सफल होने के लिए आपके द्वारा प्रदान किए गए उदाहरण का संदर्भ लें। उदाहरण वास्तव में सहायक है।
 – 
SalutonMondo
6 जुलाई 2019, 16:23

@Locolois

मैंने आपके सुझाव/समाधान की कोशिश की और कुछ स्पष्ट आवाज़ें प्राप्त कीं, जो दुर्भाग्य से अभी भी मूल की तरह नहीं थी। इसमें हर सेकेंड सफेद शोर भी होता है, जो मेरे समाधान से कम डरावना था: डी लेकिन मैंने अभी भी अपनी आवाज नहीं सुनी जिसे मैंने रिकॉर्ड किया था। मुझे यकीन नहीं है कि पीसीएम, जो android.audiorecord निर्यात बड़ा या छोटा एंडियन है, इसलिए मैंने दोनों तरीकों की कोशिश की। लेकिन बड़े एंडियन के लिए आपके द्वारा दिए गए सुझाव का उपयोग करके मैंने जो ध्वनि सुनी, वह मेरे लिए छोटे एंडियन संस्करण की तुलना में अधिक सही थी। छोटा एंडियन संस्करण भी पूरी तरह से सफेद शोर के साथ था।

क्या यह आपके स्पष्टीकरण का सही कार्यान्वयन है ?:

for (var i = 0; i < frameCount; i+=2) {     
    var msbFirst = (req.responseText.charCodeAt(i) & 0xff) + (req.responseText.charCodeAt(i + 1) & 0xff) << 8;
    var msbSigned = (msbFirst + 32768) % 65536 - 32768;
    nowBuffering[i] =  msbSigned / 65536.0;
}
0
ric 4 पद 2018, 23:35
मेरे समाधान में त्रुटि थी। मैंने एक फिक्स सबमिट किया और एक उदाहरण जोड़ा।
 – 
Locoluis
22 अप्रैल 2017, 01:17
मैं इसे आपके उदाहरण के साथ आजमाता हूं। यह अभी भी काम नहीं करता... :/ क्या आप अपने उदाहरण के साथ इस कच्चे को खेलने की कोशिश कर सकते हैं? taxameter.esy.es/example.raw
 – 
Sercan Savran
22 अप्रैल 2017, 16:00
ठीक है, मुझे यह सब गलत लगा, हर दूसरे फ्रेम की आपूर्ति। मेरे उदाहरणों ने काम किया क्योंकि उनके पास सहज डेटा था। मैंने जवाब और कामकाजी उदाहरण अपडेट किया। साथ ही, audioCtx.sampleRate के साथ प्रयोग करने या गड़बड़ करने की बिल्कुल भी आवश्यकता नहीं है।
 – 
Locoluis
22 अप्रैल 2017, 19:40
+4837923749 पहले मुझे लगा कि यह काम नहीं करता (सफारी के साथ कोशिश की)। फ़ायरफ़ॉक्स पर यह एक आकर्षण की तरह काम करता है। बहुत - बहुत धन्यवाद!!! सफ़ारी ने NotSupportedError (DOM अपवाद 9) को फेंक दिया: ऑपरेशन निम्न पंक्ति पर समर्थित नहीं है: var myAudioBuffer = audioCtx.createBuffer (चैनल, फ्रेमकाउंट, 16000); मैं ठीक करने की कोशिश करूंगा और आपको अपना समाधान बताऊंगा। धन्यवाद!
 – 
Sercan Savran
22 अप्रैल 2017, 20:01