Microphone recording for ios and android using cocos2dx

Hi,

Is there a way to record microphone for iOS and Android in cocos2dx by using same C++ Code?
Or I will have to implement it separately?
Please suggestion any solution for it.

Also I tried to use AVFoundation classes in Cocos2dx project But unable to import But in this case I can implement them for iOS only, right?. any guidelines and tutorials are much appreciated.

Thanks
Chishti

I’m pretty sure you’re going to have to write separate iOS and Android code for this. You’ll be able to use a shared header file between your implementation, but there’s going to be some iOS specific and Android specific code under the hood.

Take a look at how SimpleAudioEngine was done as a template. You could follow this pattern of how they set it up for both platforms and create your own SimpleRecordEngine, or something like that.

AVFoundation will only work for the iOS side, correct. For the Android side, I believe you’ll have to use android.media.MediaRecorder.

Could you guide me a bit to create this engine? Have I to make SimpleRecordEngine.h and SimpleRecordEngine.mm files? to call the individual functionality or what?

thanks for reply

For iOS, you would need 4 files. One of the files would get reused with the Android version.

You could try something like this:

SimpleAudioRecordEngine.h (this would be the file shared between platforms):

#ifndef __SIMPLE_AUDIO_RECORD_ENGINE_H__
#define __SIMPLE_AUDIO_RECORD_ENGINE_H__

#include "Export.h"

namespace CocosDenshion
{
    
class EXPORT_DLL SimpleAudioRecordEngine
{
public:
    static SimpleAudioRecordEngine *getInstance();
    
protected:
    SimpleAudioRecordEngine();
    virtual ~SimpleAudioRecordEngine();
    
public:
    virtual bool checkMic();
    virtual bool isRecording();
    virtual void initRecord(const char *fileName);
    virtual void startRecord();
    virtual void stopRecord();
};
    
}

iOS specific files:

SimpleAudioRecordEngine.mm

#include "SimpleAudioRecordEngine.h"
#include "SimpleAudioRecordEngine_objc.h"
#include "cocos2d.h"

USING_NS_CC;

static bool static_checkMic()
{
    return [[SimpleAudioRecordEngine sharedEngine] checkMic];
}

static bool static_isRecording()
{
    return [[SimpleAudioRecordEngine sharedEngine] isRecording];
}

static void static_initRecord(const char *fileName)
{
    [[SimpleAudioRecordEngine sharedEngine] initRecord:[NSString stringWithUTF8String:fileName]];
}

static void static_startRecord()
{
    [[SimpleAudioRecordEngine sharedEngine] startRecord];
}

static void static_stopRecord()
{
    [[SimpleAudioRecordEngine sharedEngine] stopRecord];
}

namespace CocosDenshion
{

    static SimpleAudioRecordEngine *s_pEngine;
    
    SimpleAudioRecordEngine::SimpleAudioRecordEngine()
    {
        
    }
    
    SimpleAudioRecordEngine::~SimpleAudioRecordEngine()
    {
        
    }

    SimpleAudioRecordEngine *SimpleAudioRecordEngine::getInstance()
    {
        if (!s_pEngine)
        {
            s_pEngine = new SimpleAudioRecordEngine();
        }
        
        return s_pEngine;
    }
    
    bool SimpleAudioRecordEngine::checkMic()
    {
        return static_checkMic();
    }
    
    bool SimpleAudioRecordEngine::isRecording()
    {
        return static_isRecording();
    }
    
    void SimpleAudioRecordEngine::initRecord(const char *fileName)
    {
        std::string fullPath = FileUtils::getInstance()->fullPathForFilename(fileName);
        static_initRecord(fullPath.c_str());
    }
    
    void SimpleAudioRecordEngine::startRecord()
    {
        static_startRecord();
    }
    
    void SimpleAudioRecordEngine::stopRecord()
    {
        static_stopRecord();
    }
    
}

SimpleAudioRecordEngine_objc.h

#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>

@interface SimpleAudioRecordEngine : NSObject <AVAudioRecorderDelegate>
{
    AVAudioRecorder *_recorder;
    AVAudioSession *_audioSession;
    
    NSString *_documentsPath;
}

@property (nonatomic, retain) AVAudioRecorder *recorder;

+ (SimpleAudioRecordEngine *)sharedEngine;

- (BOOL)checkMic;
- (BOOL)isRecording;

- (void)initRecord:(NSString *)fileName;
- (void)startRecord;
- (void)stopRecord;

- (NSString *)documentsPath;

@end

SimpleAudioRecordEngine_objc.m

#import "SimpleAudioRecordEngine_objc.h"
#import "audio/ios/SimpleAudioEngine_objc.h"

@implementation SimpleAudioRecordEngine

@synthesize recorder = _recorder;


static SimpleAudioRecordEngine *sharedEngine = nil;


#pragma mark -
#pragma mark Life Cycle Methods

+ (SimpleAudioRecordEngine *)sharedEngine
{
    @synchronized(self)
    {
        if (!sharedEngine)
            sharedEngine = [[SimpleAudioRecordEngine alloc] init];
    }
    return sharedEngine;
}

+ (id)alloc
{
    @synchronized(self)
    {
        NSAssert(sharedEngine == nil, @"Attempted to allocate a second instance of a singleton");
        return [super alloc];
    }
    return nil;
}

- (id)init
{
    if ((self = [super init]))
    {
        NSError *error = nil;

        _audioSession = [AVAudioSession sharedInstance];
        [_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];

        if (error)
        {
            NSLog(@"1: error: %@", [error localizedDescription]);
        }

        [_audioSession setActive:YES error:&error];

        if (error)
        {
            NSLog(@"2: error: %@", [error localizedDescription]);
        }
    }
    
    return self;
}

- (void)dealloc
{
    [_recorder stop];
    [_recorder release];
    [_documentsPath release];
    [super dealloc];
}


#pragma mark -
#pragma mark Recording Methods

- (BOOL)checkMic
{
    if (_audioSession)
        return _audioSession.inputIsAvailable;
    
    return NO;
}

- (BOOL)isRecording
{
    if (!_recorder)
        return NO;
    
    return _recorder.isRecording;
}

- (void)initRecord:(NSString *)fileName
{
    if (_recorder)
    {
        [_recorder stop];
        [_recorder release];
        _recorder = nil;
    }
    
    NSURL *fileURL = [NSURL fileURLWithPath:[[self documentsPath] stringByAppendingPathComponent:fileName]];
    
    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
                              [NSNumber numberWithFloat: 44100.0],                      AVSampleRateKey,
                              [NSNumber numberWithInt:   kAudioFormatAppleLossless],    AVFormatIDKey,
                              [NSNumber numberWithInt:   16],                           AVEncoderBitRateKey,
                              [NSNumber numberWithInt:   1],                            AVNumberOfChannelsKey,
                              [NSNumber numberWithInt:   AVAudioQualityMax],            AVEncoderAudioQualityKey,
                              nil];
    
    NSError *error = nil;

    _recorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:nil];
    _recorder.delegate = self;

    if (error)
    {
        NSLog(@"3: error: %@", [error localizedDescription]);
    }
}

- (void)startRecord
{
    if (_recorder)
    {
        if ([_recorder record])
        {
            NSLog(@"Success recording!");
        }
        else
        {
            NSLog(@"Fail recording!");
        }
    }
}

- (void)stopRecord
{
    [_recorder stop];
}

- (NSString *)documentsPath
{
    if (!_documentsPath)
    {
        NSArray *searchPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        _documentsPath = [searchPath objectAtIndex:0];
        [_documentsPath retain];
    }
    
    return _documentsPath;
}


#pragma mark -
#pragma mark Audio Recording Delegate Methods

- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{

}

@end

NOTE: this hasn’t been thoroughly tested, but seems to record audio successfully.

I haven’t looked into writing the Android side yet, and probably won’t get around to it for a while. But I think you should have enough to start with. I highly recommend looking at the existing platform specific class implementations, like SimpleAudioEngine, to see how to create your own.

Hi,

has anybody managed to record sound for Android?

Hi @krisbbus,

I have created record functionality for Android using java methods. Here is reference link:


Regards,
Gurudath

Thanks @Gurudath, my problem now is how to call a non-static method from c++, I have found some posts but none was successful, any ideas?

Regards
Christos

@krisbbus,

For non static method we need to call by using object.
Here is sample code:

 cocos2d::JniMethodInfo methodInfo;
        if(! cocos2d::JniHelper::getMethodInfo(methodInfo,"org/cocos2dx/cpp/AppActivity","stopRecording", "()V"))
        {
            return;
        }
        jclass cls = methodInfo.env->FindClass("org/cocos2dx/cpp/AppActivity");
        jobject obj = methodInfo.env->AllocObject(cls);
        methodInfo.env->CallVoidMethod(obj, methodInfo.methodID);
        methodInfo.env->DeleteLocalRef(obj);  

Regards,
Gurudath