2015-01-21 12 views
10

यहां मैं निरंतर रिकॉर्डिंग ऑडियो सिस्टम के लिए कुछ कोड लिखने की कोशिश कर रहा हूं। मैं तब एक निश्चित मात्रा के लिए ऑडियो रिकॉर्ड करने का प्रयास कर रहा हूं जब एक निश्चित आयाम सीमा टूट जाती है।लगातार रिकॉर्डिंग ऑडियो के साथ मेमोरी समस्या

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <string.h> 
#include <time.h> 
#include <portaudio.h> 
#include <sndfile.h> 

#define FRAMES_PER_BUFFER (1024) 
#define SAMPLE_SIZE (4) 

typedef struct 
{ 
    uint16_t formatType; 
    uint16_t numberOfChannels; 
    uint32_t sampleRate; 
    float* recordedSamples; 
} AudioData; 

AudioData initAudioData(uint32_t sampleRate, uint16_t channels, int type) 
{ 
    AudioData data; 
    data.formatType = type; 
    data.numberOfChannels = channels; 
    data.sampleRate = sampleRate; 
    return data; 
} 

float avg(float *data) 
{ 
    int elems = sizeof(data)/sizeof(data[0]); 
    float sum = 0; 
    for (int i = 0; i < elems; i++) 
    { 
     sum += fabs(*(data + i)); 
    } 
    return (float) sum/elems; 
} 

int main(void) 
{ 
    AudioData data = initAudioData(44100, 2, paFloat32); 
    PaStream *stream = NULL; 
    PaError err = paNoError; 
    int size = FRAMES_PER_BUFFER * data.numberOfChannels * SAMPLE_SIZE; 
    float *sampleBlock = malloc(size); 
    float *recordedSamples = NULL; 
    time_t talking = 0; 
    time_t silence = 0; 

    if((err = Pa_Initialize())) goto done; 
    PaStreamParameters inputParameters = 
    { 
     .device = Pa_GetDefaultInputDevice(), 
     .channelCount = data.numberOfChannels, 
     .sampleFormat = data.formatType, 
     .suggestedLatency = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice())->defaultHighInputLatency, 
     .hostApiSpecificStreamInfo = NULL 
    }; 
    if((err = Pa_OpenStream(&stream, &inputParameters, NULL, data.sampleRate, FRAMES_PER_BUFFER, paClipOff, NULL, NULL))) goto done; 
    if((err = Pa_StartStream(stream))) goto done; 
    for(int i = 0;;) 
    { 
     err = Pa_ReadStream(stream, sampleBlock, FRAMES_PER_BUFFER); 
     if(avg(sampleBlock) > 0.000550) // talking 
     { 
      printf("You're talking! %d\n", i); 
      i++; 
      time(&talking); 
      recordedSamples = realloc(recordedSamples, size * i); 
      if (recordedSamples) memcpy(recordedSamples + ((i - 1) * size), sampleBlock, size); // problem here writing to memory at i = 16? 
      else free(recordedSamples); 
     } 
     else //silence 
     { 
      double test = difftime(time(&silence), talking); 
      printf("Time diff: %g\n", test); 
      if (test >= 1.5) 
      { 
       // TODO: finish code processing audio snippet 
       talking = 0; 
       free(recordedSamples); // problem freeing memory? 
      } 
     } 
    } 

done: 
    free(sampleBlock); 
    Pa_Terminate(); 
    return err; 
} 

हालांकि, कोड कुछ हद तक जटिल है।

Time diff: 1.4218e+09 
You're talking! 0 
You're talking! 1 
You're talking! 2 
You're talking! 3 
You're talking! 4 
You're talking! 5 
You're talking! 6 
You're talking! 7 
You're talking! 8 
You're talking! 9 
You're talking! 10 
You're talking! 11 
You're talking! 12 
You're talking! 13 
You're talking! 14 
You're talking! 15 
(lldb) 
Xcode समस्या जा रहा है इस लाइन की ओर इशारा करते के साथ

:: कभी-कभी जब मैं Xcode में मेरा कार्यक्रम चलाने के लिए, मैं निम्नलिखित आउटपुट प्राप्त

if (recordedSamples) memcpy(recordedSamples + ((i - 1) * size), sampleBlock, size); // problem here writing to memory at i = 16? 

अन्य बार मैं कोड चलाने के लिए, मैं इस त्रुटि मिलती है :

Time diff: 1.4218e+09 
You're talking! 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 0 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 1 
Time diff: 2 
Time diff: 1.4218e+09 
CTestEnvironment(55085,0x7fff7938e300) malloc: *** error for object 0x10081ea00: pointer being freed was not allocated 
*** set a breakpoint in malloc_error_break to debug 

दोनों त्रुटियां मुझे कुछ भ्रमित कर रही हैं ... कोई सुझाव?

+0

आप का आवंटन नहीं कर रहे हैं 'recordedSamples' लेकिन पुनः आवंटित करने के लिए या कोशिश कर मुक्त यह –

+0

@Lashane कृपया' realloc' प्रलेखन – syb0rg

+0

इस लाइन पढ़ें: 'पूर्णांक elems = sizeof (डेटा)/sizeof (डेटा [0]);' समस्या है कि 'आकार (डेटा)' एक फ्लोट के आकार के बजाय एक सूचक का आकार होगा। सुझाव: int elems = sizeof (float)/sizeof (डेटा [0]); – user3629249

उत्तर

6

आप आवंटित बफर के सीमा से बाहर लिख रहे हैं:

recordedSamples = realloc(recordedSamples, size * i); 
memcpy(recordedSamples + ((i - 1) * size), sampleBlock, size); 

realloc() बाइट्स की एक निश्चित संख्या है, यहाँ size * i आवंटित करता है। परिणामस्वरूप सूचक recordedSamples में संग्रहीत है, जिसमें float* टाइप किया गया है।

memcpy() फिर recordedSamples + ((i - 1) * size पर डेटा लिखने का प्रयास करता है। पॉइंटर अंकगणित का उपयोग उस स्थान को निर्धारित करने के लिए किया जाता है जिसे लिखा जाना चाहिए। चूंकि recordedSamples प्रकार float*, recordedSample + X अंक X फ्लोट मानों (एक्स बाइट्स नहीं) के ऑफसेट पर है।

दूसरे शब्दों में, स्मृति स्थान पर recordedSamples + ((i - 1) * size अंक ((i - 1) * size * sizeof(float) बाइट्स recordedSamples के बाद। यह आम तौर पर आवंटित बफर के अंदर नहीं होता है, क्योंकि फ्लोट एक बाइट से बड़े होते हैं।

इसे ठीक करने के लिए, बड़ा सवाल यह है कि size को बाइट्स या कई फ्लोट्स माना जाता है। यह आपके द्वारा उपयोग किए जा रहे API कार्यों पर निर्भर करता है, मैंने इसे विस्तार से नहीं देखा है।

यदि यह floats की एक संख्या है, तो आप क्योंकि सभी बाइट्स पर काम करते हैं, malloc, realloc और memcpy जैसी बुनियादी स्मृति प्रबंधन कार्यों के लिए कॉल को समायोजित करने के लिए है। malloc(size) के बजाय आप malloc(size * sizeof(float)) पर कॉल करेंगे।

तो size वास्तव में बाइट्स की एक संख्या है, तो यह अधिक recordedSamples एक char* बनाने के लिए तार्किक होगा, या कम से कम memcpy((char*)recordedSamples + ...) की तरह, बाइट ऑफसेट के साथ सूचक अंकगणित करने से पहले यह डाली।

0
// Note: I do not have the portaudio.h and sndfile.h so could not compile/test 


#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <string.h> 
#include <time.h> 

#include "portaudio.h" 
#include "sndfile.h" 

#define FRAMES_PER_BUFFER (1024) 
#define SAMPLE_SIZE  (4) 
#define NUMBER_OF_CHANNELS (2) 
#define SAMPLE_RATE  (44100) 
#define SIZE    (FRAMES_PER_BUFFER * NUMBER_OF_CHANNELS * SAMPLE_SIZE) 

static const int size = SIZE; 

struct AudioData_t 
{ 
    uint16_t formatType; 
    uint16_t numberOfChannels; 
    uint32_t sampleRate; 
    float* recordedSamples; 
}; 


void initAudioData(
    struct AudioData_t *pData, 
    uint32_t sampleRate, 
    uint16_t channels, 
    int type) 
{ 
    (*pData).formatType = type; 
    (*pData).numberOfChannels = channels; 
    (*pData).sampleRate = sampleRate; 
} // end function: initAudioData 


float averageAudioLevel(float *data) 
{ 
    int elems = size/sizeof(float); // <-- 
    float sum = 0; 

    for (int i = 0; i < elems; i++) 
    { 
     sum += fabs(*(data + i)); 
    } 
    return sum/elems; // sum is float so result is float 
} // end function: averageAudioLevel 


int main(void) 
{ 
    struct AudioData_t data; 
    initAudioData(&data, SAMPLE_RATE, NUMBER_OF_CHANNELS, paFloat32); 

    PaStream *stream = NULL; 
    PaError err = paNoError; 


    float *sampleBlock = NULL; 

    if(NULL == (sampleBlock = malloc(size))) 
    { // then, malloc failed 
     perror("malloc failed"); 
     exit(EXIT_FAILURE); 
    } 

    // implied else, malloc successful 

    float *recordedSamples = NULL; 

    time_t talking = 0; 
    time_t silence = 0; 

    if(0 == (err = Pa_Initialize())) 
    { // then init successful 

     PaStreamParameters inputParameters = 
     { 
      .device = Pa_GetDefaultInputDevice(), 
      .channelCount = data.numberOfChannels, 
      .sampleFormat = data.formatType, 
      .suggestedLatency = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice())->defaultHighInputLatency, 
      .hostApiSpecificStreamInfo = NULL 
     }; 

     // if err >0, exit 
     if(0 == (err = Pa_OpenStream(&stream, &inputParameters, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff, NULL, NULL))) 
     { // then success 
      if(0 == (err = Pa_StartStream(stream))) 
      { // then success 

       int i = 0; 
       while(1) // this loop never exits 
       { 
        talking = 0; 
        if(0 == (err = Pa_ReadStream(stream, sampleBlock, FRAMES_PER_BUFFER))) 
        { 
         if(averageAudioLevel(sampleBlock) > 0.000550) // talking 
         { 
          printf("You're talking! %d\n", i); 

          i++; // counting usable audio samples 

          if(!talking) {talking = time(NULL);} // only do once per audio sample 

          // increase allocation for another audio sample (starts at 0 allocated) 
          float *temp; 
          if(NULL == (temp = realloc(recordedSamples, size * i)) 
          { // then realloc failed 
           perror(""realloc failed" "); 
           free(sampleBlock); 
           free(recordedSamples); 
           exit(EXIT_FAILURE); 
          } 

          // implied else, realloc successful 

          // update the actual allocated memory pointer 
          recordedSamples = temp; 

          // save the new sample into array of samples 
          memcpy(recordedSamples + ((i - 1) * size), sampleBlock, size);} 
         } // end if 
        } 

        else //silence 
        { 
         if(0 < i) 
         { // then some samples to evaluate 

          double elapsedTime = difftime(time(NULL), talking); 
          printf("Time diff: %g\n", elapsedTime); 

          if (elapsedTime >= 1.5) 
          { 
           // TODO: finish code processing audio snippet 

           // reset time indicators so do not process silence unless proceed by audio sound 
           talking = 0; 

           // reset audio sample counter 
           i = 0; 

           // dispose of recorded samples 
           free(recordedSamples); 

           // prep for next recording 
           recordedSamples = NULL; 
          } // end if 
         } // end if 
        } // end if 
       } // end forever loop 
      } // end if 
     } // end if 
    } // end if 


    free(sampleBlock); 
    free(recordedSamples); 
    Pa_Terminate(); 
    return err; 
} // end function: main 
+0

यह प्रश्न में निर्दिष्ट समस्याओं का कारण नहीं बन रहा है। साथ ही, कंपाइलर 'रिटर्न' मान अनुकूलन का उपयोग करता है ... – syb0rg

+0

आपके संपादन में अभी भी मेरे प्रश्न में वर्णित समस्याओं, साथ ही कुछ वाक्यविन्यास त्रुटियां भी शामिल हैं। – syb0rg

3

कीड़े के इन प्रकार के मंच मतभेद के कारण पुन: बनाने के लिए मुश्किल हैं, तो यह मुझे पता करने के लिए के लिए ठीक यहाँ क्या हो रहा है मुश्किल है, लेकिन मैं अपने कोड के साथ कुछ मुद्दों है कि संभावित कुछ करने के लिए हो सकता है का कहना है जाएगा इसके साथ।

मैंने आपके उपयोग() के उपयोग के साथ कुछ समस्याएं देखी हैं।

ध्यान दें कि नि: शुल्क (PTR) ptr का मूल्य नहीं बदलता है तो अपने उत्तरार्द्ध त्रुटि कॉल की निम्न क्रम की वजह से हो सकता है:

free(recordSamples); 
free(recordSamples); 

इसका कारण यह है कि आप परीक्षण में प्रवेश किया जा सकता है हो रहा हो सकता है > = 1.5 शर्त दो बार, और इसलिए एक डबल मुक्त। इस समस्या को हल करना इतना आसान होना चाहिए:

recordSamples = NULL; 

जब भी आप नि: शुल्क कॉल करते हैं। इस तरह, जब आप दूसरी बार कॉल करते हैं तो पॉइंटर न्यूल होता है और आपको कोई त्रुटि नहीं मिलेगी।

इसी मामले के साथ एक और संभावित मुद्दा यह है कि एक पॉइंटर जिसे मुक्त कर दिया गया है और फिर रीयलोक में पारित किया गया है, वह अनिर्धारित व्यवहार बनाएगा। कार्यान्वयन के आधार पर, यह किसी भी त्रुटि को फेंकने के बिना खुशी से एक अमान्य सूचक लौटा सकता है। यदि ऐसा है, तो यह समझ में आता है कि एक memcpy असफल हो जाएगा, हालांकि स्वीकार्य रूप से मुझे यकीन नहीं है कि यह वास्तव में आपके पहले मामले में हो रहा है या नहीं। यह संभव है कि आपके कुछ आउटपुट को फेंकने से पहले फ्लश नहीं किया गया है, इसलिए हमें त्रुटियों से पहले क्या कहा जा रहा है की पूरी तस्वीर नहीं मिल रही है। इसके लिए एक डीबगर उपयोगी होगा।

मेरी सिफारिश यह सुनिश्चित करने के लिए है कि रिकार्ड नमूने हमेशा एक मुफ्त के बाद NULL पर सेट हो जाते हैं (ऐसा लगता है कि आपके कोड में केवल दो हैं) और देखें कि क्या इससे समस्याएं हल हो जाती हैं। यदि अभी भी समस्याएं हैं, तो मैं वाल्ग्रिंड जैसे टूल का उपयोग करने की सलाह देता हूं कि इन स्मृति समस्याओं के कारण क्यों अधिक जानकारी प्राप्त हो रही है।

वालग्रिंड सिस्टम के मॉलोक को प्रतिस्थापित करके और अपने आप से मुक्त काम करता है जिसमें व्यापक मेटाडेटा ट्रैकिंग है। यह अक्सर रिपोर्ट कर सकता है कि ऐसा कुछ क्यों विफल हो सकता है।

http://valgrind.org/

+1

आह, मुझे विश्वास नहीं है कि मैं ऐसा करना भूल गया था। उस गलती को पकड़ने के लिए +1 – syb0rg

संबंधित मुद्दे