xcode设计

来源:互联网 发布:android 关闭数据库 编辑:程序博客网 时间:2024/06/08 11:03

// EZOnlineScorerRecorder.m
// EZOnlineScorerRecorder
//
// Created by Johnny on 27/03/2017.
// Copyright © 2017 LLS. All rights reserved.
//

import "EZOnlineScorerRecorder.h"

import "EZAudioSocket.h"

import "EZAudioReader.h"

import

NSString *const kEZOnlineScorerRecorderErrorDomain = @"EZOnlineScorerRecorderError";
NSString *const kEZOnlineScorerRecorderErrorRecorderErrorDescription = @"Audio reader failed to enable audio meter levels.";
NSString *const kEZOnlineScorerRecorderErrorConnectionErrorDescription = @"Audio reader failed to enqueue audio buffers.";
NSString *const kEZOnlineScorerRecorderErrorInvalidParameterDescription = @"Audio reader failed to create the audio file at the designated URL.";
NSString *const kEZOnlineScorerRecorderErrorResponseJSONErrorDescription = @"Audio reader failed to create the audio file at the designated URL.";

static NSError *errorForOnlineScorerErrorCode(EZOnlineScorerRecorderError errorCode, NSError *underlineError) {
NSString *errorDescription;
switch (errorCode) {
case EZOnlineScorerRecorderErrorRecorderError:
errorDescription = kEZOnlineScorerRecorderErrorRecorderErrorDescription;
break;
case EZOnlineScorerRecorderErrorConnectionError:
errorDescription = kEZOnlineScorerRecorderErrorConnectionErrorDescription;
break;
case EZOnlineScorerRecorderErrorInvalidParameter:
errorDescription = kEZOnlineScorerRecorderErrorInvalidParameterDescription;
break;
case EZOnlineScorerRecorderErrorResponseJSONError:
errorDescription = kEZOnlineScorerRecorderErrorResponseJSONErrorDescription;
break;
}

NSMutableDictionary *userInfo = [@{NSLocalizedDescriptionKey: errorDescription} mutableCopy];if (underlineError) {    userInfo[NSUnderlyingErrorKey] = underlineError;}NSError *error = [NSError errorWithDomain:kEZOnlineScorerRecorderErrorDomain                                     code:errorCode                                 userInfo:userInfo];return error;

}

static NSString *md5HexDigest(NSString input) {
const char
str = [input UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(str, (CC_LONG)strlen(str), result);

NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];for(int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {    [ret appendFormat:@"%02x",result[i]];}return ret;

}

@interface EZOnlineScorerRecorder ()

@property (nullable, nonatomic, strong) EZAudioSocket *audioSocket;
@property (nullable, nonatomic, strong) EZAudioReader *audioReader;
@property (readwrite, getter=isProcessing) BOOL processing;
@property (nonnull, readwrite, nonatomic) NSURL *recordURL;

@end

@implementation EZOnlineScorerRecorder {
BOOL _disposal;
}

static NSString *_appID;
static NSString *_secret;
static NSURL *_socketURL;

  • (void)configureAppID:(NSString * _Nonnull)appID secret:(NSString * Nonnull)secret
    {
    static dispatch
    once_t onceToken;
    dispatch_once(&onceToken, {
    _appID = [appID copy];
    _secret = [secret copy];
    });
    }

  • (void)setSocketURL:(NSURL *)recordURL
    {
    socketURL = [socketURL copy];
    }

pragma mark - initializer

  • (instancetype _Nullable)init
    {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException
    reason:@"-init is not a valid initializer for the class Foo"
    userInfo:nil];
    return nil;
    }

  • (instancetype _Nullable)initWithPayload:(id _Nonnull)payload
    {
    return [self initWithPayload:payload useSpeex:YES];
    }

  • (instancetype _Nullable)initWithPayload:(id Nonnull)payload
    useSpeex:(BOOL)useSpeex
    {
    if (!
    appID || !_secret) {
    return nil;
    }

    self = [super init];
    if (self) {
    _payload = [payload jsonPayload];
    _useSpeex = useSpeex;
    }
    return self;
    }

pragma mark - setter & getter

  • (BOOL)isRecording
    {
    return self.audioReader.isRecording;
    }

  • (NSURL *)socketURL
    {
    if (_socketURL) {
    return _socketURL;
    }
    //return default URL
    return [NSURL URLWithString:@"wss://rating.llsstaging.com/openapi/stream/upload"];
    }

pragma mark - Configuring and Controlling Scoring

  • (void)record
    {
    NSString *tempPath = NSTemporaryDirectory();
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL isDir = NO;
    NSError *error = nil;
    if (![fileManager fileExistsAtPath:tempPath isDirectory:&isDir]) {
    NSLog(@"Directory does not exist at dirPath %@", tempPath);
    BOOL success = [fileManager createDirectoryAtPath:tempPath withIntermediateDirectories:YES attributes:nil error:&error];
    if (!success) {
    NSLog(@"=== error: %@", error.debugDescription);
    }
    }
    NSURL *tempDir = [NSURL fileURLWithPath:tempPath isDirectory:YES];
    NSURL *temporaryAudioURL = [tempDir URLByAppendingPathComponent:@"tempScorerRecord.aac" isDirectory:NO];
    [self recordToURL:temporaryAudioURL];
    }

  • (void)recordToURL:(NSURL * Nonnull)fileURL
    {
    if (
    disposal) return;

    NSData *metaData = [self metaData];
    if (!metaData) return;

    self.recordURL = fileURL;
    self.audioSocket = [[EZAudioSocket alloc] initWithSocketURL:self.socketURL metaData:metaData useSpeex:self.useSpeex];
    self.processing = YES;
    self.audioSocket.delegate = self;
    self.audioReader = [[EZAudioReader alloc] init];
    self.audioReader.delegate = self;
    [self.audioReader recordToFileURL:fileURL];
    }

  • (void)stopRecording
    {
    if (_disposal) return;

    if (!self.audioReader || !self.audioReader.isRecording) return;

    [self.audioReader stop];
    }

  • (void)stopScoring
    {
    if (_disposal) return;

    _disposal = YES;
    self.processing = NO;

    [self.audioReader stop];
    [self.audioSocket closeImmediately];
    self.audioReader = nil;
    self.audioSocket = nil;
    }

  • (NSData * _Nullable)metaData
    {
    NSMutableDictionary *payload = [self.payload mutableCopy];
    payload[@"quality"] = self.useSpeex ? @(8) : @(-1);

    //salt
    NSInteger timestamp = (NSInteger)[NSDate date].timeIntervalSince1970;
    NSString *salt = [[NSString alloc] initWithFormat:@"%zd:%08x", timestamp, arc4random()];

    NSDictionary *metaJSON = @{@"item": payload,
    @"appID": _appID,
    @"salt": salt};

    NSError *error = nil;
    NSData *metaJSONData = [NSJSONSerialization dataWithJSONObject:metaJSON options:0 error:&error];
    if (error) {
    [self finishScorerWithErrorCode:EZOnlineScorerRecorderErrorInvalidParameter underlineError:error];
    return nil;
    }

    NSString *metaJSONString = [[NSString alloc] initWithData:metaJSONData encoding:NSUTF8StringEncoding];
    NSString *hash = md5HexDigest([[NSString alloc] initWithFormat:@"%@+%@+%@+%@", _appID, metaJSONString, salt, _secret]);
    NSString *metaString = [[NSString alloc] initWithFormat:@"%@;hash=%@", metaJSONString, hash];

    return [metaString dataUsingEncoding:NSUTF8StringEncoding];
    }

  • (void)finishScorerWithErrorCode:(EZOnlineScorerRecorderError)errorCode underlineError:(NSError * Nullable)error
    {
    if (
    disposal) return;

    [self stopScoring];

    if ([self.delegate respondsToSelector:@selector(onlineScorer:didFailWithError:)]) {
    [self.delegate onlineScorer:self didFailWithError:errorForOnlineScorerErrorCode(errorCode, error)];
    }

}

pragma mark - EZAudioSocketDelegate

  • (void)audioSocket:(EZAudioSocket * _Nonnull)audioSocket didReceiveData:(id _Nonnull)data
    {
    NSLog(@"audioSocket didReceiveData");

    if (_disposal) return;
    self.processing = NO;

    if (![data isKindOfClass:[NSDictionary class]]) {
    [self finishScorerWithErrorCode:EZOnlineScorerRecorderErrorResponseJSONError underlineError:nil];
    return;
    }

    if ([self.delegate respondsToSelector:@selector(onlineScorer:didGenerateReport:)]) {
    [self.delegate onlineScorer:self didGenerateReport:data];
    }

}

  • (void)audioSocket:(EZAudioSocket * _Nonnull)audioSocket didFailWithError:(NSError * _Nullable)error
    {
    NSLog(@"audioSocket didFailWithError: %@", error);

    if (_disposal) return;
    self.processing = NO;

    if ([self.delegate respondsToSelector:@selector(onlineScorer:didFailWithError:)]) {
    [self.delegate onlineScorer:self didFailWithError:errorForOnlineScorerErrorCode(EZOnlineScorerRecorderErrorConnectionError, error)];
    }
    }

pragma mark - EZAudioReaderDelegate

  • (void)audioReader:(EZAudioReader * _Nonnull)reader didFailWithError:(NSError * _Nonnull)error
    {
    NSLog(@"audioReader didFailWithError: %@", error);

    if (_disposal) return;

    [self finishScorerWithErrorCode:EZOnlineScorerRecorderErrorRecorderError underlineError:error];
    }

  • (void)audioReaderDidBeginReading:(EZAudioReader * _Nonnull)reader
    {
    NSLog(@"audioReaderDidBeginReading");

    if (_disposal) return;

    if ([self.delegate respondsToSelector:@selector(onlineScorerDidBeginReading:)]) {
    [self.delegate onlineScorerDidBeginReading:self];
    }
    }

  • (void)audioReader:(EZAudioReader * Nonnull)reader didVolumnChange:(float)volumn
    {
    if (
    disposal) return;

    if ([self.delegate respondsToSelector:@selector(onlineScorer:didVolumnChange:)]) {
    [self.delegate onlineScorer:self didVolumnChange:volumn];
    }
    }

  • (void)audioReader:(EZAudioReader * _Nonnull)reader didReceiveAudioData:(NSData * Nonnull)audioData
    {
    if (
    disposal) return;

    NSError *error;
    if (![self.audioSocket write:audioData error:&error]) {

  •     [self finishScorerWithErrorCode:EZOnlineScorerRecorderErrorConnectionError underlineError:error];

    }
    if ([self.delegate respondsToSelector:@selector(onlineScorer:didReceiveAudioData:)]) {
    [self.delegate onlineScorer:self didReceiveAudioData:audioData];
    }
    }

  • (void)engzoAudioRecorderDidStop:(EZAudioReader * _Nonnull)reader
    {
    NSLog(@"engzoAudioRecorderDidStop");

    if (_disposal) return;

    [self.audioSocket close];
    if ([self.delegate respondsToSelector:@selector(onlineScorerDidStop:)]) {
    [self.delegate onlineScorerDidStop:self];
    }
    }

@end

0 0
原创粉丝点击