0

I want to write a call recorder tweak in iOS (just for personal use and programming skills!). I'm using the code from this link but when the call ends, the phone crashes. By logging, I understood that the problem occurs in the convert() function when it wants to build interleaved stereo buffer. Here is the functions code with a comment showing were it crashes.

void Convert()
{        
    //File URLs
    CFURLRef micUrl = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)kMicFilePath, kCFURLPOSIXPathStyle, false);
    CFURLRef speakerUrl = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)kSpeakerFilePath, kCFURLPOSIXPathStyle, false);
    CFURLRef mixUrl = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)kResultFilePath, kCFURLPOSIXPathStyle, false);

    ExtAudioFileRef micFile = NULL;
    ExtAudioFileRef speakerFile = NULL;
    ExtAudioFileRef mixFile = NULL;

    //Opening input files (speaker and mic)
    ExtAudioFileOpenURL(micUrl, &micFile);
    ExtAudioFileOpenURL(speakerUrl, &speakerFile);

    //Reading input file audio format (mono LPCM)
    AudioStreamBasicDescription inputFormat, outputFormat;
    UInt32 descSize = sizeof(inputFormat);
    ExtAudioFileGetProperty(micFile, kExtAudioFileProperty_FileDataFormat, &descSize, &inputFormat);
    int sampleSize = inputFormat.mBytesPerFrame;

    //Filling input stream format for output file (stereo LPCM)
    FillOutASBDForLPCM(inputFormat, inputFormat.mSampleRate, 2, inputFormat.mBitsPerChannel, inputFormat.mBitsPerChannel, true, false, false);

    //Filling output file audio format (AAC)
    memset(&outputFormat, 0, sizeof(outputFormat));
    outputFormat.mFormatID = kAudioFormatMPEG4AAC;
    outputFormat.mSampleRate = 8000;
    outputFormat.mFormatFlags = kMPEG4Object_AAC_Main;
    outputFormat.mChannelsPerFrame = 2;

    //Opening output file
    ExtAudioFileCreateWithURL(mixUrl, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &mixFile);
    ExtAudioFileSetProperty(mixFile, kExtAudioFileProperty_ClientDataFormat, sizeof(inputFormat), &inputFormat);

    //Freeing URLs
    CFRelease(micUrl);
    CFRelease(speakerUrl);
    CFRelease(mixUrl);

    //Setting up audio buffers
    int bufferSizeInSamples = 64 * 1024;

    AudioBufferList micBuffer;
    micBuffer.mNumberBuffers = 1;
    micBuffer.mBuffers[0].mNumberChannels = 1;
    micBuffer.mBuffers[0].mDataByteSize = sampleSize * bufferSizeInSamples;
    micBuffer.mBuffers[0].mData = malloc(micBuffer.mBuffers[0].mDataByteSize);

    AudioBufferList speakerBuffer;
    speakerBuffer.mNumberBuffers = 1;
    speakerBuffer.mBuffers[0].mNumberChannels = 1;
    speakerBuffer.mBuffers[0].mDataByteSize = sampleSize * bufferSizeInSamples;
    speakerBuffer.mBuffers[0].mData = malloc(speakerBuffer.mBuffers[0].mDataByteSize);

    AudioBufferList mixBuffer;
    mixBuffer.mNumberBuffers = 1;
    mixBuffer.mBuffers[0].mNumberChannels = 2;
    mixBuffer.mBuffers[0].mDataByteSize = sampleSize * bufferSizeInSamples * 2;
    mixBuffer.mBuffers[0].mData = malloc(mixBuffer.mBuffers[0].mDataByteSize);

    //Converting
    while (true)
    {
        //Reading data from input files
        UInt32 framesToRead = bufferSizeInSamples;
        ExtAudioFileRead(micFile, &framesToRead, &micBuffer);
        ExtAudioFileRead(speakerFile, &framesToRead, &speakerBuffer);
        if (framesToRead == 0)
        {
            break;
        }

        //---------------------------------
        //---------------------------------            
        //The iPhone resprings just here!!!
        //---------------------------------
        //---------------------------------

        //Building interleaved stereo buffer - left channel is mic, right - speaker
        for (int i = 0; i < framesToRead; i++)
        {
            memcpy((char*)mixBuffer.mBuffers[0].mData + i * sampleSize * 2, (char*)micBuffer.mBuffers[0].mData + i * sampleSize, sampleSize);
            memcpy((char*)mixBuffer.mBuffers[0].mData + i * sampleSize * 2 + sampleSize, (char*)speakerBuffer.mBuffers[0].mData + i * sampleSize, sampleSize);
        }


        //Writing to output file - LPCM will be converted to AAC
        ExtAudioFileWrite(mixFile, framesToRead, &mixBuffer);
    }


    //Closing files
    ExtAudioFileDispose(micFile);
    ExtAudioFileDispose(speakerFile);
    ExtAudioFileDispose(mixFile);

    //Freeing audio buffers
    free(micBuffer.mBuffers[0].mData);
    free(speakerBuffer.mBuffers[0].mData);
    free(mixBuffer.mBuffers[0].mData);
}

I'm testing on an iPhone 5S.

Community
  • 1
  • 1
user3519705
  • 105
  • 9
  • Not even looking at the code, why it resprings? The code should be inside `mediaserverd` daemon. This daemon may crash, restart or whatever - it doesn't affect the SpringBoard in any way. Are you sure your tweak hooks `mediaserverd` daemon? – creker Apr 26 '14 at 17:45
  • I'm using Bundle filter `com.apple.mediaserverd`. Is it enough or should I do something else too? – user3519705 Apr 26 '14 at 19:21
  • It's enough but it's strange that SpringBoard crashes. `mediaserverd` crashed for me many times, I restarted it manually many times while debugging - no resprings. As for why it crashes. Most obvious would be non existing microphone or audio file. My example doesn't check for errors. If the code fails to open a file and then tries to read it then you get a crash. Check if those files are generated, comment out `convert` function and the code where the files are deleted. – creker Apr 26 '14 at 19:32
  • what I saw was an apple logo just like when we respring so i thought it was a respiring! I have changed it to "crash" in the text. Well when I comment the `Cleanup` and `convert` there are no files actually. I have tested it before. Why is that happening? – user3519705 Apr 26 '14 at 20:29
  • It hard to tell why. The reason why `convert` crashes is there are no files. Why is that I don't know. Put `NSLog` calls in hooked function, check if it's being called, does it runs as it should. Check `ExtAudioFileCreateWithURL` return value to see why the files are not created. – creker Apr 26 '14 at 20:54
  • Thanks for our replies. I tested it again and the files were generated and the hooked function is called; But what happens is that the audio is not clear and it's like some noise (I don't know how to explain). Why is it like that? – user3519705 Apr 27 '14 at 13:59
  • Hm, it never failed for me on iPhone 5S. I can think of one thing - may be there is some other audio components. In my hooked function there is code that checks `unitDescription.componentSubType` value to detect from which audio device samples are - mic or speaker. You can try to save in a file samples from every `unitDescription.componentSubType` and find out which produces correct audio file and from which device (mic or speaker). That's basically how I found those values in my code. If you find different valid values please report back and I will update my answer. – creker Apr 28 '14 at 12:07
  • Thank you. I thought I should do that too. I will report as soon as possible. (Right now the phone does not boot so I'm trying to fix that!) – user3519705 Apr 29 '14 at 20:36

0 Answers0