AppRTCDemo file logging.
Adds logging macros to log logs to a file. Undeletes CircularFileStream for that purpose. BUG= R=jiayl@webrtc.org, pbos@webrtc.org Review URL: https://codereview.webrtc.org/1217473011 . Cr-Commit-Position: refs/heads/master@{#9582}
This commit is contained in:
230
talk/app/webrtc/objc/RTCFileLogger.mm
Normal file
230
talk/app/webrtc/objc/RTCFileLogger.mm
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "RTCFileLogger.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/base/stream.h"
|
||||
|
||||
NSString *const kDefaultLogFileName = @"webrtc.log";
|
||||
NSUInteger const kDefaultMaxFileSize = 10 * 1024 * 1024; // 10MB.
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class CircularFileStreamLogSink : public LogSink {
|
||||
public:
|
||||
// Creates a log sink that writes to the given stream. This log sink takes
|
||||
// ownership of |stream|.
|
||||
CircularFileStreamLogSink(CircularFileStream *stream) {
|
||||
DCHECK(stream);
|
||||
_stream.reset(stream);
|
||||
}
|
||||
|
||||
~CircularFileStreamLogSink() override {}
|
||||
|
||||
void OnLogMessage(const std::string &message) override {
|
||||
if (_stream) {
|
||||
_stream->WriteAll(message.data(), message.size(), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
CircularFileStream *GetStream() { return _stream.get(); }
|
||||
|
||||
private:
|
||||
scoped_ptr<CircularFileStream> _stream;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
@implementation RTCFileLogger {
|
||||
BOOL _hasStarted;
|
||||
NSString *_filePath;
|
||||
NSUInteger _maxFileSize;
|
||||
rtc::scoped_ptr<rtc::CircularFileStreamLogSink> _logSink;
|
||||
}
|
||||
|
||||
@synthesize severity = _severity;
|
||||
|
||||
- (instancetype)init {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(
|
||||
NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirPath = [paths firstObject];
|
||||
NSString *defaultFilePath =
|
||||
[documentsDirPath stringByAppendingPathComponent:kDefaultLogFileName];
|
||||
return [self initWithFilePath:defaultFilePath
|
||||
maxFileSize:kDefaultMaxFileSize];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath
|
||||
maxFileSize:(NSUInteger)maxFileSize {
|
||||
NSParameterAssert(filePath.length);
|
||||
NSParameterAssert(maxFileSize);
|
||||
if (self = [super init]) {
|
||||
_filePath = filePath;
|
||||
_maxFileSize = maxFileSize;
|
||||
_severity = kRTCFileLoggerSeverityInfo;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self stop];
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
if (_hasStarted) {
|
||||
return;
|
||||
}
|
||||
rtc::scoped_ptr<rtc::CircularFileStream> stream;
|
||||
stream.reset(new rtc::CircularFileStream(_maxFileSize));
|
||||
_logSink.reset(new rtc::CircularFileStreamLogSink(stream.release()));
|
||||
int error = 0;
|
||||
if (!_logSink->GetStream()->Open(_filePath.UTF8String, "wb", &error)) {
|
||||
LOG(LS_ERROR) << "Failed to open log file at path: "
|
||||
<< _filePath.UTF8String
|
||||
<< " Error: "
|
||||
<< error;
|
||||
_logSink.reset();
|
||||
return;
|
||||
}
|
||||
// TODO(tkchin): Log thead info on iOS, currently this doesn't do anything.
|
||||
rtc::LogMessage::LogThreads(true);
|
||||
rtc::LogMessage::LogTimestamps(true);
|
||||
rtc::LogMessage::AddLogToStream(_logSink.get(), [self rtcSeverity]);
|
||||
_hasStarted = YES;
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
if (!_hasStarted) {
|
||||
return;
|
||||
}
|
||||
DCHECK(_logSink);
|
||||
rtc::LogMessage::RemoveLogToStream(_logSink.get());
|
||||
_hasStarted = NO;
|
||||
|
||||
// Read the ordered version of the log.
|
||||
NSData *logData = [self reorderedLogData];
|
||||
NSError *error = nil;
|
||||
// Write the ordered version back to disk.
|
||||
if (![logData writeToFile:_filePath
|
||||
options:NSDataWritingAtomic
|
||||
error:&error]) {
|
||||
LOG(LS_ERROR) << "Failed to rewrite log to disk at path: "
|
||||
<< _filePath.UTF8String;
|
||||
if (error) {
|
||||
LOG(LS_ERROR) << "Error: " << error.localizedDescription.UTF8String;
|
||||
}
|
||||
} else {
|
||||
// If we succeeded in writing to disk we don't need to hold on to the
|
||||
// stream anymore.
|
||||
_logSink.reset();
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData *)logData {
|
||||
if (_hasStarted) {
|
||||
return nil;
|
||||
}
|
||||
if (!_logSink.get()) {
|
||||
// If there isn't a previously used stream just return contents of file.
|
||||
return [[self class] contentsOfFileAtPath:_filePath];
|
||||
}
|
||||
return [self reorderedLogData];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
+ (NSData *)contentsOfFileAtPath:(NSString *)path {
|
||||
NSError *error = nil;
|
||||
NSData *contents = [NSData dataWithContentsOfFile:path
|
||||
options:0
|
||||
error:&error];
|
||||
if (error) {
|
||||
LOG(LS_ERROR) << "Failed to read contents of file at path: "
|
||||
<< path.UTF8String
|
||||
<< " Error: "
|
||||
<< error.localizedDescription.UTF8String;
|
||||
return nil;
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
- (NSData *)reorderedLogData {
|
||||
if (_hasStarted || !_logSink.get()) {
|
||||
return nil;
|
||||
}
|
||||
// We have a stream we used for writing in memory and we're not writing. The
|
||||
// stream has a pointer to where the log boundary is so it can reorder the
|
||||
// log correctly. We just need to reopen the file in read mode.
|
||||
int error = 0;
|
||||
rtc::CircularFileStream *stream = _logSink->GetStream();
|
||||
if (!stream->Open(_filePath.UTF8String, "r", &error)) {
|
||||
LOG(LS_ERROR) << "Failed to open log file at path: "
|
||||
<< _filePath.UTF8String
|
||||
<< " Error: "
|
||||
<< error;
|
||||
return nil;
|
||||
}
|
||||
size_t logSize = 0;
|
||||
size_t bytesRead = 0;
|
||||
error = 0;
|
||||
if (!stream->GetSize(&logSize)) {
|
||||
LOG(LS_ERROR) << "Failed to get log file size.";
|
||||
return nil;
|
||||
}
|
||||
// Allocate memory using malloc so we can pass it direcly to NSData without
|
||||
// copying.
|
||||
rtc::scoped_ptr<uint8_t[]> buffer(static_cast<uint8_t*>(malloc(logSize)));
|
||||
if (stream->ReadAll(buffer.get(), logSize, &bytesRead, &error)
|
||||
!= rtc::SR_SUCCESS) {
|
||||
LOG(LS_ERROR) << "Failed to read log file at path: "
|
||||
<< _filePath.UTF8String
|
||||
<< " Error: "
|
||||
<< error;
|
||||
}
|
||||
DCHECK_LE(bytesRead, logSize);
|
||||
// NSData takes ownership of the bytes and frees it on dealloc.
|
||||
return [NSData dataWithBytesNoCopy:buffer.release()
|
||||
length:bytesRead];
|
||||
}
|
||||
|
||||
- (rtc::LoggingSeverity)rtcSeverity {
|
||||
switch (_severity) {
|
||||
case kRTCFileLoggerSeverityVerbose:
|
||||
return rtc::LS_VERBOSE;
|
||||
case kRTCFileLoggerSeverityInfo:
|
||||
return rtc::LS_INFO;
|
||||
case kRTCFileLoggerSeverityWarning:
|
||||
return rtc::LS_WARNING;
|
||||
case kRTCFileLoggerSeverityError:
|
||||
return rtc::LS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
72
talk/app/webrtc/objc/public/RTCFileLogger.h
Normal file
72
talk/app/webrtc/objc/public/RTCFileLogger.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// TODO(tkchin): Move this to a common location.
|
||||
#ifndef NS_DESIGNATED_INITIALIZER
|
||||
#define NS_DESIGNATED_INITIALIZER
|
||||
#endif
|
||||
|
||||
typedef NS_ENUM(NSUInteger, RTCFileLoggerSeverity) {
|
||||
kRTCFileLoggerSeverityVerbose,
|
||||
kRTCFileLoggerSeverityInfo,
|
||||
kRTCFileLoggerSeverityWarning,
|
||||
kRTCFileLoggerSeverityError
|
||||
};
|
||||
|
||||
// This class intercepts WebRTC logs and saves them to a file. The file size
|
||||
// will not exceed the given maximum bytesize. When the maximum bytesize is
|
||||
// reached logs from the beginning and the end are preserved while the middle
|
||||
// section is overwritten instead.
|
||||
// This class is not threadsafe.
|
||||
@interface RTCFileLogger : NSObject
|
||||
|
||||
// The severity level to capture. The default is kRTCFileLoggerSeverityInfo.
|
||||
@property(nonatomic, assign) RTCFileLoggerSeverity severity;
|
||||
|
||||
// Default constructor provides default settings for file path and file size.
|
||||
- (instancetype)init;
|
||||
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath
|
||||
maxFileSize:(NSUInteger)maxFileSize
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
// Starts writing WebRTC logs to file if not already started. Overwrites any
|
||||
// existing file.
|
||||
- (void)start;
|
||||
|
||||
// Stops writing WebRTC logs to file. Rewrites the log file as required to
|
||||
// reorder logs because logs may be disordered due to use of
|
||||
// rtc::CircularFileStream. This method is also called on dealloc.
|
||||
- (void)stop;
|
||||
|
||||
// Returns the current contents of the log file. Returns nil if start has been
|
||||
// called without a stop, or if there is no data.
|
||||
- (NSData *)logData;
|
||||
|
||||
@end
|
1
talk/examples/objc/.clang-format
Symbolic link
1
talk/examples/objc/.clang-format
Symbolic link
@ -0,0 +1 @@
|
||||
../../app/webrtc/objc/.clang-format
|
@ -30,6 +30,7 @@
|
||||
#if defined(WEBRTC_IOS)
|
||||
#import "RTCAVFoundationVideoSource.h"
|
||||
#endif
|
||||
#import "RTCFileLogger.h"
|
||||
#import "RTCICEServer.h"
|
||||
#import "RTCMediaConstraints.h"
|
||||
#import "RTCMediaStream.h"
|
||||
@ -41,6 +42,7 @@
|
||||
#import "ARDAppEngineClient.h"
|
||||
#import "ARDCEODTURNClient.h"
|
||||
#import "ARDJoinResponse.h"
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDMessageResponse.h"
|
||||
#import "ARDSDPUtils.h"
|
||||
#import "ARDSignalingMessage.h"
|
||||
@ -65,7 +67,9 @@ static NSInteger const kARDAppClientErrorSetSDP = -4;
|
||||
static NSInteger const kARDAppClientErrorInvalidClient = -5;
|
||||
static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
|
||||
@implementation ARDAppClient
|
||||
@implementation ARDAppClient {
|
||||
RTCFileLogger *_fileLogger;
|
||||
}
|
||||
|
||||
@synthesize delegate = _delegate;
|
||||
@synthesize state = _state;
|
||||
@ -131,6 +135,8 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
_factory = [[RTCPeerConnectionFactory alloc] init];
|
||||
_messageQueue = [NSMutableArray array];
|
||||
_iceServers = [NSMutableArray arrayWithObject:[self defaultSTUNServer]];
|
||||
_fileLogger = [[RTCFileLogger alloc] init];
|
||||
[_fileLogger start];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@ -156,7 +162,7 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
[_turnClient requestServersWithCompletionHandler:^(NSArray *turnServers,
|
||||
NSError *error) {
|
||||
if (error) {
|
||||
NSLog(@"Error retrieving TURN servers: %@", error);
|
||||
ARDLog("Error retrieving TURN servers: %@", error.localizedDescription);
|
||||
}
|
||||
ARDAppClient *strongSelf = weakSelf;
|
||||
[strongSelf.iceServers addObjectsFromArray:turnServers];
|
||||
@ -175,12 +181,12 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
NSError *joinError =
|
||||
[[strongSelf class] errorForJoinResultType:response.result];
|
||||
if (joinError) {
|
||||
NSLog(@"Failed to join room:%@ on room server.", roomId);
|
||||
ARDLog(@"Failed to join room:%@ on room server.", roomId);
|
||||
[strongSelf disconnect];
|
||||
[strongSelf.delegate appClient:strongSelf didError:joinError];
|
||||
return;
|
||||
}
|
||||
NSLog(@"Joined room:%@ on room server.", roomId);
|
||||
ARDLog(@"Joined room:%@ on room server.", roomId);
|
||||
strongSelf.roomId = response.roomId;
|
||||
strongSelf.clientId = response.clientId;
|
||||
strongSelf.isInitiator = response.isInitiator;
|
||||
@ -272,13 +278,13 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
signalingStateChanged:(RTCSignalingState)stateChanged {
|
||||
NSLog(@"Signaling state changed: %d", stateChanged);
|
||||
ARDLog(@"Signaling state changed: %d", stateChanged);
|
||||
}
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
addedStream:(RTCMediaStream *)stream {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSLog(@"Received %lu video tracks and %lu audio tracks",
|
||||
ARDLog(@"Received %lu video tracks and %lu audio tracks",
|
||||
(unsigned long)stream.videoTracks.count,
|
||||
(unsigned long)stream.audioTracks.count);
|
||||
if (stream.videoTracks.count) {
|
||||
@ -290,17 +296,17 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
removedStream:(RTCMediaStream *)stream {
|
||||
NSLog(@"Stream was removed.");
|
||||
ARDLog(@"Stream was removed.");
|
||||
}
|
||||
|
||||
- (void)peerConnectionOnRenegotiationNeeded:
|
||||
(RTCPeerConnection *)peerConnection {
|
||||
NSLog(@"WARNING: Renegotiation needed but unimplemented.");
|
||||
ARDLog(@"WARNING: Renegotiation needed but unimplemented.");
|
||||
}
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
iceConnectionChanged:(RTCICEConnectionState)newState {
|
||||
NSLog(@"ICE state changed: %d", newState);
|
||||
ARDLog(@"ICE state changed: %d", newState);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_delegate appClient:self didChangeConnectionState:newState];
|
||||
});
|
||||
@ -308,7 +314,7 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
iceGatheringChanged:(RTCICEGatheringState)newState {
|
||||
NSLog(@"ICE gathering state changed: %d", newState);
|
||||
ARDLog(@"ICE gathering state changed: %d", newState);
|
||||
}
|
||||
|
||||
- (void)peerConnection:(RTCPeerConnection *)peerConnection
|
||||
@ -333,7 +339,7 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
error:(NSError *)error {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
NSLog(@"Failed to create session description. Error: %@", error);
|
||||
ARDLog(@"Failed to create session description. Error: %@", error);
|
||||
[self disconnect];
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: @"Failed to create session description.",
|
||||
@ -362,7 +368,7 @@ static NSInteger const kARDAppClientErrorInvalidRoom = -6;
|
||||
didSetSessionDescriptionWithError:(NSError *)error {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
NSLog(@"Failed to set session description. Error: %@", error);
|
||||
ARDLog(@"Failed to set session description. Error: %@", error);
|
||||
[self disconnect];
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: @"Failed to set session description.",
|
||||
|
@ -28,6 +28,7 @@
|
||||
#import "ARDAppEngineClient.h"
|
||||
|
||||
#import "ARDJoinResponse.h"
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDMessageResponse.h"
|
||||
#import "ARDSignalingMessage.h"
|
||||
#import "ARDUtilities.h"
|
||||
@ -57,7 +58,7 @@ static NSInteger const kARDAppEngineClientErrorBadResponse = -1;
|
||||
NSString *urlString =
|
||||
[NSString stringWithFormat:kARDRoomServerJoinFormat, roomId];
|
||||
NSURL *roomURL = [NSURL URLWithString:urlString];
|
||||
NSLog(@"Joining room:%@ on room server.", roomId);
|
||||
ARDLog(@"Joining room:%@ on room server.", roomId);
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL];
|
||||
request.HTTPMethod = @"POST";
|
||||
__weak ARDAppEngineClient *weakSelf = self;
|
||||
@ -101,7 +102,7 @@ static NSInteger const kARDAppEngineClientErrorBadResponse = -1;
|
||||
[NSString stringWithFormat:
|
||||
kARDRoomServerMessageFormat, roomId, clientId];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
NSLog(@"C->RS POST: %@", message);
|
||||
ARDLog(@"C->RS POST: %@", message);
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
request.HTTPMethod = @"POST";
|
||||
request.HTTPBody = data;
|
||||
@ -147,19 +148,19 @@ static NSInteger const kARDAppEngineClientErrorBadResponse = -1;
|
||||
NSError *error = nil;
|
||||
// We want a synchronous request so that we know that we've left the room on
|
||||
// room server before we do any further work.
|
||||
NSLog(@"C->RS: BYE");
|
||||
ARDLog(@"C->RS: BYE");
|
||||
[NSURLConnection sendSynchronousRequest:request
|
||||
returningResponse:&response
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error leaving room %@ on room server: %@",
|
||||
ARDLog(@"Error leaving room %@ on room server: %@",
|
||||
roomId, error.localizedDescription);
|
||||
if (completionHandler) {
|
||||
completionHandler(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSLog(@"Left room:%@ on room server.", roomId);
|
||||
ARDLog(@"Left room:%@ on room server.", roomId);
|
||||
if (completionHandler) {
|
||||
completionHandler(nil);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#import "ARDSDPUtils.h"
|
||||
|
||||
#import "ARDLogging.h"
|
||||
#import "RTCSessionDescription.h"
|
||||
|
||||
@implementation ARDSDPUtils
|
||||
@ -42,7 +43,7 @@
|
||||
NSMutableArray *lines =
|
||||
[NSMutableArray arrayWithArray:
|
||||
[sdpString componentsSeparatedByString:lineSeparator]];
|
||||
int mLineIndex = -1;
|
||||
NSInteger mLineIndex = -1;
|
||||
NSString *codecRtpMap = nil;
|
||||
// a=rtpmap:<payload type> <encoding name>/<clock rate>
|
||||
// [/<encoding parameters>]
|
||||
@ -70,11 +71,11 @@
|
||||
}
|
||||
}
|
||||
if (mLineIndex == -1) {
|
||||
NSLog(@"No m=video line, so can't prefer %@", codec);
|
||||
ARDLog(@"No m=video line, so can't prefer %@", codec);
|
||||
return description;
|
||||
}
|
||||
if (!codecRtpMap) {
|
||||
NSLog(@"No rtpmap for %@", codec);
|
||||
ARDLog(@"No rtpmap for %@", codec);
|
||||
return description;
|
||||
}
|
||||
NSArray *origMLineParts =
|
||||
@ -98,7 +99,7 @@
|
||||
[lines replaceObjectAtIndex:mLineIndex
|
||||
withObject:newMLine];
|
||||
} else {
|
||||
NSLog(@"Wrong SDP media description format: %@", lines[mLineIndex]);
|
||||
ARDLog(@"Wrong SDP media description format: %@", lines[mLineIndex]);
|
||||
}
|
||||
NSString *mangledSdpString = [lines componentsJoinedByString:lineSeparator];
|
||||
return [[RTCSessionDescription alloc] initWithType:description.type
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#import "ARDSignalingMessage.h"
|
||||
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDUtilities.h"
|
||||
#import "RTCICECandidate+JSON.h"
|
||||
#import "RTCSessionDescription+JSON.h"
|
||||
@ -52,7 +53,7 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
|
||||
+ (ARDSignalingMessage *)messageFromJSONString:(NSString *)jsonString {
|
||||
NSDictionary *values = [NSDictionary dictionaryWithJSONString:jsonString];
|
||||
if (!values) {
|
||||
NSLog(@"Error parsing signaling message JSON.");
|
||||
ARDLog(@"Error parsing signaling message JSON.");
|
||||
return nil;
|
||||
}
|
||||
|
||||
@ -71,7 +72,7 @@ static NSString const *kARDSignalingMessageTypeKey = @"type";
|
||||
} else if ([typeString isEqualToString:@"bye"]) {
|
||||
message = [[ARDByeMessage alloc] init];
|
||||
} else {
|
||||
NSLog(@"Unexpected type: %@", typeString);
|
||||
ARDLog(@"Unexpected type: %@", typeString);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#import "ARDWebSocketChannel.h"
|
||||
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDUtilities.h"
|
||||
#import "SRWebSocket.h"
|
||||
|
||||
@ -57,7 +58,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
_delegate = delegate;
|
||||
_socket = [[SRWebSocket alloc] initWithURL:url];
|
||||
_socket.delegate = self;
|
||||
NSLog(@"Opening WebSocket.");
|
||||
ARDLog(@"Opening WebSocket.");
|
||||
[_socket open];
|
||||
}
|
||||
return self;
|
||||
@ -104,12 +105,12 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
NSString *messageString =
|
||||
[[NSString alloc] initWithData:messageJSONObject
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"C->WSS: %@", messageString);
|
||||
ARDLog(@"C->WSS: %@", messageString);
|
||||
[_socket send:messageString];
|
||||
} else {
|
||||
NSString *dataString =
|
||||
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"C->WSS POST: %@", dataString);
|
||||
ARDLog(@"C->WSS POST: %@", dataString);
|
||||
NSString *urlString =
|
||||
[NSString stringWithFormat:@"%@/%@/%@",
|
||||
[_restURL absoluteString], _roomId, _clientId];
|
||||
@ -126,7 +127,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
return;
|
||||
}
|
||||
[_socket close];
|
||||
NSLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
|
||||
ARDLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
|
||||
NSString *urlString =
|
||||
[NSString stringWithFormat:@"%@/%@/%@",
|
||||
[_restURL absoluteString], _roomId, _clientId];
|
||||
@ -140,7 +141,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
#pragma mark - SRWebSocketDelegate
|
||||
|
||||
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
|
||||
NSLog(@"WebSocket connection opened.");
|
||||
ARDLog(@"WebSocket connection opened.");
|
||||
self.state = kARDSignalingChannelStateOpen;
|
||||
if (_roomId.length && _clientId.length) {
|
||||
[self registerWithCollider];
|
||||
@ -154,24 +155,24 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
options:0
|
||||
error:nil];
|
||||
if (![jsonObject isKindOfClass:[NSDictionary class]]) {
|
||||
NSLog(@"Unexpected message: %@", jsonObject);
|
||||
ARDLog(@"Unexpected message: %@", jsonObject);
|
||||
return;
|
||||
}
|
||||
NSDictionary *wssMessage = jsonObject;
|
||||
NSString *errorString = wssMessage[kARDWSSMessageErrorKey];
|
||||
if (errorString.length) {
|
||||
NSLog(@"WSS error: %@", errorString);
|
||||
ARDLog(@"WSS error: %@", errorString);
|
||||
return;
|
||||
}
|
||||
NSString *payload = wssMessage[kARDWSSMessagePayloadKey];
|
||||
ARDSignalingMessage *signalingMessage =
|
||||
[ARDSignalingMessage messageFromJSONString:payload];
|
||||
NSLog(@"WSS->C: %@", payload);
|
||||
ARDLog(@"WSS->C: %@", payload);
|
||||
[_delegate channel:self didReceiveMessage:signalingMessage];
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
|
||||
NSLog(@"WebSocket error: %@", error);
|
||||
ARDLog(@"WebSocket error: %@", error);
|
||||
self.state = kARDSignalingChannelStateError;
|
||||
}
|
||||
|
||||
@ -179,7 +180,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
didCloseWithCode:(NSInteger)code
|
||||
reason:(NSString *)reason
|
||||
wasClean:(BOOL)wasClean {
|
||||
NSLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
|
||||
ARDLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
|
||||
(long)code, reason, wasClean);
|
||||
NSParameterAssert(_state != kARDSignalingChannelStateError);
|
||||
self.state = kARDSignalingChannelStateClosed;
|
||||
@ -204,7 +205,7 @@ static NSString const *kARDWSSMessagePayloadKey = @"msg";
|
||||
error:nil];
|
||||
NSString *messageString =
|
||||
[[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
|
||||
ARDLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
|
||||
// Registration can fail if server rejects it. For example, if the room is
|
||||
// full.
|
||||
[_socket send:messageString];
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#import "RTCICECandidate+JSON.h"
|
||||
|
||||
#import "ARDLogging.h"
|
||||
|
||||
static NSString const *kRTCICECandidateTypeKey = @"type";
|
||||
static NSString const *kRTCICECandidateTypeValue = @"candidate";
|
||||
static NSString const *kRTCICECandidateMidKey = @"id";
|
||||
@ -56,7 +58,7 @@ static NSString const *kRTCICECandidateSdpKey = @"candidate";
|
||||
options:NSJSONWritingPrettyPrinted
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error serializing JSON: %@", error);
|
||||
ARDLog(@"Error serializing JSON: %@", error);
|
||||
return nil;
|
||||
}
|
||||
return data;
|
||||
|
88
talk/examples/objc/AppRTCDemo/common/ARDLogging.h
Normal file
88
talk/examples/objc/AppRTCDemo/common/ARDLogging.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// We route all logging through the WebRTC logger. By doing this we will get
|
||||
// both app and WebRTC logs in the same place, which we can then route to a
|
||||
// file if we need to. A side effect of this is that we get severity for free.
|
||||
typedef NS_ENUM(NSInteger, ARDLogSeverity) {
|
||||
kARDLogSeverityVerbose,
|
||||
kARDLogSeverityInfo,
|
||||
kARDLogSeverityWarning,
|
||||
kARDLogSeverityError,
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" void ARDLogToWebRTCLogger(ARDLogSeverity severity,
|
||||
NSString *logString);
|
||||
extern "C" NSString *ARDFileName(const char *filePath);
|
||||
extern "C" void ARDLogInit();
|
||||
#else
|
||||
// Logs |logString| to the WebRTC logger at the given severity.
|
||||
extern void ARDLogToWebRTCLogger(ARDLogSeverity severity, NSString *logString);
|
||||
// Returns the filename with the path prefix removed.
|
||||
extern NSString *ARDFileName(const char *filePath);
|
||||
// Initializes the correct logging levels. This should be called once on app
|
||||
// startup.
|
||||
extern void ARDLogInit();
|
||||
#endif
|
||||
|
||||
#define ARDLogString(format, ...) \
|
||||
[NSString stringWithFormat:@"(%@:%d %s): " format, \
|
||||
ARDFileName(__FILE__), \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##__VA_ARGS__]
|
||||
|
||||
#define ARDLogEx(severity, format, ...) \
|
||||
do { \
|
||||
NSString *logString = ARDLogString(format, ##__VA_ARGS__); \
|
||||
ARDLogToWebRTCLogger(severity, logString); \
|
||||
} while (false)
|
||||
|
||||
#define ARDLogVerbose(format, ...) \
|
||||
ARDLogEx(kARDLogSeverityVerbose, format, ##__VA_ARGS__) \
|
||||
|
||||
#define ARDLogInfo(format, ...) \
|
||||
ARDLogEx(kARDLogSeverityInfo, format, ##__VA_ARGS__) \
|
||||
|
||||
#define ARDLogWarning(format, ...) \
|
||||
ARDLogEx(kARDLogSeverityWarning, format, ##__VA_ARGS__) \
|
||||
|
||||
#define ARDLogError(format, ...) \
|
||||
ARDLogEx(kARDLogSeverityError, format, ##__VA_ARGS__) \
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define ARDLogDebug(format, ...) ARDLogInfo(format, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ARDLogDebug(format, ...) \
|
||||
do { \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#define ARDLog(format, ...) ARDLogInfo(format, ##__VA_ARGS__)
|
68
talk/examples/objc/AppRTCDemo/common/ARDLogging.mm
Normal file
68
talk/examples/objc/AppRTCDemo/common/ARDLogging.mm
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ARDLogging.h"
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
|
||||
void ARDLogInit() {
|
||||
#ifndef _DEBUG
|
||||
// In debug builds the default level is LS_INFO and in non-debug builds it is
|
||||
// disabled. Continue to log to console in non-debug builds, but only
|
||||
// warnings and errors.
|
||||
rtc::LogMessage::LogToDebug(rtc::LS_WARNING);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ARDLogToWebRTCLogger(ARDLogSeverity severity, NSString *logString) {
|
||||
if (logString.length) {
|
||||
const char* utf8String = logString.UTF8String;
|
||||
switch (severity) {
|
||||
case kARDLogSeverityVerbose:
|
||||
LOG(LS_VERBOSE) << utf8String;
|
||||
break;
|
||||
case kARDLogSeverityInfo:
|
||||
LOG(LS_INFO) << utf8String;
|
||||
break;
|
||||
case kARDLogSeverityWarning:
|
||||
LOG(LS_WARNING) << utf8String;
|
||||
break;
|
||||
case kARDLogSeverityError:
|
||||
LOG(LS_ERROR) << utf8String;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSString *ARDFileName(const char *filePath) {
|
||||
NSString *nsFilePath =
|
||||
[[NSString alloc] initWithBytesNoCopy:const_cast<char *>(filePath)
|
||||
length:strlen(filePath)
|
||||
encoding:NSUTF8StringEncoding
|
||||
freeWhenDone:NO];
|
||||
return nsFilePath.lastPathComponent;
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDUtilities.h"
|
||||
|
||||
@implementation NSDictionary (ARDUtilites)
|
||||
@ -36,7 +37,7 @@
|
||||
NSDictionary *dict =
|
||||
[NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error parsing JSON: %@", error.localizedDescription);
|
||||
ARDLog(@"Error parsing JSON: %@", error.localizedDescription);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
@ -46,7 +47,7 @@
|
||||
NSDictionary *dict =
|
||||
[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Error parsing JSON: %@", error.localizedDescription);
|
||||
ARDLog(@"Error parsing JSON: %@", error.localizedDescription);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
@ -84,7 +85,7 @@
|
||||
NSData *data,
|
||||
NSError *error) {
|
||||
if (error) {
|
||||
NSLog(@"Error posting data: %@", error.localizedDescription);
|
||||
ARDLog(@"Error posting data: %@", error.localizedDescription);
|
||||
if (completionHandler) {
|
||||
completionHandler(NO, data);
|
||||
}
|
||||
@ -95,7 +96,7 @@
|
||||
NSString *serverResponse = data.length > 0 ?
|
||||
[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] :
|
||||
nil;
|
||||
NSLog(@"Received bad response: %@", serverResponse);
|
||||
ARDLog(@"Received bad response: %@", serverResponse);
|
||||
if (completionHandler) {
|
||||
completionHandler(NO, data);
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
|
||||
#import "ARDAppDelegate.h"
|
||||
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDMainViewController.h"
|
||||
#import "RTCPeerConnectionFactory.h"
|
||||
|
||||
@ -43,6 +44,7 @@
|
||||
[_window makeKeyAndVisible];
|
||||
ARDMainViewController *viewController = [[ARDMainViewController alloc] init];
|
||||
_window.rootViewController = viewController;
|
||||
ARDLogInit();
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#import "RTCAVFoundationVideoSource.h"
|
||||
|
||||
#import "ARDAppClient.h"
|
||||
#import "ARDLogging.h"
|
||||
#import "ARDVideoCallView.h"
|
||||
|
||||
@interface ARDVideoCallViewController () <ARDAppClientDelegate,
|
||||
@ -69,13 +70,13 @@
|
||||
didChangeState:(ARDAppClientState)state {
|
||||
switch (state) {
|
||||
case kARDAppClientStateConnected:
|
||||
NSLog(@"Client connected.");
|
||||
ARDLog(@"Client connected.");
|
||||
break;
|
||||
case kARDAppClientStateConnecting:
|
||||
NSLog(@"Client connecting.");
|
||||
ARDLog(@"Client connecting.");
|
||||
break;
|
||||
case kARDAppClientStateDisconnected:
|
||||
NSLog(@"Client disconnected.");
|
||||
ARDLog(@"Client disconnected.");
|
||||
[self hangup];
|
||||
break;
|
||||
}
|
||||
@ -83,7 +84,7 @@
|
||||
|
||||
- (void)appClient:(ARDAppClient *)client
|
||||
didChangeConnectionState:(RTCICEConnectionState)state {
|
||||
NSLog(@"ICE state changed: %d", state);
|
||||
ARDLog(@"ICE state changed: %d", state);
|
||||
__weak ARDVideoCallViewController *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
ARDVideoCallViewController *strongSelf = weakSelf;
|
||||
|
@ -240,6 +240,7 @@
|
||||
'app/webrtc/objc/RTCDataChannel.mm',
|
||||
'app/webrtc/objc/RTCEnumConverter.h',
|
||||
'app/webrtc/objc/RTCEnumConverter.mm',
|
||||
'app/webrtc/objc/RTCFileLogger.mm',
|
||||
'app/webrtc/objc/RTCI420Frame+Internal.h',
|
||||
'app/webrtc/objc/RTCI420Frame.mm',
|
||||
'app/webrtc/objc/RTCICECandidate+Internal.h',
|
||||
@ -280,6 +281,7 @@
|
||||
'app/webrtc/objc/public/RTCAudioSource.h',
|
||||
'app/webrtc/objc/public/RTCAudioTrack.h',
|
||||
'app/webrtc/objc/public/RTCDataChannel.h',
|
||||
'app/webrtc/objc/public/RTCFileLogger.h',
|
||||
'app/webrtc/objc/public/RTCI420Frame.h',
|
||||
'app/webrtc/objc/public/RTCICECandidate.h',
|
||||
'app/webrtc/objc/public/RTCICEServer.h',
|
||||
|
@ -152,9 +152,36 @@
|
||||
|
||||
['OS=="ios" or (OS=="mac" and target_arch!="ia32" and mac_sdk>="10.8")', {
|
||||
'targets': [
|
||||
{ 'target_name': 'apprtc_signaling',
|
||||
{
|
||||
'target_name': 'apprtc_common',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'examples/objc/AppRTCDemo/common/ARDLogging.h',
|
||||
'examples/objc/AppRTCDemo/common/ARDLogging.mm',
|
||||
'examples/objc/AppRTCDemo/common/ARDUtilities.h',
|
||||
'examples/objc/AppRTCDemo/common/ARDUtilities.m',
|
||||
],
|
||||
'include_dirs': [
|
||||
'examples/objc/AppRTCDemo/common',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'examples/objc/AppRTCDemo/common',
|
||||
],
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'xcode_settings': {
|
||||
'MACOSX_DEPLOYMENT_TARGET' : '10.8',
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'apprtc_signaling',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'apprtc_common',
|
||||
'libjingle.gyp:libjingle_peerconnection_objc',
|
||||
'socketrocket',
|
||||
],
|
||||
@ -179,8 +206,6 @@
|
||||
'examples/objc/AppRTCDemo/ARDSignalingMessage.h',
|
||||
'examples/objc/AppRTCDemo/ARDSignalingMessage.m',
|
||||
'examples/objc/AppRTCDemo/ARDTURNClient.h',
|
||||
'examples/objc/AppRTCDemo/ARDUtilities.h',
|
||||
'examples/objc/AppRTCDemo/ARDUtilities.m',
|
||||
'examples/objc/AppRTCDemo/ARDWebSocketChannel.h',
|
||||
'examples/objc/AppRTCDemo/ARDWebSocketChannel.m',
|
||||
'examples/objc/AppRTCDemo/RTCICECandidate+JSON.h',
|
||||
@ -217,6 +242,7 @@
|
||||
'product_name': 'AppRTCDemo',
|
||||
'mac_bundle': 1,
|
||||
'dependencies': [
|
||||
'apprtc_common',
|
||||
'apprtc_signaling',
|
||||
],
|
||||
'conditions': [
|
||||
|
@ -49,6 +49,8 @@ config("nss_config") {
|
||||
|
||||
config("ios_config") {
|
||||
libs = [
|
||||
"CFNetwork.framework",
|
||||
|
||||
#"Foundation.framework", # Already included in //build/config:default_libs.
|
||||
"Security.framework",
|
||||
"SystemConfiguration.framework",
|
||||
|
@ -588,6 +588,7 @@
|
||||
'all_dependent_settings': {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'-framework CFNetwork',
|
||||
'-framework Foundation',
|
||||
'-framework Security',
|
||||
'-framework SystemConfiguration',
|
||||
|
@ -166,10 +166,12 @@ TEST(BitBufferTest, SetOffsetValues) {
|
||||
|
||||
// Disable death test on Android because it relies on fork() and doesn't play
|
||||
// nicely.
|
||||
#if defined(GTEST_HAS_DEATH_TEST)
|
||||
#if !defined(WEBRTC_ANDROID)
|
||||
// Passing a NULL out parameter is death.
|
||||
EXPECT_DEATH(buffer.GetCurrentOffset(&byte_offset, NULL), "");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 GolombEncoded(uint32 val) {
|
||||
|
@ -517,6 +517,113 @@ void FileStream::DoClose() {
|
||||
fclose(file_);
|
||||
}
|
||||
|
||||
CircularFileStream::CircularFileStream(size_t max_size)
|
||||
: max_write_size_(max_size),
|
||||
position_(0),
|
||||
marked_position_(max_size / 2),
|
||||
last_write_position_(0),
|
||||
read_segment_(READ_LATEST),
|
||||
read_segment_available_(0) {
|
||||
}
|
||||
|
||||
bool CircularFileStream::Open(const std::string& filename,
|
||||
const char* mode,
|
||||
int* error) {
|
||||
if (!FileStream::Open(filename.c_str(), mode, error))
|
||||
return false;
|
||||
|
||||
if (strchr(mode, "r") != NULL) { // Opened in read mode.
|
||||
// Check if the buffer has been overwritten and determine how to read the
|
||||
// log in time sequence.
|
||||
size_t file_size;
|
||||
GetSize(&file_size);
|
||||
if (file_size == position_) {
|
||||
// The buffer has not been overwritten yet. Read 0 .. file_size
|
||||
read_segment_ = READ_LATEST;
|
||||
read_segment_available_ = file_size;
|
||||
} else {
|
||||
// The buffer has been over written. There are three segments: The first
|
||||
// one is 0 .. marked_position_, which is the marked earliest log. The
|
||||
// second one is position_ .. file_size, which is the middle log. The
|
||||
// last one is marked_position_ .. position_, which is the latest log.
|
||||
read_segment_ = READ_MARKED;
|
||||
read_segment_available_ = marked_position_;
|
||||
last_write_position_ = position_;
|
||||
}
|
||||
|
||||
// Read from the beginning.
|
||||
position_ = 0;
|
||||
SetPosition(position_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StreamResult CircularFileStream::Read(void* buffer,
|
||||
size_t buffer_len,
|
||||
size_t* read,
|
||||
int* error) {
|
||||
if (read_segment_available_ == 0) {
|
||||
size_t file_size;
|
||||
switch (read_segment_) {
|
||||
case READ_MARKED: // Finished READ_MARKED and start READ_MIDDLE.
|
||||
read_segment_ = READ_MIDDLE;
|
||||
position_ = last_write_position_;
|
||||
SetPosition(position_);
|
||||
GetSize(&file_size);
|
||||
read_segment_available_ = file_size - position_;
|
||||
break;
|
||||
|
||||
case READ_MIDDLE: // Finished READ_MIDDLE and start READ_LATEST.
|
||||
read_segment_ = READ_LATEST;
|
||||
position_ = marked_position_;
|
||||
SetPosition(position_);
|
||||
read_segment_available_ = last_write_position_ - position_;
|
||||
break;
|
||||
|
||||
default: // Finished READ_LATEST and return EOS.
|
||||
return rtc::SR_EOS;
|
||||
}
|
||||
}
|
||||
|
||||
size_t local_read;
|
||||
if (!read)
|
||||
read = &local_read;
|
||||
|
||||
size_t to_read = std::min(buffer_len, read_segment_available_);
|
||||
rtc::StreamResult result =
|
||||
rtc::FileStream::Read(buffer, to_read, read, error);
|
||||
if (result == rtc::SR_SUCCESS) {
|
||||
read_segment_available_ -= *read;
|
||||
position_ += *read;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
StreamResult CircularFileStream::Write(const void* data,
|
||||
size_t data_len,
|
||||
size_t* written,
|
||||
int* error) {
|
||||
if (position_ >= max_write_size_) {
|
||||
ASSERT(position_ == max_write_size_);
|
||||
position_ = marked_position_;
|
||||
SetPosition(position_);
|
||||
}
|
||||
|
||||
size_t local_written;
|
||||
if (!written)
|
||||
written = &local_written;
|
||||
|
||||
size_t to_eof = max_write_size_ - position_;
|
||||
size_t to_write = std::min(data_len, to_eof);
|
||||
rtc::StreamResult result =
|
||||
rtc::FileStream::Write(data, to_write, written, error);
|
||||
if (result == rtc::SR_SUCCESS) {
|
||||
position_ += *written;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryStream
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -418,6 +418,39 @@ class FileStream : public StreamInterface {
|
||||
DISALLOW_COPY_AND_ASSIGN(FileStream);
|
||||
};
|
||||
|
||||
// A stream that caps the output at a certain size, dropping content from the
|
||||
// middle of the logical stream and maintaining equal parts of the start/end of
|
||||
// the logical stream.
|
||||
class CircularFileStream : public FileStream {
|
||||
public:
|
||||
explicit CircularFileStream(size_t max_size);
|
||||
|
||||
bool Open(const std::string& filename, const char* mode, int* error) override;
|
||||
StreamResult Read(void* buffer,
|
||||
size_t buffer_len,
|
||||
size_t* read,
|
||||
int* error) override;
|
||||
StreamResult Write(const void* data,
|
||||
size_t data_len,
|
||||
size_t* written,
|
||||
int* error) override;
|
||||
|
||||
private:
|
||||
enum ReadSegment {
|
||||
READ_MARKED, // Read 0 .. marked_position_
|
||||
READ_MIDDLE, // Read position_ .. file_size
|
||||
READ_LATEST, // Read marked_position_ .. position_ if the buffer was
|
||||
// overwritten or 0 .. position_ otherwise.
|
||||
};
|
||||
|
||||
size_t max_write_size_;
|
||||
size_t position_;
|
||||
size_t marked_position_;
|
||||
size_t last_write_position_;
|
||||
ReadSegment read_segment_;
|
||||
size_t read_segment_available_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryStream is a simple implementation of a StreamInterface over in-memory
|
||||
// data. Data is read and written at the current seek position. Reads return
|
||||
|
@ -8,7 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/fileutils.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/pathutils.h"
|
||||
#include "webrtc/base/stream.h"
|
||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||
|
||||
@ -370,4 +372,162 @@ TEST(FifoBufferTest, WriteOffsetAndReadOffset) {
|
||||
EXPECT_EQ(SR_BLOCK, buf.ReadOffset(out, 10, 16, NULL));
|
||||
}
|
||||
|
||||
class CircularFileStreamTest : public ::testing::Test {
|
||||
protected:
|
||||
static size_t const kMaxSize = 12;
|
||||
|
||||
CircularFileStreamTest() : is_open_(false), stream_(kMaxSize) {
|
||||
Pathname temp_dir;
|
||||
if (Filesystem::GetAppTempFolder(&temp_dir)) {
|
||||
logfile_name_ =
|
||||
Filesystem::TempFilename(temp_dir, "CircularFileStreamTest");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
int error = -1;
|
||||
is_open_ = stream_.Open(logfile_name_, "wb", &error);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (!Filesystem::IsAbsent(logfile_name_)) {
|
||||
Filesystem::DeleteFile(logfile_name_);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_open_;
|
||||
CircularFileStream stream_;
|
||||
std::string logfile_name_;
|
||||
};
|
||||
|
||||
TEST_F(CircularFileStreamTest, ReadWriteWithinCapacity) {
|
||||
EXPECT_TRUE(is_open_);
|
||||
// Write contents.
|
||||
const uint8_t bytes[] = {1, 2, 3, 4, 5, 6};
|
||||
size_t written = 0;
|
||||
int error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS, stream_.Write(bytes, sizeof(bytes), &written, &error));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(written, sizeof(bytes));
|
||||
stream_.Close();
|
||||
|
||||
// Check file contents.
|
||||
uint8_t content_bytes[sizeof(bytes)] = {};
|
||||
scoped_ptr<FileStream> content_stream(
|
||||
Filesystem::OpenFile(logfile_name_, "r"));
|
||||
size_t num_content_bytes_read = 0;
|
||||
EXPECT_TRUE(content_stream);
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS,
|
||||
content_stream->Read(content_bytes, sizeof(content_bytes),
|
||||
&num_content_bytes_read, &error));
|
||||
EXPECT_EQ(sizeof(content_bytes), num_content_bytes_read);
|
||||
ASSERT_EQ(sizeof(content_bytes), sizeof(bytes));
|
||||
EXPECT_EQ(0, memcmp(content_bytes, bytes, sizeof(content_bytes)));
|
||||
|
||||
// Check read result.
|
||||
error = 0;
|
||||
size_t file_size = 0;
|
||||
EXPECT_TRUE(stream_.Open(logfile_name_, "r", &error));
|
||||
EXPECT_TRUE(stream_.GetSize(&file_size));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(sizeof(bytes), file_size);
|
||||
scoped_ptr<uint8_t[]> read_bytes(new uint8_t[file_size]);
|
||||
size_t num_read_bytes = 0;
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS, stream_.ReadAll(read_bytes.get(), file_size,
|
||||
&num_read_bytes, &error));
|
||||
EXPECT_EQ(sizeof(bytes), num_read_bytes);
|
||||
EXPECT_EQ(0, memcmp(bytes, read_bytes.get(), file_size));
|
||||
}
|
||||
|
||||
TEST_F(CircularFileStreamTest, ReadWriteAtCapacity) {
|
||||
EXPECT_TRUE(is_open_);
|
||||
// Write contents.
|
||||
const uint8_t bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
size_t written = 0;
|
||||
int error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS, stream_.Write(bytes, sizeof(bytes), &written, &error));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(written, sizeof(bytes));
|
||||
stream_.Close();
|
||||
|
||||
// Check file contents.
|
||||
uint8_t content_bytes[sizeof(bytes)] = {};
|
||||
scoped_ptr<FileStream> content_stream(
|
||||
Filesystem::OpenFile(logfile_name_, "r"));
|
||||
size_t num_content_bytes_read = 0;
|
||||
EXPECT_TRUE(content_stream);
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS,
|
||||
content_stream->Read(content_bytes, sizeof(content_bytes),
|
||||
&num_content_bytes_read, &error));
|
||||
EXPECT_EQ(sizeof(content_bytes), num_content_bytes_read);
|
||||
ASSERT_EQ(sizeof(content_bytes), sizeof(bytes));
|
||||
EXPECT_EQ(0, memcmp(content_bytes, bytes, sizeof(content_bytes)));
|
||||
|
||||
// Check read result.
|
||||
error = 0;
|
||||
size_t file_size = 0;
|
||||
EXPECT_TRUE(stream_.Open(logfile_name_, "r", &error));
|
||||
EXPECT_TRUE(stream_.GetSize(&file_size));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(sizeof(bytes), file_size);
|
||||
scoped_ptr<uint8_t[]> read_bytes(new uint8_t[file_size]);
|
||||
size_t num_read_bytes = 0;
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS, stream_.ReadAll(read_bytes.get(), file_size,
|
||||
&num_read_bytes, &error));
|
||||
EXPECT_EQ(sizeof(bytes), num_read_bytes);
|
||||
EXPECT_EQ(0, memcmp(bytes, read_bytes.get(), file_size));
|
||||
}
|
||||
|
||||
TEST_F(CircularFileStreamTest, ReadWriteOverCapacity) {
|
||||
EXPECT_TRUE(is_open_);
|
||||
// Write contents.
|
||||
const uint8_t bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
size_t written = 0;
|
||||
int error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS,
|
||||
stream_.WriteAll(bytes, sizeof(bytes), &written, &error));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(written, sizeof(bytes));
|
||||
stream_.Close();
|
||||
|
||||
// Check file contents.
|
||||
uint8_t content_bytes[kMaxSize] = {};
|
||||
scoped_ptr<FileStream> content_stream(
|
||||
Filesystem::OpenFile(logfile_name_, "r"));
|
||||
size_t num_content_bytes_read = 0;
|
||||
EXPECT_TRUE(content_stream);
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS,
|
||||
content_stream->Read(content_bytes, sizeof(content_bytes),
|
||||
&num_content_bytes_read, &error));
|
||||
EXPECT_EQ(sizeof(content_bytes), num_content_bytes_read);
|
||||
const uint8_t expected_content_bytes[] = {
|
||||
1, 2, 3, 4, 5, 6, 13, 14, 15, 10, 11, 12};
|
||||
ASSERT_EQ(sizeof(content_bytes), sizeof(expected_content_bytes));
|
||||
EXPECT_EQ(
|
||||
0, memcmp(expected_content_bytes, content_bytes, sizeof(content_bytes)));
|
||||
|
||||
// Check read result.
|
||||
error = 0;
|
||||
size_t file_size = 0;
|
||||
EXPECT_TRUE(stream_.Open(logfile_name_, "r", &error));
|
||||
EXPECT_TRUE(stream_.GetSize(&file_size));
|
||||
EXPECT_EQ(0, error);
|
||||
EXPECT_EQ(sizeof(content_bytes), file_size);
|
||||
scoped_ptr<uint8_t[]> read_bytes(new uint8_t[file_size]);
|
||||
size_t num_read_bytes = 0;
|
||||
error = 0;
|
||||
EXPECT_EQ(SR_SUCCESS, stream_.ReadAll(read_bytes.get(), file_size,
|
||||
&num_read_bytes, &error));
|
||||
|
||||
const uint8_t expected_read_bytes[] = {
|
||||
1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15};
|
||||
EXPECT_EQ(sizeof(expected_read_bytes), num_read_bytes);
|
||||
EXPECT_EQ(0, memcmp(expected_read_bytes, read_bytes.get(), file_size));
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
Reference in New Issue
Block a user