Record audio to NSData
Asked Answered
S

3

5

I have set up a TCP connection between two iPhones and I am able to send NSData packages between the two. I would like to talk into the microphone and get the recording as an NSData object and send this to the other iPhone. I have successfulyl used Audio Queue Services to record audio and play it but I have not managed to get the recording as NSData. I posted a question about converting the recording to NSData when using Audio Queue Services but it has not got me any further.

Therefore I would like to hear if there is any other approach I can take to speak into the microphone of an iPhone and have the input as raw data?

Update:

I need to send the packages continuous while recording. E.g. every second while recording I will send the data recorded during that second.

Strutting answered 13/12, 2011 at 6:6 Comment(0)
M
5

Both Audio Queues and the RemoteIO Audio Unit will give you buffers of raw audio in real-time with fairly low latency. You can take the buffer pointer and the byte length given in each audio callback to create a new block of NSData. RemoteIO will provide the lowest latency, but may require the network messaging to be done outside the callback thread.

Microcline answered 13/12, 2011 at 9:12 Comment(6)
If I understand you correctly I should be able to use my current Audio Queues and in my AudioInputCallback do the following? NSUInteger length = inNumberPacketDescriptions * 2; NSData *packet = [NSData dataWithBytes:inBuffer->mAudioData length:length];. Is that right? I multiply by two because this should be the amount of bytes in each of my packets (this is set in the AudioStreamBasicDescription) According to idevhub.com/exploring-iphone-audio-part-1 EDIT: It seems that I cannot call self in my callback, though.Strutting
Call self outside the audio callback. Set a flag inside the callback, and poll it from the outside that self needs to be called with some data.Microcline
It seems to work now. You don't happen to have an idea how I would play the received data when the data comes continous?Strutting
The data doesn't really come over the network continuously. You need a strategy to deal with network latency jitter and non-synchronous audio sample rates. Those are two large separate questions.Microcline
I guess sending the NSData packets and adding those to a queue for playing is not an option then.Strutting
It is an option, but expect some possible problems, depending on the queue size and other factors.Microcline
G
0

Using AVAudioRecorder like this:

NSURL *filePath = //Your desired path for the file
NSDictionary *settings; //The settings for the recorded file
NSError *error = nil;
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:filePath settings:recordSetting error:&error];
....
[recorder record];
....
[recorder stop];
....

And the retrieve the NSData from the file:

NSData *audioData = [[NSData alloc] initWithContentsOfFile:filePath];

AVAudioRecorder reference, here.

Edit:

In order to retrieve chunks of the recorded audio you could use the subdataWithRange: method in the NSData class. Keep an offset from which you wish to retrieve the bytes. You can have a NSTimer getting fired every second so you can collect the bytes and send them. You will need to find out how many bytes are getting recorded every second.

Gildea answered 13/12, 2011 at 6:57 Comment(1)
I need to send the packages continuous while recording. E.g. every second while recording I will send the data recorded during that second. Will that be possible with the solution you mention? I'm sorry that I didn't clarify that in my question.Strutting
N
0

This is what I did on the recording iphone:

void AudioInputCallback(void * inUserData,
                    AudioQueueRef inAQ,
                    AudioQueueBufferRef inBuffer,
                    const AudioTimeStamp * inStartTime,
                    UInt32 inNumberPacketDescriptions,
                    const AudioStreamPacketDescription * inPacketDescs)
{
RecordState * recordState = (RecordState*)inUserData;
if (!recordState->recording)
{
    printf("Not recording, returning\n");
}

// if (inNumberPacketDescriptions == 0 && recordState->dataFormat.mBytesPerPacket != 0)
// {
//     inNumberPacketDescriptions = inBuffer->mAudioDataByteSize / recordState->dataFormat.mBytesPerPacket;
// }

printf("Writing buffer %lld\n", recordState->currentPacket);

OSStatus status = AudioFileWritePackets(recordState->audioFile,
                                        false,
                                        inBuffer->mAudioDataByteSize,
                                        inPacketDescs,
                                        recordState->currentPacket,
                                        &inNumberPacketDescriptions,
                                        inBuffer->mAudioData);
NSLog(@"DATA = %@",[NSData dataWithBytes:inBuffer->mAudioData length:inBuffer->mAudioDataByteSize]);

[[NSNotificationCenter defaultCenter] postNotificationName:@"Recording" object:[NSData dataWithBytes:inBuffer->mAudioData length:inBuffer->mAudioDataByteSize]];

if (status == 0)
{
    recordState->currentPacket += inNumberPacketDescriptions;
}

AudioQueueEnqueueBuffer(recordState->queue, inBuffer, 0, NULL);
}

I have called upon a notification which help to send data packets to the other iPhone in the network.

But I do not know how to read the data on the other side. I am still trying to figure out how that works. I will surely update once I do that.

Neelon answered 9/9, 2013 at 6:34 Comment(1)
Don't ask question in an answer. Please, edit question, add comment to make problem more clear, but not put an question in an answerHilltop

© 2022 - 2024 — McMap. All rights reserved.