目前因项目需要,接触到有关音频文件的录制,上传,下载,播放等功能,并且遇到过一些不能播放,不能下载等问题。

  一、功能:录音,播放   问题:录音成功之后文件不能播放

#import <AVFoundation/AVFoundation.h>
1、主要使用自带的AVFoundation类库,在.h文件中导入头文件


2、.h 声明

{
    AVAudioSession          *session;
    AVAudioPlayer           *player;
    AVAudioRecorder         *recorder;
}
@property(nonatomic,retain)NSURL            *recordedFile;
@property(nonatomic,retain)AVAudioPlayer    *player;
@property(nonatomic,retain)AVAudioRecorder  *recorder;

3、.m 实现


void)touchDown
 {
    session = [AVAudioSessionsharedInstance];
 //    session.delegate = self;
NSError
    [sessionsetCategory:AVAudioSessionCategoryPlayAndRecorderror:&sessionError];
     
if(session ==nil)
        NSLog(@"Error creating session: %@", [sessionErrordescription]);
else
session setActive:YESerror:nil];
    //录音设置
    NSMutableDictionary *settings = [[NSMutableDictionaryalloc]init];
    //录音格式 无法使用
    [settings setValue :[NSNumbernumberWithInt:kAudioFormatLinearPCM]forKey:AVFormatIDKey];
    //采样率
    [settings setValue :[NSNumbernumberWithFloat:11025.0]forKey:AVSampleRateKey];//44100.0
    //通道数
    [settings setValue :[NSNumbernumberWithInt:2]forKey:AVNumberOfChannelsKey];
    //线性采样位数
    //[recordSettings setValue :[NSNumber numberWithInt:16] forKey: AVLinearPCMBitDepthKey];
    //音频质量,采样质量
    [settings setValue:[NSNumbernumberWithInt:AVAudioQualityMin]forKey:AVEncoderAudioQualityKey];
     
    recorder = [[AVAudioRecorderalloc]initWithURL:self.recordedFilesettings:settingserror:nil];
    recorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES
BOOL isRecording = [recorderisRecording];
NSLog(@"isRecording%i",isRecording);
if
        //首次使用应用时如果调用record方法会询问用户是否允许使用麦克风
        [recorderprepareToRecord];
recorder  record];
//设置定时检测
        _audioTimer = [NSTimerscheduledTimerWithTimeInterval:0target:selfselector:@selector(audioPictureChange)userInfo:nilrepeats:YES];
     }
 
 }


4、将录音文件.mp3文件上传到服务器,所以需要设置录音格式为以上格式,接下来创建录音机。



5、将.caf 文件转成.mp3格式,主要使用三方的.a库 libmp3lame.a 静态库 



void)audio_PCMtoMP3
 {
    NSString *cafFilePath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/downloadFile.caf"];
     
    NSString *mp3FilePath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents/downloadFile.mp3"];
     
    NSFileManager* fileManager=[NSFileManagerdefaultManager];
if([fileManager  removeItemAtPath:mp3FilePath error:nil])
     {
NSLog(@"删除");
     }
@try
int
         
FILE *pcm =  fopen([cafFilePath cStringUsingEncoding:1],"rb"); //source 被转换的音频文件位置
fseek(pcm,  4*1024, SEEK_CUR);                                  //skip file header
FILE *mp3 =  fopen([mp3FilePath cStringUsingEncoding:1],"wb"); //output 输出生成的Mp3文件位置
         
const int PCM_SIZE =8192;
const int MP3_SIZE =8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char
 //        
lame_t lame =  lame_init();
        lame_set_in_samplerate(lame,11025.0);
lame_set_VBR(lame,  vbr_default);
        lame_init_params(lame);
         
do
fread(pcm_buffer,  2*sizeof(shortint), PCM_SIZE, pcm);
if (read ==  0)
lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
             
fwrite(mp3_buffer, write,  1, mp3);
             
while (read !=  0);
         
lame_close(lame);
fclose(mp3);
fclose(pcm);
     }
@catch
NSLog(@"%@",[exceptiondescription]);
     }
      
    @finally {
         
NSError
AVAudioPlayer *audioPlayer = [[AVAudioPlayeralloc]initWithContentsOfURL:[[NSURLalloc]initFileURLWithPath:mp3FilePath]error:&playerError];
self.player
player.volume =1.0f;
if (player ==nil)
         {
NSLog(@"ERror creating player: %@", [playerErrordescription]);
         }
        [[AVAudioSessionsharedInstance]setCategory:AVAudioSessionCategorySoloAmbienterror:nil];
        self.player.meteringEnabled=YES;
player.delegate =self;
         
     }
     
 }



转换完成之后设置播放器,注意,播放器初始化的URL必须是录音文件的URL,保证路径存在录音数据,要不会出现播放器创建失败。



二、功能:上传录音文件  问题:上传文件之后不能播放



NSURLConnection 
 
 
 
  
    NSString * urlString=[NSStringstringWithFormat:@"http://%@%@.shtml",SERVER_IP_ADDRESS,path];
    NSMutableURLRequest* request=[[NSMutableURLRequestalloc]initWithURL:[NSURLURLWithString:urlString]cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheDatatimeoutInterval:0];
    // 设置请求类型为post请求
setHTTPMethod:@"POST"];
    // 设置头部数据,指定了http post请求的编码方式为multipart/form-data(上传文件必须用这个)。
    [request setValue:[NSStringstringWithFormat:@"multipart/form-data; boundary=%@",BOUNDARY]forHTTPHeaderField:@"Content-Type"];
    NSMutableData * body=[NSMutableDatadata];
    /** 遍历字典将字典中的键值对转换成请求格式:
      --Boundary+72D4CD655314C423
      Content-Disposition: form-data; name="empId"
      
      254
      --Boundary+72D4CD655314C423
      Content-Disposition: form-data; name="shopId"
      
      18718
      */
 
  
 //设置请求体内容 遍历字典中的内容 设置成表单上传格式
enumerateKeysAndObjectsUsingBlock:^(id key,id obj,BOOL
        NSMutableString *fieldStr = [NSMutableStringstring];
        [fieldStr appendString:[NSStringstringWithFormat:@"--%@\r\n",BOUNDARY]];
        [fieldStr appendString:[NSStringstringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]];
appendString:[NSStringstringWithFormat:@"%@\r\n", obj]];
appendData:[fieldStr  dataUsingEncoding:NSUTF8StringEncoding]];
        //        NSLog(@"表单数据:%@",fieldStr);
     }];
 
   
 [body appendData:[[NSStringstringWithFormat:@"--%@\r\n",BOUNDARY]dataUsingEncoding:NSUTF8StringEncoding]];
       NSString * contentdis = [NSStringstringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",@"fileMap",@""];
        NSString * contentType = [NSStringstringWithFormat:@"Content-Type: image/jpeg\r\n\r\n" ];
appendData:[contentdis  dataUsingEncoding:NSUTF8StringEncoding]];
appendData:[contentType  dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSStringstringWithFormat:@"\r\n"]dataUsingEncoding:NSUTF8StringEncoding]];
    /**拼装成格式:
      --Boundary+72D4CD655314C423--
      */
    NSString *endString = [NSStringstringWithFormat:@"--%@--\r\n",BOUNDARY];
    [body appendData:[endStringdataUsingEncoding:NSUTF8StringEncoding]];
    // 设置request的请求体
setHTTPBody:body];
NSURLConnection  sendAsynchronousRequest:request queue:[NSOperationQueuemainQueue]completionHandler:^(NSURLResponse *response,NSData *data,NSError
        [SVProgressHUDdismiss];
if (data!=nil) {
            //        NSLog(@"data:%@",data);
NSDictionary *dic = [NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableContainerserror:nil];
             
            //                NSLog(@"dic:%@",response);
nil);
             
else{
nil,connectionError);
         }
        
     }];



三、 从服务器下载录音文件



void)loading:(NSString
 {
    receivedData=[[NSMutableDataalloc]init];
NSString *fileName = [fileUrlString  lastPathComponent];
    NSLog(@"fileName == %@",fileName);
self.Mp3Name=fileName;
NSURL *url =[NSURLURLWithString:fileUrlString];
    //创建NSURLRequest和NSURLConnection,并立即启动连接
    NSURLRequest *request = [[NSURLRequestalloc]initWithURL:urlcachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheDatatimeoutInterval:5.0f];
    NSURLConnection *connection = [[NSURLConnectionalloc]initWithRequest:requestdelegate:selfstartImmediately:YES];
if
     {
self.receivedData = [NSMutableDatadata];//初始化接收数据的缓存
     }
else
     {
        NSLog(@"Bad Connection!");
SHOW_ALERT(@"网络连接失败");
     }
     
 }
 
void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse
 {
    [receivedData  setLength:0];//置空数据
long long mp3Size = [responseexpectedContentLength];//获取要下载的文件的长度
NSLog(@"%lld",mp3Size);
     
 }
 
 //接收NSMutableData数据
void)connection:(NSURLConnection *)connection didReceiveData:(NSData
 {
 //    NSLog(@"下载的data :%@",data);
receivedData  appendData:data];
 }
 
 //接收完毕
void)connectionDidFinishLoading:(NSURLConnection
 {
cancel];
    //在保存文件和播放文件之前可以做一些判断,保证程序的健壮行:例如:文件是否存在,接收的数据是否完整等处理,此处没加,使用时注意
    NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths  objectAtIndex:0];
NSLog(@"mp3 path=%@",documentsDirectory);

    NSString *filePath = [documentsDirectorystringByAppendingPathComponent:self.Mp3Name];//mp3Name:你要保存的文件名称,包括文件类型。如果你知道文件类型的话,可以指定文件类型;如果事先不知道文件类型,可以在- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response中获取要下载的文件类型

  

//在document下创建文件
    NSFileManager *fileManager = [NSFileManagerdefaultManager];
    //    if([fileManager removeItemAtPath:filePath error:nil])
    //    {
    //        NSLog(@"删除");
    //    }
    [fileManager createFileAtPath:filePathcontents:nilattributes:nil];
    NSLog(@"mp3 createFileAtPath path=%@",filePath);
    //将下载的数据,写入文件中
    [receivedDatawriteToFile:filePathatomically:YES];
     
    //播放下载下来的mp3文件
self playVoice:filePath];
     
    //如果下载的是图片则可以用下面的方法生成图片并显示 create image from data and set it to ImageView
/*
      UIImage *image = [[UIImage alloc] initWithData:recvData];
      [imgView setImage:image];
      */
 }


四、下载文件之后,创建播放器,播放下载的文件


#pragma mark  播放录音
void)toPlayAudio:(NSNotification
 {
NSString *filePath=[text.userInfoobjectForKey:@"filePath"];
NSError
    //    NSData *audioData = [NSData dataWithContentsOfURL:[NSURL URLWithString:filePath]];
NSData  *audioData=[NSDatadataWithContentsOfFile:filePathoptions:0error:&error];
    //    NSLog(@"sudioData:%@",audioData);
     
NSError
    //创建音频 播放器
AVAudioPlayer * voicePlayer  = [[AVAudioPlayeralloc]initWithData:audioDataerror:&audiError];
self.chatPlayer
    [chatPlayer  setVolume:1];//设置音量大小
    self.chatPlayer.meteringEnabled=YES;
    self.chatPlayer.delegate=self;
    //显示录音时间
float  cTime=chatPlayer.duration;
int    time=(int)cTime;
if (chatPlayer ==nil)
     {
        NSLog(@"ERror creating player: %@", [audiErrordescription]);
else{
        //If the track is playing, pause and achange playButton text to "Play"
if([chatPlayerisPlaying])
         {
chatPlayer  pause];
if (markFromme) {
                _recordAudioImageV.image=[UIImageimageNamed:@"ic_bubble_normalr(1).png"];
else{
_recordLeftImageV.image=[UIImageimageNamed:@"ic.png"];
             }
         }
        //If the track is not player, play the track and change the play button to "Pause"
else
         {
chatPlayer  prepareToPlay];
chatPlayer  play];
//播放时  打开定时器
//开启定时器
            _chatTimer = [NSTimerscheduledTimerWithTimeInterval:0target:selfselector:@selector(playerPicChange)userInfo:nilrepeats:YES];
_chatTimer  fire];
         }
     }
 }



AVAudioSession 为AVAudioSessionCategoryPlayAndRecord 状态。



2、创建播放器的时候必须保证是已存在录音data数据的路径,或者是完整的录音data数据。[[AVAudioPlayer alloc] initWithData:audioData error:&audiError];



3、表单上传数据要注意表单格式