pic_19_1

●iPhone版
アンドロイドの場合はAudioTrackを使って割と簡単に実現できましたが、iPhoneでは単発でデータを音声にのせて送る例が見当たらず苦労しました。
AudioQueueを使って1byteのデータ('a')を送信しています。
一応動いたコードを載せておきます。

・ViewController.h

#import <UIKit/UIKit.h>
#import "AudioQueueSynth.h"

@interface ViewController : UIViewController {
    AudioQueueSynth *synth;
}
- (IBAction)sendVal:(UIButton *)sender;

@end

・ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    synth = [[AudioQueueSynth alloc]init];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)sendVal:(UIButton *)sender {
    [synth play:'a'];
}
@end

・AudioQueueSynth.h

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

#define SAMPLE_RATE 44100
#define FREQ_LOW 3150
#define FREQ_HIGH 6300
#define BAUD 630

@interface AudioQueueSynth : NSObject {
    
    AudioQueueRef audioQueueObject;
    AudioQueueBufferRef  audBuffer;
    UInt32 numPacketsToRead;
    BOOL isPrepared;
    BOOL isBusy;
    UInt16 cmd;
}

@property UInt32 numPacketsToRead;

-(void)play:(unsigned char)command;
-(void)prepareAudioQueue;
-(void)stop:(BOOL)shouldStopImmediate;

@end

・AudioQueueSynth.m

#import "AudioQueueSynth.h"

@implementation AudioQueueSynth

@synthesize numPacketsToRead;

static void outputCallback(void*                  inUserData,
                           AudioQueueRef           inAQ,
                           AudioQueueBufferRef     inBuffer
						   )
{
    AudioQueueSynth *object = (__bridge AudioQueueSynth *)inUserData;
    [object _audioQueueOutputWithQueue:inAQ];
}

- (void)_audioQueueOutputWithQueue:(AudioQueueRef)inAQ {
    
    UInt32 numPackets = 0;
    SInt16 *output = audBuffer->mAudioData;
	
    //leader
    for (int i = 0; i < 8; i++){
        //data=low
        for (int j = 0; j < FREQ_LOW/BAUD; j++){
            for(int k = 0; k < SAMPLE_RATE/FREQ_LOW; k++){
                output[numPackets] = sin((double)(2*M_PI*FREQ_LOW/SAMPLE_RATE*k))*32767;
                numPackets++;
            }
        }
    }
    //start bit
    for (int j = 0; j < FREQ_HIGH/BAUD; j++){
        for(int k = 0; k < SAMPLE_RATE/FREQ_HIGH; k++){
            output[numPackets] = sin(2*M_PI*FREQ_HIGH/SAMPLE_RATE*k)*32767;
            numPackets++;
        }
    }
    //data
    for(int i = 7; i >=0; i--) {
        if(((1<<i) & cmd) == 0) {   //data=0
            for (int j = 0; j < FREQ_LOW/BAUD; j++){
                for(int k = 0; k < SAMPLE_RATE/FREQ_LOW; k++){
                    output[numPackets] = sin(2*M_PI*FREQ_LOW/SAMPLE_RATE*k)*32767;
                    numPackets++;
                }
            }
        }else{  //data=1
            for (int j = 0; j < FREQ_HIGH/BAUD; j++){
                for(int k = 0; k < SAMPLE_RATE/FREQ_HIGH; k++){
                    output[numPackets] = sin(2*M_PI*FREQ_HIGH/SAMPLE_RATE*k)*32767;
                    numPackets++;
                }
            }
        }
    }
    //stop bit
    for (int j = 0; j < FREQ_HIGH/BAUD; j++){
        for(int k = 0; k < SAMPLE_RATE/FREQ_HIGH; k++){
            output[numPackets] = sin(2*M_PI*FREQ_HIGH/SAMPLE_RATE*k)*32767;
            numPackets++;
        }
    }
    
	audBuffer->mAudioDataByteSize = numPackets * sizeof(SInt16);
    AudioQueueEnqueueBuffer(inAQ, audBuffer, 0, NULL);
    AudioQueueStop(inAQ, NO);
    isBusy = NO;
    isPrepared = NO;
}

-(id)init {
    
    self = [super init];
    isBusy = NO;
	return self;
}


-(void)prepareAudioQueue {
    
    AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate			= 44100.0;
    audioFormat.mFormatID			= kAudioFormatLinearPCM;
    audioFormat.mFormatFlags		= kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    audioFormat.mFramesPerPacket	= 1;
    audioFormat.mChannelsPerFrame	= 1;  //モノラル
    audioFormat.mBitsPerChannel		= 16; //16bit
    audioFormat.mBytesPerPacket		= 2;
    audioFormat.mBytesPerFrame		= 2;
    audioFormat.mReserved			= 0;
    
    AudioQueueNewOutput(&audioFormat,
                        outputCallback,
                        (__bridge void *)(self),
                        NULL,NULL,0,
                        &audioQueueObject);
    
    numPacketsToRead = SAMPLE_RATE/BAUD*(8+1+8+1);
    UInt32 bufferByteSize = numPacketsToRead * audioFormat.mBytesPerPacket;
    
    AudioQueueAllocateBuffer(audioQueueObject,
                                bufferByteSize,
                                &audBuffer);
    outputCallback((__bridge void *)(self),audioQueueObject,audBuffer);
    isPrepared = YES;
}

-(void)play:(unsigned char)command {
    
	if(!isBusy){
		isBusy = YES;
		self->cmd = command;
		if(!isPrepared)[self prepareAudioQueue];
        AudioQueueStart(audioQueueObject, NULL);
	}
}

-(void)stop:(BOOL)shouldStopImmediate {
	
	AudioQueueStop(audioQueueObject, shouldStopImmediate);
	AudioQueueDispose(audioQueueObject, YES);
	audioQueueObject = NULL;
    isBusy = NO;
    isPrepared = NO;
}

-(void)dealloc {
    if(audioQueueObject)
		AudioQueueDispose(audioQueueObject, YES);
}

@end