initial commit

This commit is contained in:
Frederic Jacobs 2014-05-06 19:41:08 +02:00
commit 6373507108
919 changed files with 98519 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Exclude the build directory
build/*
Pods/*
# Exclude temp nibs and swap files
*~.nib
*.swp
*.lock
# Exclude OS X folder attributes
.DS_Store
# Exclude user-specific XCode 3 and 4 files
*.xcworkspace
xcuserdata

37
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,37 @@
## Contributor agreement
Apple requires contributors to iOS projects to relicense their code on submit. We'll have to have individual contributors sign something to enable this.
Our volunteer legal have put together a form you can sign electronically. So no scanning, faxing, or carrier pigeons involved. How modern:
https://whispersystems.org/cla/
Please go ahead and sign, putting your github username in "Address line #2", so that we can accept your pull requests at our heart's delight.
## Code Conventions
We are trying to follow the [GitHub code conventions for Objective-C](https://github.com/github/objective-c-conventions) and we appreciate that pull requests do conform with those conventions.
In addition to that, always add curly braces to your `if` conditionals, even if there is no `else`. Booleans should be declared according to their Objective-C definition, and hence take `YES` or `NO` as values.
One note, for programmers joining us from Java or similar language communities, note that [exceptions are not commonly used for errors that may occur in normal use](http://stackoverflow.com/questions/324284/throwing-an-exception-in-objective-c-cocoa/324805#324805) so familiarize yourself with **NSError**.
### UI conventions
We prefer to use [Storyboards](https://developer.apple.com/library/ios/documentation/general/conceptual/Devpedia-CocoaApp/Storyboard.html) vs. building UI elements within the code itself. We are not at the stage to provide a .strings localizable file for translating, but the goal is to have translatable strings in a single entry point so that we can reach users in their native language wherever possible.
## Tabs vs Spaces
It's the eternal debate. We chose to adopt spaces. Please set your default Xcode configuration to 4 spaces for tabs, and 4 spaces for indentation (it's Xcode's default setting).
![Tabs vs Spaces](http://cl.ly/TYPZ/Screen%20Shot%202014-01-26%20at%2019.02.28.png)
If you don't agree with us, you can use the [ClangFormat Xcode plugin](https://github.com/travisjeffery/ClangFormat-Xcode) to code with your favorite indentation style!
## BitHub
Open Whisper Systems is currently [experimenting](https://whispersystems.org/blog/bithub/) with the funding privacy Free and Open Source software. For example, this is the current Open WhisperSystems payout per commit, rendered dynamically as an image by the Open WhisperSystems BitHub instance:
[![Bithub Payment Amount](https://bithub.herokuapp.com/v1/status/payment/commit)](https://whispersystems.org/blog/bithub/)
## Contributors
Signal wouldnt be possible without the many open-source projects we depend on. Big shoutout to the maintainers of all the [pods](https://github.com/WhisperSystems/Signal-iOS/blob/master/Podfile) we use!

View File

@ -0,0 +1,27 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Message.h"
/**
* A partial implementation of the {@link Message} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* @author Cyrus Najmabadi
*/
@interface PBAbstractMessage : NSObject<PBMessage> {
@private
}
@end

View File

@ -0,0 +1,74 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AbstractMessage.h"
#import "CodedOutputStream.h"
@implementation PBAbstractMessage
- (id) init {
if ((self = [super init])) {
}
return self;
}
- (NSData*) data {
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)self.serializedSize];
PBCodedOutputStream* stream = [PBCodedOutputStream streamWithData:data];
[self writeToCodedOutputStream:stream];
return data;
}
- (BOOL) isInitialized {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (int32_t) serializedSize {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (void) writeToOutputStream:(NSOutputStream*) output {
PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output];
[self writeToCodedOutputStream:codedOutput];
[codedOutput flush];
}
- (id<PBMessage>) defaultInstance {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (PBUnknownFieldSet*) unknownFields {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage_Builder>) builder {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
@end

View File

@ -0,0 +1,25 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Message_Builder.h"
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@interface PBAbstractMessage_Builder : NSObject<PBMessage_Builder> {
}
@end

View File

@ -0,0 +1,119 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AbstractMessage_Builder.h"
#import "CodedInputStream.h"
#import "ExtensionRegistry.h"
#import "UnknownFieldSet.h"
#import "UnknownFieldSet_Builder.h"
@implementation PBAbstractMessage_Builder
- (id<PBMessage_Builder>) clone {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage_Builder>) clear {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage_Builder>) mergeFromCodedInputStream:(PBCodedInputStream*) input {
return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
}
- (id<PBMessage_Builder>) mergeFromCodedInputStream:(PBCodedInputStream*) input
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage_Builder>) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields {
PBUnknownFieldSet* merged =
[[[PBUnknownFieldSet builderWithUnknownFields:self.unknownFields]
mergeUnknownFields:unknownFields] build];
[self setUnknownFields:merged];
return self;
}
- (id<PBMessage_Builder>) mergeFromData:(NSData*) data {
PBCodedInputStream* input = [PBCodedInputStream streamWithData:data];
[self mergeFromCodedInputStream:input];
[input checkLastTagWas:0];
return self;
}
- (id<PBMessage_Builder>) mergeFromData:(NSData*) data
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
PBCodedInputStream* input = [PBCodedInputStream streamWithData:data];
[self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
[input checkLastTagWas:0];
return self;
}
- (id<PBMessage_Builder>) mergeFromInputStream:(NSInputStream*) input {
PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input];
[self mergeFromCodedInputStream:codedInput];
[codedInput checkLastTagWas:0];
return self;
}
- (id<PBMessage_Builder>) mergeFromInputStream:(NSInputStream*) input
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input];
[self mergeFromCodedInputStream:codedInput extensionRegistry:extensionRegistry];
[codedInput checkLastTagWas:0];
return self;
}
- (id<PBMessage>) build {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage>) buildPartial {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (BOOL) isInitialized {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage>) defaultInstance {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (PBUnknownFieldSet*) unknownFields {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (id<PBMessage_Builder>) setUnknownFields:(PBUnknownFieldSet*) unknownFields {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
@end

View File

@ -0,0 +1,27 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ForwardDeclarations.h"
#import "CodedInputStream.h"
#import "CodedOutputStream.h"
#import "ExtendableMessage.h"
#import "ExtendableMessage_Builder.h"
#import "ExtensionRegistry.h"
#import "GeneratedMessage.h"
#import "GeneratedMessage_Builder.h"
#import "Message_Builder.h"
#import "UnknownFieldSet.h"
#import "UnknownFieldSet_Builder.h"
#import "Utilities.h"

View File

@ -0,0 +1,184 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBExtensionRegistry;
@class PBUnknownFieldSet_Builder;
@protocol PBMessage_Builder;
/**
* Reads and decodes protocol message fields.
*
* This class contains two kinds of methods: methods that read specific
* protocol message constructs and field types (e.g. {@link #readTag()} and
* {@link #readInt32()}) and methods that read low-level values (e.g.
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
* encoded protocol messages, you should use the former methods, but if you are
* reading some other format of your own design, use the latter.
*
* @author Cyrus Najmabadi
*/
@interface PBCodedInputStream : NSObject {
@private
NSMutableData* buffer;
int32_t bufferSize;
int32_t bufferSizeAfterLimit;
int32_t bufferPos;
NSInputStream* input;
int32_t lastTag;
/**
* The total number of bytes read before the current buffer. The total
* bytes read up to the current position can be computed as
* {@code totalBytesRetired + bufferPos}.
*/
int32_t totalBytesRetired;
/** The absolute position of the end of the current message. */
int32_t currentLimit;
/** See setRecursionLimit() */
int32_t recursionDepth;
int32_t recursionLimit;
/** See setSizeLimit() */
int32_t sizeLimit;
}
+ (PBCodedInputStream*) streamWithData:(NSData*) data;
+ (PBCodedInputStream*) streamWithInputStream:(NSInputStream*) input;
/**
* Attempt to read a field tag, returning zero if we have reached EOF.
* Protocol message parsers use this to read tags, since a protocol message
* may legally end wherever a tag occurs, and zero is not a valid tag number.
*/
- (int32_t) readTag;
- (BOOL) refillBuffer:(BOOL) mustSucceed;
- (Float64) readDouble;
- (Float32) readFloat;
- (int64_t) readUInt64;
- (int32_t) readUInt32;
- (int64_t) readInt64;
- (int32_t) readInt32;
- (int64_t) readFixed64;
- (int32_t) readFixed32;
- (int32_t) readEnum;
- (int32_t) readSFixed32;
- (int64_t) readSFixed64;
- (int32_t) readSInt32;
- (int64_t) readSInt64;
/**
* Read one byte from the input.
*
* @throws InvalidProtocolBuffer The end of the stream or the current
* limit was reached.
*/
- (int8_t) readRawByte;
/**
* Read a raw Varint from the stream. If larger than 32 bits, discard the
* upper bits.
*/
- (int32_t) readRawVarint32;
- (int64_t) readRawVarint64;
- (int32_t) readRawLittleEndian32;
- (int64_t) readRawLittleEndian64;
/**
* Read a fixed size of bytes from the input.
*
* @throws InvalidProtocolBuffer The end of the stream or the current
* limit was reached.
*/
- (NSData*) readRawData:(int32_t) size;
/**
* Reads and discards a single field, given its tag value.
*
* @return {@code false} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code true}.
*/
- (BOOL) skipField:(int32_t) tag;
/**
* Reads and discards {@code size} bytes.
*
* @throws InvalidProtocolBuffer The end of the stream or the current
* limit was reached.
*/
- (void) skipRawData:(int32_t) size;
/**
* Reads and discards an entire message. This will read either until EOF
* or until an endgroup tag, whichever comes first.
*/
- (void) skipMessage;
- (BOOL) isAtEnd;
- (int32_t) pushLimit:(int32_t) byteLimit;
- (void) recomputeBufferSizeAfterLimit;
- (void) popLimit:(int32_t) oldLimit;
- (int32_t) bytesUntilLimit;
/**
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 32-bit integer, stored in a signed int.
* @return A signed 32-bit integer.
*/
int32_t decodeZigZag32(int32_t n);
/**
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 64-bit integer, stored in a signed int.
* @return A signed 64-bit integer.
*/
int64_t decodeZigZag64(int64_t n);
/** Read an embedded message field value from the stream. */
- (void) readMessage:(id<PBMessage_Builder>) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
- (BOOL) readBool;
- (NSString*) readString;
- (NSData*) readData;
- (void) readGroup:(int32_t) fieldNumber builder:(id<PBMessage_Builder>) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link UnknownFieldSet}.
*/
- (void) readUnknownGroup:(int32_t) fieldNumber builder:(PBUnknownFieldSet_Builder*) builder;
/**
* Verifies that the last call to readTag() returned the given tag value.
* This is used to verify that a nested group ended with the correct
* end tag.
*
* @throws InvalidProtocolBuffer {@code value} does not match the
* last tag.
*/
- (void) checkLastTagWas:(int32_t) value;
@end

View File

@ -0,0 +1,790 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "CodedInputStream.h"
#import "Message_Builder.h"
#import "Utilities.h"
#import "WireFormat.h"
#import "UnknownFieldSet_Builder.h"
@interface PBCodedInputStream ()
@property (retain) NSMutableData* buffer;
@property (retain) NSInputStream* input;
@end
@implementation PBCodedInputStream
const int32_t DEFAULT_RECURSION_LIMIT = 64;
const int32_t DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
const int32_t BUFFER_SIZE = 4096;
@synthesize buffer;
@synthesize input;
- (void) dealloc {
[input close];
self.buffer = nil;
self.input = nil;
}
- (void) commonInit {
currentLimit = INT_MAX;
recursionLimit = DEFAULT_RECURSION_LIMIT;
sizeLimit = DEFAULT_SIZE_LIMIT;
}
- (id) initWithData:(NSData*) data {
if ((self = [super init])) {
self.buffer = [NSMutableData dataWithData:data];
bufferSize = (int32_t)buffer.length;
self.input = nil;
[self commonInit];
}
return self;
}
- (id) initWithInputStream:(NSInputStream*) input_ {
if ((self = [super init])) {
self.buffer = [NSMutableData dataWithLength:BUFFER_SIZE];
bufferSize = 0;
self.input = input_;
[input open];
[self commonInit];
}
return self;
}
+ (PBCodedInputStream*) streamWithData:(NSData*) data {
return [[PBCodedInputStream alloc] initWithData:data];
}
+ (PBCodedInputStream*) streamWithInputStream:(NSInputStream*) input {
return [[PBCodedInputStream alloc] initWithInputStream:input];
}
/**
* Attempt to read a field tag, returning zero if we have reached EOF.
* Protocol message parsers use this to read tags, since a protocol message
* may legally end wherever a tag occurs, and zero is not a valid tag number.
*/
- (int32_t) readTag {
if (self.isAtEnd) {
lastTag = 0;
return 0;
}
lastTag = [self readRawVarint32];
if (lastTag == 0) {
// If we actually read zero, that's not a valid tag.
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid Tag" userInfo:nil];
}
return lastTag;
}
/**
* Verifies that the last call to readTag() returned the given tag value.
* This is used to verify that a nested group ended with the correct
* end tag.
*
* @throws InvalidProtocolBufferException {@code value} does not match the
* last tag.
*/
- (void) checkLastTagWas:(int32_t) value {
if (lastTag != value) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid End Tag" userInfo:nil];
}
}
/**
* Reads and discards a single field, given its tag value.
*
* @return {@code NO} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code YES}.
*/
- (BOOL) skipField:(int32_t) tag {
switch (PBWireFormatGetTagWireType(tag)) {
case PBWireFormatVarint:
[self readInt32];
return YES;
case PBWireFormatFixed64:
[self readRawLittleEndian64];
return YES;
case PBWireFormatLengthDelimited:
[self skipRawData:[self readRawVarint32]];
return YES;
case PBWireFormatStartGroup:
[self skipMessage];
[self checkLastTagWas:
PBWireFormatMakeTag(PBWireFormatGetTagFieldNumber(tag),
PBWireFormatEndGroup)];
return YES;
case PBWireFormatEndGroup:
return NO;
case PBWireFormatFixed32:
[self readRawLittleEndian32];
return YES;
default:
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Invalid Wire Type" userInfo:nil];
}
}
/**
* Reads and discards an entire message. This will read either until EOF
* or until an endgroup tag, whichever comes first.
*/
- (void) skipMessage {
while (YES) {
int32_t tag = [self readTag];
if (tag == 0 || ![self skipField:tag]) {
return;
}
}
}
/** Read a {@code double} field value from the stream. */
- (Float64) readDouble {
return convertInt64ToFloat64([self readRawLittleEndian64]);
}
/** Read a {@code float} field value from the stream. */
- (Float32) readFloat {
return convertInt32ToFloat32([self readRawLittleEndian32]);
}
/** Read a {@code uint64} field value from the stream. */
- (int64_t) readUInt64 {
return [self readRawVarint64];
}
/** Read an {@code int64} field value from the stream. */
- (int64_t) readInt64 {
return [self readRawVarint64];
}
/** Read an {@code int32} field value from the stream. */
- (int32_t) readInt32 {
return [self readRawVarint32];
}
/** Read a {@code fixed64} field value from the stream. */
- (int64_t) readFixed64 {
return [self readRawLittleEndian64];
}
/** Read a {@code fixed32} field value from the stream. */
- (int32_t) readFixed32 {
return [self readRawLittleEndian32];
}
/** Read a {@code bool} field value from the stream. */
- (BOOL) readBool {
return [self readRawVarint32] != 0;
}
/** Read a {@code string} field value from the stream. */
- (NSString*) readString {
int32_t size = [self readRawVarint32];
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
// new String(buffer, bufferPos, size, "UTF-8");
NSString* result = [[NSString alloc] initWithBytes:(((uint8_t*) buffer.bytes) + bufferPos)
length:(NSUInteger)size
encoding:NSUTF8StringEncoding];
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
NSData* data = [self readRawData:size];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
}
/** Read a {@code group} field value from the stream. */
- (void) readGroup:(int32_t) fieldNumber
builder:(id<PBMessage_Builder>) builder
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
if (recursionDepth >= recursionLimit) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil];
}
++recursionDepth;
[builder mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
[self checkLastTagWas:PBWireFormatMakeTag(fieldNumber, PBWireFormatEndGroup)];
--recursionDepth;
}
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link PBUnknownFieldSet}.
*/
- (void) readUnknownGroup:(int32_t) fieldNumber
builder:(PBUnknownFieldSet_Builder*) builder {
if (recursionDepth >= recursionLimit) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil];
}
++recursionDepth;
[builder mergeFromCodedInputStream:self];
[self checkLastTagWas:PBWireFormatMakeTag(fieldNumber, PBWireFormatEndGroup)];
--recursionDepth;
}
/** Read an embedded message field value from the stream. */
- (void) readMessage:(id<PBMessage_Builder>) builder
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
int32_t length = [self readRawVarint32];
if (recursionDepth >= recursionLimit) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"Recursion Limit Exceeded" userInfo:nil];
}
int32_t oldLimit = [self pushLimit:length];
++recursionDepth;
[builder mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
[self checkLastTagWas:0];
--recursionDepth;
[self popLimit:oldLimit];
}
/** Read a {@code bytes} field value from the stream. */
- (NSData*) readData {
int32_t size = [self readRawVarint32];
if (size < bufferSize - bufferPos && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
NSData* result = [NSData dataWithBytes:(((uint8_t*) buffer.bytes) + bufferPos) length:(NSUInteger)size];
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return [self readRawData:size];
}
}
/** Read a {@code uint32} field value from the stream. */
- (int32_t) readUInt32 {
return [self readRawVarint32];
}
/**
* Read an enum field value from the stream. Caller is responsible
* for converting the numeric value to an actual enum.
*/
- (int32_t) readEnum {
return [self readRawVarint32];
}
/** Read an {@code sfixed32} field value from the stream. */
- (int32_t) readSFixed32 {
return [self readRawLittleEndian32];
}
/** Read an {@code sfixed64} field value from the stream. */
- (int64_t) readSFixed64 {
return [self readRawLittleEndian64];
}
/** Read an {@code sint32} field value from the stream. */
- (int32_t) readSInt32 {
return decodeZigZag32([self readRawVarint32]);
}
/** Read an {@code sint64} field value from the stream. */
- (int64_t) readSInt64 {
return decodeZigZag64([self readRawVarint64]);
}
// =================================================================
/**
* Read a raw Varint from the stream. If larger than 32 bits, discard the
* upper bits.
*/
- (int32_t) readRawVarint32 {
int8_t tmp = [self readRawByte];
if (tmp >= 0) {
return tmp;
}
int32_t result = tmp & 0x7f;
if ((tmp = [self readRawByte]) >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
if ((tmp = [self readRawByte]) >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if ((tmp = [self readRawByte]) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
result |= (tmp = [self readRawByte]) << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if ([self readRawByte] >= 0) {
return result;
}
}
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"malformedVarint" userInfo:nil];
}
}
}
}
return result;
}
/** Read a raw Varint from the stream. */
- (int64_t) readRawVarint64 {
int32_t shift = 0;
int64_t result = 0;
while (shift < 64) {
int8_t b = [self readRawByte];
result |= (int64_t)(b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"malformedVarint" userInfo:nil];
}
/** Read a 32-bit little-endian integer from the stream. */
- (int32_t) readRawLittleEndian32 {
int8_t b1 = [self readRawByte];
int8_t b2 = [self readRawByte];
int8_t b3 = [self readRawByte];
int8_t b4 = [self readRawByte];
return
(((int32_t)b1 & 0xff) ) |
(((int32_t)b2 & 0xff) << 8) |
(((int32_t)b3 & 0xff) << 16) |
(((int32_t)b4 & 0xff) << 24);
}
/** Read a 64-bit little-endian integer from the stream. */
- (int64_t) readRawLittleEndian64 {
int8_t b1 = [self readRawByte];
int8_t b2 = [self readRawByte];
int8_t b3 = [self readRawByte];
int8_t b4 = [self readRawByte];
int8_t b5 = [self readRawByte];
int8_t b6 = [self readRawByte];
int8_t b7 = [self readRawByte];
int8_t b8 = [self readRawByte];
return
(((int64_t)b1 & 0xff) ) |
(((int64_t)b2 & 0xff) << 8) |
(((int64_t)b3 & 0xff) << 16) |
(((int64_t)b4 & 0xff) << 24) |
(((int64_t)b5 & 0xff) << 32) |
(((int64_t)b6 & 0xff) << 40) |
(((int64_t)b7 & 0xff) << 48) |
(((int64_t)b8 & 0xff) << 56);
}
/**
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 32-bit integer, stored in a signed int
* @return A signed 32-bit integer.
*/
int32_t decodeZigZag32(int32_t n) {
return logicalRightShift32(n, 1) ^ -(n & 1);
}
/**
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 64-bit integer, stored in a signed int
* @return A signed 64-bit integer.
*/
int64_t decodeZigZag64(int64_t n) {
return logicalRightShift64(n, 1) ^ -(n & 1);
}
/**
* Set the maximum message recursion depth. In order to prevent malicious
* messages from causing stack overflows, {@code PBCodedInputStream} limits
* how deeply messages may be nested. The default limit is 64.
*
* @return the old limit.
*/
- (int32_t) setRecursionLimit:(int32_t) limit {
if (limit < 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Recursion limit cannot be negative" userInfo:nil];
}
int32_t oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}
/**
* Set the maximum message size. In order to prevent malicious
* messages from exhausting memory or causing integer overflows,
* {@code PBCodedInputStream} limits how large a message may be.
* The default limit is 64MB. You should set this limit as small
* as you can without harming your app's functionality. Note that
* size limits only apply when reading from an {@code InputStream}, not
* when constructed around a raw byte array.
*
* @return the old limit.
*/
- (int32_t) setSizeLimit:(int32_t) limit {
if (limit < 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Size limit cannot be negative:" userInfo:nil];
}
int32_t oldLimit = sizeLimit;
sizeLimit = limit;
return oldLimit;
}
/**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
*/
- (void) resetSizeCounter {
totalBytesRetired = 0;
}
/**
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
* is called when descending into a length-delimited embedded message.
*
* @return the old limit.
*/
- (int32_t) pushLimit:(int32_t) byteLimit {
if (byteLimit < 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil];
}
byteLimit += totalBytesRetired + bufferPos;
int32_t oldLimit = currentLimit;
if (byteLimit > oldLimit) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
}
currentLimit = byteLimit;
[self recomputeBufferSizeAfterLimit];
return oldLimit;
}
- (void) recomputeBufferSizeAfterLimit {
bufferSize += bufferSizeAfterLimit;
int32_t bufferEnd = totalBytesRetired + bufferSize;
if (bufferEnd > currentLimit) {
// Limit is in current buffer.
bufferSizeAfterLimit = bufferEnd - currentLimit;
bufferSize -= bufferSizeAfterLimit;
} else {
bufferSizeAfterLimit = 0;
}
}
/**
* Discards the current limit, returning to the previous limit.
*
* @param oldLimit The old limit, as returned by {@code pushLimit}.
*/
- (void) popLimit:(int32_t) oldLimit {
currentLimit = oldLimit;
[self recomputeBufferSizeAfterLimit];
}
/**
* Returns the number of bytes to be read before the current limit.
* If no limit is set, returns -1.
*/
- (int32_t) bytesUntilLimit {
if (currentLimit == INT_MAX) {
return -1;
}
int32_t currentAbsolutePosition = totalBytesRetired + bufferPos;
return currentLimit - currentAbsolutePosition;
}
/**
* Returns true if the stream has reached the end of the input. This is the
* case if either the end of the underlying input source has been reached or
* if the stream has reached a limit created using {@link #pushLimit(int)}.
*/
- (BOOL) isAtEnd {
return bufferPos == bufferSize && ![self refillBuffer:NO];
}
/**
* Called with {@code this.buffer} is empty to read more bytes from the
* input. If {@code mustSucceed} is YES, refillBuffer() gurantees that
* either there will be at least one byte in the buffer when it returns
* or it will throw an exception. If {@code mustSucceed} is NO,
* refillBuffer() returns NO if no more bytes were available.
*/
- (BOOL) refillBuffer:(BOOL) mustSucceed {
if (bufferPos < bufferSize) {
@throw [NSException exceptionWithName:@"IllegalState" reason:@"refillBuffer called when buffer wasn't empty." userInfo:nil];
}
if (totalBytesRetired + bufferSize == currentLimit) {
// Oops, we hit a limit.
if (mustSucceed) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
} else {
return NO;
}
}
totalBytesRetired += bufferSize;
// TODO(cyrusn): does NSInputStream behave the same as java.io.InputStream
// when there is no more data?
bufferPos = 0;
bufferSize = 0;
if (input != nil) {
bufferSize = [input read:buffer.mutableBytes maxLength:buffer.length];
}
if (bufferSize <= 0) {
bufferSize = 0;
if (mustSucceed) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
} else {
return NO;
}
} else {
[self recomputeBufferSizeAfterLimit];
int32_t totalBytesRead = totalBytesRetired + bufferSize + bufferSizeAfterLimit;
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"sizeLimitExceeded" userInfo:nil];
}
return YES;
}
}
/**
* Read one byte from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
- (int8_t) readRawByte {
if (bufferPos == bufferSize) {
[self refillBuffer:YES];
}
int8_t* bytes = (int8_t*)buffer.bytes;
return bytes[bufferPos++];
}
/**
* Read a fixed size of bytes from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
- (NSData*) readRawData:(int32_t) size {
if (size < 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil];
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
[self skipRawData:currentLimit - totalBytesRetired - bufferPos];
// Then fail.
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
NSData* data = [NSData dataWithBytes:(((int8_t*) buffer.bytes) + bufferPos) length:(NSUInteger)size];
bufferPos += size;
return data;
} else if (size < BUFFER_SIZE) {
// Reading more bytes than are in the buffer, but not an excessive number
// of bytes. We can safely allocate the resulting array ahead of time.
// First copy what we have.
NSMutableData* bytes = [NSMutableData dataWithLength:(NSUInteger)size];
int32_t pos = bufferSize - bufferPos;
memcpy(bytes.mutableBytes, ((int8_t*)buffer.bytes) + bufferPos, pos);
bufferPos = bufferSize;
// We want to use refillBuffer() and then copy from the buffer into our
// byte array rather than reading directly into our byte array because
// the input may be unbuffered.
[self refillBuffer:YES];
while (size - pos > bufferSize) {
memcpy(((int8_t*)bytes.mutableBytes) + pos, buffer.bytes, bufferSize);
pos += bufferSize;
bufferPos = bufferSize;
[self refillBuffer:YES];
}
memcpy(((int8_t*)bytes.mutableBytes) + pos, buffer.bytes, size - pos);
bufferPos = size - pos;
return bytes;
} else {
// The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in
// order to trick the app into allocating a lot of memory. We avoid this
// by allocating and reading only a small chunk at a time, so that the
// malicious message must actuall* e* extremely large to cause
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
// Remember the buffer markers since we'll have to copy the bytes out of
// it later.
int32_t originalBufferPos = bufferPos;
int32_t originalBufferSize = bufferSize;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = 0;
// Read all the rest of the bytes we need.
int32_t sizeLeft = size - (originalBufferSize - originalBufferPos);
NSMutableArray* chunks = [NSMutableArray array];
while (sizeLeft > 0) {
NSMutableData* chunk = [NSMutableData dataWithLength:(NSUInteger)MIN(sizeLeft, BUFFER_SIZE)];
int32_t pos = 0;
while (pos < (int32_t)chunk.length) {
int32_t n = 0;
if (input != nil) {
n = [input read:(((uint8_t*) chunk.mutableBytes) + pos) maxLength:chunk.length - (NSUInteger)pos];
}
if (n <= 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
}
totalBytesRetired += n;
pos += n;
}
sizeLeft -= chunk.length;
[chunks addObject:chunk];
}
// OK, got everything. Now concatenate it all into one buffer.
NSMutableData* bytes = [NSMutableData dataWithLength:(NSUInteger)size];
// Start by copying the leftover bytes from this.buffer.
int32_t pos = originalBufferSize - originalBufferPos;
memcpy(bytes.mutableBytes, ((int8_t*)buffer.bytes) + originalBufferPos, pos);
// And now all the chunks.
for (NSData* chunk in chunks) {
memcpy(((int8_t*)bytes.mutableBytes) + pos, chunk.bytes, chunk.length);
pos += chunk.length;
}
// Done.
return bytes;
}
}
/**
* Reads and discards {@code size} bytes.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
- (void) skipRawData:(int32_t) size {
if (size < 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"negativeSize" userInfo:nil];
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
[self skipRawData:currentLimit - totalBytesRetired - bufferPos];
// Then fail.
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
}
if (size <= (bufferSize - bufferPos)) {
// We have all the bytes we need already.
bufferPos += size;
} else {
// Skipping more bytes than are in the buffer. First skip what we have.
int32_t pos = bufferSize - bufferPos;
totalBytesRetired += pos;
bufferPos = 0;
bufferSize = 0;
// Then skip directly from the InputStream for the rest.
while (pos < size) {
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)(size - pos)];
int32_t n = (input == nil) ? -1 : (int32_t)[input read:data.mutableBytes maxLength:(NSUInteger)(size - pos)];
if (n <= 0) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"truncatedMessage" userInfo:nil];
}
pos += n;
totalBytesRetired += n;
}
}
}
@end

View File

@ -0,0 +1,216 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBUnknownFieldSet;
@protocol PBMessage;
/**
* Encodes and writes protocol message fields.
*
* <p>This class contains two kinds of methods: methods that write specific
* protocol message constructs and field types (e.g. {@link #writeTag} and
* {@link #writeInt32}) and methods that write low-level values (e.g.
* {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
* writing encoded protocol messages, you should use the former methods, but if
* you are writing some other format of your own design, use the latter.
*
* <p>This class is totally unsynchronized.
*
* @author Cyrus Najmabadi
*/
@interface PBCodedOutputStream : NSObject {
NSMutableData* buffer;
int32_t position;
NSOutputStream* output;
}
+ (PBCodedOutputStream*) streamWithData:(NSMutableData*) data;
+ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output;
+ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output bufferSize:(int32_t) bufferSize;
/**
* Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n A signed 32-bit integer.
* @return An unsigned 32-bit integer, stored in a signed int.
*/
int32_t encodeZigZag32(int32_t n);
/**
* Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n A signed 64-bit integer.
* @return An unsigned 64-bit integer, stored in a signed int.
*/
int64_t encodeZigZag64(int64_t n);
int32_t computeDoubleSize(int32_t fieldNumber, Float64 value);
int32_t computeFloatSize(int32_t fieldNumber, Float32 value);
int32_t computeUInt64Size(int32_t fieldNumber, int64_t value);
int32_t computeInt64Size(int32_t fieldNumber, int64_t value);
int32_t computeInt32Size(int32_t fieldNumber, int32_t value);
int32_t computeFixed64Size(int32_t fieldNumber, int64_t value);
int32_t computeFixed32Size(int32_t fieldNumber, int32_t value);
int32_t computeBoolSize(int32_t fieldNumber, BOOL value);
int32_t computeStringSize(int32_t fieldNumber, NSString* value);
int32_t computeGroupSize(int32_t fieldNumber, id<PBMessage> value);
int32_t computeUnknownGroupSize(int32_t fieldNumber, PBUnknownFieldSet* value);
int32_t computeMessageSize(int32_t fieldNumber, id<PBMessage> value);
int32_t computeDataSize(int32_t fieldNumber, NSData* value);
int32_t computeUInt32Size(int32_t fieldNumber, int32_t value);
int32_t computeSFixed32Size(int32_t fieldNumber, int32_t value);
int32_t computeSFixed64Size(int32_t fieldNumber, int64_t value);
int32_t computeSInt32Size(int32_t fieldNumber, int32_t value);
int32_t computeSInt64Size(int32_t fieldNumber, int64_t value);
int32_t computeTagSize(int32_t fieldNumber);
int32_t computeDoubleSizeNoTag(Float64 value);
int32_t computeFloatSizeNoTag(Float32 value);
int32_t computeUInt64SizeNoTag(int64_t value);
int32_t computeInt64SizeNoTag(int64_t value);
int32_t computeInt32SizeNoTag(int32_t value);
int32_t computeFixed64SizeNoTag(int64_t value);
int32_t computeFixed32SizeNoTag(int32_t value);
int32_t computeBoolSizeNoTag(BOOL value);
int32_t computeStringSizeNoTag(NSString* value);
int32_t computeGroupSizeNoTag(id<PBMessage> value);
int32_t computeUnknownGroupSizeNoTag(PBUnknownFieldSet* value);
int32_t computeMessageSizeNoTag(id<PBMessage> value);
int32_t computeDataSizeNoTag(NSData* value);
int32_t computeUInt32SizeNoTag(int32_t value);
int32_t computeEnumSizeNoTag(int32_t value);
int32_t computeSFixed32SizeNoTag(int32_t value);
int32_t computeSFixed64SizeNoTag(int64_t value);
int32_t computeSInt32SizeNoTag(int32_t value);
int32_t computeSInt64SizeNoTag(int64_t value);
/**
* Compute the number of bytes that would be needed to encode a varint.
* {@code value} is treated as unsigned, so it won't be sign-extended if
* negative.
*/
int32_t computeRawVarint32Size(int32_t value);
int32_t computeRawVarint64Size(int64_t value);
/**
* Compute the number of bytes that would be needed to encode a
* MessageSet extension to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
int32_t computeMessageSetExtensionSize(int32_t fieldNumber, id<PBMessage> value);
/**
* Compute the number of bytes that would be needed to encode an
* unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
int32_t computeRawMessageSetExtensionSize(int32_t fieldNumber, NSData* value);
/**
* Compute the number of bytes that would be needed to encode an
* enum field, including tag. Caller is responsible for converting the
* enum value to its numeric value.
*/
int32_t computeEnumSize(int32_t fieldNumber, int32_t value);
/**
* Flushes the stream and forces any buffered bytes to be written. This
* does not flush the underlying NSOutputStream.
*/
- (void) flush;
- (void) writeRawByte:(uint8_t) value;
- (void) writeTag:(int32_t) fieldNumber format:(int32_t) format;
/**
* Encode and write a varint. {@code value} is treated as
* unsigned, so it won't be sign-extended if negative.
*/
- (void) writeRawVarint32:(int32_t) value;
- (void) writeRawVarint64:(int64_t) value;
- (void) writeRawLittleEndian32:(int32_t) value;
- (void) writeRawLittleEndian64:(int64_t) value;
- (void) writeRawData:(NSData*) data;
- (void) writeRawData:(NSData*) data offset:(int32_t) offset length:(int32_t) length;
- (void) writeData:(int32_t) fieldNumber value:(NSData*) value;
- (void) writeDouble:(int32_t) fieldNumber value:(Float64) value;
- (void) writeFloat:(int32_t) fieldNumber value:(Float32) value;
- (void) writeUInt64:(int32_t) fieldNumber value:(int64_t) value;
- (void) writeInt64:(int32_t) fieldNumber value:(int64_t) value;
- (void) writeInt32:(int32_t) fieldNumber value:(int32_t) value;
- (void) writeFixed64:(int32_t) fieldNumber value:(int64_t) value;
- (void) writeFixed32:(int32_t) fieldNumber value:(int32_t) value;
- (void) writeBool:(int32_t) fieldNumber value:(BOOL) value;
- (void) writeString:(int32_t) fieldNumber value:(NSString*) value;
- (void) writeGroup:(int32_t) fieldNumber value:(id<PBMessage>) value;
- (void) writeUnknownGroup:(int32_t) fieldNumber value:(PBUnknownFieldSet*) value;
- (void) writeMessage:(int32_t) fieldNumber value:(id<PBMessage>) value;
- (void) writeUInt32:(int32_t) fieldNumber value:(int32_t) value;
- (void) writeSFixed32:(int32_t) fieldNumber value:(int32_t) value;
- (void) writeSFixed64:(int32_t) fieldNumber value:(int64_t) value;
- (void) writeSInt32:(int32_t) fieldNumber value:(int32_t) value;
- (void) writeSInt64:(int32_t) fieldNumber value:(int64_t) value;
- (void) writeDoubleNoTag:(Float64) value;
- (void) writeFloatNoTag:(Float32) value;
- (void) writeUInt64NoTag:(int64_t) value;
- (void) writeInt64NoTag:(int64_t) value;
- (void) writeInt32NoTag:(int32_t) value;
- (void) writeFixed64NoTag:(int64_t) value;
- (void) writeFixed32NoTag:(int32_t) value;
- (void) writeBoolNoTag:(BOOL) value;
- (void) writeStringNoTag:(NSString*) value;
- (void) writeGroupNoTag:(int32_t) fieldNumber value:(id<PBMessage>) value;
- (void) writeUnknownGroupNoTag:(int32_t) fieldNumber value:(PBUnknownFieldSet*) value;
- (void) writeMessageNoTag:(id<PBMessage>) value;
- (void) writeDataNoTag:(NSData*) value;
- (void) writeUInt32NoTag:(int32_t) value;
- (void) writeEnumNoTag:(int32_t) value;
- (void) writeSFixed32NoTag:(int32_t) value;
- (void) writeSFixed64NoTag:(int64_t) value;
- (void) writeSInt32NoTag:(int32_t) value;
- (void) writeSInt64NoTag:(int64_t) value;
/**
* Write a MessageSet extension field to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
- (void) writeMessageSetExtension:(int32_t) fieldNumber value:(id<PBMessage>) value;
/**
* Write an unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
- (void) writeRawMessageSetExtension:(int32_t) fieldNumber value:(NSData*) value;
/**
* Write an enum field, including tag, to the stream. Caller is responsible
* for converting the enum value to its numeric value.
*/
- (void) writeEnum:(int32_t) fieldNumber value:(int32_t) value;
@end

View File

@ -0,0 +1,974 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "CodedOutputStream.h"
#import "Message.h"
#import "Utilities.h"
#import "WireFormat.h"
#import "UnknownFieldSet.h"
@interface PBCodedOutputStream ()
@property (retain) NSMutableData* buffer;
@property int32_t position;
@property (retain) NSOutputStream* output;
@end
@implementation PBCodedOutputStream
const int32_t DEFAULT_BUFFER_SIZE = 4096;
const int32_t LITTLE_ENDIAN_32_SIZE = 4;
const int32_t LITTLE_ENDIAN_64_SIZE = 8;
@synthesize output;
@synthesize buffer;
@synthesize position;
- (void) dealloc {
[output close];
self.output = nil;
self.buffer = nil;
self.position = 0;
}
- (id) initWithOutputStream:(NSOutputStream*) output_
data:(NSMutableData*) data_ {
if ((self = [super init])) {
self.output = output_;
self.buffer = data_;
self.position = 0;
[output open];
}
return self;
}
+ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output
bufferSize:(int32_t) bufferSize {
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)bufferSize];
return [[PBCodedOutputStream alloc] initWithOutputStream:output
data:data];
}
+ (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output {
return [PBCodedOutputStream streamWithOutputStream:output bufferSize:DEFAULT_BUFFER_SIZE];
}
+ (PBCodedOutputStream*) streamWithData:(NSMutableData*) data {
return [[PBCodedOutputStream alloc] initWithOutputStream:nil data:data];
}
- (void) writeDoubleNoTag:(Float64) value {
[self writeRawLittleEndian64:convertFloat64ToInt64(value)];
}
/** Write a {@code double} field, including tag, to the stream. */
- (void) writeDouble:(int32_t) fieldNumber
value:(Float64) value {
[self writeTag:fieldNumber format:PBWireFormatFixed64];
[self writeDoubleNoTag:value];
}
- (void) writeFloatNoTag:(Float32) value {
[self writeRawLittleEndian32:convertFloat32ToInt32(value)];
}
/** Write a {@code float} field, including tag, to the stream. */
- (void) writeFloat:(int32_t) fieldNumber
value:(Float32) value {
[self writeTag:fieldNumber format:PBWireFormatFixed32];
[self writeFloatNoTag:value];
}
- (void) writeUInt64NoTag:(int64_t) value {
[self writeRawVarint64:value];
}
/** Write a {@code uint64} field, including tag, to the stream. */
- (void) writeUInt64:(int32_t) fieldNumber
value:(int64_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeUInt64NoTag:value];
}
- (void) writeInt64NoTag:(int64_t) value {
[self writeRawVarint64:value];
}
/** Write an {@code int64} field, including tag, to the stream. */
- (void) writeInt64:(int32_t) fieldNumber
value:(int64_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeInt64NoTag:value];
}
- (void) writeInt32NoTag:(int32_t) value {
if (value >= 0) {
[self writeRawVarint32:value];
} else {
// Must sign-extend
[self writeRawVarint64:value];
}
}
/** Write an {@code int32} field, including tag, to the stream. */
- (void) writeInt32:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeInt32NoTag:value];
}
- (void) writeFixed64NoTag:(int64_t) value {
[self writeRawLittleEndian64:value];
}
/** Write a {@code fixed64} field, including tag, to the stream. */
- (void) writeFixed64:(int32_t) fieldNumber
value:(int64_t) value {
[self writeTag:fieldNumber format:PBWireFormatFixed64];
[self writeFixed64NoTag:value];
}
- (void) writeFixed32NoTag:(int32_t) value {
[self writeRawLittleEndian32:value];
}
/** Write a {@code fixed32} field, including tag, to the stream. */
- (void) writeFixed32:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatFixed32];
[self writeFixed32NoTag:value];
}
- (void) writeBoolNoTag:(BOOL) value {
[self writeRawByte:(value ? 1 : 0)];
}
/** Write a {@code bool} field, including tag, to the stream. */
- (void) writeBool:(int32_t) fieldNumber
value:(BOOL) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeBoolNoTag:value];
}
- (void) writeStringNoTag:(NSString*) value {
NSData* data = [value dataUsingEncoding:NSUTF8StringEncoding];
[self writeRawVarint32:(int32_t)data.length];
[self writeRawData:data];
}
/** Write a {@code string} field, including tag, to the stream. */
- (void) writeString:(int32_t) fieldNumber
value:(NSString*) value {
// TODO(cyrusn): we could probably use:
// NSString:getBytes:maxLength:usedLength:encoding:options:range:remainingRange:
// to write directly into our buffer.
[self writeTag:fieldNumber format:PBWireFormatLengthDelimited];
[self writeStringNoTag:value];
}
- (void) writeGroupNoTag:(int32_t) fieldNumber
value:(id<PBMessage>) value {
[value writeToCodedOutputStream:self];
[self writeTag:fieldNumber format:PBWireFormatEndGroup];
}
/** Write a {@code group} field, including tag, to the stream. */
- (void) writeGroup:(int32_t) fieldNumber
value:(id<PBMessage>) value {
[self writeTag:fieldNumber format:PBWireFormatStartGroup];
[self writeGroupNoTag:fieldNumber value:value];
}
- (void) writeUnknownGroupNoTag:(int32_t) fieldNumber
value:(PBUnknownFieldSet*) value {
[value writeToCodedOutputStream:self];
[self writeTag:fieldNumber format:PBWireFormatEndGroup];
}
/** Write a group represented by an {@link PBUnknownFieldSet}. */
- (void) writeUnknownGroup:(int32_t) fieldNumber
value:(PBUnknownFieldSet*) value {
[self writeTag:fieldNumber format:PBWireFormatStartGroup];
[self writeUnknownGroupNoTag:fieldNumber value:value];
}
- (void) writeMessageNoTag:(id<PBMessage>) value {
[self writeRawVarint32:[value serializedSize]];
[value writeToCodedOutputStream:self];
}
/** Write an embedded message field, including tag, to the stream. */
- (void) writeMessage:(int32_t) fieldNumber
value:(id<PBMessage>) value {
[self writeTag:fieldNumber format:PBWireFormatLengthDelimited];
[self writeMessageNoTag:value];
}
- (void) writeDataNoTag:(NSData*) value {
[self writeRawVarint32:(int32_t)value.length];
[self writeRawData:value];
}
/** Write a {@code bytes} field, including tag, to the stream. */
- (void) writeData:(int32_t) fieldNumber value:(NSData*) value {
[self writeTag:fieldNumber format:PBWireFormatLengthDelimited];
[self writeDataNoTag:value];
}
- (void) writeUInt32NoTag:(int32_t) value {
[self writeRawVarint32:value];
}
/** Write a {@code uint32} field, including tag, to the stream. */
- (void) writeUInt32:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeUInt32NoTag:value];
}
- (void) writeEnumNoTag:(int32_t) value {
[self writeRawVarint32:value];
}
/**
* Write an enum field, including tag, to the stream. Caller is responsible
* for converting the enum value to its numeric value.
*/
- (void) writeEnum:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeEnumNoTag:value];
}
- (void) writeSFixed32NoTag:(int32_t) value {
[self writeRawLittleEndian32:value];
}
/** Write an {@code sfixed32} field, including tag, to the stream. */
- (void) writeSFixed32:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatFixed32];
[self writeSFixed32NoTag:value];
}
- (void) writeSFixed64NoTag:(int64_t) value {
[self writeRawLittleEndian64:value];
}
/** Write an {@code sfixed64} field, including tag, to the stream. */
- (void) writeSFixed64:(int32_t) fieldNumber
value:(int64_t) value {
[self writeTag:fieldNumber format:PBWireFormatFixed64];
[self writeSFixed64NoTag:value];
}
- (void) writeSInt32NoTag:(int32_t) value {
[self writeRawVarint32:encodeZigZag32(value)];
}
/** Write an {@code sint32} field, including tag, to the stream. */
- (void) writeSInt32:(int32_t) fieldNumber
value:(int32_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeSInt32NoTag:value];
}
- (void) writeSInt64NoTag:(int64_t) value {
[self writeRawVarint64:encodeZigZag64(value)];
}
/** Write an {@code sint64} field, including tag, to the stream. */
- (void) writeSInt64:(int32_t) fieldNumber
value:(int64_t) value {
[self writeTag:fieldNumber format:PBWireFormatVarint];
[self writeSInt64NoTag:value];
}
/**
* Write a MessageSet extension field to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
- (void) writeMessageSetExtension:(int32_t) fieldNumber
value:(id<PBMessage>) value {
[self writeTag:PBWireFormatMessageSetItem format:PBWireFormatStartGroup];
[self writeUInt32:PBWireFormatMessageSetTypeId value:fieldNumber];
[self writeMessage:PBWireFormatMessageSetMessage value:value];
[self writeTag:PBWireFormatMessageSetItem format:PBWireFormatEndGroup];
}
/**
* Write an unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
- (void) writeRawMessageSetExtension:(int32_t) fieldNumber
value:(NSData*) value {
[self writeTag:PBWireFormatMessageSetItem format:PBWireFormatStartGroup];
[self writeUInt32:PBWireFormatMessageSetTypeId value:fieldNumber];
[self writeData:PBWireFormatMessageSetMessage value:value];
[self writeTag:PBWireFormatMessageSetItem format:PBWireFormatEndGroup];
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code double} field, including tag.
*/
int32_t computeDoubleSizeNoTag(Float64 value) {
return LITTLE_ENDIAN_64_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code float} field, including tag.
*/
int32_t computeFloatSizeNoTag(Float32 value) {
return LITTLE_ENDIAN_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code uint64} field, including tag.
*/
int32_t computeUInt64SizeNoTag(int64_t value) {
return computeRawVarint64Size(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code int64} field, including tag.
*/
int32_t computeInt64SizeNoTag(int64_t value) {
return computeRawVarint64Size(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code int32} field, including tag.
*/
int32_t computeInt32SizeNoTag(int32_t value) {
if (value >= 0) {
return computeRawVarint32Size(value);
} else {
// Must sign-extend.
return 10;
}
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code fixed64} field, including tag.
*/
int32_t computeFixed64SizeNoTag(int64_t value) {
return LITTLE_ENDIAN_64_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code fixed32} field, including tag.
*/
int32_t computeFixed32SizeNoTag(int32_t value) {
return LITTLE_ENDIAN_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code bool} field, including tag.
*/
int32_t computeBoolSizeNoTag(BOOL value) {
return 1;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code string} field, including tag.
*/
int32_t computeStringSizeNoTag(NSString* value) {
NSData* data = [value dataUsingEncoding:NSUTF8StringEncoding];
return computeRawVarint32Size((int32_t)data.length) + (int32_t)data.length;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field, including tag.
*/
int32_t computeGroupSizeNoTag(id<PBMessage> value) {
return [value serializedSize];
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field represented by an {@code PBUnknownFieldSet}, including
* tag.
*/
int32_t computeUnknownGroupSizeNoTag(PBUnknownFieldSet* value) {
return value.serializedSize;
}
/**
* Compute the number of bytes that would be needed to encode an
* embedded message field, including tag.
*/
int32_t computeMessageSizeNoTag(id<PBMessage> value) {
int32_t size = [value serializedSize];
return computeRawVarint32Size(size) + size;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
int32_t computeDataSizeNoTag(NSData* value) {
return computeRawVarint32Size((int32_t)value.length) + (int32_t)value.length;
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code uint32} field, including tag.
*/
int32_t computeUInt32SizeNoTag(int32_t value) {
return computeRawVarint32Size(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* enum field, including tag. Caller is responsible for converting the
* enum value to its numeric value.
*/
int32_t computeEnumSizeNoTag(int32_t value) {
return computeRawVarint32Size(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sfixed32} field, including tag.
*/
int32_t computeSFixed32SizeNoTag(int32_t value) {
return LITTLE_ENDIAN_32_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sfixed64} field, including tag.
*/
int32_t computeSFixed64SizeNoTag(int64_t value) {
return LITTLE_ENDIAN_64_SIZE;
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sint32} field, including tag.
*/
int32_t computeSInt32SizeNoTag(int32_t value) {
return computeRawVarint32Size(encodeZigZag32(value));
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sint64} field, including tag.
*/
int32_t computeSInt64SizeNoTag(int64_t value) {
return computeRawVarint64Size(encodeZigZag64(value));
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code double} field, including tag.
*/
int32_t computeDoubleSize(int32_t fieldNumber, Float64 value) {
return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code float} field, including tag.
*/
int32_t computeFloatSize(int32_t fieldNumber, Float32 value) {
return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code uint64} field, including tag.
*/
int32_t computeUInt64Size(int32_t fieldNumber, int64_t value) {
return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code int64} field, including tag.
*/
int32_t computeInt64Size(int32_t fieldNumber, int64_t value) {
return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code int32} field, including tag.
*/
int32_t computeInt32Size(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code fixed64} field, including tag.
*/
int32_t computeFixed64Size(int32_t fieldNumber, int64_t value) {
return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code fixed32} field, including tag.
*/
int32_t computeFixed32Size(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code bool} field, including tag.
*/
int32_t computeBoolSize(int32_t fieldNumber, BOOL value) {
return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code string} field, including tag.
*/
int32_t computeStringSize(int32_t fieldNumber, NSString* value) {
return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field, including tag.
*/
int32_t computeGroupSize(int32_t fieldNumber, id<PBMessage> value) {
return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code group} field represented by an {@code PBUnknownFieldSet}, including
* tag.
*/
int32_t computeUnknownGroupSize(int32_t fieldNumber,
PBUnknownFieldSet* value) {
return computeTagSize(fieldNumber) * 2 + computeUnknownGroupSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* embedded message field, including tag.
*/
int32_t computeMessageSize(int32_t fieldNumber, id<PBMessage> value) {
return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code bytes} field, including tag.
*/
int32_t computeDataSize(int32_t fieldNumber, NSData* value) {
return computeTagSize(fieldNumber) + computeDataSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode a
* {@code uint32} field, including tag.
*/
int32_t computeUInt32Size(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* enum field, including tag. Caller is responsible for converting the
* enum value to its numeric value.
*/
int32_t computeEnumSize(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sfixed32} field, including tag.
*/
int32_t computeSFixed32Size(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sfixed64} field, including tag.
*/
int32_t computeSFixed64Size(int32_t fieldNumber, int64_t value) {
return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sint32} field, including tag.
*/
int32_t computeSInt32Size(int32_t fieldNumber, int32_t value) {
return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
}
/**
* Compute the number of bytes that would be needed to encode an
* {@code sint64} field, including tag.
*/
int32_t computeSInt64Size(int32_t fieldNumber, int64_t value) {
return computeTagSize(fieldNumber) +
computeRawVarint64Size(encodeZigZag64(value));
}
/**
* Compute the number of bytes that would be needed to encode a
* MessageSet extension to the stream. For historical reasons,
* the wire format differs from normal fields.
*/
int32_t computeMessageSetExtensionSize(int32_t fieldNumber, id<PBMessage> value) {
return computeTagSize(PBWireFormatMessageSetItem) * 2 +
computeUInt32Size(PBWireFormatMessageSetTypeId, fieldNumber) +
computeMessageSize(PBWireFormatMessageSetMessage, value);
}
/**
* Compute the number of bytes that would be needed to encode an
* unparsed MessageSet extension field to the stream. For
* historical reasons, the wire format differs from normal fields.
*/
int32_t computeRawMessageSetExtensionSize(int32_t fieldNumber, NSData* value) {
return computeTagSize(PBWireFormatMessageSetItem) * 2 +
computeUInt32Size(PBWireFormatMessageSetTypeId, fieldNumber) +
computeDataSize(PBWireFormatMessageSetMessage, value);
}
/**
* Internal helper that writes the current buffer to the output. The
* buffer position is reset to its initial value when this returns.
*/
- (void) refreshBuffer {
if (output == nil) {
// We're writing to a single buffer.
@throw [NSException exceptionWithName:@"OutOfSpace" reason:@"" userInfo:nil];
}
[output write:buffer.bytes maxLength:(NSUInteger)position];
position = 0;
}
/**
* Flushes the stream and forces any buffered bytes to be written. This
* does not flush the underlying OutputStream.
*/
- (void) flush {
if (output != nil) {
[self refreshBuffer];
}
}
/**
* If writing to a flat array, return the space left in the array.
* Otherwise, throws {@code UnsupportedOperationException}.
*/
- (int32_t) spaceLeft {
if (output == nil) {
return (int32_t)buffer.length - position;
} else {
@throw [NSException exceptionWithName:@"UnsupportedOperation"
reason:@"spaceLeft() can only be called on CodedOutputStreams that are writing to a flat array."
userInfo:nil];
}
}
/**
* Verifies that {@link #spaceLeft()} returns zero. It's common to create
* a byte array that is exactly big enough to hold a message, then write to
* it with a {@code PBCodedOutputStream}. Calling {@code checkNoSpaceLeft()}
* after writing verifies that the message was actually as big as expected,
* which can help catch bugs.
*/
- (void) checkNoSpaceLeft {
if (self.spaceLeft != 0) {
@throw [NSException exceptionWithName:@"IllegalState" reason:@"Did not write as much data as expected." userInfo:nil];
}
}
/** Write a single byte. */
- (void) writeRawByte:(uint8_t) value {
if (position == (int32_t)buffer.length) {
[self refreshBuffer];
}
((uint8_t*)buffer.mutableBytes)[position++] = value;
}
/** Write an array of bytes. */
- (void) writeRawData:(NSData*) data {
[self writeRawData:data offset:0 length:(int32_t)data.length];
}
- (void) writeRawData:(NSData*) value offset:(int32_t) offset length:(int32_t) length {
if ((int32_t)buffer.length - position >= length) {
// We have room in the current buffer.
memcpy(((uint8_t*)buffer.mutableBytes) + position, ((uint8_t*)value.bytes) + offset, length);
position += length;
} else {
// Write extends past current buffer. Fill the rest of this buffer and flush.
int32_t bytesWritten = (int32_t)buffer.length - position;
memcpy(((uint8_t*)buffer.mutableBytes) + position, ((uint8_t*)value.bytes) + offset, bytesWritten);
offset += bytesWritten;
length -= bytesWritten;
position = (int32_t)buffer.length;
[self refreshBuffer];
// Now deal with the rest.
// Since we have an output stream, this is our buffer
// and buffer offset == 0
if (length <= (int32_t)buffer.length) {
// Fits in new buffer.
memcpy((uint8_t*)buffer.mutableBytes, ((uint8_t*)value.bytes) + offset, length);
position = length;
} else {
// Write is very big. Let's do it all at once.
[output write:((uint8_t*) value.bytes) + offset maxLength:(NSUInteger)length];
}
}
}
/** Encode and write a tag. */
- (void) writeTag:(int32_t) fieldNumber
format:(int32_t) format {
[self writeRawVarint32:PBWireFormatMakeTag(fieldNumber, format)];
}
/** Compute the number of bytes that would be needed to encode a tag. */
int32_t computeTagSize(int32_t fieldNumber) {
return computeRawVarint32Size(PBWireFormatMakeTag(fieldNumber, 0));
}
/**
* Encode and write a varint. {@code value} is treated as
* unsigned, so it won't be sign-extended if negative.
*/
- (void) writeRawVarint32:(int32_t) value {
while (YES) {
if ((value & ~0x7F) == 0) {
[self writeRawByte:(uint8_t)value];
return;
} else {
[self writeRawByte:((value & 0x7F) | 0x80)];
value = logicalRightShift32(value, 7);
}
}
}
/**
* Compute the number of bytes that would be needed to encode a varint.
* {@code value} is treated as unsigned, so it won't be sign-extended if
* negative.
*/
int32_t computeRawVarint32Size(int32_t value) {
if ((value & (0xffffffffLL << 7)) == 0) return 1;
if ((value & (0xffffffffLL << 14)) == 0) return 2;
if ((value & (0xffffffffLL << 21)) == 0) return 3;
if ((value & (0xffffffffLL << 28)) == 0) return 4;
return 5;
}
/** Encode and write a varint. */
- (void) writeRawVarint64:(int64_t) value{
while (YES) {
if ((value & ~0x7FL) == 0) {
[self writeRawByte:(uint8_t)((int32_t) value)];
return;
} else {
[self writeRawByte:(uint8_t)(((int32_t) value & 0x7F) | 0x80)];
value = logicalRightShift64(value, 7);
}
}
}
/** Compute the number of bytes that would be needed to encode a varint. */
int32_t computeRawVarint64Size(int64_t value) {
if (((uint64_t)value & (0xffffffffffffffffULL << 7)) == 0) return 1;
if (((uint64_t)value & (0xffffffffffffffffULL << 14)) == 0) return 2;
if (((uint64_t)value & (0xffffffffffffffffULL << 21)) == 0) return 3;
if (((uint64_t)value & (0xffffffffffffffffULL << 28)) == 0) return 4;
if (((uint64_t)value & (0xffffffffffffffffULL << 35)) == 0) return 5;
if (((uint64_t)value & (0xffffffffffffffffULL << 42)) == 0) return 6;
if (((uint64_t)value & (0xffffffffffffffffULL << 49)) == 0) return 7;
if (((uint64_t)value & (0xffffffffffffffffULL << 56)) == 0) return 8;
if (((uint64_t)value & (0xffffffffffffffffULL << 63)) == 0) return 9;
return 10;
}
/** Write a little-endian 32-bit integer. */
- (void) writeRawLittleEndian32:(int32_t) value {
[self writeRawByte:((value ) & 0xFF)];
[self writeRawByte:((value >> 8) & 0xFF)];
[self writeRawByte:((value >> 16) & 0xFF)];
[self writeRawByte:((value >> 24) & 0xFF)];
}
/** Write a little-endian 64-bit integer. */
- (void) writeRawLittleEndian64:(int64_t) value {
[self writeRawByte:((int32_t)(value ) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 8) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 16) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 24) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 32) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 40) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 48) & 0xFF)];
[self writeRawByte:((int32_t)(value >> 56) & 0xFF)];
}
/**
* Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n A signed 32-bit integer.
* @return An unsigned 32-bit integer, stored in a signed int
*/
int32_t encodeZigZag32(int32_t n) {
// Note: the right-shift must be arithmetic
return (n << 1) ^ (n >> 31);
}
/**
* Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n A signed 64-bit integer.
* @return An unsigned 64-bit integer, stored in a signed int
*/
int64_t encodeZigZag64(int64_t n) {
// Note: the right-shift must be arithmetic
return (n << 1) ^ (n >> 63);
}
@end

View File

@ -0,0 +1,62 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ExtensionField.h"
typedef enum {
PBExtensionTypeBool,
PBExtensionTypeFixed32,
PBExtensionTypeSFixed32,
PBExtensionTypeFloat,
PBExtensionTypeFixed64,
PBExtensionTypeSFixed64,
PBExtensionTypeDouble,
PBExtensionTypeInt32,
PBExtensionTypeInt64,
PBExtensionTypeSInt32,
PBExtensionTypeSInt64,
PBExtensionTypeUInt32,
PBExtensionTypeUInt64,
PBExtensionTypeBytes,
PBExtensionTypeString,
PBExtensionTypeMessage,
PBExtensionTypeGroup,
PBExtensionTypeEnum
} PBExtensionType;
@interface PBConcreteExtensionField : NSObject<PBExtensionField> {
@private
PBExtensionType type;
Class extendedClass;
int32_t fieldNumber;
id defaultValue;
Class messageOrGroupClass;
BOOL isRepeated;
BOOL isPacked;
BOOL isMessageSetWireFormat;
}
+ (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type
extendedClass:(Class) extendedClass
fieldNumber:(int32_t) fieldNumber
defaultValue:(id) defaultValue
messageOrGroupClass:(Class) messageOrGroupClass
isRepeated:(BOOL) isRepeated
isPacked:(BOOL) isPacked
isMessageSetWireFormat:(BOOL) isMessageSetWireFormat;
@end

View File

@ -0,0 +1,543 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ConcreteExtensionField.h"
#import "CodedOutputStream.h"
#import "CodedInputStream.h"
#import "Message_Builder.h"
#import "Message.h"
#import "ExtendableMessage_Builder.h"
@interface PBConcreteExtensionField()
@property PBExtensionType type;
@property Class extendedClass;
@property int32_t fieldNumber;
@property (retain) id defaultValue;
@property Class messageOrGroupClass;
@property BOOL isRepeated;
@property BOOL isPacked;
@property BOOL isMessageSetWireFormat;
@end
@implementation PBConcreteExtensionField
@synthesize type;
@synthesize extendedClass;
@synthesize fieldNumber;
@synthesize defaultValue;
@synthesize messageOrGroupClass;
@synthesize isRepeated;
@synthesize isPacked;
@synthesize isMessageSetWireFormat;
- (void) dealloc {
self.type = 0;
self.extendedClass = nil;
self.fieldNumber = 0;
self.defaultValue = nil;
self.messageOrGroupClass = nil;
self.isRepeated = NO;
self.isPacked = NO;
self.isMessageSetWireFormat = NO;
}
- (id) initWithType:(PBExtensionType) type_
extendedClass:(Class) extendedClass_
fieldNumber:(int32_t) fieldNumber_
defaultValue:(id) defaultValue_
messageOrGroupClass:(Class) messageOrGroupClass_
isRepeated:(BOOL) isRepeated_
isPacked:(BOOL) isPacked_
isMessageSetWireFormat:(BOOL) isMessageSetWireFormat_ {
if ((self = [super init])) {
self.type = type_;
self.extendedClass = extendedClass_;
self.fieldNumber = fieldNumber_;
self.defaultValue = defaultValue_;
self.messageOrGroupClass = messageOrGroupClass_;
self.isRepeated = isRepeated_;
self.isPacked = isPacked_;
self.isMessageSetWireFormat = isMessageSetWireFormat_;
}
return self;
}
+ (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type
extendedClass:(Class) extendedClass
fieldNumber:(int32_t) fieldNumber
defaultValue:(id) defaultValue
messageOrGroupClass:(Class) messageOrGroupClass
isRepeated:(BOOL) isRepeated
isPacked:(BOOL) isPacked
isMessageSetWireFormat:(BOOL) isMessageSetWireFormat {
return [[PBConcreteExtensionField alloc] initWithType:type
extendedClass:extendedClass
fieldNumber:fieldNumber
defaultValue:defaultValue
messageOrGroupClass:messageOrGroupClass
isRepeated:isRepeated
isPacked:isPacked
isMessageSetWireFormat:isMessageSetWireFormat];
}
- (PBWireFormat) wireType {
if (isPacked) {
return PBWireFormatLengthDelimited;
}
switch (type) {
case PBExtensionTypeBool: return PBWireFormatVarint;
case PBExtensionTypeFixed32: return PBWireFormatFixed32;
case PBExtensionTypeSFixed32: return PBWireFormatFixed32;
case PBExtensionTypeFloat: return PBWireFormatFixed32;
case PBExtensionTypeFixed64: return PBWireFormatFixed64;
case PBExtensionTypeSFixed64: return PBWireFormatFixed64;
case PBExtensionTypeDouble: return PBWireFormatFixed64;
case PBExtensionTypeInt32: return PBWireFormatVarint;
case PBExtensionTypeInt64: return PBWireFormatVarint;
case PBExtensionTypeSInt32: return PBWireFormatVarint;
case PBExtensionTypeSInt64: return PBWireFormatVarint;
case PBExtensionTypeUInt32: return PBWireFormatVarint;
case PBExtensionTypeUInt64: return PBWireFormatVarint;
case PBExtensionTypeBytes: return PBWireFormatLengthDelimited;
case PBExtensionTypeString: return PBWireFormatLengthDelimited;
case PBExtensionTypeMessage: return PBWireFormatLengthDelimited;
case PBExtensionTypeGroup: return PBWireFormatStartGroup;
case PBExtensionTypeEnum: return PBWireFormatVarint;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
BOOL typeIsFixedSize(PBExtensionType type);
BOOL typeIsFixedSize(PBExtensionType type) {
switch (type) {
case PBExtensionTypeBool:
case PBExtensionTypeFixed32:
case PBExtensionTypeSFixed32:
case PBExtensionTypeFloat:
case PBExtensionTypeFixed64:
case PBExtensionTypeSFixed64:
case PBExtensionTypeDouble:
return YES;
default:
return NO;
}
}
int32_t typeSize(PBExtensionType type);
int32_t typeSize(PBExtensionType type) {
switch (type) {
case PBExtensionTypeBool:
return 1;
case PBExtensionTypeFixed32:
case PBExtensionTypeSFixed32:
case PBExtensionTypeFloat:
return 4;
case PBExtensionTypeFixed64:
case PBExtensionTypeSFixed64:
case PBExtensionTypeDouble:
return 8;
default:
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
}
- (void) writeSingleValue:(id) value
includingTagToCodedOutputStream:(PBCodedOutputStream*) output {
switch (type) {
case PBExtensionTypeBool:
[output writeBool:fieldNumber value:[value boolValue]];
return;
case PBExtensionTypeFixed32:
[output writeFixed32:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeSFixed32:
[output writeSFixed32:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeFloat:
[output writeFloat:fieldNumber value:[value floatValue]];
return;
case PBExtensionTypeFixed64:
[output writeFixed64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeSFixed64:
[output writeSFixed64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeDouble:
[output writeDouble:fieldNumber value:[value doubleValue]];
return;
case PBExtensionTypeInt32:
[output writeInt32:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeInt64:
[output writeInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeSInt32:
[output writeSInt32:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeSInt64:
[output writeSInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeUInt32:
[output writeUInt32:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeUInt64:
[output writeUInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeBytes:
[output writeData:fieldNumber value:value];
return;
case PBExtensionTypeString:
[output writeString:fieldNumber value:value];
return;
case PBExtensionTypeGroup:
[output writeGroup:fieldNumber value:value];
return;
case PBExtensionTypeEnum:
[output writeEnum:fieldNumber value:[value intValue]];
return;
case PBExtensionTypeMessage:
if (isMessageSetWireFormat) {
[output writeMessageSetExtension:fieldNumber value:value];
} else {
[output writeMessage:fieldNumber value:value];
}
return;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) writeSingleValue:(id) value
noTagToCodedOutputStream:(PBCodedOutputStream*) output {
switch (type) {
case PBExtensionTypeBool:
[output writeBoolNoTag:[value boolValue]];
return;
case PBExtensionTypeFixed32:
[output writeFixed32NoTag:[value intValue]];
return;
case PBExtensionTypeSFixed32:
[output writeSFixed32NoTag:[value intValue]];
return;
case PBExtensionTypeFloat:
[output writeFloatNoTag:[value floatValue]];
return;
case PBExtensionTypeFixed64:
[output writeFixed64NoTag:[value longLongValue]];
return;
case PBExtensionTypeSFixed64:
[output writeSFixed64NoTag:[value longLongValue]];
return;
case PBExtensionTypeDouble:
[output writeDoubleNoTag:[value doubleValue]];
return;
case PBExtensionTypeInt32:
[output writeInt32NoTag:[value intValue]];
return;
case PBExtensionTypeInt64:
[output writeInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeSInt32:
[output writeSInt32NoTag:[value intValue]];
return;
case PBExtensionTypeSInt64:
[output writeSInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeUInt32:
[output writeUInt32NoTag:[value intValue]];
return;
case PBExtensionTypeUInt64:
[output writeUInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeBytes:
[output writeDataNoTag:value];
return;
case PBExtensionTypeString:
[output writeStringNoTag:value];
return;
case PBExtensionTypeGroup:
[output writeGroupNoTag:fieldNumber value:value];
return;
case PBExtensionTypeEnum:
[output writeEnumNoTag:[value intValue]];
return;
case PBExtensionTypeMessage:
[output writeMessageNoTag:value];
return;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (int32_t) computeSingleSerializedSizeNoTag:(id) value {
switch (type) {
case PBExtensionTypeBool: return computeBoolSizeNoTag([value boolValue]);
case PBExtensionTypeFixed32: return computeFixed32SizeNoTag([value intValue]);
case PBExtensionTypeSFixed32: return computeSFixed32SizeNoTag([value intValue]);
case PBExtensionTypeFloat: return computeFloatSizeNoTag([value floatValue]);
case PBExtensionTypeFixed64: return computeFixed64SizeNoTag([value longLongValue]);
case PBExtensionTypeSFixed64: return computeSFixed64SizeNoTag([value longLongValue]);
case PBExtensionTypeDouble: return computeDoubleSizeNoTag([value doubleValue]);
case PBExtensionTypeInt32: return computeInt32SizeNoTag([value intValue]);
case PBExtensionTypeInt64: return computeInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeSInt32: return computeSInt32SizeNoTag([value intValue]);
case PBExtensionTypeSInt64: return computeSInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeUInt32: return computeUInt32SizeNoTag([value intValue]);
case PBExtensionTypeUInt64: return computeUInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeBytes: return computeDataSizeNoTag(value);
case PBExtensionTypeString: return computeStringSizeNoTag(value);
case PBExtensionTypeGroup: return computeGroupSizeNoTag(value);
case PBExtensionTypeEnum: return computeEnumSizeNoTag([value intValue]);
case PBExtensionTypeMessage: return computeMessageSizeNoTag(value);
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (int32_t) computeSingleSerializedSizeIncludingTag:(id) value {
switch (type) {
case PBExtensionTypeBool: return computeBoolSize(fieldNumber, [value boolValue]);
case PBExtensionTypeFixed32: return computeFixed32Size(fieldNumber, [value intValue]);
case PBExtensionTypeSFixed32: return computeSFixed32Size(fieldNumber, [value intValue]);
case PBExtensionTypeFloat: return computeFloatSize(fieldNumber, [value floatValue]);
case PBExtensionTypeFixed64: return computeFixed64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeSFixed64: return computeSFixed64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeDouble: return computeDoubleSize(fieldNumber, [value doubleValue]);
case PBExtensionTypeInt32: return computeInt32Size(fieldNumber, [value intValue]);
case PBExtensionTypeInt64: return computeInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeSInt32: return computeSInt32Size(fieldNumber, [value intValue]);
case PBExtensionTypeSInt64: return computeSInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeUInt32: return computeUInt32Size(fieldNumber, [value intValue]);
case PBExtensionTypeUInt64: return computeUInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeBytes: return computeDataSize(fieldNumber, value);
case PBExtensionTypeString: return computeStringSize(fieldNumber, value);
case PBExtensionTypeGroup: return computeGroupSize(fieldNumber, value);
case PBExtensionTypeEnum: return computeEnumSize(fieldNumber, [value intValue]);
case PBExtensionTypeMessage:
if (isMessageSetWireFormat) {
return computeMessageSetExtensionSize(fieldNumber, value);
} else {
return computeMessageSize(fieldNumber, value);
}
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) writeRepeatedValues:(NSArray*) values
includingTagsToCodedOutputStream:(PBCodedOutputStream*) output {
if (isPacked) {
[output writeTag:fieldNumber format:PBWireFormatLengthDelimited];
int32_t dataSize = 0;
if (typeIsFixedSize(type)) {
dataSize = (int32_t)values.count * typeSize(type);
} else {
for (id value in values) {
dataSize += [self computeSingleSerializedSizeNoTag:value];
}
}
[output writeRawVarint32:dataSize];
for (id value in values) {
[self writeSingleValue:value noTagToCodedOutputStream:output];
}
} else {
for (id value in values) {
[self writeSingleValue:value includingTagToCodedOutputStream:output];
}
}
}
- (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output {
if (isRepeated) {
[self writeRepeatedValues:value includingTagsToCodedOutputStream:output];
} else {
[self writeSingleValue:value includingTagToCodedOutputStream:output];
}
}
- (int32_t) computeRepeatedSerializedSizeIncludingTags:(NSArray*) values {
if (isPacked) {
int32_t size = 0;
if (typeIsFixedSize(type)) {
size = (int32_t)values.count * typeSize(type);
} else {
for (id value in values) {
size += [self computeSingleSerializedSizeNoTag:value];
}
}
return size + computeTagSize(fieldNumber) + computeRawVarint32Size(size);
} else {
int32_t size = 0;
for (id value in values) {
size += [self computeSingleSerializedSizeIncludingTag:value];
}
return size;
}
}
- (int32_t) computeSerializedSizeIncludingTag:(id) value {
if (isRepeated) {
return [self computeRepeatedSerializedSizeIncludingTags:value];
} else {
return [self computeSingleSerializedSizeIncludingTag:value];
}
}
- (void) mergeMessageSetExtentionFromCodedInputStream:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields {
@throw [NSException exceptionWithName:@"NYI" reason:@"" userInfo:nil];
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
//int typeId = 0;
// ByteString rawBytes = null;
//
// while (true) {
// final int tag = input.readTag();
// if (tag == 0) {
// break;
// }
//
// if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
// typeId = input.readUInt32();
// // Zero is not a valid type ID.
// if (typeId != 0) {
// if (rawBytes != null) {
// unknownFields.mergeField(typeId,
// UnknownFieldSet.Field.newBuilder()
// .addLengthDelimited(rawBytes)
// .build());
// rawBytes = null;
// }
// }
// } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
// if (typeId == 0) {
// // We haven't seen a type ID yet, so we have to store the raw bytes
// // for now.
// rawBytes = input.readBytes();
// } else {
// unknownFields.mergeField(typeId,
// UnknownFieldSet.Field.newBuilder()
// .addLengthDelimited(input.readBytes())
// .build());
// }
// } else {
// // Unknown fieldNumber. Skip it.
// if (!input.skipField(tag)) {
// break; // end of group
// }
// }
// }
//
// input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
}
- (id) readSingleValueFromCodedInputStream:(PBCodedInputStream*) input
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
switch (type) {
case PBExtensionTypeBool: return [NSNumber numberWithBool:[input readBool]];
case PBExtensionTypeFixed32: return [NSNumber numberWithInt:[input readFixed32]];
case PBExtensionTypeSFixed32: return [NSNumber numberWithInt:[input readSFixed32]];
case PBExtensionTypeFloat: return [NSNumber numberWithFloat:[input readFloat]];
case PBExtensionTypeFixed64: return [NSNumber numberWithLongLong:[input readFixed64]];
case PBExtensionTypeSFixed64: return [NSNumber numberWithLongLong:[input readSFixed64]];
case PBExtensionTypeDouble: return [NSNumber numberWithDouble:[input readDouble]];
case PBExtensionTypeInt32: return [NSNumber numberWithInt:[input readInt32]];
case PBExtensionTypeInt64: return [NSNumber numberWithLongLong:[input readInt64]];
case PBExtensionTypeSInt32: return [NSNumber numberWithInt:[input readSInt32]];
case PBExtensionTypeSInt64: return [NSNumber numberWithLongLong:[input readSInt64]];
case PBExtensionTypeUInt32: return [NSNumber numberWithInt:[input readUInt32]];
case PBExtensionTypeUInt64: return [NSNumber numberWithLongLong:[input readUInt64]];
case PBExtensionTypeBytes: return [input readData];
case PBExtensionTypeString: return [input readString];
case PBExtensionTypeEnum: return [NSNumber numberWithInt:[input readEnum]];
case PBExtensionTypeGroup:
{
id<PBMessage_Builder> builder = [messageOrGroupClass builder];
[input readGroup:fieldNumber builder:builder extensionRegistry:extensionRegistry];
return [builder build];
}
case PBExtensionTypeMessage:
{
id<PBMessage_Builder> builder = [messageOrGroupClass builder];
[input readMessage:builder extensionRegistry:extensionRegistry];
return [builder build];
}
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) mergeFromCodedInputStream:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
builder:(PBExtendableMessage_Builder*) builder
tag:(int32_t) tag {
if (isPacked) {
int32_t length = [input readRawVarint32];
int32_t limit = [input pushLimit:length];
while ([input bytesUntilLimit] > 0) {
id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry];
[builder addExtension:self value:value];
}
[input popLimit:limit];
} else if (isMessageSetWireFormat) {
[self mergeMessageSetExtentionFromCodedInputStream:input
unknownFields:unknownFields];
} else {
id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry];
if (isRepeated) {
[builder addExtension:self value:value];
} else {
[builder setExtension:self value:value];
}
}
}
@end

View File

@ -0,0 +1,77 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "GeneratedMessage.h"
@protocol PBExtensionField;
/**
* Generated message classes for message types that contain extension ranges
* subclass this.
*
* <p>This class implements type-safe accessors for extensions. They
* implement all the same operations that you can do with normal fields --
* e.g. "has", "get", and "getCount" -- but for extensions. The extensions
* are identified using instances of the class {@link GeneratedExtension};
* the protocol compiler generates a static instance of this class for every
* extension in its input. Through the magic of generics, all is made
* type-safe.
*
* <p>For example, imagine you have the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* <p>Then you might write code like:
*
* <pre>
* MyProto.Foo foo = getFoo();
* int i = foo.getExtension(MyProto.bar);
* </pre>
*
* <p>See also {@link ExtendableBuilder}.
*/
@interface PBExtendableMessage : PBGeneratedMessage {
@private
NSMutableDictionary* extensionMap;
NSMutableDictionary* extensionRegistry;
}
@property (retain) NSMutableDictionary* extensionMap;
@property (retain) NSMutableDictionary* extensionRegistry;
- (BOOL) hasExtension:(id<PBExtensionField>) extension;
- (id) getExtension:(id<PBExtensionField>) extension;
//@protected
- (BOOL) extensionsAreInitialized;
- (int32_t) extensionsSerializedSize;
- (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output
from:(int32_t) startInclusive
to:(int32_t) endExclusive;
/* @internal */
- (void) ensureExtensionIsRegistered:(id<PBExtensionField>) extension;
@end

View File

@ -0,0 +1,106 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ExtendableMessage.h"
#import "ExtensionField.h"
@implementation PBExtendableMessage
@synthesize extensionMap;
@synthesize extensionRegistry;
- (void) dealloc {
self.extensionMap = nil;
self.extensionRegistry = nil;
}
- (BOOL) isInitialized:(id) object {
if ([object isKindOfClass:[NSArray class]]) {
for (id child in object) {
if (![self isInitialized:child]) {
return NO;
}
}
} else if ([object conformsToProtocol:@protocol(PBMessage)]) {
return [object isInitialized];
}
return YES;
}
- (BOOL) extensionsAreInitialized {
return [self isInitialized:extensionMap.allValues];
}
- (id) getExtension:(id<PBExtensionField>) extension {
[self ensureExtensionIsRegistered:extension];
id value = [extensionMap objectForKey:[NSNumber numberWithInt:[extension fieldNumber]]];
if (value != nil) {
return value;
}
return [extension defaultValue];
}
- (void) ensureExtensionIsRegistered:(id<PBExtensionField>) extension {
if ([extension extendedClass] != [self class]) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Trying to use an extension for another type" userInfo:nil];
}
if (extensionRegistry == nil) {
self.extensionRegistry = [NSMutableDictionary dictionary];
}
[extensionRegistry setObject:extension
forKey:[NSNumber numberWithInt:[extension fieldNumber]]];
}
- (BOOL) hasExtension:(id<PBExtensionField>) extension {
return nil != [extensionMap objectForKey:[NSNumber numberWithInt:[extension fieldNumber]]];
}
- (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output
from:(int32_t) startInclusive
to:(int32_t) endExclusive {
// man, i really wish Cocoa had a Sorted/TreeMap
NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSNumber* number in sortedKeys) {
int32_t fieldNumber = [number intValue];
if (fieldNumber >= startInclusive && fieldNumber < endExclusive) {
id<PBExtensionField> extension = [extensionRegistry objectForKey:number];
id value = [extensionMap objectForKey:number];
[extension writeValue:value includingTagToCodedOutputStream:output];
}
}
}
- (int32_t) extensionsSerializedSize {
int32_t size = 0;
for (NSNumber* number in extensionMap) {
id<PBExtensionField> extension = [extensionRegistry objectForKey:number];
id value = [extensionMap objectForKey:number];
size += [extension computeSerializedSizeIncludingTag:value];
}
return size;
}
@end

View File

@ -0,0 +1,75 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "GeneratedMessage_Builder.h"
@protocol PBExtensionField;
@class PBExtendableMessage_Builder;
@class PBExtendableMessage;
/**
* Generated message builders for message types that contain extension ranges
* subclass this.
*
* <p>This class implements type-safe accessors for extensions. They
* implement all the same operations that you can do with normal fields --
* e.g. "get", "set", and "add" -- but for extensions. The extensions are
* identified using instances of the class {@link GeneratedExtension}; the
* protocol compiler generates a static instance of this class for every
* extension in its input. Through the magic of generics, all is made
* type-safe.
*
* <p>For example, imagine you have the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* <p>Then you might write code like:
*
* <pre>
* MyProto.Foo foo =
* MyProto.Foo.newBuilder()
* .setExtension(MyProto.bar, 123)
* .build();
* </pre>
*
* <p>See also {@link ExtendableMessage}.
*/
@interface PBExtendableMessage_Builder : PBGeneratedMessage_Builder {
}
- (id) getExtension:(id<PBExtensionField>) extension;
- (BOOL) hasExtension:(id<PBExtensionField>) extension;
- (PBExtendableMessage_Builder*) setExtension:(id<PBExtensionField>) extension
value:(id) value;
- (PBExtendableMessage_Builder*) addExtension:(id<PBExtensionField>) extension
value:(id) value;
- (PBExtendableMessage_Builder*) setExtension:(id<PBExtensionField>) extension
index:(int32_t) index
value:(id) value;
- (PBExtendableMessage_Builder*) clearExtension:(id<PBExtensionField>) extension;
/* @protected */
- (void) mergeExtensionFields:(PBExtendableMessage*) other;
@end

View File

@ -0,0 +1,173 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ExtendableMessage_Builder.h"
#import "ExtendableMessage.h"
#import "ExtensionField.h"
#import "WireFormat.h"
#import "ExtensionRegistry.h"
@implementation PBExtendableMessage_Builder
- (PBExtendableMessage*) internalGetResult {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code YES} unless the tag is an end-group tag.
*/
- (BOOL) parseUnknownField:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
tag:(int32_t) tag {
PBExtendableMessage* message = [self internalGetResult];
int32_t wireType = PBWireFormatGetTagWireType(tag);
int32_t fieldNumber = PBWireFormatGetTagFieldNumber(tag);
id<PBExtensionField> extension = [extensionRegistry getExtension:[message class]
fieldNumber:fieldNumber];
if (extension != nil) {
if ([extension wireType] == wireType) {
[extension mergeFromCodedInputStream:input
unknownFields:unknownFields
extensionRegistry:extensionRegistry
builder:self
tag:tag];
return YES;
}
}
return [super parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag];
}
- (id) getExtension:(id<PBExtensionField>) extension {
return [[self internalGetResult] getExtension:extension];
}
- (BOOL) hasExtension:(id<PBExtensionField>) extension {
return [[self internalGetResult] hasExtension:extension];
}
- (PBExtendableMessage_Builder*) setExtension:(id<PBExtensionField>) extension
value:(id) value {
PBExtendableMessage* message = [self internalGetResult];
[message ensureExtensionIsRegistered:extension];
if ([extension isRepeated]) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call addExtension() for repeated types." userInfo:nil];
}
if (message.extensionMap == nil) {
message.extensionMap = [NSMutableDictionary dictionary];
}
[message.extensionMap setObject:value forKey:[NSNumber numberWithInt:[extension fieldNumber]]];
return self;
}
- (PBExtendableMessage_Builder*) addExtension:(id<PBExtensionField>) extension
value:(id) value {
PBExtendableMessage* message = [self internalGetResult];
[message ensureExtensionIsRegistered:extension];
if (![extension isRepeated]) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call setExtension() for singular types." userInfo:nil];
}
if (message.extensionMap == nil) {
message.extensionMap = [NSMutableDictionary dictionary];
}
NSNumber* fieldNumber = [NSNumber numberWithInt:[extension fieldNumber]];
NSMutableArray* list = [message.extensionMap objectForKey:fieldNumber];
if (list == nil) {
list = [NSMutableArray array];
[message.extensionMap setObject:list forKey:fieldNumber];
}
[list addObject:value];
return self;
}
- (PBExtendableMessage_Builder*) setExtension:(id<PBExtensionField>) extension
index:(int32_t) index
value:(id) value {
PBExtendableMessage* message = [self internalGetResult];
[message ensureExtensionIsRegistered:extension];
if (![extension isRepeated]) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Must call setExtension() for singular types." userInfo:nil];
}
if (message.extensionMap == nil) {
message.extensionMap = [NSMutableDictionary dictionary];
}
NSNumber* fieldNumber = [NSNumber numberWithInt:[extension fieldNumber]];
NSMutableArray* list = [message.extensionMap objectForKey:fieldNumber];
[list replaceObjectAtIndex:(NSUInteger)index withObject:value];
return self;
}
- (PBExtendableMessage_Builder*) clearExtension:(id<PBExtensionField>) extension {
PBExtendableMessage* message = [self internalGetResult];
[message ensureExtensionIsRegistered:extension];
[message.extensionMap removeObjectForKey:[NSNumber numberWithInt:[extension fieldNumber]]];
return self;
}
- (void) mergeExtensionFields:(PBExtendableMessage*) other {
PBExtendableMessage* thisMessage = [self internalGetResult];
if ([thisMessage class] != [other class]) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Cannot merge extensions from a different type" userInfo:nil];
}
if (other.extensionMap.count > 0) {
if (thisMessage.extensionMap == nil) {
thisMessage.extensionMap = [NSMutableDictionary dictionary];
}
NSDictionary* registry = other.extensionRegistry;
for (NSNumber* fieldNumber in other.extensionMap) {
id<PBExtensionField> thisField = [registry objectForKey:fieldNumber];
id value = [other.extensionMap objectForKey:fieldNumber];
if ([thisField isRepeated]) {
NSMutableArray* list = [thisMessage.extensionMap objectForKey:fieldNumber];
if (list == nil) {
list = [NSMutableArray array];
[thisMessage.extensionMap setObject:list forKey:fieldNumber];
}
[list addObjectsFromArray:value];
} else {
[thisMessage.extensionMap setObject:value forKey:fieldNumber];
}
}
}
}
@end

View File

@ -0,0 +1,36 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "WireFormat.h"
@class PBCodedInputStream;
@class PBUnknownFieldSet_Builder;
@class PBExtendableMessage_Builder;
@class PBCodedOutputStream;
@class PBExtensionRegistry;
@protocol PBExtensionField
- (int32_t) fieldNumber;
- (PBWireFormat) wireType;
- (BOOL) isRepeated;
- (Class) extendedClass;
- (id) defaultValue;
- (void) mergeFromCodedInputStream:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
builder:(PBExtendableMessage_Builder*) builder
tag:(int32_t) tag;
- (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output;
- (int32_t) computeSerializedSizeIncludingTag:(id) value;
@end

View File

@ -0,0 +1,83 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* A table of known extensions, searchable by name or field number. When
* parsing a protocol message that might have extensions, you must provide
* an {@code ExtensionRegistry} in which you have registered any extensions
* that you want to be able to parse. Otherwise, those extensions will just
* be treated like unknown fields.
*
* <p>For example, if you had the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* Then you might write code like:
*
* <pre>
* ExtensionRegistry registry = ExtensionRegistry.newInstance();
* registry.add(MyProto.bar);
* MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
* </pre>
*
* <p>Background:
*
* <p>You might wonder why this is necessary. Two alternatives might come to
* mind. First, you might imagine a system where generated extensions are
* automatically registered when their containing classes are loaded. This
* is a popular technique, but is bad design; among other things, it creates a
* situation where behavior can change depending on what classes happen to be
* loaded. It also introduces a security vulnerability, because an
* unprivileged class could cause its code to be called unexpectedly from a
* privileged class by registering itself as an extension of the right type.
*
* <p>Another option you might consider is lazy parsing: do not parse an
* extension until it is first requested, at which point the caller must
* provide a type to use. This introduces a different set of problems. First,
* it would require a mutex lock any time an extension was accessed, which
* would be slow. Second, corrupt data would not be detected until first
* access, at which point it would be much harder to deal with it. Third, it
* could violate the expectation that message objects are immutable, since the
* type provided could be any arbitrary message class. An unpriviledged user
* could take advantage of this to inject a mutable object into a message
* belonging to priviledged code and create mischief.
*
* @author Cyrus Najmabadi
*/
@protocol PBExtensionField;
@interface PBExtensionRegistry : NSObject {
@protected
NSDictionary* classMap;
}
+ (PBExtensionRegistry*) emptyRegistry;
- (id<PBExtensionField>) getExtension:(Class) clazz fieldNumber:(NSInteger) fieldNumber;
/* @protected */
- (id) initWithClassMap:(NSDictionary*) classMap;
- (id) keyForClass:(Class) clazz;
@end

View File

@ -0,0 +1,62 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ExtensionRegistry.h"
@interface PBExtensionRegistry()
@property (retain) NSDictionary* classMap;
@end
@implementation PBExtensionRegistry
@synthesize classMap;
- (void) dealloc {
self.classMap = nil;
}
static PBExtensionRegistry* emptyRegistry = nil;
+ (void) initialize {
if (self == [PBExtensionRegistry class]) {
emptyRegistry = [[PBExtensionRegistry alloc] initWithClassMap:[NSDictionary dictionary]];
}
}
- (id) initWithClassMap:(NSDictionary*) map_{
if ((self = [super init])) {
self.classMap = map_;
}
return self;
}
- (id) keyForClass:(Class) clazz {
return NSStringFromClass(clazz);
}
+ (PBExtensionRegistry*) emptyRegistry {
return emptyRegistry;
}
- (id<PBExtensionField>) getExtension:(Class) clazz fieldNumber:(NSInteger) fieldNumber {
NSDictionary* extensionMap = [classMap objectForKey:[self keyForClass:clazz]];
return [extensionMap objectForKey:[NSNumber numberWithInteger:fieldNumber]];
}
@end

View File

@ -0,0 +1,42 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBCodedOutputStream;
@interface PBField : NSObject {
@protected
NSMutableArray* mutableVarintList;
NSMutableArray* mutableFixed32List;
NSMutableArray* mutableFixed64List;
NSMutableArray* mutableLengthDelimitedList;
NSMutableArray* mutableGroupList;
}
- (NSArray*) varintList;
- (NSArray*) fixed32List;
- (NSArray*) fixed64List;
- (NSArray*) lengthDelimitedList;
- (NSArray*) groupList;
+ (PBField*) defaultInstance;
- (void) writeTo:(int32_t) fieldNumber
output:(PBCodedOutputStream*) output;
- (int32_t) getSerializedSize:(int32_t) fieldNumber;
- (void) writeAsMessageSetExtensionTo:(int32_t) fieldNumber
output:(PBCodedOutputStream*) output;
- (int32_t) getSerializedSizeAsMessageSetExtension:(int32_t) fieldNumber;
@end

View File

@ -0,0 +1,143 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Field.h"
#import "CodedOutputStream.h"
#import "MutableField.h"
@interface PBField ()
@property (retain) NSMutableArray* mutableVarintList;
@property (retain) NSMutableArray* mutableFixed32List;
@property (retain) NSMutableArray* mutableFixed64List;
@property (retain) NSMutableArray* mutableLengthDelimitedList;
@property (retain) NSMutableArray* mutableGroupList;
@end
@implementation PBField
static PBField* defaultInstance = nil;
+ (void) initialize {
if (self == [PBField class]) {
defaultInstance = [[PBField alloc] init];
}
}
@synthesize mutableVarintList;
@synthesize mutableFixed32List;
@synthesize mutableFixed64List;
@synthesize mutableLengthDelimitedList;
@synthesize mutableGroupList;
- (void) dealloc {
self.mutableVarintList = nil;
self.mutableFixed32List = nil;
self.mutableFixed64List = nil;
self.mutableLengthDelimitedList = nil;
self.mutableGroupList = nil;
}
+ (PBField*) defaultInstance {
return defaultInstance;
}
- (NSArray*) varintList {
return mutableVarintList;
}
- (NSArray*) fixed32List {
return mutableFixed32List;
}
- (NSArray*) fixed64List {
return mutableFixed64List;
}
- (NSArray*) lengthDelimitedList {
return mutableLengthDelimitedList;
}
- (NSArray*) groupList {
return mutableGroupList;
}
- (void) writeTo:(int32_t) fieldNumber
output:(PBCodedOutputStream*) output {
for (NSNumber* value in self.varintList) {
[output writeUInt64:fieldNumber value:value.longLongValue];
}
for (NSNumber* value in self.fixed32List) {
[output writeFixed32:fieldNumber value:value.intValue];
}
for (NSNumber* value in self.fixed64List) {
[output writeFixed64:fieldNumber value:value.longLongValue];
}
for (NSData* value in self.lengthDelimitedList) {
[output writeData:fieldNumber value:value];
}
for (PBUnknownFieldSet* value in self.groupList) {
[output writeUnknownGroup:fieldNumber value:value];
}
}
- (int32_t) getSerializedSize:(int32_t) fieldNumber {
int32_t result = 0;
for (NSNumber* value in self.varintList) {
result += computeUInt64Size(fieldNumber, value.longLongValue);
}
for (NSNumber* value in self.fixed32List) {
result += computeFixed32Size(fieldNumber, value.intValue);
}
for (NSNumber* value in self.fixed64List) {
result += computeFixed64Size(fieldNumber, value.longLongValue);
}
for (NSData* value in self.lengthDelimitedList) {
result += computeDataSize(fieldNumber, value);
}
for (PBUnknownFieldSet* value in self.groupList) {
result += computeUnknownGroupSize(fieldNumber, value);
}
return result;
}
- (void) writeAsMessageSetExtensionTo:(int32_t) fieldNumber
output:(PBCodedOutputStream*) output {
for (NSData* value in self.lengthDelimitedList) {
[output writeRawMessageSetExtension:fieldNumber value:value];
}
}
- (int32_t) getSerializedSizeAsMessageSetExtension:(int32_t) fieldNumber {
int32_t result = 0;
for (NSData* value in self.lengthDelimitedList) {
result += computeRawMessageSetExtensionSize(fieldNumber, value);
}
return result;
}
@end

View File

@ -0,0 +1,32 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@protocol PBMessage;
@protocol PBMessage_Builder;
@protocol PBExtensionField;
@class PBAbstractMessage;
@class PBCodedInputStream;
@class PBCodedOutputStream;
@class PBConcreteExtensionField;
@class PBExtendableMessage_Builder;
@class PBExtendableMessage;
@class PBExtensionRegistry;
@class PBField;
@class PBGeneratedMessage;
@class PBGeneratedMessage_Builder;
@class PBMutableExtensionRegistry;
@class PBMutableField;
@class PBUnknownFieldSet;
@class PBUnknownFieldSet_Builder;

View File

@ -0,0 +1,33 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AbstractMessage.h"
/**
* All generated protocol message classes extend this class. This class
* implements most of the Message and Builder interfaces using Java reflection.
* Users can ignore this class and pretend that generated messages implement
* the Message interface directly.
*
* @author Cyrus Najmabadi
*/
@interface PBGeneratedMessage : PBAbstractMessage {
@private
PBUnknownFieldSet* unknownFields;
@protected
int32_t memoizedSerializedSize;
}
@end

View File

@ -0,0 +1,42 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "GeneratedMessage.h"
#import "UnknownFieldSet.h"
@interface PBGeneratedMessage ()
@property (retain) PBUnknownFieldSet* unknownFields;
@end
@implementation PBGeneratedMessage
@synthesize unknownFields;
- (void) dealloc {
self.unknownFields = nil;
}
- (id) init {
if ((self = [super init])) {
self.unknownFields = [PBUnknownFieldSet defaultInstance];
memoizedSerializedSize = -1;
}
return self;
}
@end

View File

@ -0,0 +1,30 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "AbstractMessage_Builder.h"
@class PBUnknownFieldSet_Builder;
@interface PBGeneratedMessage_Builder : PBAbstractMessage_Builder {
}
/* @protected */
- (BOOL) parseUnknownField:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
tag:(int32_t) tag;
- (void) checkInitialized;
@end

View File

@ -0,0 +1,92 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "GeneratedMessage_Builder.h"
#import "GeneratedMessage.h"
#import "Message.h"
#import "Message_Builder.h"
#import "UnknownFieldSet.h"
#import "UnknownFieldSet_Builder.h"
@interface PBGeneratedMessage ()
@property (retain) PBUnknownFieldSet* unknownFields;
@end
@implementation PBGeneratedMessage_Builder
/**
* Get the message being built. We don't just pass this to the
* constructor because it becomes null when build() is called.
*/
- (PBGeneratedMessage*) internalGetResult {
@throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil];
}
- (void) checkInitialized {
PBGeneratedMessage* result = self.internalGetResult;
if (result != nil && !result.isInitialized) {
@throw [NSException exceptionWithName:@"UninitializedMessage" reason:@"" userInfo:nil];
}
}
- (PBUnknownFieldSet*) unknownFields {
return self.internalGetResult.unknownFields;
}
- (id<PBMessage_Builder>) setUnknownFields:(PBUnknownFieldSet*) unknownFields {
self.internalGetResult.unknownFields = unknownFields;
return self;
}
- (id<PBMessage_Builder>) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields {
PBGeneratedMessage* result = self.internalGetResult;
result.unknownFields =
[[[PBUnknownFieldSet builderWithUnknownFields:result.unknownFields]
mergeUnknownFields:unknownFields] build];
return self;
}
- (BOOL) isInitialized {
return self.internalGetResult.isInitialized;
}
/**
* Called by subclasses to parse an unknown field.
* @return {@code YES} unless the tag is an end-group tag.
*/
- (BOOL) parseUnknownField:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSet_Builder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
tag:(int32_t) tag {
return [unknownFields mergeFieldFrom:tag input:input];
}
- (void) checkInitializedParsed {
PBGeneratedMessage* result = self.internalGetResult;
if (result != nil && !result.isInitialized) {
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"" userInfo:nil];
}
}
@end

View File

@ -0,0 +1,70 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBUnknownFieldSet;
@class PBCodedOutputStream;
@protocol PBMessage_Builder;
/**
* Abstract interface implemented by Protocol Message objects.
*
* @author Cyrus Najmabadi
*/
@protocol PBMessage<NSObject>
/**
* Get an instance of the type with all fields set to their default values.
* This may or may not be a singleton. This differs from the
* {@code getDefaultInstance()} method of generated message classes in that
* this method is an abstract method of the {@code Message} interface
* whereas {@code getDefaultInstance()} is a static method of a specific
* class. They return the same thing.
*/
- (id<PBMessage>) defaultInstance;
/**
* Get the {@code UnknownFieldSet}
*/
- (PBUnknownFieldSet*) unknownFields;
/**
* Get the number of bytes required to encode this message. The result
* is only computed on the first call and memoized after that.
*/
- (int32_t) serializedSize;
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
- (BOOL) isInitialized;
/**
* Serializes the message and writes it to {@code output}. This does not
* flush or close the stream.
*/
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
- (void) writeToOutputStream:(NSOutputStream*) output;
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
- (NSData*) data;
/**
* Constructs a new builder for a message of the same type as this message.
*/
- (id<PBMessage_Builder>) builder;
@end

View File

@ -0,0 +1,134 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@protocol PBMessage;
@protocol PBMessage_Builder;
@class PBUnknownFieldSet;
@class PBCodedInputStream;
@class PBExtensionRegistry;
/**
* Abstract interface implemented by Protocol Message builders.
*/
@protocol PBMessage_Builder<NSObject>
/** Resets all fields to their default values. */
- (id<PBMessage_Builder>) clear;
/**
* Construct the final message. Once this is called, the Builder is no
* longer valid, and calling any other method may throw a
* NullPointerException. If you need to continue working with the builder
* after calling {@code build()}, {@code clone()} it first.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
*/
- (id<PBMessage>) build;
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
*/
- (id<PBMessage>) buildPartial;
- (id<PBMessage_Builder>) clone;
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
- (BOOL) isInitialized;
/**
* Get the message's type's default instance.
* See {@link Message#getDefaultInstanceForType()}.
*/
- (id<PBMessage>) defaultInstance;
- (PBUnknownFieldSet*) unknownFields;
- (id<PBMessage_Builder>) setUnknownFields:(PBUnknownFieldSet*) unknownFields;
/**
* Merge some unknown fields into the {@link UnknownFieldSet} for this
* message.
*/
- (id<PBMessage_Builder>) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields;
/**
* Parses a message of this type from the input and merges it with this
* message, as if using {@link Builder#mergeFrom(Message)}.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
* required fields, it will throw an {@link UninitializedMessageException},
* which is a {@code RuntimeException} and thus might not be caught. There
* are a few good ways to deal with this:
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
* <li>Parse the message separately using one of the static
* {@code parseFrom} methods, then use {@link #mergeFrom(Message)}
* to merge it with this one. {@code parseFrom} will throw an
* {@link InvalidProtocolBufferException} (an {@code IOException})
* if some required fields are missing.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
- (id<PBMessage_Builder>) mergeFromCodedInputStream:(PBCodedInputStream*) input;
/**
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
* parses extensions. The extensions that you want to be able to parse
* must be registered in {@code extensionRegistry}. Extensions not in
* the registry will be treated as unknown fields.
*/
- (id<PBMessage_Builder>) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
- (id<PBMessage_Builder>) mergeFromData:(NSData*) data;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
- (id<PBMessage_Builder>) mergeFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
* reads the <i>entire</i> input (unless it throws an exception). If you
* want it to stop earlier, you will need to wrap your input in some
* wrapper stream that limits reading. Despite usually reading the entire
* input, this does not close the stream.
*/
- (id<PBMessage_Builder>) mergeFromInputStream:(NSInputStream*) input;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
- (id<PBMessage_Builder>) mergeFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
@end

View File

@ -0,0 +1,26 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ExtensionRegistry.h"
@interface PBMutableExtensionRegistry : PBExtensionRegistry {
@private
NSMutableDictionary* mutableClassMap;
}
+ (PBMutableExtensionRegistry*) registry;
- (void) addExtension:(id<PBExtensionField>) extension;
@end

View File

@ -0,0 +1,65 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "MutableExtensionRegistry.h"
#import "ExtensionField.h"
@interface PBMutableExtensionRegistry()
@property (retain) NSMutableDictionary* mutableClassMap;
@end
@implementation PBMutableExtensionRegistry
@synthesize mutableClassMap;
- (void) dealloc {
self.mutableClassMap = nil;
}
- (id) initWithClassMap:(NSMutableDictionary*) mutableClassMap_ {
if ((self = [super initWithClassMap:mutableClassMap_])) {
self.mutableClassMap = mutableClassMap_;
}
return self;
}
+ (PBMutableExtensionRegistry*) registry {
return [[PBMutableExtensionRegistry alloc] initWithClassMap:[NSMutableDictionary dictionary]];
}
- (void) addExtension:(id<PBExtensionField>) extension {
if (extension == nil) {
return;
}
Class extendedClass = [extension extendedClass];
id key = [self keyForClass:extendedClass];
NSMutableDictionary* extensionMap = [classMap objectForKey:key];
if (extensionMap == nil) {
extensionMap = [NSMutableDictionary dictionary];
[mutableClassMap setObject:extensionMap forKey:key];
}
[extensionMap setObject:extension
forKey:[NSNumber numberWithInteger:[extension fieldNumber]]];
}
@end

View File

@ -0,0 +1,33 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Field.h"
@class PBUnknownFieldSet;
@interface PBMutableField : PBField {
}
+ (PBMutableField*) field;
- (PBMutableField*) mergeFromField:(PBField*) other;
- (PBMutableField*) clear;
- (PBMutableField*) addVarint:(int64_t) value;
- (PBMutableField*) addFixed32:(int32_t) value;
- (PBMutableField*) addFixed64:(int64_t) value;
- (PBMutableField*) addLengthDelimited:(NSData*) value;
- (PBMutableField*) addGroup:(PBUnknownFieldSet*) value;
@end

View File

@ -0,0 +1,138 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "MutableField.h"
#import "Field.h"
@interface PBField ()
@property (retain) NSMutableArray* mutableVarintList;
@property (retain) NSMutableArray* mutableFixed32List;
@property (retain) NSMutableArray* mutableFixed64List;
@property (retain) NSMutableArray* mutableLengthDelimitedList;
@property (retain) NSMutableArray* mutableGroupList;
@end
@implementation PBMutableField
+ (PBMutableField*) field {
return [[PBMutableField alloc] init];
}
- (id) init {
if ((self = [super init])) {
}
return self;
}
- (PBMutableField*) clear {
self.mutableVarintList = nil;
self.mutableFixed32List = nil;
self.mutableFixed64List = nil;
self.mutableLengthDelimitedList = nil;
self.mutableGroupList = nil;
return self;
}
- (PBMutableField*) mergeFromField:(PBField*) other {
if (other.varintList.count > 0) {
if (mutableVarintList == nil) {
self.mutableVarintList = [NSMutableArray array];
}
[mutableVarintList addObjectsFromArray:other.varintList];
}
if (other.fixed32List.count > 0) {
if (mutableFixed32List == nil) {
self.mutableFixed32List = [NSMutableArray array];
}
[mutableFixed32List addObjectsFromArray:other.fixed32List];
}
if (other.fixed64List.count > 0) {
if (mutableFixed64List == nil) {
self.mutableFixed64List = [NSMutableArray array];
}
[mutableFixed64List addObjectsFromArray:other.fixed64List];
}
if (other.lengthDelimitedList.count > 0) {
if (mutableLengthDelimitedList == nil) {
self.mutableLengthDelimitedList = [NSMutableArray array];
}
[mutableLengthDelimitedList addObjectsFromArray:other.lengthDelimitedList];
}
if (other.groupList.count > 0) {
if (mutableGroupList == nil) {
self.mutableGroupList = [NSMutableArray array];
}
[mutableGroupList addObjectsFromArray:other.groupList];
}
return self;
}
- (PBMutableField*) addVarint:(int64_t) value {
if (mutableVarintList == nil) {
self.mutableVarintList = [NSMutableArray array];
}
[mutableVarintList addObject:[NSNumber numberWithLongLong:value]];
return self;
}
- (PBMutableField*) addFixed32:(int32_t) value {
if (mutableFixed32List == nil) {
self.mutableFixed32List = [NSMutableArray array];
}
[mutableFixed32List addObject:[NSNumber numberWithInt:value]];
return self;
}
- (PBMutableField*) addFixed64:(int64_t) value {
if (mutableFixed64List == nil) {
self.mutableFixed64List = [NSMutableArray array];
}
[mutableFixed64List addObject:[NSNumber numberWithLongLong:value]];
return self;
}
- (PBMutableField*) addLengthDelimited:(NSData*) value {
if (mutableLengthDelimitedList == nil) {
self.mutableLengthDelimitedList = [NSMutableArray array];
}
[mutableLengthDelimitedList addObject:value];
return self;
}
- (PBMutableField*) addGroup:(PBUnknownFieldSet*) value {
if (mutableGroupList == nil) {
self.mutableGroupList = [NSMutableArray array];
}
[mutableGroupList addObject:value];
return self;
}
@end

View File

@ -0,0 +1,36 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Bootstrap.h"
#import "AbstractMessage.h"
#import "AbstractMessage_Builder.h"
#import "CodedInputStream.h"
#import "CodedOutputStream.h"
#import "ConcreteExtensionField.h"
#import "ExtendableMessage.h"
#import "ExtendableMessage_Builder.h"
#import "ExtensionField.h"
#import "ExtensionRegistry.h"
#import "Field.h"
#import "GeneratedMessage.h"
#import "GeneratedMessage_Builder.h"
#import "Message.h"
#import "Message_Builder.h"
#import "MutableExtensionRegistry.h"
#import "MutableField.h"
#import "UnknownFieldSet.h"
#import "UnknownFieldSet_Builder.h"
#import "Utilities.h"
#import "WireFormat.h"

View File

@ -0,0 +1,26 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@interface PBTextFormat : NSObject {
}
+ (int32_t) parseInt32:(NSString*) text;
+ (int32_t) parseUInt32:(NSString*) text;
+ (int64_t) parseInt64:(NSString*) text;
+ (int64_t) parseUInt64:(NSString*) text;
+ (NSData*) unescapeBytes:(NSString*) input;
@end

View File

@ -0,0 +1,238 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "TextFormat.h"
#import "Utilities.h"
@implementation PBTextFormat
BOOL allZeroes(NSString* string);
BOOL allZeroes(NSString* string) {
for (int i = 0; i < (int32_t)string.length; i++) {
if ([string characterAtIndex:(NSUInteger)i] != '0') {
return NO;
}
}
return YES;
}
/** Is this an octal digit? */
BOOL isOctal(unichar c);
BOOL isOctal(unichar c) {
return '0' <= c && c <= '7';
}
/** Is this an octal digit? */
BOOL isDecimal(unichar c);
BOOL isDecimal(unichar c) {
return '0' <= c && c <= '9';
}
/** Is this a hex digit? */
BOOL isHex(unichar c);
BOOL isHex(unichar c) {
return
isDecimal(c) ||
('a' <= c && c <= 'f') ||
('A' <= c && c <= 'F');
}
+ (int64_t) parseInteger:(NSString*) text
isSigned:(BOOL) isSigned
isLong:(BOOL) isLong {
if (text.length == 0) {
@throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number was blank" userInfo:nil];
}
if (isblank([text characterAtIndex:0])) {
@throw [NSException exceptionWithName:@"NumberFormat" reason:@"Invalid character" userInfo:nil];
}
if ([text hasPrefix:@"-"]) {
if (!isSigned) {
@throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number must be positive" userInfo:nil];
}
}
// now call into the appropriate conversion utilities.
int64_t result;
const char* in_string = text.UTF8String;
char* out_string = NULL;
errno = 0;
if (isLong) {
if (isSigned) {
result = strtoll(in_string, &out_string, 0);
} else {
result = convertUInt64ToInt64(strtoull(in_string, &out_string, 0));
}
} else {
if (isSigned) {
result = strtol(in_string, &out_string, 0);
} else {
result = convertUInt32ToInt32(strtoul(in_string, &out_string, 0));
}
}
// from the man pages:
// (Thus, i* tr is not `\0' but **endptr is `\0' on return, the entire
// string was valid.)
if (*in_string == 0 || *out_string != 0) {
@throw [NSException exceptionWithName:@"NumberFormat" reason:@"IllegalNumber" userInfo:nil];
}
if (errno == ERANGE) {
@throw [NSException exceptionWithName:@"NumberFormat" reason:@"Number out of range" userInfo:nil];
}
return result;
}
/**
* Parse a 32-bit signed integer from the text. This function recognizes
* the prefixes "0x" and "0" to signify hexidecimal and octal numbers,
* respectively.
*/
+ (int32_t) parseInt32:(NSString*) text {
return (int32_t)[self parseInteger:text isSigned:YES isLong:NO];
}
/**
* Parse a 32-bit unsigned integer from the text. This function recognizes
* the prefixes "0x" and "0" to signify hexidecimal and octal numbers,
* respectively. The result is coerced to a (signed) {@code int} when returned.
*/
+ (int32_t) parseUInt32:(NSString*) text {
return (int32_t)[self parseInteger:text isSigned:NO isLong:NO];
}
/**
* Parse a 64-bit signed integer from the text. This function recognizes
* the prefixes "0x" and "0" to signify hexidecimal and octal numbers,
* respectively.
*/
+ (int64_t) parseInt64:(NSString*) text {
return [self parseInteger:text isSigned:YES isLong:YES];
}
/**
* Parse a 64-bit unsigned integer from the text. This function recognizes
* the prefixes "0x" and "0" to signify hexidecimal and octal numbers,
* respectively. The result is coerced to a (signed) {@code long} when
* returned.
*/
+ (int64_t) parseUInt64:(NSString*) text {
return [self parseInteger:text isSigned:NO isLong:YES];
}
/**
* Interpret a character as a digit (in any base up to 36) and return the
* numeric value. This is like {@code Character.digit()} but we don't accept
* non-ASCII digits.
*/
int32_t digitValue(unichar c);
int32_t digitValue(unichar c) {
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'z') {
return c - 'a' + 10;
} else {
return c - 'A' + 10;
}
}
/**
* Un-escape a byte sequence as escaped using
* {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with
* "\x") are also recognized.
*/
+ (NSData*) unescapeBytes:(NSString*) input {
NSMutableData* result = [NSMutableData dataWithLength:input.length];
int32_t pos = 0;
for (int32_t i = 0; i < (int32_t)input.length; i++) {
unichar c = [input characterAtIndex:(NSUInteger)i];
if (c == '\\') {
if (i + 1 < (int32_t)input.length) {
++i;
c = [input characterAtIndex:(NSUInteger)i];
if (isOctal(c)) {
// Octal escape.
int32_t code = digitValue(c);
if (i + 1 < (int32_t)input.length && isOctal([input characterAtIndex:(NSUInteger)(i + 1)])) {
++i;
code = code * 8 + digitValue([input characterAtIndex:(NSUInteger)i]);
}
if (i + 1 < (int32_t)input.length && isOctal([input characterAtIndex:(NSUInteger)(i + 1)])) {
++i;
code = code * 8 + digitValue([input characterAtIndex:(NSUInteger)i]);
}
((int8_t*)result.mutableBytes)[pos++] = (int8_t)code;
} else {
switch (c) {
case 'a' : ((int8_t*)result.mutableBytes)[pos++] = 0x07; break;
case 'b' : ((int8_t*)result.mutableBytes)[pos++] = '\b'; break;
case 'f' : ((int8_t*)result.mutableBytes)[pos++] = '\f'; break;
case 'n' : ((int8_t*)result.mutableBytes)[pos++] = '\n'; break;
case 'r' : ((int8_t*)result.mutableBytes)[pos++] = '\r'; break;
case 't' : ((int8_t*)result.mutableBytes)[pos++] = '\t'; break;
case 'v' : ((int8_t*)result.mutableBytes)[pos++] = 0x0b; break;
case '\\': ((int8_t*)result.mutableBytes)[pos++] = '\\'; break;
case '\'': ((int8_t*)result.mutableBytes)[pos++] = '\''; break;
case '"' : ((int8_t*)result.mutableBytes)[pos++] = '\"'; break;
case 'x': // hex escape
{
int32_t code = 0;
if (i + 1 < (int32_t)input.length && isHex([input characterAtIndex:(NSUInteger)(i + 1)])) {
++i;
code = digitValue([input characterAtIndex:(NSUInteger)i]);
} else {
@throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence: '\\x' with no digits" userInfo:nil];
}
if (i + 1 < (int32_t)input.length && isHex([input characterAtIndex:(NSUInteger)(i + 1)])) {
++i;
code = code * 16 + digitValue([input characterAtIndex:(NSUInteger)i]);
}
((int8_t*)result.mutableBytes)[pos++] = (int8_t)code;
break;
}
default:
@throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence" userInfo:nil];
}
}
} else {
@throw [NSException exceptionWithName:@"InvalidEscape" reason:@"Invalid escape sequence: '\\' at end of string" userInfo:nil];
}
} else {
((int8_t*)result.mutableBytes)[pos++] = (int8_t)c;
}
}
[result setLength:(NSUInteger)pos];
return result;
}
@end

View File

@ -0,0 +1,45 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBUnknownFieldSet_Builder;
@class PBUnknownFieldSet;
@class PBField;
@class PBCodedOutputStream;
@interface PBUnknownFieldSet : NSObject {
@private
NSDictionary* fields;
}
@property (readonly, retain) NSDictionary* fields;
+ (PBUnknownFieldSet*) defaultInstance;
+ (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields;
+ (PBUnknownFieldSet*) parseFromData:(NSData*) data;
+ (PBUnknownFieldSet_Builder*) builder;
+ (PBUnknownFieldSet_Builder*) builderWithUnknownFields:(PBUnknownFieldSet*) other;
- (void) writeAsMessageSetTo:(PBCodedOutputStream*) output;
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
- (NSData*) data;
- (int32_t) serializedSize;
- (int32_t) serializedSizeAsMessageSet;
- (BOOL) hasField:(int32_t) number;
- (PBField*) getField:(int32_t) number;
@end

View File

@ -0,0 +1,161 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "UnknownFieldSet.h"
#import "CodedInputStream.h"
#import "CodedOutputStream.h"
#import "Field.h"
#import "UnknownFieldSet_Builder.h"
@interface PBUnknownFieldSet()
@property (retain) NSDictionary* fields;
@end
@implementation PBUnknownFieldSet
static PBUnknownFieldSet* defaultInstance = nil;
+ (void) initialize {
if (self == [PBUnknownFieldSet class]) {
defaultInstance = [PBUnknownFieldSet setWithFields:[NSMutableDictionary dictionary]];
}
}
@synthesize fields;
- (void) dealloc {
self.fields = nil;
}
+ (PBUnknownFieldSet*) defaultInstance {
return defaultInstance;
}
- (id) initWithFields:(NSMutableDictionary*) fields_ {
if ((self = [super init])) {
self.fields = fields_;
}
return self;
}
+ (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields {
return [[PBUnknownFieldSet alloc] initWithFields:fields];
}
- (BOOL) hasField:(int32_t) number {
return [fields objectForKey:[NSNumber numberWithInt:number]] != nil;
}
- (PBField*) getField:(int32_t) number {
PBField* result = [fields objectForKey:[NSNumber numberWithInt:number]];
return (result == nil) ? [PBField defaultInstance] : result;
}
- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
NSArray* sortedKeys = [fields.allKeys sortedArrayUsingSelector:@selector(compare:)];
for (NSNumber* number in sortedKeys) {
PBField* value = [fields objectForKey:number];
[value writeTo:number.intValue output:output];
}
}
- (void) writeToOutputStream:(NSOutputStream*) output {
PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output];
[self writeToCodedOutputStream:codedOutput];
[codedOutput flush];
}
+ (PBUnknownFieldSet*) parseFromCodedInputStream:(PBCodedInputStream*) input {
return [[[PBUnknownFieldSet builder] mergeFromCodedInputStream:input] build];
}
+ (PBUnknownFieldSet*) parseFromData:(NSData*) data {
return [[[PBUnknownFieldSet builder] mergeFromData:data] build];
}
+ (PBUnknownFieldSet*) parseFromInputStream:(NSInputStream*) input {
return [[[PBUnknownFieldSet builder] mergeFromInputStream:input] build];
}
+ (PBUnknownFieldSet_Builder*) builder {
return [[PBUnknownFieldSet_Builder alloc] init];
}
+ (PBUnknownFieldSet_Builder*) builderWithUnknownFields:(PBUnknownFieldSet*) copyFrom {
return [[PBUnknownFieldSet builder] mergeUnknownFields:copyFrom];
}
/** Get the number of bytes required to encode this set. */
- (int32_t) serializedSize {
int32_t result = 0;
for (NSNumber* number in fields) {
result += [[fields objectForKey:number] getSerializedSize:number.intValue];
}
return result;
}
/**
* Serializes the set and writes it to {@code output} using
* {@code MessageSet} wire format.
*/
- (void) writeAsMessageSetTo:(PBCodedOutputStream*) output {
for (NSNumber* number in fields) {
[[fields objectForKey:number] writeAsMessageSetExtensionTo:number.intValue output:output];
}
}
/**
* Get the number of bytes required to encode this set using
* {@code MessageSet} wire format.
*/
- (int32_t) serializedSizeAsMessageSet {
int32_t result = 0;
for (NSNumber* number in fields) {
result += [[fields objectForKey:number] getSerializedSizeAsMessageSetExtension:number.intValue];
}
return result;
}
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around {@link #writeTo(PBCodedOutputStream)}.
*/
- (NSData*) data {
NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)self.serializedSize];
PBCodedOutputStream* output = [PBCodedOutputStream streamWithData:data];
[self writeToCodedOutputStream:output];
return data;
}
@end

View File

@ -0,0 +1,51 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
@class PBField;
@class PBMutableField;
@class PBUnknownFieldSet;
@class PBUnknownFieldSet_Builder;
@class PBCodedInputStream;
@interface PBUnknownFieldSet_Builder : NSObject {
@private
NSMutableDictionary* fields;
// Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a
// row (important when parsing an unknown repeated field).
int32_t lastFieldNumber;
PBMutableField* lastField;
}
+ (PBUnknownFieldSet_Builder*) newBuilder:(PBUnknownFieldSet*) unknownFields;
- (PBUnknownFieldSet*) build;
- (PBUnknownFieldSet_Builder*) mergeUnknownFields:(PBUnknownFieldSet*) other;
- (PBUnknownFieldSet_Builder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
- (PBUnknownFieldSet_Builder*) mergeFromData:(NSData*) data;
- (PBUnknownFieldSet_Builder*) mergeFromInputStream:(NSInputStream*) input;
- (PBUnknownFieldSet_Builder*) mergeVarintField:(int32_t) number value:(int32_t) value;
- (BOOL) mergeFieldFrom:(int32_t) tag input:(PBCodedInputStream*) input;
- (PBUnknownFieldSet_Builder*) addField:(PBField*) field forNumber:(int32_t) number;
- (PBUnknownFieldSet_Builder*) clear;
- (PBUnknownFieldSet_Builder*) mergeField:(PBField*) field forNumber:(int32_t) number;
@end

View File

@ -0,0 +1,237 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "UnknownFieldSet_Builder.h"
#import "CodedInputStream.h"
#import "Field.h"
#import "MutableField.h"
#import "UnknownFieldSet.h"
#import "WireFormat.h"
@interface PBUnknownFieldSet_Builder ()
@property (retain) NSMutableDictionary* fields;
@property int32_t lastFieldNumber;
@property (retain) PBMutableField* lastField;
@end
@implementation PBUnknownFieldSet_Builder
@synthesize fields;
@synthesize lastFieldNumber;
@synthesize lastField;
- (void) dealloc {
self.fields = nil;
self.lastFieldNumber = 0;
self.lastField = nil;
}
- (id) init {
if ((self = [super init])) {
self.fields = [NSMutableDictionary dictionary];
}
return self;
}
+ (PBUnknownFieldSet_Builder*) newBuilder:(PBUnknownFieldSet*) unknownFields {
PBUnknownFieldSet_Builder* builder = [[PBUnknownFieldSet_Builder alloc] init];
[builder mergeUnknownFields:unknownFields];
return builder;
}
/**
* Add a field to the {@code PBUnknownFieldSet}. If a field with the same
* number already exists, it is removed.
*/
- (PBUnknownFieldSet_Builder*) addField:(PBField*) field forNumber:(int32_t) number {
if (number == 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil];
}
if (lastField != nil && lastFieldNumber == number) {
// Discard this.
self.lastField = nil;
lastFieldNumber = 0;
}
[fields setObject:field forKey:[NSNumber numberWithInt:number]];
return self;
}
/**
* Get a field builder for the given field number which includes any
* values that already exist.
*/
- (PBMutableField*) getFieldBuilder:(int32_t) number {
if (lastField != nil) {
if (number == lastFieldNumber) {
return lastField;
}
// Note: addField() will reset lastField and lastFieldNumber.
[self addField:lastField forNumber:lastFieldNumber];
}
if (number == 0) {
return nil;
} else {
PBField* existing = [fields objectForKey:[NSNumber numberWithInt:number]];
lastFieldNumber = number;
self.lastField = [PBMutableField field];
if (existing != nil) {
[lastField mergeFromField:existing];
}
return lastField;
}
}
- (PBUnknownFieldSet*) build {
[self getFieldBuilder:0]; // Force lastField to be built.
PBUnknownFieldSet* result;
if (fields.count == 0) {
result = [PBUnknownFieldSet defaultInstance];
} else {
result = [PBUnknownFieldSet setWithFields:fields];
}
self.fields = nil;
return result;
}
/** Check if the given field number is present in the set. */
- (BOOL) hasField:(int32_t) number {
if (number == 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil];
}
return number == lastFieldNumber || ([fields objectForKey:[NSNumber numberWithInt:number]] != nil);
}
/**
* Add a field to the {@code PBUnknownFieldSet}. If a field with the same
* number already exists, the two are merged.
*/
- (PBUnknownFieldSet_Builder*) mergeField:(PBField*) field forNumber:(int32_t) number {
if (number == 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"" userInfo:nil];
}
if ([self hasField:number]) {
[[self getFieldBuilder:number] mergeFromField:field];
} else {
// Optimization: We could call getFieldBuilder(number).mergeFrom(field)
// in this case, but that would create a copy of the PBField object.
// We'd rather reuse the one passed to us, so call addField() instead.
[self addField:field forNumber:number];
}
return self;
}
- (PBUnknownFieldSet_Builder*) mergeUnknownFields:(PBUnknownFieldSet*) other {
if (other != [PBUnknownFieldSet defaultInstance]) {
for (NSNumber* number in other.fields) {
PBField* field = [other.fields objectForKey:number];
[self mergeField:field forNumber:[number intValue]];
}
}
return self;
}
- (PBUnknownFieldSet_Builder*) mergeFromData:(NSData*) data {
PBCodedInputStream* input = [PBCodedInputStream streamWithData:data];
[self mergeFromCodedInputStream:input];
[input checkLastTagWas:0];
return self;
}
- (PBUnknownFieldSet_Builder*) mergeFromInputStream:(NSInputStream*) input {
@throw [NSException exceptionWithName:@"" reason:@"" userInfo:nil];
}
- (PBUnknownFieldSet_Builder*) mergeVarintField:(int32_t) number value:(int32_t) value {
if (number == 0) {
@throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Zero is not a valid field number." userInfo:nil];
}
[[self getFieldBuilder:number] addVarint:value];
return self;
}
/**
* Parse a single field from {@code input} and merge it into this set.
* @param tag The field's tag number, which was already parsed.
* @return {@code NO} if the tag is an engroup tag.
*/
- (BOOL) mergeFieldFrom:(int32_t) tag input:(PBCodedInputStream*) input {
int32_t number = PBWireFormatGetTagFieldNumber(tag);
switch (PBWireFormatGetTagWireType(tag)) {
case PBWireFormatVarint:
[[self getFieldBuilder:number] addVarint:[input readInt64]];
return YES;
case PBWireFormatFixed64:
[[self getFieldBuilder:number] addFixed64:[input readFixed64]];
return YES;
case PBWireFormatLengthDelimited:
[[self getFieldBuilder:number] addLengthDelimited:[input readData]];
return YES;
case PBWireFormatStartGroup: {
PBUnknownFieldSet_Builder* subBuilder = [PBUnknownFieldSet builder];
[input readUnknownGroup:number builder:subBuilder];
[[self getFieldBuilder:number] addGroup:[subBuilder build]];
return YES;
}
case PBWireFormatEndGroup:
return NO;
case PBWireFormatFixed32:
[[self getFieldBuilder:number] addFixed32:[input readFixed32]];
return YES;
default:
@throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"" userInfo:nil];
}
}
/**
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
- (PBUnknownFieldSet_Builder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
while (YES) {
int32_t tag = [input readTag];
if (tag == 0 || ![self mergeFieldFrom:tag input:input]) {
break;
}
}
return self;
}
- (PBUnknownFieldSet_Builder*) clear {
self.fields = [NSMutableDictionary dictionary];
self.lastFieldNumber = 0;
self.lastField = nil;
return self;
}
@end

View File

@ -0,0 +1,26 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
int64_t convertFloat64ToInt64(Float64 f);
int32_t convertFloat32ToInt32(Float32 f);
Float64 convertInt64ToFloat64(int64_t f);
Float32 convertInt32ToFloat32(int32_t f);
uint64_t convertInt64ToUInt64(int64_t i);
int64_t convertUInt64ToInt64(uint64_t u);
uint32_t convertInt32ToUInt32(int32_t i);
int64_t convertUInt32ToInt32(uint32_t u);
int32_t logicalRightShift32(int32_t value, int32_t spaces);
int64_t logicalRightShift64(int64_t value, int32_t spaces);

View File

@ -0,0 +1,79 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "Utilities.h"
int64_t convertFloat64ToInt64(Float64 v) {
union { Float64 f; int64_t i; } u;
u.f = v;
return u.i;
}
int32_t convertFloat32ToInt32(Float32 v) {
union { Float32 f; int32_t i; } u;
u.f = v;
return u.i;
}
Float64 convertInt64ToFloat64(int64_t v) {
union { Float64 f; int64_t i; } u;
u.i = v;
return u.f;
}
Float32 convertInt32ToFloat32(int32_t v) {
union { Float32 f; int32_t i; } u;
u.i = v;
return u.f;
}
uint64_t convertInt64ToUInt64(int64_t v) {
union { int64_t i; uint64_t u; } u;
u.i = v;
return u.u;
}
int64_t convertUInt64ToInt64(uint64_t v) {
union { int64_t i; uint64_t u; } u;
u.u = v;
return u.i;
}
uint32_t convertInt32ToUInt32(int32_t v) {
union { int32_t i; uint32_t u; } u;
u.i = v;
return u.u;
}
int64_t convertUInt32ToInt32(uint32_t v) {
union { int32_t i; uint32_t u; } u;
u.u = v;
return u.i;
}
int32_t logicalRightShift32(int32_t value, int32_t spaces) {
return (int32_t)convertUInt32ToInt32((convertInt32ToUInt32(value) >> spaces));
}
int64_t logicalRightShift64(int64_t value, int32_t spaces) {
return convertUInt64ToInt64((convertInt64ToUInt64(value) >> spaces));
}

View File

@ -0,0 +1,38 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
typedef enum {
PBWireFormatVarint = 0,
PBWireFormatFixed64 = 1,
PBWireFormatLengthDelimited = 2,
PBWireFormatStartGroup = 3,
PBWireFormatEndGroup = 4,
PBWireFormatFixed32 = 5,
PBWireFormatTagTypeBits = 3,
PBWireFormatTagTypeMask = 7 /* = (1 << PBWireFormatTagTypeBits) - 1*/,
PBWireFormatMessageSetItem = 1,
PBWireFormatMessageSetTypeId = 2,
PBWireFormatMessageSetMessage = 3
} PBWireFormat;
int32_t PBWireFormatMakeTag(int32_t fieldNumber, int32_t wireType);
int32_t PBWireFormatGetTagWireType(int32_t tag);
int32_t PBWireFormatGetTagFieldNumber(int32_t tag);
#define PBWireFormatMessageSetItemTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatStartGroup))
#define PBWireFormatMessageSetItemEndTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatEndGroup))
#define PBWireFormatMessageSetTypeIdTag (PBWireFormatMakeTag(PBWireFormatMessageSetTypeId, PBWireFormatVarint))
#define PBWireFormatMessageSetMessageTag (PBWireFormatMakeTag(PBWireFormatMessageSetMessage, PBWireFormatLengthDelimited))

View File

@ -0,0 +1,31 @@
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "WireFormat.h"
#import "Utilities.h"
int32_t PBWireFormatMakeTag(int32_t fieldNumber, int32_t wireType) {
return (fieldNumber << PBWireFormatTagTypeBits) | wireType;
}
int32_t PBWireFormatGetTagWireType(int32_t tag) {
return tag & PBWireFormatTagTypeMask;
}
int32_t PBWireFormatGetTagFieldNumber(int32_t tag) {
return logicalRightShift32(tag, PBWireFormatTagTypeBits);
}

View File

@ -0,0 +1,777 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
A1B989FE1725EC3E00B6E8B5 /* time_scale.c in Sources */ = {isa = PBXBuildFile; fileRef = A1B989FD1725EC3E00B6E8B5 /* time_scale.c */; };
A1B98A8A1725EC6400B6E8B5 /* adsi.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A011725EC6400B6E8B5 /* adsi.h */; };
A1B98A8B1725EC6400B6E8B5 /* arctan2.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A021725EC6400B6E8B5 /* arctan2.h */; };
A1B98A8C1725EC6400B6E8B5 /* async.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A031725EC6400B6E8B5 /* async.h */; };
A1B98A8D1725EC6400B6E8B5 /* at_interpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A041725EC6400B6E8B5 /* at_interpreter.h */; };
A1B98A8E1725EC6400B6E8B5 /* awgn.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A051725EC6400B6E8B5 /* awgn.h */; };
A1B98A8F1725EC6400B6E8B5 /* bell_r2_mf.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A061725EC6400B6E8B5 /* bell_r2_mf.h */; };
A1B98A901725EC6400B6E8B5 /* bert.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A071725EC6400B6E8B5 /* bert.h */; };
A1B98A911725EC6400B6E8B5 /* biquad.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A081725EC6400B6E8B5 /* biquad.h */; };
A1B98A921725EC6400B6E8B5 /* bit_operations.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A091725EC6400B6E8B5 /* bit_operations.h */; };
A1B98A931725EC6400B6E8B5 /* bitstream.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0A1725EC6400B6E8B5 /* bitstream.h */; };
A1B98A941725EC6400B6E8B5 /* complex.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0B1725EC6400B6E8B5 /* complex.h */; };
A1B98A951725EC6400B6E8B5 /* complex_filters.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0C1725EC6400B6E8B5 /* complex_filters.h */; };
A1B98A961725EC6400B6E8B5 /* complex_vector_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0D1725EC6400B6E8B5 /* complex_vector_float.h */; };
A1B98A971725EC6400B6E8B5 /* complex_vector_int.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0E1725EC6400B6E8B5 /* complex_vector_int.h */; };
A1B98A981725EC6400B6E8B5 /* crc.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A0F1725EC6400B6E8B5 /* crc.h */; };
A1B98A991725EC6400B6E8B5 /* dc_restore.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A101725EC6400B6E8B5 /* dc_restore.h */; };
A1B98A9A1725EC6400B6E8B5 /* dds.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A111725EC6400B6E8B5 /* dds.h */; };
A1B98A9B1725EC6400B6E8B5 /* dtmf.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A121725EC6400B6E8B5 /* dtmf.h */; };
A1B98A9C1725EC6400B6E8B5 /* echo.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A131725EC6400B6E8B5 /* echo.h */; };
A1B98A9D1725EC6400B6E8B5 /* expose.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A141725EC6400B6E8B5 /* expose.h */; };
A1B98A9E1725EC6400B6E8B5 /* fast_convert.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A151725EC6400B6E8B5 /* fast_convert.h */; };
A1B98A9F1725EC6400B6E8B5 /* fax.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A161725EC6400B6E8B5 /* fax.h */; };
A1B98AA01725EC6400B6E8B5 /* fax_modems.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A171725EC6400B6E8B5 /* fax_modems.h */; };
A1B98AA11725EC6400B6E8B5 /* fir.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A181725EC6400B6E8B5 /* fir.h */; };
A1B98AA21725EC6400B6E8B5 /* fsk.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A191725EC6400B6E8B5 /* fsk.h */; };
A1B98AA31725EC6400B6E8B5 /* g168models.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1A1725EC6400B6E8B5 /* g168models.h */; };
A1B98AA41725EC6400B6E8B5 /* g711.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1B1725EC6400B6E8B5 /* g711.h */; };
A1B98AA51725EC6400B6E8B5 /* g722.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1C1725EC6400B6E8B5 /* g722.h */; };
A1B98AA61725EC6400B6E8B5 /* g726.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1D1725EC6400B6E8B5 /* g726.h */; };
A1B98AA71725EC6400B6E8B5 /* gsm0610.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1E1725EC6400B6E8B5 /* gsm0610.h */; };
A1B98AA81725EC6400B6E8B5 /* hdlc.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A1F1725EC6400B6E8B5 /* hdlc.h */; };
A1B98AA91725EC6400B6E8B5 /* ima_adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A201725EC6400B6E8B5 /* ima_adpcm.h */; };
A1B98AAA1725EC6400B6E8B5 /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A211725EC6400B6E8B5 /* logging.h */; };
A1B98AAB1725EC6400B6E8B5 /* lpc10.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A221725EC6400B6E8B5 /* lpc10.h */; };
A1B98AAC1725EC6400B6E8B5 /* modem_connect_tones.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A231725EC6400B6E8B5 /* modem_connect_tones.h */; };
A1B98AAD1725EC6400B6E8B5 /* modem_echo.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A241725EC6400B6E8B5 /* modem_echo.h */; };
A1B98AAE1725EC6400B6E8B5 /* noise.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A251725EC6400B6E8B5 /* noise.h */; };
A1B98AAF1725EC6400B6E8B5 /* oki_adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A261725EC6400B6E8B5 /* oki_adpcm.h */; };
A1B98AB01725EC6400B6E8B5 /* playout.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A271725EC6400B6E8B5 /* playout.h */; };
A1B98AB11725EC6400B6E8B5 /* plc.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A281725EC6400B6E8B5 /* plc.h */; };
A1B98AB21725EC6400B6E8B5 /* power_meter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A291725EC6400B6E8B5 /* power_meter.h */; };
A1B98AB31725EC6400B6E8B5 /* adsi.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A2B1725EC6400B6E8B5 /* adsi.h */; };
A1B98AB41725EC6400B6E8B5 /* async.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A2C1725EC6400B6E8B5 /* async.h */; };
A1B98AB51725EC6400B6E8B5 /* at_interpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A2D1725EC6400B6E8B5 /* at_interpreter.h */; };
A1B98AB61725EC6400B6E8B5 /* awgn.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A2E1725EC6400B6E8B5 /* awgn.h */; };
A1B98AB71725EC6500B6E8B5 /* bell_r2_mf.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A2F1725EC6400B6E8B5 /* bell_r2_mf.h */; };
A1B98AB81725EC6500B6E8B5 /* bert.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A301725EC6400B6E8B5 /* bert.h */; };
A1B98AB91725EC6500B6E8B5 /* bitstream.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A311725EC6400B6E8B5 /* bitstream.h */; };
A1B98ABA1725EC6500B6E8B5 /* dtmf.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A321725EC6400B6E8B5 /* dtmf.h */; };
A1B98ABB1725EC6500B6E8B5 /* echo.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A331725EC6400B6E8B5 /* echo.h */; };
A1B98ABC1725EC6500B6E8B5 /* fax.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A341725EC6400B6E8B5 /* fax.h */; };
A1B98ABD1725EC6500B6E8B5 /* fax_modems.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A351725EC6400B6E8B5 /* fax_modems.h */; };
A1B98ABE1725EC6500B6E8B5 /* fsk.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A361725EC6400B6E8B5 /* fsk.h */; };
A1B98ABF1725EC6500B6E8B5 /* g711.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A371725EC6400B6E8B5 /* g711.h */; };
A1B98AC01725EC6500B6E8B5 /* g722.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A381725EC6400B6E8B5 /* g722.h */; };
A1B98AC11725EC6500B6E8B5 /* g726.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A391725EC6400B6E8B5 /* g726.h */; };
A1B98AC21725EC6500B6E8B5 /* gsm0610.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3A1725EC6400B6E8B5 /* gsm0610.h */; };
A1B98AC31725EC6500B6E8B5 /* hdlc.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3B1725EC6400B6E8B5 /* hdlc.h */; };
A1B98AC41725EC6500B6E8B5 /* ima_adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3C1725EC6400B6E8B5 /* ima_adpcm.h */; };
A1B98AC51725EC6500B6E8B5 /* logging.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3D1725EC6400B6E8B5 /* logging.h */; };
A1B98AC61725EC6500B6E8B5 /* lpc10.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3E1725EC6400B6E8B5 /* lpc10.h */; };
A1B98AC71725EC6500B6E8B5 /* modem_connect_tones.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A3F1725EC6400B6E8B5 /* modem_connect_tones.h */; };
A1B98AC81725EC6500B6E8B5 /* modem_echo.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A401725EC6400B6E8B5 /* modem_echo.h */; };
A1B98AC91725EC6500B6E8B5 /* noise.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A411725EC6400B6E8B5 /* noise.h */; };
A1B98ACA1725EC6500B6E8B5 /* oki_adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A421725EC6400B6E8B5 /* oki_adpcm.h */; };
A1B98ACB1725EC6500B6E8B5 /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A431725EC6400B6E8B5 /* queue.h */; };
A1B98ACC1725EC6500B6E8B5 /* schedule.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A451725EC6400B6E8B5 /* schedule.h */; };
A1B98ACD1725EC6500B6E8B5 /* sig_tone.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A461725EC6400B6E8B5 /* sig_tone.h */; };
A1B98ACE1725EC6500B6E8B5 /* silence_gen.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A471725EC6400B6E8B5 /* silence_gen.h */; };
A1B98ACF1725EC6500B6E8B5 /* super_tone_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A481725EC6400B6E8B5 /* super_tone_rx.h */; };
A1B98AD01725EC6500B6E8B5 /* super_tone_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A491725EC6400B6E8B5 /* super_tone_tx.h */; };
A1B98AD11725EC6500B6E8B5 /* swept_tone.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4A1725EC6400B6E8B5 /* swept_tone.h */; };
A1B98AD21725EC6500B6E8B5 /* t30.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4B1725EC6400B6E8B5 /* t30.h */; };
A1B98AD31725EC6500B6E8B5 /* t30_dis_dtc_dcs_bits.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4C1725EC6400B6E8B5 /* t30_dis_dtc_dcs_bits.h */; };
A1B98AD41725EC6500B6E8B5 /* t31.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4D1725EC6400B6E8B5 /* t31.h */; };
A1B98AD51725EC6500B6E8B5 /* t38_core.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4E1725EC6400B6E8B5 /* t38_core.h */; };
A1B98AD61725EC6500B6E8B5 /* t38_gateway.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A4F1725EC6400B6E8B5 /* t38_gateway.h */; };
A1B98AD71725EC6500B6E8B5 /* t38_non_ecm_buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A501725EC6400B6E8B5 /* t38_non_ecm_buffer.h */; };
A1B98AD81725EC6500B6E8B5 /* t38_terminal.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A511725EC6400B6E8B5 /* t38_terminal.h */; };
A1B98AD91725EC6500B6E8B5 /* t4_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A521725EC6400B6E8B5 /* t4_rx.h */; };
A1B98ADA1725EC6500B6E8B5 /* t4_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A531725EC6400B6E8B5 /* t4_tx.h */; };
A1B98ADB1725EC6500B6E8B5 /* time_scale.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A541725EC6400B6E8B5 /* time_scale.h */; };
A1B98ADC1725EC6500B6E8B5 /* tone_detect.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A551725EC6400B6E8B5 /* tone_detect.h */; };
A1B98ADD1725EC6500B6E8B5 /* tone_generate.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A561725EC6400B6E8B5 /* tone_generate.h */; };
A1B98ADE1725EC6500B6E8B5 /* v17rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A571725EC6400B6E8B5 /* v17rx.h */; };
A1B98ADF1725EC6500B6E8B5 /* v17tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A581725EC6400B6E8B5 /* v17tx.h */; };
A1B98AE01725EC6500B6E8B5 /* v18.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A591725EC6400B6E8B5 /* v18.h */; };
A1B98AE11725EC6500B6E8B5 /* v22bis.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5A1725EC6400B6E8B5 /* v22bis.h */; };
A1B98AE21725EC6500B6E8B5 /* v27ter_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5B1725EC6400B6E8B5 /* v27ter_rx.h */; };
A1B98AE31725EC6500B6E8B5 /* v27ter_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5C1725EC6400B6E8B5 /* v27ter_tx.h */; };
A1B98AE41725EC6500B6E8B5 /* v29rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5D1725EC6400B6E8B5 /* v29rx.h */; };
A1B98AE51725EC6500B6E8B5 /* v29tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5E1725EC6400B6E8B5 /* v29tx.h */; };
A1B98AE61725EC6500B6E8B5 /* v42.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A5F1725EC6400B6E8B5 /* v42.h */; };
A1B98AE71725EC6500B6E8B5 /* v42bis.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A601725EC6400B6E8B5 /* v42bis.h */; };
A1B98AE81725EC6500B6E8B5 /* v8.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A611725EC6400B6E8B5 /* v8.h */; };
A1B98AE91725EC6500B6E8B5 /* queue.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A621725EC6400B6E8B5 /* queue.h */; };
A1B98AEA1725EC6500B6E8B5 /* saturated.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A631725EC6400B6E8B5 /* saturated.h */; };
A1B98AEB1725EC6500B6E8B5 /* schedule.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A641725EC6400B6E8B5 /* schedule.h */; };
A1B98AEC1725EC6500B6E8B5 /* sig_tone.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A651725EC6400B6E8B5 /* sig_tone.h */; };
A1B98AED1725EC6500B6E8B5 /* silence_gen.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A661725EC6400B6E8B5 /* silence_gen.h */; };
A1B98AEE1725EC6500B6E8B5 /* super_tone_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A671725EC6400B6E8B5 /* super_tone_rx.h */; };
A1B98AEF1725EC6500B6E8B5 /* super_tone_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A681725EC6400B6E8B5 /* super_tone_tx.h */; };
A1B98AF01725EC6500B6E8B5 /* swept_tone.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A691725EC6400B6E8B5 /* swept_tone.h */; };
A1B98AF11725EC6500B6E8B5 /* t30.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6A1725EC6400B6E8B5 /* t30.h */; };
A1B98AF21725EC6500B6E8B5 /* t30_api.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6B1725EC6400B6E8B5 /* t30_api.h */; };
A1B98AF31725EC6500B6E8B5 /* t30_fcf.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6C1725EC6400B6E8B5 /* t30_fcf.h */; };
A1B98AF41725EC6500B6E8B5 /* t30_logging.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6D1725EC6400B6E8B5 /* t30_logging.h */; };
A1B98AF51725EC6500B6E8B5 /* t31.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6E1725EC6400B6E8B5 /* t31.h */; };
A1B98AF61725EC6500B6E8B5 /* t35.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A6F1725EC6400B6E8B5 /* t35.h */; };
A1B98AF71725EC6500B6E8B5 /* t38_core.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A701725EC6400B6E8B5 /* t38_core.h */; };
A1B98AF81725EC6500B6E8B5 /* t38_gateway.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A711725EC6400B6E8B5 /* t38_gateway.h */; };
A1B98AF91725EC6500B6E8B5 /* t38_non_ecm_buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A721725EC6400B6E8B5 /* t38_non_ecm_buffer.h */; };
A1B98AFA1725EC6500B6E8B5 /* t38_terminal.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A731725EC6400B6E8B5 /* t38_terminal.h */; };
A1B98AFB1725EC6500B6E8B5 /* t4_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A741725EC6400B6E8B5 /* t4_rx.h */; };
A1B98AFC1725EC6500B6E8B5 /* t4_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A751725EC6400B6E8B5 /* t4_tx.h */; };
A1B98AFD1725EC6500B6E8B5 /* telephony.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A761725EC6400B6E8B5 /* telephony.h */; };
A1B98AFE1725EC6500B6E8B5 /* time_scale.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A771725EC6400B6E8B5 /* time_scale.h */; };
A1B98AFF1725EC6500B6E8B5 /* timing.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A781725EC6400B6E8B5 /* timing.h */; };
A1B98B001725EC6500B6E8B5 /* tone_detect.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A791725EC6400B6E8B5 /* tone_detect.h */; };
A1B98B011725EC6500B6E8B5 /* tone_generate.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7A1725EC6400B6E8B5 /* tone_generate.h */; };
A1B98B021725EC6500B6E8B5 /* v17rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7B1725EC6400B6E8B5 /* v17rx.h */; };
A1B98B031725EC6500B6E8B5 /* v17tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7C1725EC6400B6E8B5 /* v17tx.h */; };
A1B98B041725EC6500B6E8B5 /* v18.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7D1725EC6400B6E8B5 /* v18.h */; };
A1B98B051725EC6500B6E8B5 /* v22bis.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7E1725EC6400B6E8B5 /* v22bis.h */; };
A1B98B061725EC6500B6E8B5 /* v27ter_rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A7F1725EC6400B6E8B5 /* v27ter_rx.h */; };
A1B98B071725EC6500B6E8B5 /* v27ter_tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A801725EC6400B6E8B5 /* v27ter_tx.h */; };
A1B98B081725EC6500B6E8B5 /* v29rx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A811725EC6400B6E8B5 /* v29rx.h */; };
A1B98B091725EC6500B6E8B5 /* v29tx.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A821725EC6400B6E8B5 /* v29tx.h */; };
A1B98B0A1725EC6500B6E8B5 /* v42.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A831725EC6400B6E8B5 /* v42.h */; };
A1B98B0B1725EC6500B6E8B5 /* v42bis.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A841725EC6400B6E8B5 /* v42bis.h */; };
A1B98B0C1725EC6500B6E8B5 /* v8.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A851725EC6400B6E8B5 /* v8.h */; };
A1B98B0D1725EC6500B6E8B5 /* vector_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A861725EC6400B6E8B5 /* vector_float.h */; };
A1B98B0E1725EC6500B6E8B5 /* vector_int.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A871725EC6400B6E8B5 /* vector_int.h */; };
A1B98B0F1725EC6500B6E8B5 /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B98A881725EC6400B6E8B5 /* version.h */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
A1B989641725EC1300B6E8B5 /* libspandsp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libspandsp.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1B989FD1725EC3E00B6E8B5 /* time_scale.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = time_scale.c; sourceTree = "<group>"; };
A1B98A011725EC6400B6E8B5 /* adsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adsi.h; sourceTree = "<group>"; };
A1B98A021725EC6400B6E8B5 /* arctan2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arctan2.h; sourceTree = "<group>"; };
A1B98A031725EC6400B6E8B5 /* async.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = async.h; sourceTree = "<group>"; };
A1B98A041725EC6400B6E8B5 /* at_interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = at_interpreter.h; sourceTree = "<group>"; };
A1B98A051725EC6400B6E8B5 /* awgn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = awgn.h; sourceTree = "<group>"; };
A1B98A061725EC6400B6E8B5 /* bell_r2_mf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bell_r2_mf.h; sourceTree = "<group>"; };
A1B98A071725EC6400B6E8B5 /* bert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bert.h; sourceTree = "<group>"; };
A1B98A081725EC6400B6E8B5 /* biquad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = biquad.h; sourceTree = "<group>"; };
A1B98A091725EC6400B6E8B5 /* bit_operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_operations.h; sourceTree = "<group>"; };
A1B98A0A1725EC6400B6E8B5 /* bitstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitstream.h; sourceTree = "<group>"; };
A1B98A0B1725EC6400B6E8B5 /* complex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = complex.h; sourceTree = "<group>"; };
A1B98A0C1725EC6400B6E8B5 /* complex_filters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = complex_filters.h; sourceTree = "<group>"; };
A1B98A0D1725EC6400B6E8B5 /* complex_vector_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = complex_vector_float.h; sourceTree = "<group>"; };
A1B98A0E1725EC6400B6E8B5 /* complex_vector_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = complex_vector_int.h; sourceTree = "<group>"; };
A1B98A0F1725EC6400B6E8B5 /* crc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crc.h; sourceTree = "<group>"; };
A1B98A101725EC6400B6E8B5 /* dc_restore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dc_restore.h; sourceTree = "<group>"; };
A1B98A111725EC6400B6E8B5 /* dds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dds.h; sourceTree = "<group>"; };
A1B98A121725EC6400B6E8B5 /* dtmf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtmf.h; sourceTree = "<group>"; };
A1B98A131725EC6400B6E8B5 /* echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = echo.h; sourceTree = "<group>"; };
A1B98A141725EC6400B6E8B5 /* expose.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = expose.h; sourceTree = "<group>"; };
A1B98A151725EC6400B6E8B5 /* fast_convert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fast_convert.h; sourceTree = "<group>"; };
A1B98A161725EC6400B6E8B5 /* fax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fax.h; sourceTree = "<group>"; };
A1B98A171725EC6400B6E8B5 /* fax_modems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fax_modems.h; sourceTree = "<group>"; };
A1B98A181725EC6400B6E8B5 /* fir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fir.h; sourceTree = "<group>"; };
A1B98A191725EC6400B6E8B5 /* fsk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsk.h; sourceTree = "<group>"; };
A1B98A1A1725EC6400B6E8B5 /* g168models.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g168models.h; sourceTree = "<group>"; };
A1B98A1B1725EC6400B6E8B5 /* g711.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g711.h; sourceTree = "<group>"; };
A1B98A1C1725EC6400B6E8B5 /* g722.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g722.h; sourceTree = "<group>"; };
A1B98A1D1725EC6400B6E8B5 /* g726.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g726.h; sourceTree = "<group>"; };
A1B98A1E1725EC6400B6E8B5 /* gsm0610.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsm0610.h; sourceTree = "<group>"; };
A1B98A1F1725EC6400B6E8B5 /* hdlc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hdlc.h; sourceTree = "<group>"; };
A1B98A201725EC6400B6E8B5 /* ima_adpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ima_adpcm.h; sourceTree = "<group>"; };
A1B98A211725EC6400B6E8B5 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = "<group>"; };
A1B98A221725EC6400B6E8B5 /* lpc10.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lpc10.h; sourceTree = "<group>"; };
A1B98A231725EC6400B6E8B5 /* modem_connect_tones.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem_connect_tones.h; sourceTree = "<group>"; };
A1B98A241725EC6400B6E8B5 /* modem_echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem_echo.h; sourceTree = "<group>"; };
A1B98A251725EC6400B6E8B5 /* noise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noise.h; sourceTree = "<group>"; };
A1B98A261725EC6400B6E8B5 /* oki_adpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = oki_adpcm.h; sourceTree = "<group>"; };
A1B98A271725EC6400B6E8B5 /* playout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playout.h; sourceTree = "<group>"; };
A1B98A281725EC6400B6E8B5 /* plc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = plc.h; sourceTree = "<group>"; };
A1B98A291725EC6400B6E8B5 /* power_meter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = power_meter.h; sourceTree = "<group>"; };
A1B98A2B1725EC6400B6E8B5 /* adsi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adsi.h; sourceTree = "<group>"; };
A1B98A2C1725EC6400B6E8B5 /* async.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = async.h; sourceTree = "<group>"; };
A1B98A2D1725EC6400B6E8B5 /* at_interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = at_interpreter.h; sourceTree = "<group>"; };
A1B98A2E1725EC6400B6E8B5 /* awgn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = awgn.h; sourceTree = "<group>"; };
A1B98A2F1725EC6400B6E8B5 /* bell_r2_mf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bell_r2_mf.h; sourceTree = "<group>"; };
A1B98A301725EC6400B6E8B5 /* bert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bert.h; sourceTree = "<group>"; };
A1B98A311725EC6400B6E8B5 /* bitstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitstream.h; sourceTree = "<group>"; };
A1B98A321725EC6400B6E8B5 /* dtmf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dtmf.h; sourceTree = "<group>"; };
A1B98A331725EC6400B6E8B5 /* echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = echo.h; sourceTree = "<group>"; };
A1B98A341725EC6400B6E8B5 /* fax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fax.h; sourceTree = "<group>"; };
A1B98A351725EC6400B6E8B5 /* fax_modems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fax_modems.h; sourceTree = "<group>"; };
A1B98A361725EC6400B6E8B5 /* fsk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsk.h; sourceTree = "<group>"; };
A1B98A371725EC6400B6E8B5 /* g711.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g711.h; sourceTree = "<group>"; };
A1B98A381725EC6400B6E8B5 /* g722.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g722.h; sourceTree = "<group>"; };
A1B98A391725EC6400B6E8B5 /* g726.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g726.h; sourceTree = "<group>"; };
A1B98A3A1725EC6400B6E8B5 /* gsm0610.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gsm0610.h; sourceTree = "<group>"; };
A1B98A3B1725EC6400B6E8B5 /* hdlc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hdlc.h; sourceTree = "<group>"; };
A1B98A3C1725EC6400B6E8B5 /* ima_adpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ima_adpcm.h; sourceTree = "<group>"; };
A1B98A3D1725EC6400B6E8B5 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = "<group>"; };
A1B98A3E1725EC6400B6E8B5 /* lpc10.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lpc10.h; sourceTree = "<group>"; };
A1B98A3F1725EC6400B6E8B5 /* modem_connect_tones.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem_connect_tones.h; sourceTree = "<group>"; };
A1B98A401725EC6400B6E8B5 /* modem_echo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modem_echo.h; sourceTree = "<group>"; };
A1B98A411725EC6400B6E8B5 /* noise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noise.h; sourceTree = "<group>"; };
A1B98A421725EC6400B6E8B5 /* oki_adpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = oki_adpcm.h; sourceTree = "<group>"; };
A1B98A431725EC6400B6E8B5 /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = "<group>"; };
A1B98A441725EC6400B6E8B5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
A1B98A451725EC6400B6E8B5 /* schedule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = schedule.h; sourceTree = "<group>"; };
A1B98A461725EC6400B6E8B5 /* sig_tone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sig_tone.h; sourceTree = "<group>"; };
A1B98A471725EC6400B6E8B5 /* silence_gen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = silence_gen.h; sourceTree = "<group>"; };
A1B98A481725EC6400B6E8B5 /* super_tone_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = super_tone_rx.h; sourceTree = "<group>"; };
A1B98A491725EC6400B6E8B5 /* super_tone_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = super_tone_tx.h; sourceTree = "<group>"; };
A1B98A4A1725EC6400B6E8B5 /* swept_tone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = swept_tone.h; sourceTree = "<group>"; };
A1B98A4B1725EC6400B6E8B5 /* t30.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30.h; sourceTree = "<group>"; };
A1B98A4C1725EC6400B6E8B5 /* t30_dis_dtc_dcs_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30_dis_dtc_dcs_bits.h; sourceTree = "<group>"; };
A1B98A4D1725EC6400B6E8B5 /* t31.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t31.h; sourceTree = "<group>"; };
A1B98A4E1725EC6400B6E8B5 /* t38_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_core.h; sourceTree = "<group>"; };
A1B98A4F1725EC6400B6E8B5 /* t38_gateway.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_gateway.h; sourceTree = "<group>"; };
A1B98A501725EC6400B6E8B5 /* t38_non_ecm_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_non_ecm_buffer.h; sourceTree = "<group>"; };
A1B98A511725EC6400B6E8B5 /* t38_terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_terminal.h; sourceTree = "<group>"; };
A1B98A521725EC6400B6E8B5 /* t4_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t4_rx.h; sourceTree = "<group>"; };
A1B98A531725EC6400B6E8B5 /* t4_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t4_tx.h; sourceTree = "<group>"; };
A1B98A541725EC6400B6E8B5 /* time_scale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_scale.h; sourceTree = "<group>"; };
A1B98A551725EC6400B6E8B5 /* tone_detect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tone_detect.h; sourceTree = "<group>"; };
A1B98A561725EC6400B6E8B5 /* tone_generate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tone_generate.h; sourceTree = "<group>"; };
A1B98A571725EC6400B6E8B5 /* v17rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v17rx.h; sourceTree = "<group>"; };
A1B98A581725EC6400B6E8B5 /* v17tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v17tx.h; sourceTree = "<group>"; };
A1B98A591725EC6400B6E8B5 /* v18.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v18.h; sourceTree = "<group>"; };
A1B98A5A1725EC6400B6E8B5 /* v22bis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v22bis.h; sourceTree = "<group>"; };
A1B98A5B1725EC6400B6E8B5 /* v27ter_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v27ter_rx.h; sourceTree = "<group>"; };
A1B98A5C1725EC6400B6E8B5 /* v27ter_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v27ter_tx.h; sourceTree = "<group>"; };
A1B98A5D1725EC6400B6E8B5 /* v29rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v29rx.h; sourceTree = "<group>"; };
A1B98A5E1725EC6400B6E8B5 /* v29tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v29tx.h; sourceTree = "<group>"; };
A1B98A5F1725EC6400B6E8B5 /* v42.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v42.h; sourceTree = "<group>"; };
A1B98A601725EC6400B6E8B5 /* v42bis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v42bis.h; sourceTree = "<group>"; };
A1B98A611725EC6400B6E8B5 /* v8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8.h; sourceTree = "<group>"; };
A1B98A621725EC6400B6E8B5 /* queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = "<group>"; };
A1B98A631725EC6400B6E8B5 /* saturated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = saturated.h; sourceTree = "<group>"; };
A1B98A641725EC6400B6E8B5 /* schedule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = schedule.h; sourceTree = "<group>"; };
A1B98A651725EC6400B6E8B5 /* sig_tone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sig_tone.h; sourceTree = "<group>"; };
A1B98A661725EC6400B6E8B5 /* silence_gen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = silence_gen.h; sourceTree = "<group>"; };
A1B98A671725EC6400B6E8B5 /* super_tone_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = super_tone_rx.h; sourceTree = "<group>"; };
A1B98A681725EC6400B6E8B5 /* super_tone_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = super_tone_tx.h; sourceTree = "<group>"; };
A1B98A691725EC6400B6E8B5 /* swept_tone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = swept_tone.h; sourceTree = "<group>"; };
A1B98A6A1725EC6400B6E8B5 /* t30.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30.h; sourceTree = "<group>"; };
A1B98A6B1725EC6400B6E8B5 /* t30_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30_api.h; sourceTree = "<group>"; };
A1B98A6C1725EC6400B6E8B5 /* t30_fcf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30_fcf.h; sourceTree = "<group>"; };
A1B98A6D1725EC6400B6E8B5 /* t30_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t30_logging.h; sourceTree = "<group>"; };
A1B98A6E1725EC6400B6E8B5 /* t31.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t31.h; sourceTree = "<group>"; };
A1B98A6F1725EC6400B6E8B5 /* t35.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t35.h; sourceTree = "<group>"; };
A1B98A701725EC6400B6E8B5 /* t38_core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_core.h; sourceTree = "<group>"; };
A1B98A711725EC6400B6E8B5 /* t38_gateway.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_gateway.h; sourceTree = "<group>"; };
A1B98A721725EC6400B6E8B5 /* t38_non_ecm_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_non_ecm_buffer.h; sourceTree = "<group>"; };
A1B98A731725EC6400B6E8B5 /* t38_terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t38_terminal.h; sourceTree = "<group>"; };
A1B98A741725EC6400B6E8B5 /* t4_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t4_rx.h; sourceTree = "<group>"; };
A1B98A751725EC6400B6E8B5 /* t4_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = t4_tx.h; sourceTree = "<group>"; };
A1B98A761725EC6400B6E8B5 /* telephony.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = telephony.h; sourceTree = "<group>"; };
A1B98A771725EC6400B6E8B5 /* time_scale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_scale.h; sourceTree = "<group>"; };
A1B98A781725EC6400B6E8B5 /* timing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timing.h; sourceTree = "<group>"; };
A1B98A791725EC6400B6E8B5 /* tone_detect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tone_detect.h; sourceTree = "<group>"; };
A1B98A7A1725EC6400B6E8B5 /* tone_generate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tone_generate.h; sourceTree = "<group>"; };
A1B98A7B1725EC6400B6E8B5 /* v17rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v17rx.h; sourceTree = "<group>"; };
A1B98A7C1725EC6400B6E8B5 /* v17tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v17tx.h; sourceTree = "<group>"; };
A1B98A7D1725EC6400B6E8B5 /* v18.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v18.h; sourceTree = "<group>"; };
A1B98A7E1725EC6400B6E8B5 /* v22bis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v22bis.h; sourceTree = "<group>"; };
A1B98A7F1725EC6400B6E8B5 /* v27ter_rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v27ter_rx.h; sourceTree = "<group>"; };
A1B98A801725EC6400B6E8B5 /* v27ter_tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v27ter_tx.h; sourceTree = "<group>"; };
A1B98A811725EC6400B6E8B5 /* v29rx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v29rx.h; sourceTree = "<group>"; };
A1B98A821725EC6400B6E8B5 /* v29tx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v29tx.h; sourceTree = "<group>"; };
A1B98A831725EC6400B6E8B5 /* v42.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v42.h; sourceTree = "<group>"; };
A1B98A841725EC6400B6E8B5 /* v42bis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v42bis.h; sourceTree = "<group>"; };
A1B98A851725EC6400B6E8B5 /* v8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v8.h; sourceTree = "<group>"; };
A1B98A861725EC6400B6E8B5 /* vector_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_float.h; sourceTree = "<group>"; };
A1B98A871725EC6400B6E8B5 /* vector_int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_int.h; sourceTree = "<group>"; };
A1B98A881725EC6400B6E8B5 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
A1B98A891725EC6400B6E8B5 /* version.h.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = version.h.in; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A1B989611725EC1300B6E8B5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A1B9895B1725EC1300B6E8B5 = {
isa = PBXGroup;
children = (
A1B989711725EC1A00B6E8B5 /* src */,
A1B989651725EC1300B6E8B5 /* Products */,
);
sourceTree = "<group>";
};
A1B989651725EC1300B6E8B5 /* Products */ = {
isa = PBXGroup;
children = (
A1B989641725EC1300B6E8B5 /* libspandsp.a */,
);
name = Products;
sourceTree = "<group>";
};
A1B989711725EC1A00B6E8B5 /* src */ = {
isa = PBXGroup;
children = (
A1B989FD1725EC3E00B6E8B5 /* time_scale.c */,
A1B98A001725EC6400B6E8B5 /* spandsp */,
);
name = src;
sourceTree = "<group>";
};
A1B98A001725EC6400B6E8B5 /* spandsp */ = {
isa = PBXGroup;
children = (
A1B98A011725EC6400B6E8B5 /* adsi.h */,
A1B98A021725EC6400B6E8B5 /* arctan2.h */,
A1B98A031725EC6400B6E8B5 /* async.h */,
A1B98A041725EC6400B6E8B5 /* at_interpreter.h */,
A1B98A051725EC6400B6E8B5 /* awgn.h */,
A1B98A061725EC6400B6E8B5 /* bell_r2_mf.h */,
A1B98A071725EC6400B6E8B5 /* bert.h */,
A1B98A081725EC6400B6E8B5 /* biquad.h */,
A1B98A091725EC6400B6E8B5 /* bit_operations.h */,
A1B98A0A1725EC6400B6E8B5 /* bitstream.h */,
A1B98A0B1725EC6400B6E8B5 /* complex.h */,
A1B98A0C1725EC6400B6E8B5 /* complex_filters.h */,
A1B98A0D1725EC6400B6E8B5 /* complex_vector_float.h */,
A1B98A0E1725EC6400B6E8B5 /* complex_vector_int.h */,
A1B98A0F1725EC6400B6E8B5 /* crc.h */,
A1B98A101725EC6400B6E8B5 /* dc_restore.h */,
A1B98A111725EC6400B6E8B5 /* dds.h */,
A1B98A121725EC6400B6E8B5 /* dtmf.h */,
A1B98A131725EC6400B6E8B5 /* echo.h */,
A1B98A141725EC6400B6E8B5 /* expose.h */,
A1B98A151725EC6400B6E8B5 /* fast_convert.h */,
A1B98A161725EC6400B6E8B5 /* fax.h */,
A1B98A171725EC6400B6E8B5 /* fax_modems.h */,
A1B98A181725EC6400B6E8B5 /* fir.h */,
A1B98A191725EC6400B6E8B5 /* fsk.h */,
A1B98A1A1725EC6400B6E8B5 /* g168models.h */,
A1B98A1B1725EC6400B6E8B5 /* g711.h */,
A1B98A1C1725EC6400B6E8B5 /* g722.h */,
A1B98A1D1725EC6400B6E8B5 /* g726.h */,
A1B98A1E1725EC6400B6E8B5 /* gsm0610.h */,
A1B98A1F1725EC6400B6E8B5 /* hdlc.h */,
A1B98A201725EC6400B6E8B5 /* ima_adpcm.h */,
A1B98A211725EC6400B6E8B5 /* logging.h */,
A1B98A221725EC6400B6E8B5 /* lpc10.h */,
A1B98A231725EC6400B6E8B5 /* modem_connect_tones.h */,
A1B98A241725EC6400B6E8B5 /* modem_echo.h */,
A1B98A251725EC6400B6E8B5 /* noise.h */,
A1B98A261725EC6400B6E8B5 /* oki_adpcm.h */,
A1B98A271725EC6400B6E8B5 /* playout.h */,
A1B98A281725EC6400B6E8B5 /* plc.h */,
A1B98A291725EC6400B6E8B5 /* power_meter.h */,
A1B98A2A1725EC6400B6E8B5 /* private */,
A1B98A621725EC6400B6E8B5 /* queue.h */,
A1B98A631725EC6400B6E8B5 /* saturated.h */,
A1B98A641725EC6400B6E8B5 /* schedule.h */,
A1B98A651725EC6400B6E8B5 /* sig_tone.h */,
A1B98A661725EC6400B6E8B5 /* silence_gen.h */,
A1B98A671725EC6400B6E8B5 /* super_tone_rx.h */,
A1B98A681725EC6400B6E8B5 /* super_tone_tx.h */,
A1B98A691725EC6400B6E8B5 /* swept_tone.h */,
A1B98A6A1725EC6400B6E8B5 /* t30.h */,
A1B98A6B1725EC6400B6E8B5 /* t30_api.h */,
A1B98A6C1725EC6400B6E8B5 /* t30_fcf.h */,
A1B98A6D1725EC6400B6E8B5 /* t30_logging.h */,
A1B98A6E1725EC6400B6E8B5 /* t31.h */,
A1B98A6F1725EC6400B6E8B5 /* t35.h */,
A1B98A701725EC6400B6E8B5 /* t38_core.h */,
A1B98A711725EC6400B6E8B5 /* t38_gateway.h */,
A1B98A721725EC6400B6E8B5 /* t38_non_ecm_buffer.h */,
A1B98A731725EC6400B6E8B5 /* t38_terminal.h */,
A1B98A741725EC6400B6E8B5 /* t4_rx.h */,
A1B98A751725EC6400B6E8B5 /* t4_tx.h */,
A1B98A761725EC6400B6E8B5 /* telephony.h */,
A1B98A771725EC6400B6E8B5 /* time_scale.h */,
A1B98A781725EC6400B6E8B5 /* timing.h */,
A1B98A791725EC6400B6E8B5 /* tone_detect.h */,
A1B98A7A1725EC6400B6E8B5 /* tone_generate.h */,
A1B98A7B1725EC6400B6E8B5 /* v17rx.h */,
A1B98A7C1725EC6400B6E8B5 /* v17tx.h */,
A1B98A7D1725EC6400B6E8B5 /* v18.h */,
A1B98A7E1725EC6400B6E8B5 /* v22bis.h */,
A1B98A7F1725EC6400B6E8B5 /* v27ter_rx.h */,
A1B98A801725EC6400B6E8B5 /* v27ter_tx.h */,
A1B98A811725EC6400B6E8B5 /* v29rx.h */,
A1B98A821725EC6400B6E8B5 /* v29tx.h */,
A1B98A831725EC6400B6E8B5 /* v42.h */,
A1B98A841725EC6400B6E8B5 /* v42bis.h */,
A1B98A851725EC6400B6E8B5 /* v8.h */,
A1B98A861725EC6400B6E8B5 /* vector_float.h */,
A1B98A871725EC6400B6E8B5 /* vector_int.h */,
A1B98A881725EC6400B6E8B5 /* version.h */,
A1B98A891725EC6400B6E8B5 /* version.h.in */,
);
path = spandsp;
sourceTree = "<group>";
};
A1B98A2A1725EC6400B6E8B5 /* private */ = {
isa = PBXGroup;
children = (
A1B98A2B1725EC6400B6E8B5 /* adsi.h */,
A1B98A2C1725EC6400B6E8B5 /* async.h */,
A1B98A2D1725EC6400B6E8B5 /* at_interpreter.h */,
A1B98A2E1725EC6400B6E8B5 /* awgn.h */,
A1B98A2F1725EC6400B6E8B5 /* bell_r2_mf.h */,
A1B98A301725EC6400B6E8B5 /* bert.h */,
A1B98A311725EC6400B6E8B5 /* bitstream.h */,
A1B98A321725EC6400B6E8B5 /* dtmf.h */,
A1B98A331725EC6400B6E8B5 /* echo.h */,
A1B98A341725EC6400B6E8B5 /* fax.h */,
A1B98A351725EC6400B6E8B5 /* fax_modems.h */,
A1B98A361725EC6400B6E8B5 /* fsk.h */,
A1B98A371725EC6400B6E8B5 /* g711.h */,
A1B98A381725EC6400B6E8B5 /* g722.h */,
A1B98A391725EC6400B6E8B5 /* g726.h */,
A1B98A3A1725EC6400B6E8B5 /* gsm0610.h */,
A1B98A3B1725EC6400B6E8B5 /* hdlc.h */,
A1B98A3C1725EC6400B6E8B5 /* ima_adpcm.h */,
A1B98A3D1725EC6400B6E8B5 /* logging.h */,
A1B98A3E1725EC6400B6E8B5 /* lpc10.h */,
A1B98A3F1725EC6400B6E8B5 /* modem_connect_tones.h */,
A1B98A401725EC6400B6E8B5 /* modem_echo.h */,
A1B98A411725EC6400B6E8B5 /* noise.h */,
A1B98A421725EC6400B6E8B5 /* oki_adpcm.h */,
A1B98A431725EC6400B6E8B5 /* queue.h */,
A1B98A441725EC6400B6E8B5 /* README */,
A1B98A451725EC6400B6E8B5 /* schedule.h */,
A1B98A461725EC6400B6E8B5 /* sig_tone.h */,
A1B98A471725EC6400B6E8B5 /* silence_gen.h */,
A1B98A481725EC6400B6E8B5 /* super_tone_rx.h */,
A1B98A491725EC6400B6E8B5 /* super_tone_tx.h */,
A1B98A4A1725EC6400B6E8B5 /* swept_tone.h */,
A1B98A4B1725EC6400B6E8B5 /* t30.h */,
A1B98A4C1725EC6400B6E8B5 /* t30_dis_dtc_dcs_bits.h */,
A1B98A4D1725EC6400B6E8B5 /* t31.h */,
A1B98A4E1725EC6400B6E8B5 /* t38_core.h */,
A1B98A4F1725EC6400B6E8B5 /* t38_gateway.h */,
A1B98A501725EC6400B6E8B5 /* t38_non_ecm_buffer.h */,
A1B98A511725EC6400B6E8B5 /* t38_terminal.h */,
A1B98A521725EC6400B6E8B5 /* t4_rx.h */,
A1B98A531725EC6400B6E8B5 /* t4_tx.h */,
A1B98A541725EC6400B6E8B5 /* time_scale.h */,
A1B98A551725EC6400B6E8B5 /* tone_detect.h */,
A1B98A561725EC6400B6E8B5 /* tone_generate.h */,
A1B98A571725EC6400B6E8B5 /* v17rx.h */,
A1B98A581725EC6400B6E8B5 /* v17tx.h */,
A1B98A591725EC6400B6E8B5 /* v18.h */,
A1B98A5A1725EC6400B6E8B5 /* v22bis.h */,
A1B98A5B1725EC6400B6E8B5 /* v27ter_rx.h */,
A1B98A5C1725EC6400B6E8B5 /* v27ter_tx.h */,
A1B98A5D1725EC6400B6E8B5 /* v29rx.h */,
A1B98A5E1725EC6400B6E8B5 /* v29tx.h */,
A1B98A5F1725EC6400B6E8B5 /* v42.h */,
A1B98A601725EC6400B6E8B5 /* v42bis.h */,
A1B98A611725EC6400B6E8B5 /* v8.h */,
);
path = private;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
A1B989621725EC1300B6E8B5 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
A1B98A8A1725EC6400B6E8B5 /* adsi.h in Headers */,
A1B98A8B1725EC6400B6E8B5 /* arctan2.h in Headers */,
A1B98A8C1725EC6400B6E8B5 /* async.h in Headers */,
A1B98A8D1725EC6400B6E8B5 /* at_interpreter.h in Headers */,
A1B98A8E1725EC6400B6E8B5 /* awgn.h in Headers */,
A1B98A8F1725EC6400B6E8B5 /* bell_r2_mf.h in Headers */,
A1B98A901725EC6400B6E8B5 /* bert.h in Headers */,
A1B98A911725EC6400B6E8B5 /* biquad.h in Headers */,
A1B98A921725EC6400B6E8B5 /* bit_operations.h in Headers */,
A1B98A931725EC6400B6E8B5 /* bitstream.h in Headers */,
A1B98A941725EC6400B6E8B5 /* complex.h in Headers */,
A1B98A951725EC6400B6E8B5 /* complex_filters.h in Headers */,
A1B98A961725EC6400B6E8B5 /* complex_vector_float.h in Headers */,
A1B98A971725EC6400B6E8B5 /* complex_vector_int.h in Headers */,
A1B98A981725EC6400B6E8B5 /* crc.h in Headers */,
A1B98A991725EC6400B6E8B5 /* dc_restore.h in Headers */,
A1B98A9A1725EC6400B6E8B5 /* dds.h in Headers */,
A1B98A9B1725EC6400B6E8B5 /* dtmf.h in Headers */,
A1B98A9C1725EC6400B6E8B5 /* echo.h in Headers */,
A1B98A9D1725EC6400B6E8B5 /* expose.h in Headers */,
A1B98A9E1725EC6400B6E8B5 /* fast_convert.h in Headers */,
A1B98A9F1725EC6400B6E8B5 /* fax.h in Headers */,
A1B98AA01725EC6400B6E8B5 /* fax_modems.h in Headers */,
A1B98AA11725EC6400B6E8B5 /* fir.h in Headers */,
A1B98AA21725EC6400B6E8B5 /* fsk.h in Headers */,
A1B98AA31725EC6400B6E8B5 /* g168models.h in Headers */,
A1B98AA41725EC6400B6E8B5 /* g711.h in Headers */,
A1B98AA51725EC6400B6E8B5 /* g722.h in Headers */,
A1B98AA61725EC6400B6E8B5 /* g726.h in Headers */,
A1B98AA71725EC6400B6E8B5 /* gsm0610.h in Headers */,
A1B98AA81725EC6400B6E8B5 /* hdlc.h in Headers */,
A1B98AA91725EC6400B6E8B5 /* ima_adpcm.h in Headers */,
A1B98AAA1725EC6400B6E8B5 /* logging.h in Headers */,
A1B98AAB1725EC6400B6E8B5 /* lpc10.h in Headers */,
A1B98AAC1725EC6400B6E8B5 /* modem_connect_tones.h in Headers */,
A1B98AAD1725EC6400B6E8B5 /* modem_echo.h in Headers */,
A1B98AAE1725EC6400B6E8B5 /* noise.h in Headers */,
A1B98AAF1725EC6400B6E8B5 /* oki_adpcm.h in Headers */,
A1B98AB01725EC6400B6E8B5 /* playout.h in Headers */,
A1B98AB11725EC6400B6E8B5 /* plc.h in Headers */,
A1B98AB21725EC6400B6E8B5 /* power_meter.h in Headers */,
A1B98AB31725EC6400B6E8B5 /* adsi.h in Headers */,
A1B98AB41725EC6400B6E8B5 /* async.h in Headers */,
A1B98AB51725EC6400B6E8B5 /* at_interpreter.h in Headers */,
A1B98AB61725EC6400B6E8B5 /* awgn.h in Headers */,
A1B98AB71725EC6500B6E8B5 /* bell_r2_mf.h in Headers */,
A1B98AB81725EC6500B6E8B5 /* bert.h in Headers */,
A1B98AB91725EC6500B6E8B5 /* bitstream.h in Headers */,
A1B98ABA1725EC6500B6E8B5 /* dtmf.h in Headers */,
A1B98ABB1725EC6500B6E8B5 /* echo.h in Headers */,
A1B98ABC1725EC6500B6E8B5 /* fax.h in Headers */,
A1B98ABD1725EC6500B6E8B5 /* fax_modems.h in Headers */,
A1B98ABE1725EC6500B6E8B5 /* fsk.h in Headers */,
A1B98ABF1725EC6500B6E8B5 /* g711.h in Headers */,
A1B98AC01725EC6500B6E8B5 /* g722.h in Headers */,
A1B98AC11725EC6500B6E8B5 /* g726.h in Headers */,
A1B98AC21725EC6500B6E8B5 /* gsm0610.h in Headers */,
A1B98AC31725EC6500B6E8B5 /* hdlc.h in Headers */,
A1B98AC41725EC6500B6E8B5 /* ima_adpcm.h in Headers */,
A1B98AC51725EC6500B6E8B5 /* logging.h in Headers */,
A1B98AC61725EC6500B6E8B5 /* lpc10.h in Headers */,
A1B98AC71725EC6500B6E8B5 /* modem_connect_tones.h in Headers */,
A1B98AC81725EC6500B6E8B5 /* modem_echo.h in Headers */,
A1B98AC91725EC6500B6E8B5 /* noise.h in Headers */,
A1B98ACA1725EC6500B6E8B5 /* oki_adpcm.h in Headers */,
A1B98ACB1725EC6500B6E8B5 /* queue.h in Headers */,
A1B98ACC1725EC6500B6E8B5 /* schedule.h in Headers */,
A1B98ACD1725EC6500B6E8B5 /* sig_tone.h in Headers */,
A1B98ACE1725EC6500B6E8B5 /* silence_gen.h in Headers */,
A1B98ACF1725EC6500B6E8B5 /* super_tone_rx.h in Headers */,
A1B98AD01725EC6500B6E8B5 /* super_tone_tx.h in Headers */,
A1B98AD11725EC6500B6E8B5 /* swept_tone.h in Headers */,
A1B98AD21725EC6500B6E8B5 /* t30.h in Headers */,
A1B98AD31725EC6500B6E8B5 /* t30_dis_dtc_dcs_bits.h in Headers */,
A1B98AD41725EC6500B6E8B5 /* t31.h in Headers */,
A1B98AD51725EC6500B6E8B5 /* t38_core.h in Headers */,
A1B98AD61725EC6500B6E8B5 /* t38_gateway.h in Headers */,
A1B98AD71725EC6500B6E8B5 /* t38_non_ecm_buffer.h in Headers */,
A1B98AD81725EC6500B6E8B5 /* t38_terminal.h in Headers */,
A1B98AD91725EC6500B6E8B5 /* t4_rx.h in Headers */,
A1B98ADA1725EC6500B6E8B5 /* t4_tx.h in Headers */,
A1B98ADB1725EC6500B6E8B5 /* time_scale.h in Headers */,
A1B98ADC1725EC6500B6E8B5 /* tone_detect.h in Headers */,
A1B98ADD1725EC6500B6E8B5 /* tone_generate.h in Headers */,
A1B98ADE1725EC6500B6E8B5 /* v17rx.h in Headers */,
A1B98ADF1725EC6500B6E8B5 /* v17tx.h in Headers */,
A1B98AE01725EC6500B6E8B5 /* v18.h in Headers */,
A1B98AE11725EC6500B6E8B5 /* v22bis.h in Headers */,
A1B98AE21725EC6500B6E8B5 /* v27ter_rx.h in Headers */,
A1B98AE31725EC6500B6E8B5 /* v27ter_tx.h in Headers */,
A1B98AE41725EC6500B6E8B5 /* v29rx.h in Headers */,
A1B98AE51725EC6500B6E8B5 /* v29tx.h in Headers */,
A1B98AE61725EC6500B6E8B5 /* v42.h in Headers */,
A1B98AE71725EC6500B6E8B5 /* v42bis.h in Headers */,
A1B98AE81725EC6500B6E8B5 /* v8.h in Headers */,
A1B98AE91725EC6500B6E8B5 /* queue.h in Headers */,
A1B98AEA1725EC6500B6E8B5 /* saturated.h in Headers */,
A1B98AEB1725EC6500B6E8B5 /* schedule.h in Headers */,
A1B98AEC1725EC6500B6E8B5 /* sig_tone.h in Headers */,
A1B98AED1725EC6500B6E8B5 /* silence_gen.h in Headers */,
A1B98AEE1725EC6500B6E8B5 /* super_tone_rx.h in Headers */,
A1B98AEF1725EC6500B6E8B5 /* super_tone_tx.h in Headers */,
A1B98AF01725EC6500B6E8B5 /* swept_tone.h in Headers */,
A1B98AF11725EC6500B6E8B5 /* t30.h in Headers */,
A1B98AF21725EC6500B6E8B5 /* t30_api.h in Headers */,
A1B98AF31725EC6500B6E8B5 /* t30_fcf.h in Headers */,
A1B98AF41725EC6500B6E8B5 /* t30_logging.h in Headers */,
A1B98AF51725EC6500B6E8B5 /* t31.h in Headers */,
A1B98AF61725EC6500B6E8B5 /* t35.h in Headers */,
A1B98AF71725EC6500B6E8B5 /* t38_core.h in Headers */,
A1B98AF81725EC6500B6E8B5 /* t38_gateway.h in Headers */,
A1B98AF91725EC6500B6E8B5 /* t38_non_ecm_buffer.h in Headers */,
A1B98AFA1725EC6500B6E8B5 /* t38_terminal.h in Headers */,
A1B98AFB1725EC6500B6E8B5 /* t4_rx.h in Headers */,
A1B98AFC1725EC6500B6E8B5 /* t4_tx.h in Headers */,
A1B98AFD1725EC6500B6E8B5 /* telephony.h in Headers */,
A1B98AFE1725EC6500B6E8B5 /* time_scale.h in Headers */,
A1B98AFF1725EC6500B6E8B5 /* timing.h in Headers */,
A1B98B001725EC6500B6E8B5 /* tone_detect.h in Headers */,
A1B98B011725EC6500B6E8B5 /* tone_generate.h in Headers */,
A1B98B021725EC6500B6E8B5 /* v17rx.h in Headers */,
A1B98B031725EC6500B6E8B5 /* v17tx.h in Headers */,
A1B98B041725EC6500B6E8B5 /* v18.h in Headers */,
A1B98B051725EC6500B6E8B5 /* v22bis.h in Headers */,
A1B98B061725EC6500B6E8B5 /* v27ter_rx.h in Headers */,
A1B98B071725EC6500B6E8B5 /* v27ter_tx.h in Headers */,
A1B98B081725EC6500B6E8B5 /* v29rx.h in Headers */,
A1B98B091725EC6500B6E8B5 /* v29tx.h in Headers */,
A1B98B0A1725EC6500B6E8B5 /* v42.h in Headers */,
A1B98B0B1725EC6500B6E8B5 /* v42bis.h in Headers */,
A1B98B0C1725EC6500B6E8B5 /* v8.h in Headers */,
A1B98B0D1725EC6500B6E8B5 /* vector_float.h in Headers */,
A1B98B0E1725EC6500B6E8B5 /* vector_int.h in Headers */,
A1B98B0F1725EC6500B6E8B5 /* version.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
A1B989631725EC1300B6E8B5 /* spandsp */ = {
isa = PBXNativeTarget;
buildConfigurationList = A1B989681725EC1300B6E8B5 /* Build configuration list for PBXNativeTarget "spandsp" */;
buildPhases = (
A1B989601725EC1300B6E8B5 /* Sources */,
A1B989611725EC1300B6E8B5 /* Frameworks */,
A1B989621725EC1300B6E8B5 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = spandsp;
productName = spandsp;
productReference = A1B989641725EC1300B6E8B5 /* libspandsp.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A1B9895C1725EC1300B6E8B5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Twisted Oak Studios";
};
buildConfigurationList = A1B9895F1725EC1300B6E8B5 /* Build configuration list for PBXProject "spandsp" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = A1B9895B1725EC1300B6E8B5;
productRefGroup = A1B989651725EC1300B6E8B5 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A1B989631725EC1300B6E8B5 /* spandsp */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
A1B989601725EC1300B6E8B5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A1B989FE1725EC3E00B6E8B5 /* time_scale.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
A1B989661725EC1300B6E8B5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
A1B989671725EC1300B6E8B5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = iphoneos;
};
name = Release;
};
A1B989691725EC1300B6E8B5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
};
name = Debug;
};
A1B9896A1725EC1300B6E8B5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A1B9895F1725EC1300B6E8B5 /* Build configuration list for PBXProject "spandsp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1B989661725EC1300B6E8B5 /* Debug */,
A1B989671725EC1300B6E8B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A1B989681725EC1300B6E8B5 /* Build configuration list for PBXNativeTarget "spandsp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A1B989691725EC1300B6E8B5 /* Debug */,
A1B9896A1725EC1300B6E8B5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = A1B9895C1725EC1300B6E8B5 /* Project object */;
}

View File

@ -0,0 +1,516 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* adsi.h - Analogue display services interface and other call ID related handling.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: adsi.h,v 1.40 2009/05/22 16:39:01 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_ADSI_H_)
#define _SPANDSP_ADSI_H_
/*! \page adsi_page ADSI transmission and reception
\section adsi_page_sec_1 What does it do?
Although ADSI has a specific meaning in some places, the term is used here to indicate
any form of Analogue Display Service Interface, which includes caller ID, SMS, and others.
The ADSI module provides for the transmission and reception of ADSI messages
in various formats. Currently, the supported formats are:
- Bellcore/Telcordia GR-30 CORE CLASS (Custom Local Area Signaling Services) standard
(North America, Australia, China, Taiwan, and Hong Kong).
- ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) FSK standard
(France, Germany, Norway, Italy, Spain, South Africa, Turkey, and the UK).
- ETSI Caller-ID support for the UK, British Telecom SIN227 and SIN242.
- ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard
variant 1 (Belgium, Brazil, Denmark, Finland, Iceland, India, Netherlands, Saudi Arabia,
Sweden and Uruguay).
- ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard
variant 2 (Denmark and Holland).
- ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard
variant 3.
- ETSI ETS 300 648, ETS 300 659-1 CLIP (Calling Line Identity Presentation) DTMF standard
variant 4. (Taiwan and Kuwait).
- ETSI Caller-ID support in UK (British Telecom), British Telecomm SIN227, SIN242.
- Nippon Telegraph & Telephone Corporation JCLIP (Japanese Calling Line Identity
Presentation) standard.
- Telecommunications Authority of Singapore ACLIP (Analog Calling Line Identity
Presentation) standard.
- TDD (Telecommunications Device for the Deaf).
\section adsi_page_sec_2 How does it work?
\section adsi_page_sec_2a The Bellcore CLASS specification
Most FSK based CLI formats are similar to the US CLASS one, which is as follows:
The alert tone for CLI during a call is at least 100ms of silence, then
2130Hz + 2750Hz for 88ms to 110ms. When CLI is presented at ringing time,
this tone is not sent. In the US, CLI is usually sent between the first
two rings. This silence period is long in the US, so the message fits easily.
In other places, where the standard ring tone has much smaller silences,
a line voltage reversal is used to wake up a power saving receiver, then the
message is sent, then the phone begins to ring.
The message is sent using a Bell 202 FSK modem. The data rate is 1200 bits
per second. The message protocol uses 8-bit data words (bytes), each bounded
by a start bit and a stop bit.
Channel Carrier Message Message Data Checksum
Seizure Signal Type Length Word(s) Word
Signal Word Word
\section adsi_page_sec_2a1 CHANNEL SEIZURE SIGNAL
The channel seizure is 30 continuous bytes of 55h (01010101), including
the start and stop bits (i.e. 300 bits of alternations in total).
This provides a detectable alternating function to the CPE (i.e. the
modem data pump).
\section adsi_page_sec_2a2 CARRIER SIGNAL
The carrier signal consists of 180 bits of 1s. This may be reduced to 80
bits of 1s for caller ID on call waiting.
\section adsi_page_sec_2a3 MESSAGE TYPE WORD
Various message types are defined. The commonest ones for the US CLASS
standard are:
- Type 0x04 (SDMF) - single data message. Simple caller ID (CND)
- Type 0x80 (MDMF) - multiple data message. A more flexible caller ID,
with extra information.
Other messages support message waiting, for voice mail, and other display features.
\section adsi_page_sec_2a4 MESSAGE LENGTH WORD
The message length word specifies the total number of data words
to follow.
\section adsi_page_sec_2a5 DATA WORDS
The data words contain the actual message.
\section adsi_page_sec_2a6 CHECKSUM WORD
The Checksum Word contains the twos complement of the modulo 256
sum of the other words in the data message (i.e., message type,
message length, and data words). The receiving equipment may
calculate the modulo 256 sum of the received words and add this
sum to the received checksum word. A result of zero generally
indicates that the message was correctly received. Message
retransmission is not supported. The sumcheck word should be followed
by a minimum of two stop bits.
\section adsi_page_sec_2b The ETSI CLIP specification
The ETSI CLIP specification uses similar messages to the Bellcore specification.
They are not, however, identical. First, ETSI use the V.23 modem standard, rather
than Bell 202. Second, different fields, and different message types are available.
The wake up indication generally differs from the Bellcore specification, to
accomodate differences in European ring cadences.
\section adsi_page_sec_2c The ETSI caller ID by DTMF specification
CLI by DTMF is usually sent in a very simple way. The exchange does not give
any prior warning (no reversal, or ring) to wake up the receiver. It just
sends a string of DTMF digits. Around the world several variants of this
basic scheme are used.
One variant of the digit string is used in Belgium, Brazil, Denmark, Finland, Iceland,
India, Netherlands, Saudi Arabia, Sweden and Uruguay:
- A<caller's phone number>D<redirected number>B<special information>C
Each of these fields may be omitted. The following special information codes are defined
- "00" indicates the calling party number is not available.
- "10" indicates that the presentation of the calling party number is restricted.
A second variant of the digit string is one of the following:
- A<caller's phone number>#
- D1# Number not available because the caller has restricted it.
- D2# Number not available because the call is international.
- D3# Number not available due to technical reasons.
A third variant of the digit string is used in Taiwan and Kuwait:
- D<caller's phone number>C
A forth variant of the digit string is used in Denmark and Holland:
- <caller's phone number>#
There is no distinctive start marker in this format.
\section adsi_page_sec_2d The Japanese specification from NTT
The Japanese caller ID specification is considerably different from any of the others. It
uses V.23 modem signals, but the message structure is uniqeue. Also, the message is delivered
while off hook. This results in a sequence
- The phone line rings
- CPE answers and waits for the caller ID message
- CPE hangs up on receipt of the caller ID message
- The phone line rings a second time
- The CPE answers a second time, connecting the called party with the caller.
Timeouts are, obviously, required to ensure this system behaves well when the caller ID message
or the second ring are missing.
*/
enum
{
ADSI_STANDARD_NONE = 0,
ADSI_STANDARD_CLASS = 1,
ADSI_STANDARD_CLIP = 2,
ADSI_STANDARD_ACLIP = 3,
ADSI_STANDARD_JCLIP = 4,
ADSI_STANDARD_CLIP_DTMF = 5,
ADSI_STANDARD_TDD = 6
};
/* In some of the messages code characters are used, as follows:
'C' for public callbox
'L' for long distance
'O' for overseas
'P' for private
'S' for service conflict
Taiwan and Kuwait change this pattern to:
'C' for coin/public callbox
'I' for international call
'O' for out of area call
'P' for private
*/
/*! Definitions for CLASS (Custom Local Area Signaling Services) */
enum
{
/*! Single data message caller ID */
CLASS_SDMF_CALLERID = 0x04,
/*! Multiple data message caller ID */
CLASS_MDMF_CALLERID = 0x80,
/*! Single data message message waiting */
CLASS_SDMF_MSG_WAITING = 0x06,
/*! Multiple data message message waiting */
CLASS_MDMF_MSG_WAITING = 0x82
};
/*! CLASS MDMF message IDs */
enum
{
/*! Date and time (MMDDHHMM) */
MCLASS_DATETIME = 0x01,
/*! Caller number */
MCLASS_CALLER_NUMBER = 0x02,
/*! Dialed number */
MCLASS_DIALED_NUMBER = 0x03,
/*! Caller number absent: 'O' or 'P' */
MCLASS_ABSENCE1 = 0x04,
/*! Call forward: universal ('0'), on busy ('1'), or on unanswered ('2') */
MCLASS_REDIRECT = 0x05,
/*! Long distance: 'L' */
MCLASS_QUALIFIER = 0x06,
/*! Caller's name */
MCLASS_CALLER_NAME = 0x07,
/*! Caller's name absent: 'O' or 'P' */
MCLASS_ABSENCE2 = 0x08,
/*! Alternate route */
MCLASS_ALT_ROUTE = 0x09
};
/*! CLASS MDMF message waiting message IDs */
/*! Message waiting/not waiting */
#define MCLASS_VISUAL_INDICATOR 0x0B
/*! Definitions for CLIP (Calling Line Identity Presentation) (from ETS 300 659-1) */
enum
{
/*! Multiple data message caller ID */
CLIP_MDMF_CALLERID = 0x80,
/*! Multiple data message message waiting */
CLIP_MDMF_MSG_WAITING = 0x82,
/*! Multiple data message charge information */
CLIP_MDMF_CHARGE_INFO = 0x86,
/*! Multiple data message SMS */
CLIP_MDMF_SMS = 0x89
};
/*! CLIP message IDs (from ETS 300 659-1) */
enum
{
/*! Date and time (MMDDHHMM) */
CLIP_DATETIME = 0x01,
/*! Caller number (AKA calling line identity) */
CLIP_CALLER_NUMBER = 0x02,
/*! Dialed number (AKA called line identity) */
CLIP_DIALED_NUMBER = 0x03,
/*! Caller number absent: 'O' or 'P' (AKA reason for absence of calling line identity) */
CLIP_ABSENCE1 = 0x04,
/*! Caller's name (AKA calling party name) */
CLIP_CALLER_NAME = 0x07,
/*! Caller's name absent: 'O' or 'P' (AKA reason for absence of calling party name) */
CLIP_ABSENCE2 = 0x08,
/*! Visual indicator */
CLIP_VISUAL_INDICATOR = 0x0B,
/*! Message ID */
CLIP_MESSAGE_ID = 0x0D,
/*! Complementary calling line identity */
CLIP_COMPLEMENTARY_CALLER_NUMBER = 0x10,
/*! Call type - voice call (1), ring-back-when-free call (2), calling name delivery (3) or msg waiting call(0x81) */
CLIP_CALLTYPE = 0x11,
/*! Number of messages */
CLIP_NUM_MSG = 0x13,
/*! Type of forwarded call */
CLIP_TYPE_OF_FORWARDED_CALL = 0x15,
/*! Type of calling user */
CLIP_TYPE_OF_CALLING_USER = 0x16,
/*! Redirecting number */
CLIP_REDIR_NUMBER = 0x1A,
/*! Charge */
CLIP_CHARGE = 0x20,
/*! Duration of the call */
CLIP_DURATION = 0x23,
/*! Additional charge */
CLIP_ADD_CHARGE = 0x21,
/*! Display information */
CLIP_DISPLAY_INFO = 0x50,
/*! Service information */
CLIP_SERVICE_INFO = 0x55
};
/*! Definitions for A-CLIP (Analog Calling Line Identity Presentation) */
enum
{
/*! Single data message caller ID frame */
ACLIP_SDMF_CALLERID = 0x04,
/*! Multiple data message caller ID frame */
ACLIP_MDMF_CALLERID = 0x80
};
/*! A-CLIP MDM message IDs */
enum
{
/*! Date and time (MMDDHHMM) */
ACLIP_DATETIME = 0x01,
/*! Caller number */
ACLIP_CALLER_NUMBER = 0x02,
/*! Dialed number */
ACLIP_DIALED_NUMBER = 0x03,
/*! Caller number absent: 'O' or 'P' */
ACLIP_NUMBER_ABSENCE = 0x04,
/*! Call forward: universal, on busy, or on unanswered */
ACLIP_REDIRECT = 0x05,
/*! Long distance call: 'L' */
ACLIP_QUALIFIER = 0x06,
/*! Caller's name */
ACLIP_CALLER_NAME = 0x07,
/*! Caller's name absent: 'O' or 'P' */
ACLIP_NAME_ABSENCE = 0x08
};
/*! Definitions for J-CLIP (Japan Calling Line Identity Presentation) */
/*! Multiple data message caller ID frame */
#define JCLIP_MDMF_CALLERID 0x40
/*! J-CLIP MDM message IDs */
enum
{
/*! Caller number */
JCLIP_CALLER_NUMBER = 0x02,
/*! Caller number data extension signal */
JCLIP_CALLER_NUM_DES = 0x21,
/*! Dialed number */
JCLIP_DIALED_NUMBER = 0x09,
/*! Dialed number data extension signal */
JCLIP_DIALED_NUM_DES = 0x22,
/*! Caller number absent: 'C', 'O', 'P' or 'S' */
JCLIP_ABSENCE = 0x04
};
/* Definitions for CLIP-DTMF and its variants */
/*! Caller number is '#' terminated DTMF. */
#define CLIP_DTMF_HASH_TERMINATED '#'
/*! Caller number is 'C' terminated DTMF. */
#define CLIP_DTMF_C_TERMINATED 'C'
/*! Caller number */
#define CLIP_DTMF_HASH_CALLER_NUMBER 'A'
/*! Caller number absent: private (1), overseas (2) or not available (3) */
#define CLIP_DTMF_HASH_ABSENCE 'D'
/*! Caller ID field with no explicit field type */
#define CLIP_DTMF_HASH_UNSPECIFIED 0
/*! Caller number */
#define CLIP_DTMF_C_CALLER_NUMBER 'A'
/*! Diverting number */
#define CLIP_DTMF_C_REDIRECT_NUMBER 'D'
/*! Caller number absent: private/restricted (00) or not available (10) */
#define CLIP_DTMF_C_ABSENCE 'B'
/*!
ADSI transmitter descriptor. This contains all the state information for an ADSI
(caller ID, CLASS, CLIP, ACLIP) transmit channel.
*/
typedef struct adsi_tx_state_s adsi_tx_state_t;
/*!
ADSI receiver descriptor. This contains all the state information for an ADSI
(caller ID, CLASS, CLIP, ACLIP, JCLIP) receive channel.
*/
typedef struct adsi_rx_state_s adsi_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Initialise an ADSI receive context.
\param s The ADSI receive context.
\param standard The code for the ADSI standard to be used.
\param put_msg A callback routine called to deliver the received messages
to the application.
\param user_data An opaque pointer for the callback routine.
\return A pointer to the initialised context, or NULL if there was a problem.
*/
SPAN_DECLARE(adsi_rx_state_t *) adsi_rx_init(adsi_rx_state_t *s,
int standard,
put_msg_func_t put_msg,
void *user_data);
/*! \brief Release an ADSI receive context.
\param s The ADSI receive context.
\return 0 for OK.
*/
SPAN_DECLARE(int) adsi_rx_release(adsi_rx_state_t *s);
/*! \brief Free the resources of an ADSI receive context.
\param s The ADSI receive context.
\return 0 for OK.
*/
SPAN_DECLARE(int) adsi_rx_free(adsi_rx_state_t *s);
/*! \brief Receive a chunk of ADSI audio.
\param s The ADSI receive context.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed.
*/
SPAN_DECLARE(int) adsi_rx(adsi_rx_state_t *s, const int16_t amp[], int len);
/*! \brief Initialise an ADSI transmit context.
\param s The ADSI transmit context.
\param standard The code for the ADSI standard to be used.
\return A pointer to the initialised context, or NULL if there was a problem.
*/
SPAN_DECLARE(adsi_tx_state_t *) adsi_tx_init(adsi_tx_state_t *s, int standard);
/*! \brief Release an ADSI transmit context.
\param s The ADSI transmit context.
\return 0 for OK.
*/
SPAN_DECLARE(int) adsi_tx_release(adsi_tx_state_t *s);
/*! \brief Free the resources of an ADSI transmit context.
\param s The ADSI transmit context.
\return 0 for OK.
*/
SPAN_DECLARE(int) adsi_tx_free(adsi_tx_state_t *s);
/*! \brief Adjust the preamble associated with an ADSI transmit context.
\param s The ADSI transmit context.
\param preamble_len The number of bits of preamble.
\param preamble_ones_len The number of bits of continuous one before a message.
\param postamble_ones_len The number of bits of continuous one after a message.
\param stop_bits The number of stop bits per character.
*/
SPAN_DECLARE(void) adsi_tx_set_preamble(adsi_tx_state_t *s,
int preamble_len,
int preamble_ones_len,
int postamble_ones_len,
int stop_bits);
/*! \brief Generate a block of ADSI audio samples.
\param s The ADSI transmit context.
\param amp The audio sample buffer.
\param max_len The number of samples to be generated.
\return The number of samples actually generated.
*/
SPAN_DECLARE(int) adsi_tx(adsi_tx_state_t *s, int16_t amp[], int max_len);
/*! \brief Request generation of an ADSI alert tone.
\param s The ADSI transmit context.
*/
SPAN_DECLARE(void) adsi_tx_send_alert_tone(adsi_tx_state_t *s);
/*! \brief Put a message into the input buffer of an ADSI transmit context.
\param s The ADSI transmit context.
\param msg The message.
\param len The length of the message.
\return The length actually added. If a message is already in progress
in the transmitter, this function will return zero, as it will
not successfully add the message to the buffer. If the message is
invalid (e.g. it is too long), this function will return -1.
*/
SPAN_DECLARE(int) adsi_tx_put_message(adsi_tx_state_t *s, const uint8_t *msg, int len);
/*! \brief Get a field from an ADSI message.
\param s The ADSI receive context.
\param msg The message buffer.
\param msg_len The length of the message.
\param pos Current position within the message. Set to -1 when starting a message.
\param field_type The type code for the field.
\param field_body Pointer to the body of the field.
\param field_len The length of the field, or -1 for no more fields, or -2 for message structure corrupt.
*/
SPAN_DECLARE(int) adsi_next_field(adsi_rx_state_t *s, const uint8_t *msg, int msg_len, int pos, uint8_t *field_type, uint8_t const **field_body, int *field_len);
/*! \brief Insert the header or a field into an ADSI message.
\param s The ADSI transmit context.
\param msg The message buffer.
\param len The current length of the message.
\param field_type The type code for the new field.
\param field_body Pointer to the body of the new field.
\param field_len The length of the new field.
*/
SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint8_t field_type, uint8_t const *field_body, int field_len);
/*! \brief Return a short name for an ADSI standard
\param standard The code for the standard.
\return A pointer to the name.
*/
SPAN_DECLARE(const char *) adsi_standard_to_str(int standard);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,108 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* arctan2.h - A quick rough approximate arc tan
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: arctan2.h,v 1.13 2008/05/29 13:04:19 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_ARCTAN2_H_)
#define _SPANDSP_ARCTAN2_H_
/*! \page arctan2_page Fast approximate four quadrant arc-tangent
\section arctan2_page_sec_1 What does it do?
This module provides a fast approximate 4-quadrant arc tangent function,
based on something at dspguru.com. The worst case error is about 4.07 degrees.
This is fine for many "where am I" type evaluations in comms. work.
\section arctan2_page_sec_2 How does it work?
???.
*/
#if defined(__cplusplus)
extern "C"
{
#endif
/* This returns its answer as a signed 32 bit integer phase value. */
static __inline__ int32_t arctan2(float y, float x)
{
float abs_y;
float angle;
if (x == 0.0f || y == 0.0f)
return 0;
abs_y = fabsf(y);
/* If we are in quadrant II or III, flip things around */
if (x < 0.0f)
angle = 3.0f - (x + abs_y)/(abs_y - x);
else
angle = 1.0f - (x - abs_y)/(abs_y + x);
angle *= 536870912.0f;
/* If we are in quadrant III or IV, negate to return an
answer in the range +-pi */
if (y < 0.0f)
angle = -angle;
return (int32_t) angle;
}
/*- End of function --------------------------------------------------------*/
#if 0
/* This returns its answer in radians, in the range +-pi. */
static __inline__ float arctan2f(float y, float x)
{
float angle;
float fx;
float fy;
if (x == 0.0f || y == 0.0f)
return 0;
fx = fabsf(x);
fy = fabsf(y);
/* Deal with the octants */
/* N.B. 0.28125 == (1/4 + 1/32) */
if (fy > fx)
angle = 3.1415926f/2.0f - fx*fy/(y*y + 0.28125f*x*x);
else
angle = fy*fx/(x*x + 0.28125f*y*y);
/* Deal with the quadrants, to bring the final answer to the range +-pi */
if (x < 0.0f)
angle = 3.1415926f - angle;
if (y < 0.0f)
angle = -angle;
return angle;
}
/*- End of function --------------------------------------------------------*/
#endif
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,213 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* async.h - Asynchronous serial bit stream encoding and decoding
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: async.h,v 1.25 2009/04/23 14:12:34 steveu Exp $
*/
/*! \file */
/*! \page async_page Asynchronous bit stream processing
\section async_page_sec_1 What does it do?
The asynchronous serial bit stream processing module provides
generation and decoding facilities for most asynchronous data
formats. It supports:
- 1 or 2 stop bits.
- Odd, even or no parity.
- 5, 6, 7, or 8 bit characters.
- V.14 rate adaption.
The input to this module is a bit stream. This means any symbol synchronisation
and decoding must occur before data is fed to this module.
\section async_page_sec_2 The transmitter
???.
\section async_page_sec_3 The receiver
???.
*/
#if !defined(_SPANDSP_ASYNC_H_)
#define _SPANDSP_ASYNC_H_
/*! Special "bit" values for the bitstream put and get functions, and the signal status functions. */
enum
{
/*! \brief The carrier signal has dropped. */
SIG_STATUS_CARRIER_DOWN = -1,
/*! \brief The carrier signal is up. This merely indicates that carrier
energy has been seen. It is not an indication that the carrier is either
valid, or of the expected type. */
SIG_STATUS_CARRIER_UP = -2,
/*! \brief The modem is training. This is an early indication that the
signal seems to be of the right type. This may be needed in time critical
applications, like T.38, to forward an early indication of what is happening
on the wire. */
SIG_STATUS_TRAINING_IN_PROGRESS = -3,
/*! \brief The modem has trained, and is ready for data exchange. */
SIG_STATUS_TRAINING_SUCCEEDED = -4,
/*! \brief The modem has failed to train. */
SIG_STATUS_TRAINING_FAILED = -5,
/*! \brief Packet framing (e.g. HDLC framing) is OK. */
SIG_STATUS_FRAMING_OK = -6,
/*! \brief The data stream has ended. */
SIG_STATUS_END_OF_DATA = -7,
/*! \brief An abort signal (e.g. an HDLC abort) has been received. */
SIG_STATUS_ABORT = -8,
/*! \brief A break signal (e.g. an async break) has been received. */
SIG_STATUS_BREAK = -9,
/*! \brief A modem has completed its task, and shut down. */
SIG_STATUS_SHUTDOWN_COMPLETE = -10,
/*! \brief Regular octet report for things like HDLC to the MTP standards. */
SIG_STATUS_OCTET_REPORT = -11,
/*! \brief Notification that a modem has detected signal quality degradation. */
SIG_STATUS_POOR_SIGNAL_QUALITY = -12,
/*! \brief Notification that a modem retrain has occurred. */
SIG_STATUS_MODEM_RETRAIN_OCCURRED = -13
};
/*! Message put function for data pumps */
typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len);
/*! Message get function for data pumps */
typedef int (*get_msg_func_t)(void *user_data, uint8_t *msg, int max_len);
/*! Byte put function for data pumps */
typedef void (*put_byte_func_t)(void *user_data, int byte);
/*! Byte get function for data pumps */
typedef int (*get_byte_func_t)(void *user_data);
/*! Bit put function for data pumps */
typedef void (*put_bit_func_t)(void *user_data, int bit);
/*! Bit get function for data pumps */
typedef int (*get_bit_func_t)(void *user_data);
/*! Completion callback function for tx data pumps */
typedef void (*modem_tx_status_func_t)(void *user_data, int status);
/*! Completion callback function for rx data pumps */
typedef void (*modem_rx_status_func_t)(void *user_data, int status);
enum
{
/*! No parity bit should be used */
ASYNC_PARITY_NONE = 0,
/*! An even parity bit will exist, after the data bits */
ASYNC_PARITY_EVEN,
/*! An odd parity bit will exist, after the data bits */
ASYNC_PARITY_ODD
};
/*!
Asynchronous data transmit descriptor. This defines the state of a single
working instance of a byte to asynchronous serial converter, for use
in FSK modems.
*/
typedef struct async_tx_state_s async_tx_state_t;
/*!
Asynchronous data receive descriptor. This defines the state of a single
working instance of an asynchronous serial to byte converter, for use
in FSK modems.
*/
typedef struct async_rx_state_s async_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Convert a signal status to a short text description.
\brief Convert a signal status to a short text description.
\param status The modem signal status.
\return A pointer to the description. */
SPAN_DECLARE(const char *) signal_status_to_str(int status);
/*! Initialise an asynchronous data transmit context.
\brief Initialise an asynchronous data transmit context.
\param s The transmitter context.
\param data_bits The number of data bit.
\param parity_bits The type of parity.
\param stop_bits The number of stop bits.
\param use_v14 TRUE if V.14 rate adaption processing should be used.
\param get_byte The callback routine used to get the data to be transmitted.
\param user_data An opaque pointer.
\return A pointer to the initialised context, or NULL if there was a problem. */
SPAN_DECLARE(async_tx_state_t *) async_tx_init(async_tx_state_t *s,
int data_bits,
int parity_bits,
int stop_bits,
int use_v14,
get_byte_func_t get_byte,
void *user_data);
SPAN_DECLARE(int) async_tx_release(async_tx_state_t *s);
SPAN_DECLARE(int) async_tx_free(async_tx_state_t *s);
/*! Get the next bit of a transmitted serial bit stream.
\brief Get the next bit of a transmitted serial bit stream.
\param user_data An opaque point which must point to a transmitter context.
\return the next bit, or PUTBIT_END_OF_DATA to indicate the data stream has ended. */
SPAN_DECLARE_NONSTD(int) async_tx_get_bit(void *user_data);
/*! Initialise an asynchronous data receiver context.
\brief Initialise an asynchronous data receiver context.
\param s The receiver context.
\param data_bits The number of data bits.
\param parity_bits The type of parity.
\param stop_bits The number of stop bits.
\param use_v14 TRUE if V.14 rate adaption processing should be used.
\param put_byte The callback routine used to put the received data.
\param user_data An opaque pointer.
\return A pointer to the initialised context, or NULL if there was a problem. */
SPAN_DECLARE(async_rx_state_t *) async_rx_init(async_rx_state_t *s,
int data_bits,
int parity_bits,
int stop_bits,
int use_v14,
put_byte_func_t put_byte,
void *user_data);
SPAN_DECLARE(int) async_rx_release(async_rx_state_t *s);
SPAN_DECLARE(int) async_rx_free(async_rx_state_t *s);
/*! Accept a bit from a received serial bit stream
\brief Accept a bit from a received serial bit stream
\param user_data An opaque point which must point to a receiver context.
\param bit The new bit. Some special values are supported for this field.
- SIG_STATUS_CARRIER_UP
- SIG_STATUS_CARRIER_DOWN
- SIG_STATUS_TRAINING_SUCCEEDED
- SIG_STATUS_TRAINING_FAILED
- SIG_STATUS_END_OF_DATA */
SPAN_DECLARE_NONSTD(void) async_rx_put_bit(void *user_data, int bit);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,199 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* at_interpreter.h - AT command interpreter to V.251, V.252, V.253, T.31 and the 3GPP specs.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004, 2005, 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: at_interpreter.h,v 1.23 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_AT_INTERPRETER_H_)
#define _SPANDSP_AT_INTERPRETER_H_
/*! \page at_page AT command interpreter
\section at_page_sec_1 What does it do?
The AT interpreter module implements V.251, V.252, V.253, T.31 and various 3GPP
modem control commands.
\section at_page_sec_2 How does it work?
*/
typedef struct at_state_s at_state_t;
typedef int (at_modem_control_handler_t)(at_state_t *s, void *user_data, int op, const char *num);
typedef int (at_tx_handler_t)(at_state_t *s, void *user_data, const uint8_t *buf, size_t len);
typedef int (at_class1_handler_t)(at_state_t *s, void *user_data, int direction, int operation, int val);
enum at_rx_mode_e
{
AT_MODE_ONHOOK_COMMAND,
AT_MODE_OFFHOOK_COMMAND,
AT_MODE_CONNECTED,
AT_MODE_DELIVERY,
AT_MODE_HDLC,
AT_MODE_STUFFED
};
enum at_call_event_e
{
AT_CALL_EVENT_ALERTING = 1,
AT_CALL_EVENT_CONNECTED,
AT_CALL_EVENT_ANSWERED,
AT_CALL_EVENT_BUSY,
AT_CALL_EVENT_NO_DIALTONE,
AT_CALL_EVENT_NO_ANSWER,
AT_CALL_EVENT_HANGUP
};
enum at_modem_control_operation_e
{
/*! Start an outgoing call. */
AT_MODEM_CONTROL_CALL,
/*! Answer an incoming call. */
AT_MODEM_CONTROL_ANSWER,
/*! Hangup a call. */
AT_MODEM_CONTROL_HANGUP,
/*! Take the line off hook. */
AT_MODEM_CONTROL_OFFHOOK,
/*! Put the line on hook. */
AT_MODEM_CONTROL_ONHOOK,
/*! Control V.24 Circuit 108, "data terminal ready". */
AT_MODEM_CONTROL_DTR,
/*! Control V.24 Circuit 105, "request to send". */
AT_MODEM_CONTROL_RTS,
/*! Control V.24 Circuit 106, "clear to send". */
AT_MODEM_CONTROL_CTS,
/*! Control V.24 Circuit 109, "receive line signal detector" (i.e. carrier detect). */
AT_MODEM_CONTROL_CAR,
/*! Control V.24 Circuit 125, "ring indicator". */
AT_MODEM_CONTROL_RNG,
/*! Control V.24 Circuit 107, "data set ready". */
AT_MODEM_CONTROL_DSR,
/*! Set the caller ID for outgoing calls. */
AT_MODEM_CONTROL_SETID,
/* The remainder of the control functions should not get past the modem, to the
application. */
AT_MODEM_CONTROL_RESTART,
AT_MODEM_CONTROL_DTE_TIMEOUT
};
enum
{
AT_RESPONSE_CODE_OK = 0,
AT_RESPONSE_CODE_CONNECT,
AT_RESPONSE_CODE_RING,
AT_RESPONSE_CODE_NO_CARRIER,
AT_RESPONSE_CODE_ERROR,
AT_RESPONSE_CODE_XXX,
AT_RESPONSE_CODE_NO_DIALTONE,
AT_RESPONSE_CODE_BUSY,
AT_RESPONSE_CODE_NO_ANSWER,
AT_RESPONSE_CODE_FCERROR,
AT_RESPONSE_CODE_FRH3
};
/*!
AT profile.
*/
typedef struct
{
/*! TRUE if character echo is enabled */
int echo;
/*! TRUE if verbose reporting is enabled */
int verbose;
/*! TRUE if result codes are verbose */
int result_code_format;
/*! TRUE if pulse dialling is the default */
int pulse_dial;
/*! ??? */
int double_escape;
/*! ??? */
int adaptive_receive;
/*! The state of all possible S registers */
uint8_t s_regs[100];
} at_profile_t;
#if defined(__cplusplus)
extern "C"
{
#endif
SPAN_DECLARE(void) at_set_at_rx_mode(at_state_t *s, int new_mode);
SPAN_DECLARE(void) at_put_response(at_state_t *s, const char *t);
SPAN_DECLARE(void) at_put_numeric_response(at_state_t *s, int val);
SPAN_DECLARE(void) at_put_response_code(at_state_t *s, int code);
SPAN_DECLARE(void) at_reset_call_info(at_state_t *s);
/*! Set the call information for an AT interpreter.
\brief Set the call information for an AT interpreter.
\param s The AT interpreter context.
\param id .
\param value . */
SPAN_DECLARE(void) at_set_call_info(at_state_t *s, char const *id, char const *value);
SPAN_DECLARE(void) at_display_call_info(at_state_t *s);
SPAN_DECLARE(int) at_modem_control(at_state_t *s, int op, const char *num);
SPAN_DECLARE(void) at_call_event(at_state_t *s, int event);
SPAN_DECLARE(void) at_interpreter(at_state_t *s, const char *cmd, int len);
SPAN_DECLARE(void) at_set_class1_handler(at_state_t *s, at_class1_handler_t handler, void *user_data);
/*! Initialise an AT interpreter context.
\brief Initialise an AT interpreter context.
\param s The AT context.
\param at_tx_handler x.
\param at_tx_user_data x.
\param modem_control_handler x.
\param modem_control_user_data x.
\return A pointer to the AT context, or NULL if there was a problem. */
SPAN_DECLARE(at_state_t *) at_init(at_state_t *s,
at_tx_handler_t *at_tx_handler,
void *at_tx_user_data,
at_modem_control_handler_t *modem_control_handler,
void *modem_control_user_data);
/*! Release an AT interpreter context.
\brief Release an AT interpreter context.
\param s The AT context.
\return 0 for OK */
SPAN_DECLARE(int) at_release(at_state_t *s);
/*! Free an AT interpreter context.
\brief Free an AT interpreter context.
\param s The AT context.
\return 0 for OK */
SPAN_DECLARE(int) at_free(at_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,96 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* awgn.h - An additive Gaussian white noise generator
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: awgn.h,v 1.18 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
/* This code is based on some demonstration code in a research
paper somewhere. I can't track down where I got the original from,
so that due recognition can be given. The original had no explicit
copyright notice, and I hope nobody objects to its use here.
Having a reasonable Gaussian noise generator is pretty important for
telephony testing (in fact, pretty much any DSP testing), and this
one seems to have served me OK. Since the generation of Gaussian
noise is only for test purposes, and not a core system component,
I don't intend to worry excessively about copyright issues, unless
someone worries me.
The non-core nature of this code also explains why it is unlikely
to ever be optimised. */
#if !defined(_SPANDSP_AWGN_H_)
#define _SPANDSP_AWGN_H_
/*! \page awgn_page Additive white gaussian noise (AWGN) generation
\section awgn_page_sec_1 What does it do?
Adding noise is not the most useful thing in most DSP applications, but it is
awfully useful for test suites.
\section awgn_page_sec_2 How does it work?
This code is based on some demonstration code in a research paper somewhere. I
can't track down where I got the original from, so that due recognition can be
given. The original had no explicit copyright notice, and I hope nobody objects
to its use here.
Having a reasonable Gaussian noise generator is pretty important for telephony
testing (in fact, pretty much any DSP testing), and this one seems to have
served me OK. Since the generation of Gaussian noise is only for test purposes,
and not a core system component, I don't intend to worry excessively about
copyright issues, unless someone worries me.
The non-core nature of this code also explains why it is unlikely to ever be
optimised.
*/
/*!
AWGN generator descriptor. This contains all the state information for an AWGN generator.
*/
typedef struct awgn_state_s awgn_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
SPAN_DECLARE(awgn_state_t *) awgn_init_dbm0(awgn_state_t *s, int idum, float level);
SPAN_DECLARE(awgn_state_t *) awgn_init_dbov(awgn_state_t *s, int idum, float level);
SPAN_DECLARE(int) awgn_release(awgn_state_t *s);
SPAN_DECLARE(int) awgn_free(awgn_state_t *s);
SPAN_DECLARE(int16_t) awgn(awgn_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,275 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bell_r2_mf.h - Bell MF and MFC/R2 tone generation and detection.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bell_r2_mf.h,v 1.24 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_BELL_R2_MF_H_)
#define _SPANDSP_BELL_R2_MF_H_
/*! \page mfc_r2_tone_generation_page MFC/R2 tone generation
\section mfc_r2_tone_generation_page_sec_1 What does it do?
The MFC/R2 tone generation module provides for the generation of the
repertoire of 15 dual tones needs for the digital MFC/R2 signalling protocol.
\section mfc_r2_tone_generation_page_sec_2 How does it work?
*/
/*! \page bell_mf_tone_generation_page Bell MF tone generation
\section bell_mf_tone_generation_page_sec_1 What does it do?
The Bell MF tone generation module provides for the generation of the
repertoire of 15 dual tones needs for various Bell MF signalling protocols.
\section bell_mf_tone_generation_page_sec_2 How does it work?
Basic Bell MF tone generation specs:
- Tone on time = KP: 100+-7ms. All other signals: 68+-7ms
- Tone off time (between digits) = 68+-7ms
- Frequency tolerance +- 1.5%
- Signal level -7+-1dBm per frequency
*/
/*! \page mfc_r2_tone_rx_page MFC/R2 tone receiver
\section mfc_r2_tone_rx_page_sec_1 What does it do?
The MFC/R2 tone receiver module provides for the detection of the
repertoire of 15 dual tones needs for the digital MFC/R2 signalling protocol.
It is compliant with ITU-T Q.441D.
\section mfc_r2_tone_rx_page_sec_2 How does it work?
Basic MFC/R2 tone detection specs:
- Receiver response range: -5dBm to -35dBm
- Difference in level for a pair of frequencies
- Adjacent tones: <5dB
- Non-adjacent tones: <7dB
- Receiver not to detect a signal of 2 frequencies of level -5dB and
duration <7ms.
- Receiver not to recognise a signal of 2 frequencies having a difference
in level >=20dB.
- Max received signal frequency error: +-10Hz
- The sum of the operate and release times of a 2 frequency signal not to
exceed 80ms (there are no individual specs for the operate and release
times).
- Receiver not to release for signal interruptions <=7ms.
- System malfunction due to signal interruptions >7ms (typically 20ms) is
prevented by further logic elements.
*/
/*! \page bell_mf_tone_rx_page Bell MF tone receiver
\section bell_mf_tone_rx_page_sec_1 What does it do?
The Bell MF tone receiver module provides for the detection of the
repertoire of 15 dual tones needs for various Bell MF signalling protocols.
It is compliant with ITU-T Q.320, ITU-T Q.322, ITU-T Q.323B.
\section bell_mf_tone_rx_page_sec_2 How does it work?
Basic Bell MF tone detection specs:
- Frequency tolerance +- 1.5% +-10Hz
- Signal level -14dBm to 0dBm
- Perform a "two and only two tones present" test.
- Twist <= 6dB accepted
- Receiver sensitive to signals above -22dBm per frequency
- Test for a minimum of 55ms if KP, or 30ms of other signals.
- Signals to be recognised if the two tones arrive within 8ms of each other.
- Invalid signals result in the return of the re-order tone.
Note: Above -3dBm the signal starts to clip. We can detect with a little clipping,
but not up to 0dBm, which the above spec seems to require. There isn't a lot
we can do about that. Is the spec. incorrectly worded about the dBm0 reference
point, or have I misunderstood it?
*/
/*! The maximum number of Bell MF digits we can buffer. */
#define MAX_BELL_MF_DIGITS 128
/*!
Bell MF generator state descriptor. This defines the state of a single
working instance of a Bell MF generator.
*/
typedef struct bell_mf_tx_state_s bell_mf_tx_state_t;
/*!
Bell MF digit detector descriptor.
*/
typedef struct bell_mf_rx_state_s bell_mf_rx_state_t;
/*!
MFC/R2 tone detector descriptor.
*/
typedef struct r2_mf_tx_state_s r2_mf_tx_state_t;
/*!
MFC/R2 tone detector descriptor.
*/
typedef struct r2_mf_rx_state_s r2_mf_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Generate a buffer of Bell MF tones.
\param s The Bell MF generator context.
\param amp The buffer for the generated signal.
\param max_samples The required number of generated samples.
\return The number of samples actually generated. This may be less than
max_samples if the input buffer empties. */
SPAN_DECLARE(int) bell_mf_tx(bell_mf_tx_state_t *s, int16_t amp[], int max_samples);
/*! \brief Put a string of digits in a Bell MF generator's input buffer.
\param s The Bell MF generator context.
\param digits The string of digits to be added.
\param len The length of the string of digits. If negative, the string is
assumed to be a NULL terminated string.
\return The number of digits actually added. This may be less than the
length of the digit string, if the buffer fills up. */
SPAN_DECLARE(int) bell_mf_tx_put(bell_mf_tx_state_t *s, const char *digits, int len);
/*! \brief Initialise a Bell MF generator context.
\param s The Bell MF generator context.
\return A pointer to the Bell MF generator context.*/
SPAN_DECLARE(bell_mf_tx_state_t *) bell_mf_tx_init(bell_mf_tx_state_t *s);
/*! \brief Release a Bell MF generator context.
\param s The Bell MF generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s);
/*! \brief Free a Bell MF generator context.
\param s The Bell MF generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s);
/*! \brief Generate a block of R2 MF tones.
\param s The R2 MF generator context.
\param amp The buffer for the generated signal.
\param samples The required number of generated samples.
\return The number of samples actually generated. */
SPAN_DECLARE(int) r2_mf_tx(r2_mf_tx_state_t *s, int16_t amp[], int samples);
/*! \brief Generate a block of R2 MF tones.
\param s The R2 MF generator context.
\param digit The digit to be generated.
\return 0 for OK, or -1 for a bad request. */
SPAN_DECLARE(int) r2_mf_tx_put(r2_mf_tx_state_t *s, char digit);
/*! \brief Initialise an R2 MF tone generator context.
\param s The R2 MF generator context.
\param fwd TRUE if the context is for forward signals. FALSE if the
context is for backward signals.
\return A pointer to the MFC/R2 generator context.*/
SPAN_DECLARE(r2_mf_tx_state_t *) r2_mf_tx_init(r2_mf_tx_state_t *s, int fwd);
/*! \brief Release an R2 MF tone generator context.
\param s The R2 MF tone generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) r2_mf_tx_release(r2_mf_tx_state_t *s);
/*! \brief Free an R2 MF tone generator context.
\param s The R2 MF tone generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) r2_mf_tx_free(r2_mf_tx_state_t *s);
/*! Process a block of received Bell MF audio samples.
\brief Process a block of received Bell MF audio samples.
\param s The Bell MF receiver context.
\param amp The audio sample buffer.
\param samples The number of samples in the buffer.
\return The number of samples unprocessed. */
SPAN_DECLARE(int) bell_mf_rx(bell_mf_rx_state_t *s, const int16_t amp[], int samples);
/*! \brief Get a string of digits from a Bell MF receiver's output buffer.
\param s The Bell MF receiver context.
\param buf The buffer for the received digits.
\param max The maximum number of digits to be returned,
\return The number of digits actually returned. */
SPAN_DECLARE(size_t) bell_mf_rx_get(bell_mf_rx_state_t *s, char *buf, int max);
/*! \brief Initialise a Bell MF receiver context.
\param s The Bell MF receiver context.
\param callback An optional callback routine, used to report received digits. If
no callback routine is set, digits may be collected, using the bell_mf_rx_get()
function.
\param user_data An opaque pointer which is associated with the context,
and supplied in callbacks.
\return A pointer to the Bell MF receiver context.*/
SPAN_DECLARE(bell_mf_rx_state_t *) bell_mf_rx_init(bell_mf_rx_state_t *s,
digits_rx_callback_t callback,
void *user_data);
/*! \brief Release a Bell MF receiver context.
\param s The Bell MF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) bell_mf_rx_release(bell_mf_rx_state_t *s);
/*! \brief Free a Bell MF receiver context.
\param s The Bell MF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) bell_mf_rx_free(bell_mf_rx_state_t *s);
/*! Process a block of received R2 MF audio samples.
\brief Process a block of received R2 MF audio samples.
\param s The R2 MF receiver context.
\param amp The audio sample buffer.
\param samples The number of samples in the buffer.
\return The number of samples unprocessed. */
SPAN_DECLARE(int) r2_mf_rx(r2_mf_rx_state_t *s, const int16_t amp[], int samples);
/*! \brief Get the current digit from an R2 MF receiver.
\param s The R2 MF receiver context.
\return The number digits being received. */
SPAN_DECLARE(int) r2_mf_rx_get(r2_mf_rx_state_t *s);
/*! \brief Initialise an R2 MF receiver context.
\param s The R2 MF receiver context.
\param fwd TRUE if the context is for forward signals. FALSE if the
context is for backward signals.
\param callback An optional callback routine, used to report received digits. If
no callback routine is set, digits may be collected, using the r2_mf_rx_get()
function.
\param user_data An opaque pointer which is associated with the context,
and supplied in callbacks.
\return A pointer to the R2 MF receiver context. */
SPAN_DECLARE(r2_mf_rx_state_t *) r2_mf_rx_init(r2_mf_rx_state_t *s,
int fwd,
tone_report_func_t callback,
void *user_data);
/*! \brief Release an R2 MF receiver context.
\param s The R2 MF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) r2_mf_rx_release(r2_mf_rx_state_t *s);
/*! \brief Free an R2 MF receiver context.
\param s The R2 MF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) r2_mf_rx_free(r2_mf_rx_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,162 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bert.h - Bit error rate tests.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bert.h,v 1.23 2009/02/10 13:06:47 steveu Exp $
*/
#if !defined(_SPANDSP_BERT_H_)
#define _SPANDSP_BERT_H_
/*! \page bert_page The Bit Error Rate tester
\section bert_page_sec_1 What does it do?
The Bit Error Rate tester generates a pseudo random bit stream. It also accepts such
a pattern, synchronises to it, and checks the bit error rate in this stream.
\section bert_page_sec_2 How does it work?
The Bit Error Rate tester generates a bit stream, with a repeating 2047 bit pseudo
random pattern, using an 11 stage polynomial generator. It also accepts such a pattern,
synchronises to it, and checks the bit error rate in this stream. If the error rate is
excessive the tester assumes synchronisation has been lost, and it attempts to
resynchronise with the stream.
The bit error rate is continuously assessed against decadic ranges -
> 1 in 10^2
> 1 in 10^3
> 1 in 10^4
> 1 in 10^5
> 1 in 10^6
> 1 in 10^7
< 1 in 10^7
To ensure fairly smooth results from this assessment, each decadic level is assessed
over 10/error rate bits. That is, to assess if the signal's BER is above or below 1 in 10^5
the software looks over 10*10^5 => 10^6 bits.
*/
enum
{
BERT_REPORT_SYNCED = 0,
BERT_REPORT_UNSYNCED,
BERT_REPORT_REGULAR,
BERT_REPORT_GT_10_2,
BERT_REPORT_LT_10_2,
BERT_REPORT_LT_10_3,
BERT_REPORT_LT_10_4,
BERT_REPORT_LT_10_5,
BERT_REPORT_LT_10_6,
BERT_REPORT_LT_10_7
};
/* The QBF strings should be:
"VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )"
"ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )"
*/
enum
{
BERT_PATTERN_ZEROS = 0,
BERT_PATTERN_ONES,
BERT_PATTERN_7_TO_1,
BERT_PATTERN_3_TO_1,
BERT_PATTERN_1_TO_1,
BERT_PATTERN_1_TO_3,
BERT_PATTERN_1_TO_7,
BERT_PATTERN_QBF,
BERT_PATTERN_ITU_O151_23,
BERT_PATTERN_ITU_O151_20,
BERT_PATTERN_ITU_O151_15,
BERT_PATTERN_ITU_O152_11,
BERT_PATTERN_ITU_O153_9
};
/*!
Bit error rate tester (BERT) results descriptor. This is used to report the
results of a BER test.
*/
typedef struct
{
int total_bits;
int bad_bits;
int resyncs;
} bert_results_t;
typedef void (*bert_report_func_t)(void *user_data, int reason, bert_results_t *bert_results);
/*!
Bit error rate tester (BERT) descriptor. This defines the working state for a
single instance of the BERT.
*/
typedef struct bert_state_s bert_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Return a short description of a BERT event.
\param event The event type.
\return A pointer to a short text string describing the event. */
SPAN_DECLARE(const char *) bert_event_to_str(int event);
/*! Initialise a BERT context.
\param s The BERT context.
\param limit The maximum test duration.
\param pattern One of the supported BERT signal patterns.
\param resync_len ???
\param resync_percent The percentage of bad bits which will cause a resync.
\return The BERT context. */
SPAN_DECLARE(bert_state_t *) bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent);
SPAN_DECLARE(int) bert_release(bert_state_t *s);
SPAN_DECLARE(int) bert_free(bert_state_t *s);
/*! Get the next bit of the BERT sequence from the generator.
\param s The BERT context.
\return The bit. */
SPAN_DECLARE(int) bert_get_bit(bert_state_t *s);
/*! Put the next bit of the BERT sequence to the analyser.
\param s The BERT context.
\param bit The bit. */
SPAN_DECLARE(void) bert_put_bit(bert_state_t *s, int bit);
/*! Set the callback function for reporting the test status.
\param s The BERT context.
\param freq The required frequency of regular reports.
\param reporter The callback function.
\param user_data An opaque pointer passed to the reporter routine. */
SPAN_DECLARE(void) bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data);
/*! Get the results of the BERT.
\param s The BERT context.
\param results The results.
\return The size of the result structure. */
SPAN_DECLARE(int) bert_result(bert_state_t *s, bert_results_t *results);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,117 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* biquad.h - General telephony bi-quad section routines (currently this just
* handles canonic/type 2 form)
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: biquad.h,v 1.14 2008/04/17 14:26:59 steveu Exp $
*/
/*! \page biquad_page Bi-quadratic filter sections
\section biquad_page_sec_1 What does it do?
???.
\section biquad_page_sec_2 How does it work?
???.
*/
#if !defined(_SPANDSP_BIQUAD_H_)
#define _SPANDSP_BIQUAD_H_
typedef struct
{
int32_t gain;
int32_t a1;
int32_t a2;
int32_t b1;
int32_t b2;
int32_t z1;
int32_t z2;
#if FIRST_ORDER_NOISE_SHAPING
int32_t residue;
#elif SECOND_ORDER_NOISE_SHAPING
int32_t residue1;
int32_t residue2;
#endif
} biquad2_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void biquad2_init(biquad2_state_t *bq,
int32_t gain,
int32_t a1,
int32_t a2,
int32_t b1,
int32_t b2)
{
bq->gain = gain;
bq->a1 = a1;
bq->a2 = a2;
bq->b1 = b1;
bq->b2 = b2;
bq->z1 = 0;
bq->z2 = 0;
#if FIRST_ORDER_NOISE_SHAPING
bq->residue = 0;
#elif SECOND_ORDER_NOISE_SHAPING
bq->residue1 = 0;
bq->residue2 = 0;
#endif
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t biquad2(biquad2_state_t *bq, int16_t sample)
{
int32_t y;
int32_t z0;
z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;
bq->z2 = bq->z1;
bq->z1 = z0 >> 15;
#if FIRST_ORDER_NOISE_SHAPING
y += bq->residue;
bq->residue = y & 0x7FFF;
#elif SECOND_ORDER_NOISE_SHAPING
y += (2*bq->residue1 - bq->residue2);
bq->residue2 = bq->residue1;
bq->residue1 = y & 0x7FFF;
#endif
y >>= 15;
return (int16_t) y;
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,314 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bit_operations.h - Various bit level operations, such as bit reversal
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bit_operations.h,v 1.27 2009/07/10 13:15:56 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_BIT_OPERATIONS_H_)
#define _SPANDSP_BIT_OPERATIONS_H_
#if defined(__i386__) || defined(__x86_64__)
#if !defined(__SUNPRO_C) || (__SUNPRO_C >= 0x0590)
#define SPANDSP_USE_86_ASM
#endif
#endif
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Find the bit position of the highest set bit in a word
\param bits The word to be searched
\return The bit number of the highest set bit, or -1 if the word is zero. */
static __inline__ int top_bit(unsigned int bits)
{
#if defined(SPANDSP_USE_86_ASM)
int res;
__asm__ (" xorl %[res],%[res];\n"
" decl %[res];\n"
" bsrl %[bits],%[res]\n"
: [res] "=&r" (res)
: [bits] "rm" (bits));
return res;
#elif defined(__ppc__) || defined(__powerpc__)
int res;
__asm__ ("cntlzw %[res],%[bits];\n"
: [res] "=&r" (res)
: [bits] "r" (bits));
return 31 - res;
#elif defined(_M_IX86)
/* Visual Studio i386 */
__asm
{
xor eax, eax
dec eax
bsr eax, bits
}
#elif defined(_M_X64)
/* Visual Studio x86_64 */
/* TODO: Need the appropriate x86_64 code */
int res;
if (bits == 0)
return -1;
res = 0;
if (bits & 0xFFFF0000)
{
bits &= 0xFFFF0000;
res += 16;
}
if (bits & 0xFF00FF00)
{
bits &= 0xFF00FF00;
res += 8;
}
if (bits & 0xF0F0F0F0)
{
bits &= 0xF0F0F0F0;
res += 4;
}
if (bits & 0xCCCCCCCC)
{
bits &= 0xCCCCCCCC;
res += 2;
}
if (bits & 0xAAAAAAAA)
{
bits &= 0xAAAAAAAA;
res += 1;
}
return res;
#else
int res;
if (bits == 0)
return -1;
res = 0;
if (bits & 0xFFFF0000)
{
bits &= 0xFFFF0000;
res += 16;
}
if (bits & 0xFF00FF00)
{
bits &= 0xFF00FF00;
res += 8;
}
if (bits & 0xF0F0F0F0)
{
bits &= 0xF0F0F0F0;
res += 4;
}
if (bits & 0xCCCCCCCC)
{
bits &= 0xCCCCCCCC;
res += 2;
}
if (bits & 0xAAAAAAAA)
{
bits &= 0xAAAAAAAA;
res += 1;
}
return res;
#endif
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the bit position of the lowest set bit in a word
\param bits The word to be searched
\return The bit number of the lowest set bit, or -1 if the word is zero. */
static __inline__ int bottom_bit(unsigned int bits)
{
int res;
#if defined(SPANDSP_USE_86_ASM)
__asm__ (" xorl %[res],%[res];\n"
" decl %[res];\n"
" bsfl %[bits],%[res]\n"
: [res] "=&r" (res)
: [bits] "rm" (bits));
return res;
#else
if (bits == 0)
return -1;
res = 31;
if (bits & 0x0000FFFF)
{
bits &= 0x0000FFFF;
res -= 16;
}
if (bits & 0x00FF00FF)
{
bits &= 0x00FF00FF;
res -= 8;
}
if (bits & 0x0F0F0F0F)
{
bits &= 0x0F0F0F0F;
res -= 4;
}
if (bits & 0x33333333)
{
bits &= 0x33333333;
res -= 2;
}
if (bits & 0x55555555)
{
bits &= 0x55555555;
res -= 1;
}
return res;
#endif
}
/*- End of function --------------------------------------------------------*/
/*! \brief Bit reverse a byte.
\param data The byte to be reversed.
\return The bit reversed version of data. */
static __inline__ uint8_t bit_reverse8(uint8_t x)
{
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
/* If multiply is fast */
return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16;
#else
/* If multiply is slow, but we have a barrel shifter */
x = (x >> 4) | (x << 4);
x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
#endif
}
/*- End of function --------------------------------------------------------*/
/*! \brief Bit reverse a 16 bit word.
\param data The word to be reversed.
\return The bit reversed version of data. */
SPAN_DECLARE(uint16_t) bit_reverse16(uint16_t data);
/*! \brief Bit reverse a 32 bit word.
\param data The word to be reversed.
\return The bit reversed version of data. */
SPAN_DECLARE(uint32_t) bit_reverse32(uint32_t data);
/*! \brief Bit reverse each of the four bytes in a 32 bit word.
\param data The word to be reversed.
\return The bit reversed version of data. */
SPAN_DECLARE(uint32_t) bit_reverse_4bytes(uint32_t data);
#if defined(__x86_64__)
/*! \brief Bit reverse each of the eight bytes in a 64 bit word.
\param data The word to be reversed.
\return The bit reversed version of data. */
SPAN_DECLARE(uint64_t) bit_reverse_8bytes(uint64_t data);
#endif
/*! \brief Bit reverse each bytes in a buffer.
\param to The buffer to place the reversed data in.
\param from The buffer containing the data to be reversed.
\param len The length of the data in the buffer. */
SPAN_DECLARE(void) bit_reverse(uint8_t to[], const uint8_t from[], int len);
/*! \brief Find the number of set bits in a 32 bit word.
\param x The word to be searched.
\return The number of set bits. */
SPAN_DECLARE(int) one_bits32(uint32_t x);
/*! \brief Create a mask as wide as the number in a 32 bit word.
\param x The word to be searched.
\return The mask. */
SPAN_DECLARE(uint32_t) make_mask32(uint32_t x);
/*! \brief Create a mask as wide as the number in a 16 bit word.
\param x The word to be searched.
\return The mask. */
SPAN_DECLARE(uint16_t) make_mask16(uint16_t x);
/*! \brief Find the least significant one in a word, and return a word
with just that bit set.
\param x The word to be searched.
\return The word with the single set bit. */
static __inline__ uint32_t least_significant_one32(uint32_t x)
{
return (x & (-(int32_t) x));
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the most significant one in a word, and return a word
with just that bit set.
\param x The word to be searched.
\return The word with the single set bit. */
static __inline__ uint32_t most_significant_one32(uint32_t x)
{
#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
return 1 << top_bit(x);
#else
x = make_mask32(x);
return (x ^ (x >> 1));
#endif
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a byte.
\param x The byte to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity8(uint8_t x)
{
x = (x ^ (x >> 4)) & 0x0F;
return (0x6996 >> x) & 1;
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a 16 bit word.
\param x The word to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity16(uint16_t x)
{
x ^= (x >> 8);
x = (x ^ (x >> 4)) & 0x0F;
return (0x6996 >> x) & 1;
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the parity of a 32 bit word.
\param x The word to be checked.
\return 1 for odd, or 0 for even. */
static __inline__ int parity32(uint32_t x)
{
x ^= (x >> 16);
x ^= (x >> 8);
x = (x ^ (x >> 4)) & 0x0F;
return (0x6996 >> x) & 1;
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,81 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bitstream.h - Bitstream composition and decomposition routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bitstream.h,v 1.14.4.1 2009/12/28 12:20:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_BITSTREAM_H_)
#define _SPANDSP_BITSTREAM_H_
/*! \page bitstream_page Bitstream composition and decomposition
\section bitstream_page_sec_1 What does it do?
\section bitstream_page_sec_2 How does it work?
*/
/*! Bitstream handler state */
typedef struct bitstream_state_s bitstream_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Put a chunk of bits into the output buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream output buffer.
\param value The value to be pushed into the output buffer.
\param bits The number of bits of value to be pushed. 1 to 25 bits is valid. */
SPAN_DECLARE(void) bitstream_put(bitstream_state_t *s, uint8_t **c, uint32_t value, int bits);
/*! \brief Get a chunk of bits from the input buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream input buffer.
\param bits The number of bits of value to be grabbed. 1 to 25 bits is valid.
\return The value retrieved from the input buffer. */
SPAN_DECLARE(uint32_t) bitstream_get(bitstream_state_t *s, const uint8_t **c, int bits);
/*! \brief Flush any residual bit to the output buffer.
\param s A pointer to the bitstream context.
\param c A pointer to the bitstream output buffer. */
SPAN_DECLARE(void) bitstream_flush(bitstream_state_t *s, uint8_t **c);
/*! \brief Initialise a bitstream context.
\param s A pointer to the bitstream context.
\param lsb_first TRUE if the bit stream is LSB first, else its MSB first.
\return A pointer to the bitstream context. */
SPAN_DECLARE(bitstream_state_t *) bitstream_init(bitstream_state_t *s, int direction);
SPAN_DECLARE(int) bitstream_release(bitstream_state_t *s);
SPAN_DECLARE(int) bitstream_free(bitstream_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,507 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* complex.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex.h,v 1.20 2009/02/21 05:39:08 steveu Exp $
*/
/*! \file */
/*! \page complex_page Complex number support
\section complex_page_sec_1 What does it do?
Complex number support is part of the C99 standard. However, support for this
in C compilers is still patchy. A set of complex number feaures is provided as
a "temporary" measure, until native C language complex number support is
widespread.
*/
#if !defined(_SPANDSP_COMPLEX_H_)
#define _SPANDSP_COMPLEX_H_
/*!
Floating complex type.
*/
typedef struct
{
/*! \brief Real part. */
float re;
/*! \brief Imaginary part. */
float im;
} complexf_t;
/*!
Floating complex type.
*/
typedef struct
{
/*! \brief Real part. */
double re;
/*! \brief Imaginary part. */
double im;
} complex_t;
#if defined(HAVE_LONG_DOUBLE)
/*!
Long double complex type.
*/
typedef struct
{
/*! \brief Real part. */
long double re;
/*! \brief Imaginary part. */
long double im;
} complexl_t;
#endif
/*!
Complex integer type.
*/
typedef struct
{
/*! \brief Real part. */
int re;
/*! \brief Imaginary part. */
int im;
} complexi_t;
/*!
Complex 16 bit integer type.
*/
typedef struct
{
/*! \brief Real part. */
int16_t re;
/*! \brief Imaginary part. */
int16_t im;
} complexi16_t;
/*!
Complex 32 bit integer type.
*/
typedef struct
{
/*! \brief Real part. */
int32_t re;
/*! \brief Imaginary part. */
int32_t im;
} complexi32_t;
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ complexf_t complex_setf(float re, float im)
{
complexf_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_set(double re, double im)
{
complex_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_setl(long double re, long double im)
{
complexl_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_seti(int re, int im)
{
complexi_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_seti16(int16_t re, int16_t im)
{
complexi16_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_seti32(int32_t re, int32_t im)
{
complexi32_t z;
z.re = re;
z.im = im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexf_t complex_addf(const complexf_t *x, const complexf_t *y)
{
complexf_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_add(const complex_t *x, const complex_t *y)
{
complex_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_addl(const complexl_t *x, const complexl_t *y)
{
complexl_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_addi(const complexi_t *x, const complexi_t *y)
{
complexi_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_addi16(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_addi32(const complexi32_t *x, const complexi32_t *y)
{
complexi32_t z;
z.re = x->re + y->re;
z.im = x->im + y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexf_t complex_subf(const complexf_t *x, const complexf_t *y)
{
complexf_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_sub(const complex_t *x, const complex_t *y)
{
complex_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_subl(const complexl_t *x, const complexl_t *y)
{
complexl_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_subi(const complexi_t *x, const complexi_t *y)
{
complexi_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_subi16(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_subi32(const complexi32_t *x, const complexi32_t *y)
{
complexi32_t z;
z.re = x->re - y->re;
z.im = x->im - y->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexf_t complex_mulf(const complexf_t *x, const complexf_t *y)
{
complexf_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_mul(const complex_t *x, const complex_t *y)
{
complex_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_mull(const complexl_t *x, const complexl_t *y)
{
complexl_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_muli(const complexi_t *x, const complexi_t *y)
{
complexi_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_muli16(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = (int16_t) ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im);
z.im = (int16_t) ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re);
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_mul_q1_15(const complexi16_t *x, const complexi16_t *y)
{
complexi16_t z;
z.re = (int16_t) (((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 15);
z.im = (int16_t) (((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 15);
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_muli32i16(const complexi32_t *x, const complexi16_t *y)
{
complexi32_t z;
z.re = x->re*(int32_t) y->re - x->im*(int32_t) y->im;
z.im = x->re*(int32_t) y->im + x->im*(int32_t) y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_muli32(const complexi32_t *x, const complexi32_t *y)
{
complexi32_t z;
z.re = x->re*y->re - x->im*y->im;
z.im = x->re*y->im + x->im*y->re;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexf_t complex_divf(const complexf_t *x, const complexf_t *y)
{
complexf_t z;
float f;
f = y->re*y->re + y->im*y->im;
z.re = ( x->re*y->re + x->im*y->im)/f;
z.im = (-x->re*y->im + x->im*y->re)/f;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_div(const complex_t *x, const complex_t *y)
{
complex_t z;
double f;
f = y->re*y->re + y->im*y->im;
z.re = ( x->re*y->re + x->im*y->im)/f;
z.im = (-x->re*y->im + x->im*y->re)/f;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_divl(const complexl_t *x, const complexl_t *y)
{
complexl_t z;
long double f;
f = y->re*y->re + y->im*y->im;
z.re = ( x->re*y->re + x->im*y->im)/f;
z.im = (-x->re*y->im + x->im*y->re)/f;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexf_t complex_conjf(const complexf_t *x)
{
complexf_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complex_t complex_conj(const complex_t *x)
{
complex_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ complexl_t complex_conjl(const complexl_t *x)
{
complexl_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ complexi_t complex_conji(const complexi_t *x)
{
complexi_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi16_t complex_conji16(const complexi16_t *x)
{
complexi16_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ complexi32_t complex_conji32(const complexi32_t *x)
{
complexi32_t z;
z.re = x->re;
z.im = -x->im;
return z;
}
/*- End of function --------------------------------------------------------*/
static __inline__ float powerf(const complexf_t *x)
{
return x->re*x->re + x->im*x->im;
}
/*- End of function --------------------------------------------------------*/
static __inline__ double power(const complex_t *x)
{
return x->re*x->re + x->im*x->im;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ long double powerl(const complexl_t *x)
{
return x->re*x->re + x->im*x->im;
}
/*- End of function --------------------------------------------------------*/
#endif
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,75 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* complex_filters.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_filters.h,v 1.14 2009/02/03 16:28:41 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_FILTERS_H_)
#define _SPANDSP_COMPLEX_FILTERS_H_
typedef struct filter_s filter_t;
typedef float (*filter_step_func_t)(filter_t *fi, float x);
/*! Filter state */
typedef struct
{
int nz;
int np;
filter_step_func_t fsf;
} fspec_t;
struct filter_s
{
fspec_t *fs;
float sum;
int ptr; /* Only for moving average filters */
float v[];
};
typedef struct
{
filter_t *ref;
filter_t *imf;
} cfilter_t;
#if defined(__cplusplus)
extern "C"
{
#endif
SPAN_DECLARE(filter_t *) filter_create(fspec_t *fs);
SPAN_DECLARE(void) filter_delete(filter_t *fi);
SPAN_DECLARE(float) filter_step(filter_t *fi, float x);
SPAN_DECLARE(cfilter_t *) cfilter_create(fspec_t *fs);
SPAN_DECLARE(void) cfilter_delete(cfilter_t *cfi);
SPAN_DECLARE(complexf_t) cfilter_step(cfilter_t *cfi, const complexf_t *z);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,172 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* complex_vector_float.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_float.h,v 1.13 2009/02/04 13:18:53 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_VECTOR_FLOAT_H_)
#define _SPANDSP_COMPLEX_VECTOR_FLOAT_H_
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void cvec_copyf(complexf_t z[], const complexf_t x[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i];
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_copy(complex_t z[], const complex_t x[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i];
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ void cvec_copyl(complexl_t z[], const complexl_t x[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = x[i];
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ void cvec_zerof(complexf_t z[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = complex_setf(0.0f, 0.0f);
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zero(complex_t z[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = complex_set(0.0, 0.0);
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ void cvec_zerol(complexl_t z[], int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = complex_setl(0.0, 0.0);
}
/*- End of function --------------------------------------------------------*/
#endif
static __inline__ void cvec_setf(complexf_t z[], complexf_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_set(complex_t z[], complex_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
static __inline__ void cvec_setl(complexl_t z[], complexl_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
#endif
SPAN_DECLARE(void) cvec_mulf(complexf_t z[], const complexf_t x[], const complexf_t y[], int n);
SPAN_DECLARE(void) cvec_mul(complex_t z[], const complex_t x[], const complex_t y[], int n);
#if defined(HAVE_LONG_DOUBLE)
SPAN_DECLARE(void) cvec_mull(complexl_t z[], const complexl_t x[], const complexl_t y[], int n);
#endif
/*! \brief Find the dot product of two complex float vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexf_t) cvec_dot_prodf(const complexf_t x[], const complexf_t y[], int n);
/*! \brief Find the dot product of two complex double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
SPAN_DECLARE(complex_t) cvec_dot_prod(const complex_t x[], const complex_t y[], int n);
#if defined(HAVE_LONG_DOUBLE)
/*! \brief Find the dot product of two complex long double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexl_t) cvec_dot_prodl(const complexl_t x[], const complexl_t y[], int n);
#endif
/*! \brief Find the dot product of two complex float vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexf_t) cvec_circular_dot_prodf(const complexf_t x[], const complexf_t y[], int n, int pos);
SPAN_DECLARE(void) cvec_lmsf(const complexf_t x[], complexf_t y[], int n, const complexf_t *error);
SPAN_DECLARE(void) cvec_circular_lmsf(const complexf_t x[], complexf_t y[], int n, int pos, const complexf_t *error);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,131 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* complex_vector_int.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_int.h,v 1.4 2009/01/31 08:48:11 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_VECTOR_INT_H_)
#define _SPANDSP_COMPLEX_VECTOR_INT_H_
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void cvec_copyi(complexi_t z[], const complexi_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_copyi16(complexi16_t z[], const complexi16_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_copyi32(complexi32_t z[], const complexi32_t x[], int n)
{
memcpy(z, x, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi(complexi_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi16(complexi16_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_zeroi32(complexi32_t z[], int n)
{
memset(z, 0, n*sizeof(z[0]));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti(complexi_t z[], complexi_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti16(complexi16_t z[], complexi16_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void cvec_seti32(complexi32_t z[], complexi32_t *x, int n)
{
int i;
for (i = 0; i < n; i++)
z[i] = *x;
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the dot product of two complex int16_t vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexi32_t) cvec_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n);
/*! \brief Find the dot product of two complex int32_t vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexi32_t) cvec_dot_prodi32(const complexi32_t x[], const complexi32_t y[], int n);
/*! \brief Find the dot product of two complex int16_t vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
SPAN_DECLARE(complexi32_t) cvec_circular_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n, int pos);
SPAN_DECLARE(void) cvec_lmsi16(const complexi16_t x[], complexi16_t y[], int n, const complexi16_t *error);
SPAN_DECLARE(void) cvec_circular_lmsi16(const complexi16_t x[], complexi16_t y[], int n, int pos, const complexi16_t *error);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,98 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* crc.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: crc.h,v 1.5 2009/01/31 08:48:11 steveu Exp $
*/
/*! \file */
/*! \page crc_page CRC
\section crc_page_sec_1 What does it do?
\section crc_page_sec_2 How does it work?
*/
#if !defined(_SPANDSP_CRC_H_)
#define _SPANDSP_CRC_H_
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Calculate the ITU/CCITT CRC-32 value in buffer.
\param buf The buffer containing the data.
\param len The length of the frame.
\param crc The initial CRC value. This is usually 0xFFFFFFFF, or 0 for a new block (it depends on
the application). It is previous returned CRC value for the continuation of a block.
\return The CRC value.
*/
SPAN_DECLARE(uint32_t) crc_itu32_calc(const uint8_t *buf, int len, uint32_t crc);
/*! \brief Append an ITU/CCITT CRC-32 value to a frame.
\param buf The buffer containing the frame. This must be at least 2 bytes longer than
the frame it contains, to allow room for the CRC value.
\param len The length of the frame.
\return The new length of the frame.
*/
SPAN_DECLARE(int) crc_itu32_append(uint8_t *buf, int len);
/*! \brief Check the ITU/CCITT CRC-32 value in a frame.
\param buf The buffer containing the frame.
\param len The length of the frame.
\return TRUE if the CRC is OK, else FALSE.
*/
SPAN_DECLARE(int) crc_itu32_check(const uint8_t *buf, int len);
/*! \brief Calculate the ITU/CCITT CRC-16 value in buffer.
\param buf The buffer containing the data.
\param len The length of the frame.
\param crc The initial CRC value. This is usually 0xFFFF, or 0 for a new block (it depends on
the application). It is previous returned CRC value for the continuation of a block.
\return The CRC value.
*/
SPAN_DECLARE(uint16_t) crc_itu16_calc(const uint8_t *buf, int len, uint16_t crc);
/*! \brief Append an ITU/CCITT CRC-16 value to a frame.
\param buf The buffer containing the frame. This must be at least 2 bytes longer than
the frame it contains, to allow room for the CRC value.
\param len The length of the frame.
\return The new length of the frame.
*/
SPAN_DECLARE(int) crc_itu16_append(uint8_t *buf, int len);
/*! \brief Check the ITU/CCITT CRC-16 value in a frame.
\param buf The buffer containing the frame.
\param len The length of the frame.
\return TRUE if the CRC is OK, else FALSE.
*/
SPAN_DECLARE(int) crc_itu16_check(const uint8_t *buf, int len);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,93 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* dc_restore.h - General telephony routines to restore the zero D.C.
* level to audio which has a D.C. bias.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dc_restore.h,v 1.24 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_DC_RESTORE_H_)
#define _SPANDSP_DC_RESTORE_H_
/*! \page dc_restore_page Removing DC bias from a signal
\section dc_restore_page_sec_1 What does it do?
Telecoms signals often contain considerable DC, but DC upsets a lot of signal
processing functions. Placing a zero DC restorer at the front of the processing
chain can often simplify the downstream processing.
\section dc_restore_page_sec_2 How does it work?
The DC restorer uses a leaky integrator to provide a long-ish term estimate of
the DC bias in the signal. A 32 bit estimate is used for the 16 bit audio, so
the noise introduced by the estimation can be keep in the lower bits, and the 16
bit DC value, which is subtracted from the signal, is fairly clean. The
following code fragment shows the algorithm used. dc_bias is a 32 bit integer,
while the sample and the resulting clean_sample are 16 bit integers.
dc_bias += ((((int32_t) sample << 15) - dc_bias) >> 14);
clean_sample = sample - (dc_bias >> 15);
*/
/*!
Zero DC restoration descriptor. This defines the working state for a single
instance of DC content filter.
*/
typedef struct
{
int32_t state;
} dc_restore_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ void dc_restore_init(dc_restore_state_t *dc)
{
dc->state = 0;
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t dc_restore(dc_restore_state_t *dc, int16_t sample)
{
dc->state += ((((int32_t) sample << 15) - dc->state) >> 14);
return (int16_t) (sample - (dc->state >> 15));
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc)
{
return (int16_t) (dc->state >> 15);
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,259 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* dds.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dds.h,v 1.23 2009/01/31 08:48:11 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_DDS_H_)
#define _SPANDSP_DDS_H_
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Find the phase rate value to achieve a particular frequency.
\param frequency The desired frequency, in Hz.
\return The phase rate which while achieve the desired frequency.
*/
SPAN_DECLARE(int32_t) dds_phase_rate(float frequency);
/*! \brief Find the frequency, in Hz, equivalent to a phase rate.
\param phase_rate The phase rate.
\return The equivalent frequency, in Hz.
*/
SPAN_DECLARE(float) dds_frequency(int32_t phase_rate);
/*! \brief Find the scaling factor needed to achieve a specified level in dBm0.
\param level The desired signal level, in dBm0.
\return The scaling factor.
*/
SPAN_DECLARE(int16_t) dds_scaling_dbm0(float level);
/*! \brief Find the scaling factor needed to achieve a specified level in dBmov.
\param level The desired signal level, in dBmov.
\return The scaling factor.
*/
SPAN_DECLARE(int16_t) dds_scaling_dbov(float level);
/*! \brief Find the amplitude for a particular phase.
\param phase The desired phase 32 bit phase.
\return The signal amplitude.
*/
SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase);
/*! \brief Find the amplitude for a particular phase offset from an accumulated phase.
\param phase_acc The accumulated phase.
\param phase_offset The phase offset.
\return The signal amplitude.
*/
SPAN_DECLARE(int16_t) dds_offset(uint32_t phase_acc, int32_t phase_offset);
/*! \brief Advance the phase, without returning any new signal sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
*/
SPAN_DECLARE(void) dds_advance(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate an integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The signal amplitude, between -32767 and 32767.
*/
SPAN_DECLARE(int16_t) dds(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Lookup the integer value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The signal amplitude, between -32767 and 32767.
*/
SPAN_DECLARE(int16_t) dds_lookup(uint32_t phase);
/*! \brief Generate an integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The signal amplitude, between -32767 and 32767.
*/
SPAN_DECLARE(int16_t) dds_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase);
/*! \brief Lookup the complex integer value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi_t) dds_lookup_complexi(uint32_t phase);
/*! \brief Generate a complex integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi_t) dds_complexi(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a complex integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi_t) dds_complexi_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase);
/*! \brief Generate a complex 16 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi16_t) dds_lookup_complexi16(uint32_t phase);
/*! \brief Generate a complex 16 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi16_t) dds_complexi16(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a complex 16bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi16_t) dds_complexi16_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi32_t) dds_lookup_complexi32(uint32_t phase);
/*! \brief Generate a complex 32 bit integer tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi32_t) dds_complexi32(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a complex 32 bit integer tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-32767, -32767) and (32767, 32767).
*/
SPAN_DECLARE(complexi32_t) dds_complexi32_mod(uint32_t *phase_acc, int32_t phase_rate, int16_t scale, int32_t phase);
/*! \brief Find the phase rate equivalent to a frequency, in Hz.
\param frequency The frequency, in Hz.
\return The equivalent phase rate.
*/
SPAN_DECLARE(int32_t) dds_phase_ratef(float frequency);
/*! \brief Find the frequency, in Hz, equivalent to a phase rate.
\param phase_rate The phase rate.
\return The equivalent frequency, in Hz.
*/
SPAN_DECLARE(float) dds_frequencyf(int32_t phase_rate);
/*! \brief Find the scaling factor equivalent to a dBm0 value.
\param level The signal level in dBm0.
\return The equivalent scaling factor.
*/
SPAN_DECLARE(float) dds_scaling_dbm0f(float level);
/*! \brief Find the scaling factor equivalent to a dBmov value.
\param level The signal level in dBmov.
\return The equivalent scaling factor.
*/
SPAN_DECLARE(float) dds_scaling_dbovf(float level);
/*! \brief Advance the phase, without returning any new signal sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
*/
SPAN_DECLARE(void) dds_advancef(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Generate a floating point tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The signal amplitude, between -1.0 and 1.0.
*/
SPAN_DECLARE(float) ddsf(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Lookup the floating point value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The signal amplitude, between -1.0 and 1.0.
*/
SPAN_DECLARE(float) dds_lookupf(uint32_t phase);
/*! \brief Generate a floating point tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The signal amplitude, between -1.0 and 1.0.
*/
SPAN_DECLARE(float) dds_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase);
/*! \brief Generate a complex floating point tone sample.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0).
*/
SPAN_DECLARE(complexf_t) dds_complexf(uint32_t *phase_acc, int32_t phase_rate);
/*! \brief Lookup the complex value of a specified phase.
\param phase The phase accumulator value to be looked up.
\return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0).
*/
SPAN_DECLARE(complexf_t) dds_lookup_complexf(uint32_t phase_acc);
/*! \brief Generate a complex floating point tone sample, with modulation.
\param phase_acc A pointer to a phase accumulator value.
\param phase_rate The phase increment to be applied.
\param scale The scaling factor.
\param phase The phase offset.
\return The complex signal amplitude, between (-1.0, -1.0) and (1.0, 1.0).
*/
SPAN_DECLARE(complexf_t) dds_complex_modf(uint32_t *phase_acc, int32_t phase_rate, float scale, int32_t phase);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,218 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* dtmf.h - DTMF tone generation and detection.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001, 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dtmf.h,v 1.32 2009/02/10 13:06:47 steveu Exp $
*/
#if !defined(_SPANDSP_DTMF_H_)
#define _SPANDSP_DTMF_H_
/*! \page dtmf_rx_page DTMF receiver
\section dtmf_rx_page_sec_1 What does it do?
The DTMF receiver detects the standard DTMF digits. It is compliant with
ITU-T Q.23, ITU-T Q.24, and the local DTMF specifications of most administrations.
Its passes the test suites. It also scores *very* well on the standard
talk-off tests.
The current design uses floating point extensively. It is not tolerant of DC.
It is expected that a DC restore stage will be placed before the DTMF detector.
Unless the dial tone filter is switched on, the detector has poor tolerance
of dial tone. Whether this matter depends on your application. If you are using
the detector in an IVR application you will need proper echo cancellation to
get good performance in the presence of speech prompts, so dial tone will not
exist. If you do need good dial tone tolerance, a dial tone filter can be
enabled in the detector.
The DTMF receiver's design assumes the channel is free of any DC component.
\section dtmf_rx_page_sec_2 How does it work?
Like most other DSP based DTMF detector's, this one uses the Goertzel algorithm
to look for the DTMF tones. What makes each detector design different is just how
that algorithm is used.
Basic DTMF specs:
- Minimum tone on = 40ms
- Minimum tone off = 50ms
- Maximum digit rate = 10 per second
- Normal twist <= 8dB accepted
- Reverse twist <= 4dB accepted
- S/N >= 15dB will detect OK
- Attenuation <= 26dB will detect OK
- Frequency tolerance +- 1.5% will detect, +-3.5% will reject
TODO:
*/
/*! \page dtmf_tx_page DTMF tone generation
\section dtmf_tx_page_sec_1 What does it do?
The DTMF tone generation module provides for the generation of the
repertoire of 16 DTMF dual tones.
\section dtmf_tx_page_sec_2 How does it work?
*/
#define MAX_DTMF_DIGITS 128
typedef void (*digits_rx_callback_t)(void *user_data, const char *digits, int len);
/*!
DTMF generator state descriptor. This defines the state of a single
working instance of a DTMF generator.
*/
typedef struct dtmf_tx_state_s dtmf_tx_state_t;
/*!
DTMF digit detector descriptor.
*/
typedef struct dtmf_rx_state_s dtmf_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Generate a buffer of DTMF tones.
\param s The DTMF generator context.
\param amp The buffer for the generated signal.
\param max_samples The required number of generated samples.
\return The number of samples actually generated. This may be less than
max_samples if the input buffer empties. */
SPAN_DECLARE(int) dtmf_tx(dtmf_tx_state_t *s, int16_t amp[], int max_samples);
/*! \brief Put a string of digits in a DTMF generator's input buffer.
\param s The DTMF generator context.
\param digits The string of digits to be added.
\param len The length of the string of digits. If negative, the string is
assumed to be a NULL terminated string.
\return The number of digits actually added. This may be less than the
length of the digit string, if the buffer fills up. */
SPAN_DECLARE(int) dtmf_tx_put(dtmf_tx_state_t *s, const char *digits, int len);
/*! \brief Change the transmit level for a DTMF tone generator context.
\param s The DTMF generator context.
\param level The level of the low tone, in dBm0.
\param twist The twist, in dB. */
SPAN_DECLARE(void) dtmf_tx_set_level(dtmf_tx_state_t *s, int level, int twist);
/*! \brief Change the transmit on and off time for a DTMF tone generator context.
\param s The DTMF generator context.
\param on-time The on time, in ms.
\param off_time The off time, in ms. */
SPAN_DECLARE(void) dtmf_tx_set_timing(dtmf_tx_state_t *s, int on_time, int off_time);
/*! \brief Initialise a DTMF tone generator context.
\param s The DTMF generator context.
\return A pointer to the DTMF generator context. */
SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s);
/*! \brief Release a DTMF tone generator context.
\param s The DTMF tone generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) dtmf_tx_release(dtmf_tx_state_t *s);
/*! \brief Free a DTMF tone generator context.
\param s The DTMF tone generator context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) dtmf_tx_free(dtmf_tx_state_t *s);
/*! Set a optional realtime callback for a DTMF receiver context. This function
is called immediately a confirmed state change occurs in the received DTMF. It
is called with the ASCII value for a DTMF tone pair, or zero to indicate no tone
is being received.
\brief Set a realtime callback for a DTMF receiver context.
\param s The DTMF receiver context.
\param callback Callback routine used to report the start and end of digits.
\param user_data An opaque pointer which is associated with the context,
and supplied in callbacks. */
SPAN_DECLARE(void) dtmf_rx_set_realtime_callback(dtmf_rx_state_t *s,
tone_report_func_t callback,
void *user_data);
/*! \brief Adjust a DTMF receiver context.
\param s The DTMF receiver context.
\param filter_dialtone TRUE to enable filtering of dialtone, FALSE
to disable, < 0 to leave unchanged.
\param twist Acceptable twist, in dB. < 0 to leave unchanged.
\param reverse_twist Acceptable reverse twist, in dB. < 0 to leave unchanged.
\param threshold The minimum acceptable tone level for detection, in dBm0.
<= -99 to leave unchanged. */
SPAN_DECLARE(void) dtmf_rx_parms(dtmf_rx_state_t *s,
int filter_dialtone,
int twist,
int reverse_twist,
int threshold);
/*! Process a block of received DTMF audio samples.
\brief Process a block of received DTMF audio samples.
\param s The DTMF receiver context.
\param amp The audio sample buffer.
\param samples The number of samples in the buffer.
\return The number of samples unprocessed. */
SPAN_DECLARE(int) dtmf_rx(dtmf_rx_state_t *s, const int16_t amp[], int samples);
/*! Get the status of DTMF detection during processing of the last audio
chunk.
\brief Get the status of DTMF detection during processing of the last
audio chunk.
\param s The DTMF receiver context.
\return The current digit status. Either 'x' for a "maybe" condition, or the
digit being detected. */
SPAN_DECLARE(int) dtmf_rx_status(dtmf_rx_state_t *s);
/*! \brief Get a string of digits from a DTMF receiver's output buffer.
\param s The DTMF receiver context.
\param digits The buffer for the received digits.
\param max The maximum number of digits to be returned,
\return The number of digits actually returned. */
SPAN_DECLARE(size_t) dtmf_rx_get(dtmf_rx_state_t *s, char *digits, int max);
/*! \brief Initialise a DTMF receiver context.
\param s The DTMF receiver context.
\param callback An optional callback routine, used to report received digits. If
no callback routine is set, digits may be collected, using the dtmf_rx_get()
function.
\param user_data An opaque pointer which is associated with the context,
and supplied in callbacks.
\return A pointer to the DTMF receiver context. */
SPAN_DECLARE(dtmf_rx_state_t *) dtmf_rx_init(dtmf_rx_state_t *s,
digits_rx_callback_t callback,
void *user_data);
/*! \brief Release a DTMF receiver context.
\param s The DTMF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) dtmf_rx_release(dtmf_rx_state_t *s);
/*! \brief Free a DTMF receiver context.
\param s The DTMF receiver context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) dtmf_rx_free(dtmf_rx_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,194 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* echo.h - An echo cancellor, suitable for electrical and acoustic
* cancellation. This code does not currently comply with
* any relevant standards (e.g. G.164/5/7/8).
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: echo.h,v 1.20 2009/09/22 13:11:04 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_ECHO_H_)
#define _SPANDSP_ECHO_H_
/*! \page echo_can_page Line echo cancellation for voice
\section echo_can_page_sec_1 What does it do?
This module aims to provide G.168-2002 compliant echo cancellation, to remove
electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
\section echo_can_page_sec_2 How does it work?
The heart of the echo cancellor is FIR filter. This is adapted to match the echo
impulse response of the telephone line. It must be long enough to adequately cover
the duration of that impulse response. The signal transmitted to the telephone line
is passed through the FIR filter. Once the FIR is properly adapted, the resulting
output is an estimate of the echo signal received from the line. This is subtracted
from the received signal. The result is an estimate of the signal which originated
at the far end of the line, free from echos of our own transmitted signal.
The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was
introduced in 1960. It is the commonest form of filter adaption used in things
like modem line equalisers and line echo cancellers. There it works very well.
However, it only works well for signals of constant amplitude. It works very poorly
for things like speech echo cancellation, where the signal level varies widely.
This is quite easy to fix. If the signal level is normalised - similar to applying
AGC - LMS can work as well for a signal of varying amplitude as it does for a modem
signal. This normalised least mean squares (NLMS) algorithm is the commonest one used
for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially
the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS.
However, factors such as computational complexity and patents favour the use of NLMS.
A simple refinement to NLMS can improve its performance with speech. NLMS tends
to adapt best to the strongest parts of a signal. If the signal is white noise,
the NLMS algorithm works very well. However, speech has more low frequency than
high frequency content. Pre-whitening (i.e. filtering the signal to flatten
its spectrum) the echo signal improves the adapt rate for speech, and ensures the
final residual signal is not heavily biased towards high frequencies. A very low
complexity filter is adequate for this, so pre-whitening adds little to the
compute requirements of the echo canceller.
An FIR filter adapted using pre-whitened NLMS performs well, provided certain
conditions are met:
- The transmitted signal has poor self-correlation.
- There is no signal being generated within the environment being cancelled.
The difficulty is that neither of these can be guaranteed.
If the adaption is performed while transmitting noise (or something fairly noise
like, such as voice) the adaption works very well. If the adaption is performed
while transmitting something highly correlative (typically narrow band energy
such as signalling tones or DTMF), the adaption can go seriously wrong. The reason
is there is only one solution for the adaption on a near random signal - the impulse
response of the line. For a repetitive signal, there are any number of solutions
which converge the adaption, and nothing guides the adaption to choose the generalised
one. Allowing an untrained canceller to converge on this kind of narrowband
energy probably a good thing, since at least it cancels the tones. Allowing a well
converged canceller to continue converging on such energy is just a way to ruin
its generalised adaption. A narrowband detector is needed, so adapation can be
suspended at appropriate times.
The adaption process is based on trying to eliminate the received signal. When
there is any signal from within the environment being cancelled it may upset the
adaption process. Similarly, if the signal we are transmitting is small, noise
may dominate and disturb the adaption process. If we can ensure that the
adaption is only performed when we are transmitting a significant signal level,
and the environment is not, things will be OK. Clearly, it is easy to tell when
we are sending a significant signal. Telling, if the environment is generating a
significant signal, and doing it with sufficient speed that the adaption will
not have diverged too much more we stop it, is a little harder.
The key problem in detecting when the environment is sourcing significant energy
is that we must do this very quickly. Given a reasonably long sample of the
received signal, there are a number of strategies which may be used to assess
whether that signal contains a strong far end component. However, by the time
that assessment is complete the far end signal will have already caused major
mis-convergence in the adaption process. An assessment algorithm is needed which
produces a fairly accurate result from a very short burst of far end energy.
\section echo_can_page_sec_3 How do I use it?
The echo cancellor processes both the transmit and receive streams sample by
sample. The processing function is not declared inline. Unfortunately,
cancellation requires many operations per sample, so the call overhead is only a
minor burden.
*/
#include "fir.h"
/* Mask bits for the adaption mode */
enum
{
ECHO_CAN_USE_ADAPTION = 0x01,
ECHO_CAN_USE_NLP = 0x02,
ECHO_CAN_USE_CNG = 0x04,
ECHO_CAN_USE_CLIP = 0x08,
ECHO_CAN_USE_SUPPRESSOR = 0x10,
ECHO_CAN_USE_TX_HPF = 0x20,
ECHO_CAN_USE_RX_HPF = 0x40,
ECHO_CAN_DISABLE = 0x80
};
/*!
G.168 echo canceller descriptor. This defines the working state for a line
echo canceller.
*/
typedef struct echo_can_state_s echo_can_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Create a voice echo canceller context.
\param len The length of the canceller, in samples.
\return The new canceller context, or NULL if the canceller could not be created.
*/
SPAN_DECLARE(echo_can_state_t *) echo_can_init(int len, int adaption_mode);
/*! Release a voice echo canceller context.
\param ec The echo canceller context.
\return 0 for OK, else -1.
*/
SPAN_DECLARE(int) echo_can_release(echo_can_state_t *ec);
/*! Free a voice echo canceller context.
\param ec The echo canceller context.
\return 0 for OK, else -1.
*/
SPAN_DECLARE(int) echo_can_free(echo_can_state_t *ec);
/*! Flush (reinitialise) a voice echo canceller context.
\param ec The echo canceller context.
*/
SPAN_DECLARE(void) echo_can_flush(echo_can_state_t *ec);
/*! Set the adaption mode of a voice echo canceller context.
\param ec The echo canceller context.
\param adaption_mode The mode.
*/
SPAN_DECLARE(void) echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode);
/*! Process a sample through a voice echo canceller.
\param ec The echo canceller context.
\param tx The transmitted audio sample.
\param rx The received audio sample.
\return The clean (echo cancelled) received sample.
*/
SPAN_DECLARE(int16_t) echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx);
/*! Process to high pass filter the tx signal.
\param ec The echo canceller context.
\param tx The transmitted auio sample.
\return The HP filtered transmit sample, send this to your D/A.
*/
SPAN_DECLARE(int16_t) echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx);
SPAN_DECLARE(void) echo_can_snapshot(echo_can_state_t *ec);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,90 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* expose.h - Expose the internal structures of spandsp, for users who
* really need that.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2008 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: expose.h,v 1.14.4.1 2009/12/19 09:47:56 steveu Exp $
*/
/*! \file */
/* TRY TO ONLY INCLUDE THIS IF YOU REALLY REALLY HAVE TO */
#if !defined(_SPANDSP_EXPOSE_H_)
#define _SPANDSP_EXPOSE_H_
#include <spandsp/private/logging.h>
#include <spandsp/private/schedule.h>
#include <spandsp/private/bitstream.h>
#include <spandsp/private/queue.h>
#include <spandsp/private/awgn.h>
#include <spandsp/private/noise.h>
#include <spandsp/private/bert.h>
#include <spandsp/private/tone_generate.h>
#include <spandsp/private/bell_r2_mf.h>
#include <spandsp/private/sig_tone.h>
#include <spandsp/private/dtmf.h>
#include <spandsp/private/g711.h>
#include <spandsp/private/g722.h>
#include <spandsp/private/g726.h>
#include <spandsp/private/lpc10.h>
#include <spandsp/private/gsm0610.h>
#include <spandsp/private/oki_adpcm.h>
#include <spandsp/private/ima_adpcm.h>
#include <spandsp/private/hdlc.h>
#include <spandsp/private/time_scale.h>
#include <spandsp/private/super_tone_tx.h>
#include <spandsp/private/super_tone_rx.h>
#include <spandsp/private/silence_gen.h>
#include <spandsp/private/swept_tone.h>
#include <spandsp/private/echo.h>
#include <spandsp/private/modem_echo.h>
#include <spandsp/private/async.h>
#include <spandsp/private/fsk.h>
#include <spandsp/private/v29rx.h>
#include <spandsp/private/v29tx.h>
#include <spandsp/private/v17rx.h>
#include <spandsp/private/v17tx.h>
#include <spandsp/private/v22bis.h>
#include <spandsp/private/v27ter_rx.h>
#include <spandsp/private/v27ter_tx.h>
#include <spandsp/private/modem_connect_tones.h>
#include <spandsp/private/at_interpreter.h>
#include <spandsp/private/fax_modems.h>
#include <spandsp/private/t4_rx.h>
#include <spandsp/private/t4_tx.h>
#include <spandsp/private/t30.h>
#include <spandsp/private/fax.h>
#include <spandsp/private/t38_core.h>
#include <spandsp/private/t38_non_ecm_buffer.h>
#include <spandsp/private/t38_gateway.h>
#include <spandsp/private/t38_terminal.h>
#include <spandsp/private/t31.h>
#include <spandsp/private/v8.h>
#include <spandsp/private/v18.h>
#include <spandsp/private/v42.h>
#include <spandsp/private/v42bis.h>
#include <spandsp/private/adsi.h>
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,438 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fast_convert.h - Quick ways to convert floating point numbers to integers
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2009 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fast_convert.h,v 1.9 2009/10/03 04:37:25 steveu Exp $
*/
#if !defined(_SPANDSP_FAST_CONVERT_H_)
#define _SPANDSP_FAST_CONVERT_H_
#if defined(__cplusplus)
extern "C"
{
#endif
/* The following code, to handle issues with lrint() and lrintf() on various
* platforms, is adapted from similar code in libsndfile, which is:
*
* Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
/*
* On Intel Pentium processors (especially PIII and probably P4), converting
* from float to int is very slow. To meet the C specs, the code produced by
* most C compilers targeting Pentium needs to change the FPU rounding mode
* before the float to int conversion is performed.
*
* Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
* is this flushing of the pipeline which is so slow.
*
* Fortunately the ISO C99 specification defines the functions lrint, lrintf,
* llrint and llrintf which fix this problem as a side effect.
*
* On Unix-like systems, the configure process should have detected the
* presence of these functions. If they weren't found we have to replace them
* here with a standard C cast.
*/
/*
* The C99 prototypes for these functions are as follows:
*
* int rintf(float x);
* int rint(double x);
* long int lrintf(float x);
* long int lrint(double x);
* long long int llrintf(float x);
* long long int llrint(double x);
*
* The presence of the required functions are detected during the configure
* process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
* the config file.
*/
#if defined(__CYGWIN__)
#if !defined(__cplusplus)
/*
* CYGWIN has lrint and lrintf functions, but they are slow and buggy:
* http://sourceware.org/ml/cygwin/2005-06/msg00153.html
* http://sourceware.org/ml/cygwin/2005-09/msg00047.html
* The latest version of cygwin seems to have made no effort to fix this.
* These replacement functions (pulled from the Public Domain MinGW
* math.h header) replace the native versions.
*/
static __inline__ long int lrint(double x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
static __inline__ long int lrintf(float x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
#endif
/* The fastest way to convert is the equivalent of lrint() */
static __inline__ long int lfastrint(double x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
static __inline__ long int lfastrintf(float x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
#elif defined(__GNUC__) || (__SUNPRO_C >= 0x0590)
#if defined(__i386__)
/* These routines are guaranteed fast on an i386 machine. Using the built in
lrint() and lrintf() should be similar, but they may not always be enabled.
Sometimes, especially with "-O0", you might get slow calls to routines. */
static __inline__ long int lfastrint(double x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
static __inline__ long int lfastrintf(float x)
{
long int retval;
__asm__ __volatile__
(
"fistpl %0"
: "=m" (retval)
: "t" (x)
: "st"
);
return retval;
}
#elif defined(__x86_64__)
/* On an x86_64 machine, the fastest thing seems to be a pure assignment from a
double or float to an int. It looks like the design on the x86_64 took account
of the default behaviour specified for C. */
static __inline__ long int lfastrint(double x)
{
return (long int) (x);
}
static __inline__ long int lfastrintf(float x)
{
return (long int) (x);
}
#elif defined(__ppc__) || defined(__powerpc__)
static __inline__ long int lfastrint(register double x)
{
int res[2];
__asm__ __volatile__
(
"fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (x) /* Input */
: "memory"
);
return res[1];
}
static __inline__ long int lfastrintf(register float x)
{
int res[2];
__asm__ __volatile__
(
"fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (x) /* Input */
: "memory"
);
return res[1];
}
#else
/* Fallback routines, for unrecognised platforms */
static __inline__ long int lfastrint(double x)
{
return (long int) x;
}
static __inline__ long int lfastrintf(float x)
{
return (long int) x;
}
#endif
#elif defined(_M_IX86)
/* Visual Studio i386 */
/*
* Win32 doesn't seem to have the lrint() and lrintf() functions.
* Therefore implement inline versions of these functions here.
*/
__inline long int lrint(double x)
{
long int i;
_asm
{
fld x
fistp i
};
return i;
}
__inline long int lrintf(float x)
{
long int i;
_asm
{
fld x
fistp i
};
return i;
}
__inline float rintf(float flt)
{
_asm
{ fld flt
frndint
}
}
__inline double rint(double dbl)
{
_asm
{
fld dbl
frndint
}
}
__inline long int lfastrint(double x)
{
long int i;
_asm
{
fld x
fistp i
};
return i;
}
__inline long int lfastrintf(float x)
{
long int i;
_asm
{
fld x
fistp i
};
return i;
}
#elif defined(_M_X64)
/* Visual Studio x86_64 */
/* x86_64 machines will do best with a simple assignment. */
#include <intrin.h>
__inline long int lrint(double x)
{
return (long int)_mm_cvtsd_si64x( _mm_loadu_pd ((const double*)&x) );
}
__inline long int lrintf(float x)
{
return _mm_cvt_ss2si( _mm_load_ss((const float*)&x) );
}
__inline long int lfastrint(double x)
{
return (long int) (x);
}
__inline long int lfastrintf(float x)
{
return (long int) (x);
}
#elif defined(__MWERKS__) && defined(macintosh)
/* This MacOS 9 solution was provided by Stephane Letz */
long int __inline__ lfastrint(register double x)
{
long int res[2];
asm
{
fctiw x, x
stfd x, res
}
return res[1];
}
long int __inline__ lfastrintf(register float x)
{
long int res[2];
asm
{
fctiw x, x
stfd x, res
}
return res[1];
}
#elif defined(__MACH__) && defined(__APPLE__) && (defined(__ppc__) || defined(__powerpc__))
/* For Apple Mac OS/X - do recent versions still need this? */
static __inline__ long int lfastrint(register double x)
{
int res[2];
__asm__ __volatile__
(
"fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (x) /* Input */
: "memory"
);
return res[1];
}
static __inline__ long int lfastrintf(register float x)
{
int res[2];
__asm__ __volatile__
(
"fctiw %1, %1\n\t"
"stfd %1, %0"
: "=m" (res) /* Output */
: "f" (x) /* Input */
: "memory"
);
return res[1];
}
#else
/* There is nothing else to do, but use a simple casting operation, instead of a real
rint() type function. Since we are only trying to use rint() to speed up conversions,
the accuracy issues related to changing the rounding scheme are of little concern
to us. */
#if !defined(__sgi) && !defined(__sunos) && !defined(__solaris) && !defined(__sun)
#warning "No usable lrint() and lrintf() functions available."
#warning "Replacing these functions with a simple C cast."
#endif
static __inline__ long int lrint(double x)
{
return (long int) (x);
}
static __inline__ long int lrintf(float x)
{
return (long int) (x);
}
static __inline__ long int lfastrint(double x)
{
return (long int) (x);
}
static __inline__ long int lfastrintf(float x)
{
return (long int) (x);
}
#endif
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,133 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fax.h - definitions for analogue line ITU T.30 fax processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax.h,v 1.39 2009/03/13 12:59:26 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_FAX_H_)
#define _SPANDSP_FAX_H_
/*! \page fax_page FAX over analogue modem handling
\section fax_page_sec_1 What does it do?
\section fax_page_sec_2 How does it work?
*/
typedef struct fax_state_s fax_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Apply T.30 receive processing to a block of audio samples.
\brief Apply T.30 receive processing to a block of audio samples.
\param s The FAX context.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. This should only be non-zero if
the software has reached the end of the FAX call.
*/
SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
/*! Apply fake T.30 receive processing when a block of audio samples is missing (e.g due
to packet loss).
\brief Apply fake T.30 receive processing.
\param s The FAX context.
\param len The number of samples to fake.
\return The number of samples unprocessed. This should only be non-zero if
the software has reached the end of the FAX call.
*/
SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len);
/*! Apply T.30 transmit processing to generate a block of audio samples.
\brief Apply T.30 transmit processing to generate a block of audio samples.
\param s The FAX context.
\param amp The audio sample buffer.
\param max_len The number of samples to be generated.
\return The number of samples actually generated. This will be zero when
there is nothing to send.
*/
SPAN_DECLARE(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len);
/*! Select whether silent audio will be sent when FAX transmit is idle.
\brief Select whether silent audio will be sent when FAX transmit is idle.
\param s The FAX context.
\param transmit_on_idle TRUE if silent audio should be output when the FAX transmitter is
idle. FALSE to transmit zero length audio when the FAX transmitter is idle. The default
behaviour is FALSE.
*/
SPAN_DECLARE(void) fax_set_transmit_on_idle(fax_state_t *s, int transmit_on_idle);
/*! Select whether talker echo protection tone will be sent for the image modems.
\brief Select whether TEP will be sent for the image modems.
\param s The FAX context.
\param use_tep TRUE if TEP should be sent.
*/
SPAN_DECLARE(void) fax_set_tep_mode(fax_state_t *s, int use_tep);
/*! Get a pointer to the T.30 engine associated with a FAX context.
\brief Get a pointer to the T.30 engine associated with a FAX context.
\param s The FAX context.
\return A pointer to the T.30 context, or NULL.
*/
SPAN_DECLARE(t30_state_t *) fax_get_t30_state(fax_state_t *s);
/*! Get a pointer to the logging context associated with a FAX context.
\brief Get a pointer to the logging context associated with a FAX context.
\param s The FAX context.
\return A pointer to the logging context, or NULL.
*/
SPAN_DECLARE(logging_state_t *) fax_get_logging_state(fax_state_t *s);
/*! Initialise a FAX context.
\brief Initialise a FAX context.
\param s The FAX context.
\param calling_party TRUE if the context is for a calling party. FALSE if the
context is for an answering party.
\return A pointer to the FAX context, or NULL if there was a problem.
*/
SPAN_DECLARE(fax_state_t *) fax_init(fax_state_t *s, int calling_party);
/*! Release a FAX context.
\brief Release a FAX context.
\param s The FAX context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) fax_release(fax_state_t *s);
/*! Free a FAX context.
\brief Free a FAX context.
\param s The FAX context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) fax_free(fax_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,91 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fax_modems.h - definitions for the analogue modem set for fax processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2008 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_modems.h,v 1.11 2009/04/26 12:55:23 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_FAX_MODEMS_H_)
#define _SPANDSP_FAX_MODEMS_H_
enum
{
FAX_MODEM_NONE = -1,
FAX_MODEM_FLUSH = 0,
FAX_MODEM_SILENCE_TX,
FAX_MODEM_SILENCE_RX,
FAX_MODEM_CED_TONE,
FAX_MODEM_CNG_TONE,
FAX_MODEM_NOCNG_TONE,
FAX_MODEM_V21_TX,
FAX_MODEM_V17_TX,
FAX_MODEM_V27TER_TX,
FAX_MODEM_V29_TX,
FAX_MODEM_V21_RX,
FAX_MODEM_V17_RX,
FAX_MODEM_V27TER_RX,
FAX_MODEM_V29_RX
};
/*!
The set of modems needed for FAX, plus the auxilliary stuff, like tone generation.
*/
typedef struct fax_modems_state_s fax_modems_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/* N.B. the following are currently a work in progress */
SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len);
SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len);
SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len);
SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
SPAN_DECLARE(void) fax_modems_start_rx_modem(fax_modems_state_t *s, int which);
SPAN_DECLARE(void) fax_modems_set_tep_mode(fax_modems_state_t *s, int use_tep);
SPAN_DECLARE(fax_modems_state_t *) fax_modems_init(fax_modems_state_t *s,
int use_tep,
hdlc_frame_handler_t hdlc_accept,
hdlc_underflow_handler_t hdlc_tx_underflow,
put_bit_func_t non_ecm_put_bit,
get_bit_func_t non_ecm_get_bit,
tone_report_func_t tone_callback,
void *user_data);
SPAN_DECLARE(int) fax_modems_release(fax_modems_state_t *s);
SPAN_DECLARE(int) fax_modems_free(fax_modems_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,304 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fir.h - General telephony FIR routines
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2002 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fir.h,v 1.13 2008/04/17 14:27:00 steveu Exp $
*/
/*! \page fir_page FIR filtering
\section fir_page_sec_1 What does it do?
???.
\section fir_page_sec_2 How does it work?
???.
*/
#if !defined(_SPANDSP_FIR_H_)
#define _SPANDSP_FIR_H_
#if defined(USE_MMX) || defined(USE_SSE2)
#include "mmx.h"
#endif
/*!
16 bit integer FIR descriptor. This defines the working state for a single
instance of an FIR filter using 16 bit integer coefficients.
*/
typedef struct
{
int taps;
int curr_pos;
const int16_t *coeffs;
int16_t *history;
} fir16_state_t;
/*!
32 bit integer FIR descriptor. This defines the working state for a single
instance of an FIR filter using 32 bit integer coefficients, and filtering
16 bit integer data.
*/
typedef struct
{
int taps;
int curr_pos;
const int32_t *coeffs;
int16_t *history;
} fir32_state_t;
/*!
Floating point FIR descriptor. This defines the working state for a single
instance of an FIR filter using floating point coefficients and data.
*/
typedef struct
{
int taps;
int curr_pos;
const float *coeffs;
float *history;
} fir_float_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
static __inline__ const int16_t *fir16_create(fir16_state_t *fir,
const int16_t *coeffs,
int taps)
{
fir->taps = taps;
fir->curr_pos = taps - 1;
fir->coeffs = coeffs;
#if defined(USE_MMX) || defined(USE_SSE2)
if ((fir->history = malloc(2*taps*sizeof(int16_t))))
memset(fir->history, 0, 2*taps*sizeof(int16_t));
#else
if ((fir->history = (int16_t *) malloc(taps*sizeof(int16_t))))
memset(fir->history, 0, taps*sizeof(int16_t));
#endif
return fir->history;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void fir16_flush(fir16_state_t *fir)
{
#if defined(USE_MMX) || defined(USE_SSE2)
memset(fir->history, 0, 2*fir->taps*sizeof(int16_t));
#else
memset(fir->history, 0, fir->taps*sizeof(int16_t));
#endif
}
/*- End of function --------------------------------------------------------*/
static __inline__ void fir16_free(fir16_state_t *fir)
{
free(fir->history);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample)
{
int i;
int32_t y;
#if defined(USE_MMX)
mmx_t *mmx_coeffs;
mmx_t *mmx_hist;
fir->history[fir->curr_pos] = sample;
fir->history[fir->curr_pos + fir->taps] = sample;
mmx_coeffs = (mmx_t *) fir->coeffs;
mmx_hist = (mmx_t *) &fir->history[fir->curr_pos];
i = fir->taps;
pxor_r2r(mm4, mm4);
/* 8 samples per iteration, so the filter must be a multiple of 8 long. */
while (i > 0)
{
movq_m2r(mmx_coeffs[0], mm0);
movq_m2r(mmx_coeffs[1], mm2);
movq_m2r(mmx_hist[0], mm1);
movq_m2r(mmx_hist[1], mm3);
mmx_coeffs += 2;
mmx_hist += 2;
pmaddwd_r2r(mm1, mm0);
pmaddwd_r2r(mm3, mm2);
paddd_r2r(mm0, mm4);
paddd_r2r(mm2, mm4);
i -= 8;
}
movq_r2r(mm4, mm0);
psrlq_i2r(32, mm0);
paddd_r2r(mm0, mm4);
movd_r2m(mm4, y);
emms();
#elif defined(USE_SSE2)
xmm_t *xmm_coeffs;
xmm_t *xmm_hist;
fir->history[fir->curr_pos] = sample;
fir->history[fir->curr_pos + fir->taps] = sample;
xmm_coeffs = (xmm_t *) fir->coeffs;
xmm_hist = (xmm_t *) &fir->history[fir->curr_pos];
i = fir->taps;
pxor_r2r(xmm4, xmm4);
/* 16 samples per iteration, so the filter must be a multiple of 16 long. */
while (i > 0)
{
movdqu_m2r(xmm_coeffs[0], xmm0);
movdqu_m2r(xmm_coeffs[1], xmm2);
movdqu_m2r(xmm_hist[0], xmm1);
movdqu_m2r(xmm_hist[1], xmm3);
xmm_coeffs += 2;
xmm_hist += 2;
pmaddwd_r2r(xmm1, xmm0);
pmaddwd_r2r(xmm3, xmm2);
paddd_r2r(xmm0, xmm4);
paddd_r2r(xmm2, xmm4);
i -= 16;
}
movdqa_r2r(xmm4, xmm0);
psrldq_i2r(8, xmm0);
paddd_r2r(xmm0, xmm4);
movdqa_r2r(xmm4, xmm0);
psrldq_i2r(4, xmm0);
paddd_r2r(xmm0, xmm4);
movd_r2m(xmm4, y);
#else
int offset1;
int offset2;
fir->history[fir->curr_pos] = sample;
offset2 = fir->curr_pos;
offset1 = fir->taps - offset2;
y = 0;
for (i = fir->taps - 1; i >= offset1; i--)
y += fir->coeffs[i]*fir->history[i - offset1];
for ( ; i >= 0; i--)
y += fir->coeffs[i]*fir->history[i + offset2];
#endif
if (fir->curr_pos <= 0)
fir->curr_pos = fir->taps;
fir->curr_pos--;
return (int16_t) (y >> 15);
}
/*- End of function --------------------------------------------------------*/
static __inline__ const int16_t *fir32_create(fir32_state_t *fir,
const int32_t *coeffs,
int taps)
{
fir->taps = taps;
fir->curr_pos = taps - 1;
fir->coeffs = coeffs;
fir->history = (int16_t *) malloc(taps*sizeof(int16_t));
if (fir->history)
memset(fir->history, '\0', taps*sizeof(int16_t));
return fir->history;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void fir32_flush(fir32_state_t *fir)
{
memset(fir->history, 0, fir->taps*sizeof(int16_t));
}
/*- End of function --------------------------------------------------------*/
static __inline__ void fir32_free(fir32_state_t *fir)
{
free(fir->history);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample)
{
int i;
int32_t y;
int offset1;
int offset2;
fir->history[fir->curr_pos] = sample;
offset2 = fir->curr_pos;
offset1 = fir->taps - offset2;
y = 0;
for (i = fir->taps - 1; i >= offset1; i--)
y += fir->coeffs[i]*fir->history[i - offset1];
for ( ; i >= 0; i--)
y += fir->coeffs[i]*fir->history[i + offset2];
if (fir->curr_pos <= 0)
fir->curr_pos = fir->taps;
fir->curr_pos--;
return (int16_t) (y >> 15);
}
/*- End of function --------------------------------------------------------*/
static __inline__ const float *fir_float_create(fir_float_state_t *fir,
const float *coeffs,
int taps)
{
fir->taps = taps;
fir->curr_pos = taps - 1;
fir->coeffs = coeffs;
fir->history = (float *) malloc(taps*sizeof(float));
if (fir->history)
memset(fir->history, '\0', taps*sizeof(float));
return fir->history;
}
/*- End of function --------------------------------------------------------*/
static __inline__ void fir_float_free(fir_float_state_t *fir)
{
free(fir->history);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample)
{
int i;
float y;
int offset1;
int offset2;
fir->history[fir->curr_pos] = sample;
offset2 = fir->curr_pos;
offset1 = fir->taps - offset2;
y = 0;
for (i = fir->taps - 1; i >= offset1; i--)
y += fir->coeffs[i]*fir->history[i - offset1];
for ( ; i >= 0; i--)
y += fir->coeffs[i]*fir->history[i + offset2];
if (fir->curr_pos <= 0)
fir->curr_pos = fir->taps;
fir->curr_pos--;
return (int16_t) y;
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,255 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* fsk.h - FSK modem transmit and receive parts
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.h,v 1.41 2009/11/02 13:25:20 steveu Exp $
*/
/*! \file */
/*! \page fsk_page FSK modems
\section fsk_page_sec_1 What does it do?
Most of the oldest telephony modems use incoherent FSK modulation. This module can
be used to implement both the transmit and receive sides of a number of these
modems. There are integrated definitions for:
- V.21
- V.23
- Bell 103
- Bell 202
- Weitbrecht (Used for TDD - Telecoms Device for the Deaf)
The audio output or input is a stream of 16 bit samples, at 8000 samples/second.
The transmit and receive sides can be used independantly.
\section fsk_page_sec_2 The transmitter
The FSK transmitter uses a DDS generator to synthesise the waveform. This
naturally produces phase coherent transitions, as the phase update rate is
switched, producing a clean spectrum. The symbols are not generally an integer
number of samples long. However, the symbol time for the fastest data rate
generally used (1200bps) is more than 7 samples long. The jitter resulting from
switching at the nearest sample is, therefore, acceptable. No interpolation is
used.
\section fsk_page_sec_3 The receiver
The FSK receiver uses a quadrature correlation technique to demodulate the
signal. Two DDS quadrature oscillators are used. The incoming signal is
correlated with the oscillator signals over a period of one symbol. The
oscillator giving the highest net correlation from its I and Q outputs is the
one that matches the frequency being transmitted during the correlation
interval. Because the transmission is totally asynchronous, the demodulation
process must run sample by sample to find the symbol transitions. The
correlation is performed on a sliding window basis, so the computational load of
demodulating sample by sample is not great.
Two modes of symbol synchronisation are provided:
- In synchronous mode, symbol transitions are smoothed, to track their true
position in the prescence of high timing jitter. This provides the most
reliable symbol recovery in poor signal to noise conditions. However, it
takes a little time to settle, so it not really suitable for data streams
which must start up instantaneously (e.g. the TDD systems used by hearing
impaired people).
- In asynchronous mode each transition is taken at face value, with no temporal
smoothing. There is no settling time for this mode, but when the signal to
noise ratio is very poor it does not perform as well as the synchronous mode.
*/
#if !defined(_SPANDSP_FSK_H_)
#define _SPANDSP_FSK_H_
/*!
FSK modem specification. This defines the frequencies, signal levels and
baud rate (== bit rate for simple FSK) for a single channel of an FSK modem.
*/
typedef struct
{
/*! Short text name for the modem. */
const char *name;
/*! The frequency of the zero bit state, in Hz */
int freq_zero;
/*! The frequency of the one bit state, in Hz */
int freq_one;
/*! The transmit power level, in dBm0 */
int tx_level;
/*! The minimum acceptable receive power level, in dBm0 */
int min_level;
/*! The bit rate of the modem, in units of 1/100th bps */
int baud_rate;
} fsk_spec_t;
/* Predefined FSK modem channels */
enum
{
FSK_V21CH1 = 0,
FSK_V21CH2,
FSK_V23CH1,
FSK_V23CH2,
FSK_BELL103CH1,
FSK_BELL103CH2,
FSK_BELL202,
FSK_WEITBRECHT, /* 45.45 baud version, used for TDD (Telecom Device for the Deaf) */
FSK_WEITBRECHT50 /* 50 baud version, used for TDD (Telecom Device for the Deaf) */
};
enum
{
FSK_FRAME_MODE_ASYNC = 0,
FSK_FRAME_MODE_SYNC = 1,
FSK_FRAME_MODE_5N1_FRAMES = 7, /* 5 bits of data + start bit + stop bit */
FSK_FRAME_MODE_7N1_FRAMES = 9, /* 7 bits of data + start bit + stop bit */
FSK_FRAME_MODE_8N1_FRAMES = 10 /* 8 bits of data + start bit + stop bit */
};
SPAN_DECLARE_DATA extern const fsk_spec_t preset_fsk_specs[];
/*!
FSK modem transmit descriptor. This defines the state of a single working
instance of an FSK modem transmitter.
*/
typedef struct fsk_tx_state_s fsk_tx_state_t;
/* The longest window will probably be 106 for 75 baud */
#define FSK_MAX_WINDOW_LEN 128
/*!
FSK modem receive descriptor. This defines the state of a single working
instance of an FSK modem receiver.
*/
typedef struct fsk_rx_state_s fsk_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an FSK modem transmit context.
\brief Initialise an FSK modem transmit context.
\param s The modem context.
\param spec The specification of the modem tones and rate.
\param get_bit The callback routine used to get the data to be transmitted.
\param user_data An opaque pointer.
\return A pointer to the modem context, or NULL if there was a problem. */
SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s,
const fsk_spec_t *spec,
get_bit_func_t get_bit,
void *user_data);
SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec);
SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s);
SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s);
/*! Adjust an FSK modem transmit context's power output.
\brief Adjust an FSK modem transmit context's power output.
\param s The modem context.
\param power The power level, in dBm0 */
SPAN_DECLARE(void) fsk_tx_power(fsk_tx_state_t *s, float power);
SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data);
/*! Change the modem status report function associated with an FSK modem transmit context.
\brief Change the modem status report function associated with an FSK modem transmit context.
\param s The modem context.
\param handler The callback routine used to report modem status changes.
\param user_data An opaque pointer. */
SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data);
/*! Generate a block of FSK modem audio samples.
\brief Generate a block of FSK modem audio samples.
\param s The modem context.
\param amp The audio sample buffer.
\param len The number of samples to be generated.
\return The number of samples actually generated.
*/
SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len);
/*! Get the current received signal power.
\param s The modem context.
\return The signal power, in dBm0. */
SPAN_DECLARE(float) fsk_rx_signal_power(fsk_rx_state_t *s);
/*! Adjust an FSK modem receive context's carrier detect power threshold.
\brief Adjust an FSK modem receive context's carrier detect power threshold.
\param s The modem context.
\param cutoff The power level, in dBm0 */
SPAN_DECLARE(void) fsk_rx_signal_cutoff(fsk_rx_state_t *s, float cutoff);
/*! Initialise an FSK modem receive context.
\brief Initialise an FSK modem receive context.
\param s The modem context.
\param spec The specification of the modem tones and rate.
\param framing_mode 0 for fully asynchronous mode. 1 for synchronous mode. >1 for
this many bits per asynchronous character frame.
\param put_bit The callback routine used to put the received data.
\param user_data An opaque pointer.
\return A pointer to the modem context, or NULL if there was a problem. */
SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
const fsk_spec_t *spec,
int framing_mode,
put_bit_func_t put_bit,
void *user_data);
SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode);
SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s);
SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s);
/*! Process a block of received FSK modem audio samples.
\brief Process a block of received FSK modem audio samples.
\param s The modem context.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed.
*/
SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
/*! Fake processing of a missing block of received FSK modem audio samples
(e.g due to packet loss).
\brief Fake processing of a missing block of received FSK modem audio samples.
\param s The modem context.
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len);
SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data);
/*! Change the modem status report function associated with an FSK modem receive context.
\brief Change the modem status report function associated with an FSK modem receive context.
\param s The modem context.
\param handler The callback routine used to report modem status changes.
\param user_data An opaque pointer. */
SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,340 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* g168models.h - line models for echo cancellation tests against the G.168
* spec.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: g168models.h,v 1.9 2008/08/29 09:28:13 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_G168MODELS_H_)
#define _SPANDSP_G168MODELS_H_
/*! \page g168_test_data_page The test data from the G.168 specification
*/
/*!
The line model from section D.2 of G.168.
These are the coefficients for the line simulation model defined in
section D.2 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d2_coeffs[] =
{
-436, -829, -2797, -4208, -17968, -11215, 46150, 34480,
-10427, 9049, -1309, -6320, 390, -8191, -1751, -6051,
-3796, -4055, -3948, -2557, -3372, -1808, -2259, -1300,
-1098, -618, -340, -61, 323, 419, 745, 716,
946, 880, 1014, 976, 1033, 1091, 1053, 1042,
794, 831, 899, 716, 390, 313, 304, 304,
73, -119, -109, -176, -359, -407, -512, -580,
-704, -618, -685, -791, -772, -820, -839, -724
};
#define LINE_MODEL_D2_GAIN 1.39E-5f
/*!
The line model from section D.3 of G.168.
These are the coefficients for the line simulation model defined in
section D.3 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d3_coeffs[] =
{
-381, 658, 1730, -51, -3511, -1418, 7660, 8861,
-8106, -21370, -5307, 23064, 24020, 1020, -12374, -16296,
-19524, -7480, 13509, 17115, 13952, 13952, 97, -9326,
-9046, -15208, -9853, -3858, -1979, 6029, 5616, 7214,
6820, 3935, 3919, 921, 1316, -693, -759, -1517,
-2176, -2028, -2654, -1814, -2077, -1468, -1221, -842,
-463, -298, -68, 64, 493, 723, 789, 954,
756, 839, 872, 1020, 789, 822, 558, 658,
476, 377, 377, 262, 97, -68, -183, -232,
-331, -347, -430, -314, -430, -463, -463, -414,
-381, -479, -479, -512, -479, -397, -430, -397,
-298, -265, -249, -216, -249, -265, -166, -232
};
#define LINE_MODEL_D3_GAIN 1.44E-5f
/*!
The line model from section D.4 of G.168.
These are the coefficients for the line simulation model defined in
section D.4 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d4_coeffs[] =
{
-448, -436, 2230, 2448, -4178, -7050, 5846, 18581,
2322, -26261, -16249, 21637, 25649, -2267, -10311, -4693,
-12690, -7428, 14164, 13467, 4438, 8627, 456, -11879,
-6352, -5104, -7496, 3271, 6566, 4277, 11131, 7562,
1475, 3728, -3525, -7301, -3101, -9269, -6146, -2553,
-6272, 811, 124, 788, 5147, 2172, 5387, 4598,
3535, 4004, 2311, 2150, 1017, 330, -139, -573,
-1100, -1157, -1180, -1455, -1123, -1386, -1123, -1066,
-1020, -1100, -1008, -1077, -1088, -917, -917, -963,
-814, -871, -734, -642, -562, -356, -379, -345,
-230, -233, -333, -356, -390, -310, -265, -368,
-310, -310, -390, -482, -459, -482, -551, -573
};
#define LINE_MODEL_D4_GAIN 1.52E-5f
/*!
The line model from section D.5 of G.168.
These are the coefficients for the line simulation model defined in
section D.5 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d5_coeffs[] =
{
160, 312, -241, -415, 897, 908, -1326, -1499,
2405, 3347, -3624, -7733, 4041, 14484, -1477, -21739,
-4470, 25356, 11458, -19696, -11800, 5766, 789, 6633,
14624, -6975, -17156, -187, 149, 1515, 14907, 4345,
-7128, -2757, -10185, -7083, 6850, 3944, 6969, 8694,
-4068, -3852, -5793, -9371, 453, 1060, 3965, 9463,
2393, 2784, -892, -7366, -3376, -5847, -2399, 3011,
1537, 6623, 4205, 1602, 1592, -4752, -3646, -5207,
-5577, -501, -1174, 4041, 5647, 4628, 7252, 2123,
2654, -881, -4113, -3244, -7289, -3830, -4600, -2508,
431, -144, 4184, 2372, 4617, 3576, 2382, 2839,
-404, 539, -1803, -1401, -1705, -2269, -783, -1608,
-220, -306, 257, 615, 225, 561, 8, 344,
127, -57, 182, 41, 203, -111, 95, -79,
30, 84, -13, -68, -241, -68, -24, 19,
-57, -24, 30, -68, 84, -155, -68, 19
};
#define LINE_MODEL_D5_GAIN 1.77E-5f
/*!
The line model from section D.6 of G.168.
These are the coefficients for the line simulation model defined in
section D.6 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d6_coeffs[] =
{
293, 268, 475, 460, 517, 704, 581, 879,
573, 896, 604, 787, 561, 538, 440, 97,
265, -385, 20, -938, -523, -1438, -1134, -1887,
-1727, -1698, -4266, -22548, -43424, 2743, 25897, 7380,
21499, 11983, 10400, 11667, 3889, 7241, 925, 2018,
-821, -2068, -2236, -4283, -3406, -5022, -4039, -4842,
-4104, -4089, -3582, -2978, -2734, -1805, -1608, -645,
-495, 279, 471, 947, 1186, 1438, 1669, 1640,
1901, 1687, 1803, 1543, 1566, 1342, 1163, 963,
733, 665, 323, 221, -14, -107, -279, -379,
-468, -513, -473, -588, -612, -652, -616, -566,
-515, -485, -404, -344, -290, -202, -180, -123
};
#define LINE_MODEL_D6_GAIN 9.33E-6f
/*!
The line model from section D.7 of G.168.
These are the coefficients for the line simulation model defined in
section D.8 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d7_coeffs[] =
{
29, 109, -83, 198, -294, -135, -415, -202,
-444, -337, -313, -450, -105, -503, 145, -490,
267, -231, 340, 77, 343, 783, 158, 1341,
195, 1798, 344, 1845, 629, 1604, 1182, 940,
5163, 19522, 8421, -50953, -9043, 18046, -13553, 13336,
-3471, -107, 1788, -7409, 2469, -7994, 490, -3860,
-837, 490, -636, 3682, 1141, 5019, 2635, 5025,
3946, 4414, 4026, 3005, 3380, 1616, 2007, 158,
388, -1198, -1117, -2134, -2547, -2589, -3310, -2778,
-3427, -2779, -3116, -2502, -2399, -1956, -1539, -1239,
-570, -377, 251, 331, 964, 1177, 1449, 1564,
1724, 1871, 1767, 1802, 1630, 1632, 1379, 1271,
1063, 856, 711, 482, 289, 54, -137, -321,
-490, -638, -764, -836, -800, -859, -838, -837,
-834, -740, -673, -581, -493, -436, -327, -201
};
#define LINE_MODEL_D7_GAIN 1.51E-5f
/*!
The line model from section D.8 of G.168.
These are the coefficients for the line simulation model defined in
section D.8 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d8_coeffs[] =
{
258, -111, 337, -319, 347, -434, 192, -450,
-108, -343, -596, -177, -1187, -52, -1781, -147,
-1959, -326, -1601, -1389, -13620, -720, 33818, -10683,
-6742, 12489, -9862, 8950, -1574, 758, 3526, -3118,
2421, -8966, -4901, 11385, 18072, -14410, -7473, 19836,
-16854, -3115, 9483, -17799, 7399, -4342, -7415, 7929,
-10726, 6239, -2526, -1317, 5345, -4565, 6868, -2195,
3425, 1969, -109, 3963, -1275, 3087, -892, 1239,
2, -427, 596, -1184, 551, -1244, 141, -743,
-415, -372, -769, -183, -785, -270, -659, -377,
-523, -325, -245, -255, -60, 35, 218, 149,
340, 233, 365, 303, 251, 230, 209, 179
};
#define LINE_MODEL_D8_GAIN 2.33E-5f
/*!
The line model from section D.9 of G.168.
These are the coefficients for the line simulation model defined in
section D.9 of G.168. It may be used with the fir32_xxx
routines to build a line simulator.
*/
const int32_t line_model_d9_coeffs[] =
{
80, 31, 4, 42, 42, -61, -81, -64,
121, -102, -26, 1002, -9250, -22562, 39321, 35681,
-35289, 25312, -1457, -229, 15659, -6786, 16791, 3860,
2239, -28730, -11885, 33871, -176, -16421, 18173, -9669,
-10163, 9941, -19365, 3592, -5907, -10257, 5336, -12933,
4348, -4802, -1791, 3035, -4433, 5553, -2596, 3992,
1255, 1450, 4079, 324, 4340, 1059, 3083, 1917,
1756, 2478, 1027, 1871, 845, 1284, 813, 806,
869, 471, 646, 438, 449, 432, 473, 394,
452, 538, 717, 723, 850, 756, 753, 899,
555, 669, 619, 500, 650, 615, 516, 492,
427, 291, 356, 147, 107, -50, -88, -59,
-238, -165, -183
};
#define LINE_MODEL_D9_GAIN 1.33E-5f
/*!
The filter coefficients for the bandpass filter specified for level measurements
in section 6.4.1.2.1 of G.168.
*/
const float level_measurement_bp_coeffs[] =
{
0.0000, 0.0006, 0.0005, 0.0004, 0.0011,
0.0000, 0.0015, -0.0003, 0.0012, -0.0002,
0.0000, 0.0002, -0.0020, 0.0005, -0.0040,
0.0000, -0.0047, -0.0019, -0.0033, -0.0047,
0.0000, -0.0068, 0.0036, -0.0057, 0.0054,
0.0000, 0.0044, 0.0095, 0.0017, 0.0188,
0.0000, 0.0225, 0.0024, 0.0163, 0.0092,
0.0000, 0.0164, -0.0210, 0.0161, -0.0375,
0.0000, -0.0406, -0.0357, -0.0267, -0.0871,
0.0000, -0.1420, 0.0289, -0.1843, 0.0475,
0.8006, 0.0475, -0.1843, 0.0289, -0.1420,
0.0000, -0.0871, -0.0267, -0.0357, -0.0406,
0.0000, -0.0375, 0.0161, -0.0210, 0.0164,
0.0000, 0.0092, 0.0163, 0.0024, 0.0225,
0.0000, 0.0188, 0.0017, 0.0095, 0.0044,
0.0000, 0.0054, -0.0057, 0.0036, -0.0068,
0.0000, -0.0047, -0.0033, -0.0019, -0.0047,
0.0000, -0.0040, 0.0005, -0.0020, 0.0002,
0.0000, -0.0002, 0.0012, -0.0003, 0.0015,
0.0000, 0.0011, 0.0004, 0.0005, 0.0006,
0.0000
};
/*!
The composite source signal "voiced" section from section C.1 of G.168.
*/
const int css_c1[] =
{
-155, 276, 517, 578, 491, 302, 86, -103,
-207, -198, 60, 190, 543, 948, 1362, 1741,
2043, 2276, 2422, 2500, 2552, 2595, 2655, 2758,
2896, 3060, 3224, 3370, 3500, 3569, 3603, 3603,
3595, 3586, 3595, 3638, 3724, 3819, 3922, 4000,
4043, 4034, 3974, 3862, 3724, 3577, 3439, 3336,
3267, 3224, 3198, 3172, 3129, 3043, 2914, 2750,
2560, 2353, 2155, 1991, 1853, 1750, 1672, 1603,
1534, 1440, 1310, 1146, 965, 776, 603, 448,
345, 276, 250, 250, 267, 267, 241, 190,
103, -9, -138, -267, -388, -491, -569, -638,
-698, -759, -813, -888, -957, -1034, -1103, -1146,
-1181, -1190, -1198, -1215, -1259, -1327, -1457, -1629,
-1853, -2121, -2414, -2707, -3017, -3319, -3612, -3913,
-4224, -4560, -4922, -5301, -5715, -6137, -6560, -6948,
-7301, -7568, -7732, -7758, -7620, -7310, -6810, -6155,
-5344, -4439, -3474, -2508, -1595, -802
};
/*!
The composite source signal "voiced" section from section C.3 of G.168.
*/
const int css_c3[] =
{
-198, -112, -9, 103, 233, 388, 543, 724,
896, 1060, 1233, 1388, 1517, 1638, 1747, 1810,
1845, 1845, 1802, 1707, 1569, 1379, 1146, 871,
560, 233, -121, -491, -871, -1250, -1638, -2043,
-2465, -2896, -3345, -3819, -4310, -4810, -5319, -5836,
-6353, -6853, -7353, -7836, -8292, -8715, -9077, -9370,
-9542, -9542, -9361, -8956, -8327, -7465, -6396, -5163,
-3827, -2448, -1103, 155, 1293, 2241, 3034, 3655,
4138, 4517, 4827, 5094, 5344, 5594, 5827, 6043,
6215, 6344, 6413, 6422, 6379, 6310, 6215, 6120,
6051, 6000, 5991, 5991, 6000, 6008, 5991, 5939,
5853, 5715, 5560, 5387, 5215, 5043, 4879, 4732,
4586, 4439, 4276, 4086, 3870, 3629, 3370, 3086,
2801, 2534, 2267, 2034, 1819, 1612, 1422, 1224,
1026, 819, 603, 388, 181, 9, -181, -328,
-448, -543, -629, -707, -784, -871, -948, -1026,
-1112, -1181, -1241, -1276, -1293, -1302, -1293, -1267,
-1250, -1233, -1224, -1224, -1224, -1224, -1215, -1198,
-1172, -1129, -1077, -1026, -974, -922, -888, -871,
-845, -828, -810, -793, -767, -741, -698, -672,
-638, -603, -595, -586, -595, -603, -621, -629,
-938, -638, -638, -638, -638, -638, -647, -664,
-690, -724, -767, -793, -819, -845, -853, -871,
-879, -888, -896, -922, -948, -974, -1009, -1026,
-1052, -1069, -1077, -1069, -1060, -1060, -1052, -1043,
-1043, -1052, -1060, -1060, -1060, -1052, -1034, -1017,
-991, -957, -931, -905, -888, -862, -845, -819,
-793, -767, -724, -672, -621, -560, -509, -457,
-397, -345, -276, -207, -112
};
/*!
From section 6.4.2.7 of G.168 - Test No. 6 Non-divergence on narrow-band signals.
These tones and tone pairs are each applied for 5 seconds.
*/
const int tones_6_4_2_7[][2] =
{
{ 697, 0},
{ 941, 0},
{1336, 0},
{1633, 0},
{ 697, 1209},
{ 770, 1336},
{ 852, 1477},
{ 941, 1633},
{ 0, 0}
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,327 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* g711.h - In line A-law and u-law conversion routines
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: g711.h,v 1.19 2009/04/12 09:12:10 steveu Exp $
*/
/*! \file */
/*! \page g711_page A-law and mu-law handling
Lookup tables for A-law and u-law look attractive, until you consider the impact
on the CPU cache. If it causes a substantial area of your processor cache to get
hit too often, cache sloshing will severely slow things down. The main reason
these routines are slow in C, is the lack of direct access to the CPU's "find
the first 1" instruction. A little in-line assembler fixes that, and the
conversion routines can be faster than lookup tables, in most real world usage.
A "find the first 1" instruction is available on most modern CPUs, and is a
much underused feature.
If an assembly language method of bit searching is not available, these routines
revert to a method that can be a little slow, so the cache thrashing might not
seem so bad :(
Feel free to submit patches to add fast "find the first 1" support for your own
favourite processor.
Look up tables are used for transcoding between A-law and u-law, since it is
difficult to achieve the precise transcoding procedure laid down in the G.711
specification by other means.
*/
#if !defined(_SPANDSP_G711_H_)
#define _SPANDSP_G711_H_
/* The usual values to use on idle channels, to emulate silence */
/*! Idle value for A-law channels */
#define G711_ALAW_IDLE_OCTET 0x5D
/*! Idle value for u-law channels */
#define G711_ULAW_IDLE_OCTET 0xFF
enum
{
G711_ALAW = 0,
G711_ULAW
};
/*!
G.711 state
*/
typedef struct g711_state_s g711_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/* N.B. It is tempting to use look-up tables for A-law and u-law conversion.
* However, you should consider the cache footprint.
*
* A 64K byte table for linear to x-law and a 512 byte table for x-law to
* linear sound like peanuts these days, and shouldn't an array lookup be
* real fast? No! When the cache sloshes as badly as this one will, a tight
* calculation may be better. The messiest part is normally finding the
* segment, but a little inline assembly can fix that on an i386, x86_64 and
* many other modern processors.
*/
/*
* Mu-law is basically as follows:
*
* Biased Linear Input Code Compressed Code
* ------------------------ ---------------
* 00000001wxyza 000wxyz
* 0000001wxyzab 001wxyz
* 000001wxyzabc 010wxyz
* 00001wxyzabcd 011wxyz
* 0001wxyzabcde 100wxyz
* 001wxyzabcdef 101wxyz
* 01wxyzabcdefg 110wxyz
* 1wxyzabcdefgh 111wxyz
*
* Each biased linear code has a leading 1 which identifies the segment
* number. The value of the segment number is equal to 7 minus the number
* of leading 0's. The quantization interval is directly available as the
* four bits wxyz. * The trailing bits (a - h) are ignored.
*
* Ordinarily the complement of the resulting code word is used for
* transmission, and so the code word is complemented before it is returned.
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
/* Enable the trap as per the MIL-STD */
//#define ULAW_ZEROTRAP
/*! Bias for u-law encoding from linear. */
#define ULAW_BIAS 0x84
/*! \brief Encode a linear sample to u-law
\param linear The sample to encode.
\return The u-law value.
*/
static __inline__ uint8_t linear_to_ulaw(int linear)
{
uint8_t u_val;
int mask;
int seg;
/* Get the sign and the magnitude of the value. */
if (linear >= 0)
{
linear = ULAW_BIAS + linear;
mask = 0xFF;
}
else
{
linear = ULAW_BIAS - linear;
mask = 0x7F;
}
seg = top_bit(linear | 0xFF) - 7;
/*
* Combine the sign, segment, quantization bits,
* and complement the code word.
*/
if (seg >= 8)
u_val = (uint8_t) (0x7F ^ mask);
else
u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask);
#ifdef ULAW_ZEROTRAP
/* Optional ITU trap */
if (u_val == 0)
u_val = 0x02;
#endif
return u_val;
}
/*- End of function --------------------------------------------------------*/
/*! \brief Decode an u-law sample to a linear value.
\param ulaw The u-law sample to decode.
\return The linear value.
*/
static __inline__ int16_t ulaw_to_linear(uint8_t ulaw)
{
int t;
/* Complement to obtain normal u-law value. */
ulaw = ~ulaw;
/*
* Extract and bias the quantization bits. Then
* shift up by the segment number and subtract out the bias.
*/
t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4);
return (int16_t) ((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS));
}
/*- End of function --------------------------------------------------------*/
/*
* A-law is basically as follows:
*
* Linear Input Code Compressed Code
* ----------------- ---------------
* 0000000wxyza 000wxyz
* 0000001wxyza 001wxyz
* 000001wxyzab 010wxyz
* 00001wxyzabc 011wxyz
* 0001wxyzabcd 100wxyz
* 001wxyzabcde 101wxyz
* 01wxyzabcdef 110wxyz
* 1wxyzabcdefg 111wxyz
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
/*! The A-law alternate mark inversion mask */
#define ALAW_AMI_MASK 0x55
/*! \brief Encode a linear sample to A-law
\param linear The sample to encode.
\return The A-law value.
*/
static __inline__ uint8_t linear_to_alaw(int linear)
{
int mask;
int seg;
if (linear >= 0)
{
/* Sign (bit 7) bit = 1 */
mask = ALAW_AMI_MASK | 0x80;
}
else
{
/* Sign (bit 7) bit = 0 */
mask = ALAW_AMI_MASK;
linear = -linear - 1;
}
/* Convert the scaled magnitude to segment number. */
seg = top_bit(linear | 0xFF) - 7;
if (seg >= 8)
{
if (linear >= 0)
{
/* Out of range. Return maximum value. */
return (uint8_t) (0x7F ^ mask);
}
/* We must be just a tiny step below zero */
return (uint8_t) (0x00 ^ mask);
}
/* Combine the sign, segment, and quantization bits. */
return (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask);
}
/*- End of function --------------------------------------------------------*/
/*! \brief Decode an A-law sample to a linear value.
\param alaw The A-law sample to decode.
\return The linear value.
*/
static __inline__ int16_t alaw_to_linear(uint8_t alaw)
{
int i;
int seg;
alaw ^= ALAW_AMI_MASK;
i = ((alaw & 0x0F) << 4);
seg = (((int) alaw & 0x70) >> 4);
if (seg)
i = (i + 0x108) << (seg - 1);
else
i += 8;
return (int16_t) ((alaw & 0x80) ? i : -i);
}
/*- End of function --------------------------------------------------------*/
/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711.
\param alaw The A-law sample to transcode.
\return The best matching u-law value.
*/
SPAN_DECLARE(uint8_t) alaw_to_ulaw(uint8_t alaw);
/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711.
\param ulaw The u-law sample to transcode.
\return The best matching A-law value.
*/
SPAN_DECLARE(uint8_t) ulaw_to_alaw(uint8_t ulaw);
/*! \brief Decode from u-law or A-law to linear.
\param s The G.711 context.
\param amp The linear audio buffer.
\param g711_data The G.711 data.
\param g711_bytes The number of G.711 samples to decode.
\return The number of samples of linear audio produced.
*/
SPAN_DECLARE(int) g711_decode(g711_state_t *s,
int16_t amp[],
const uint8_t g711_data[],
int g711_bytes);
/*! \brief Encode from linear to u-law or A-law.
\param s The G.711 context.
\param g711_data The G.711 data.
\param amp The linear audio buffer.
\param len The number of samples to encode.
\return The number of G.711 samples produced.
*/
SPAN_DECLARE(int) g711_encode(g711_state_t *s,
uint8_t g711_data[],
const int16_t amp[],
int len);
/*! \brief Transcode between u-law and A-law.
\param s The G.711 context.
\param g711_out The resulting G.711 data.
\param g711_in The original G.711 data.
\param g711_bytes The number of G.711 samples to transcode.
\return The number of G.711 samples produced.
*/
SPAN_DECLARE(int) g711_transcode(g711_state_t *s,
uint8_t g711_out[],
const uint8_t g711_in[],
int g711_bytes);
/*! Initialise a G.711 encode or decode context.
\param s The G.711 context.
\param mode The G.711 mode.
\return A pointer to the G.711 context, or NULL for error. */
SPAN_DECLARE(g711_state_t *) g711_init(g711_state_t *s, int mode);
/*! Release a G.711 encode or decode context.
\param s The G.711 context.
\return 0 for OK. */
SPAN_DECLARE(int) g711_release(g711_state_t *s);
/*! Free a G.711 encode or decode context.
\param s The G.711 context.
\return 0 for OK. */
SPAN_DECLARE(int) g711_free(g711_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,130 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* g722.h - The ITU G.722 codec.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based on a single channel G.722 codec which is:
*
***** Copyright (c) CMU 1993 *****
* Computer Science, Speech Group
* Chengxiang Lu and Alex Hauptmann
*
* $Id: g722.h,v 1.26 2009/04/12 09:12:10 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_G722_H_)
#define _SPANDSP_G722_H_
/*! \page g722_page G.722 encoding and decoding
\section g722_page_sec_1 What does it do?
The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
support an option for the linear audio to be an 8k samples/second stream. In this mode the
codec is considerably faster, and still fully compatible with wideband terminals using G.722.
\section g722_page_sec_2 How does it work?
???.
*/
enum
{
G722_SAMPLE_RATE_8000 = 0x0001,
G722_PACKED = 0x0002
};
/*!
G.722 encode state
*/
typedef struct g722_encode_state_s g722_encode_state_t;
/*!
G.722 decode state
*/
typedef struct g722_decode_state_s g722_decode_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an G.722 encode context.
\param s The G.722 encode context.
\param rate The required bit rate for the G.722 data.
The valid rates are 64000, 56000 and 48000.
\param options
\return A pointer to the G.722 encode context, or NULL for error. */
SPAN_DECLARE(g722_encode_state_t *) g722_encode_init(g722_encode_state_t *s, int rate, int options);
/*! Release a G.722 encode context.
\param s The G.722 encode context.
\return 0 for OK. */
SPAN_DECLARE(int) g722_encode_release(g722_encode_state_t *s);
/*! Free a G.722 encode context.
\param s The G.722 encode context.
\return 0 for OK. */
SPAN_DECLARE(int) g722_encode_free(g722_encode_state_t *s);
/*! Encode a buffer of linear PCM data to G.722
\param s The G.722 context.
\param g722_data The G.722 data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of G.722 data produced. */
SPAN_DECLARE(int) g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
/*! Initialise an G.722 decode context.
\param s The G.722 decode context.
\param rate The bit rate of the G.722 data.
The valid rates are 64000, 56000 and 48000.
\param options
\return A pointer to the G.722 decode context, or NULL for error. */
SPAN_DECLARE(g722_decode_state_t *) g722_decode_init(g722_decode_state_t *s, int rate, int options);
/*! Release a G.722 decode context.
\param s The G.722 decode context.
\return 0 for OK. */
SPAN_DECLARE(int) g722_decode_release(g722_decode_state_t *s);
/*! Free a G.722 decode context.
\param s The G.722 decode context.
\return 0 for OK. */
SPAN_DECLARE(int) g722_decode_free(g722_decode_state_t *s);
/*! Decode a buffer of G.722 data to linear PCM.
\param s The G.722 context.
\param amp The audio sample buffer.
\param g722_data
\param len
\return The number of samples returned. */
SPAN_DECLARE(int) g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -0,0 +1,122 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* g726.h - ITU G.726 codec.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: g726.h,v 1.26 2009/04/12 09:12:10 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_G726_H_)
#define _SPANDSP_G726_H_
/*! \page g726_page G.726 encoding and decoding
\section g726_page_sec_1 What does it do?
The G.726 module is a bit exact implementation of the full ITU G.726 specification.
It supports:
- 16 kbps, 24kbps, 32kbps, and 40kbps operation.
- Tandem adjustment, for interworking with A-law and u-law.
- Annex A support, for use in environments not using A-law or u-law.
It passes the ITU tests.
\section g726_page_sec_2 How does it work?
???.
*/
enum
{
G726_ENCODING_LINEAR = 0, /* Interworking with 16 bit signed linear */
G726_ENCODING_ULAW, /* Interworking with u-law */
G726_ENCODING_ALAW /* Interworking with A-law */
};
enum
{
G726_PACKING_NONE = 0,
G726_PACKING_LEFT = 1,
G726_PACKING_RIGHT = 2
};
/*!
G.726 state
*/
typedef struct g726_state_s g726_state_t;
typedef int16_t (*g726_decoder_func_t)(g726_state_t *s, uint8_t code);
typedef uint8_t (*g726_encoder_func_t)(g726_state_t *s, int16_t amp);
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise a G.726 encode or decode context.
\param s The G.726 context.
\param bit_rate The required bit rate for the ADPCM data.
The valid rates are 16000, 24000, 32000 and 40000.
\param ext_coding The coding used outside G.726.
\param packing One of the G.726_PACKING_xxx options.
\return A pointer to the G.726 context, or NULL for error. */
SPAN_DECLARE(g726_state_t *) g726_init(g726_state_t *s, int bit_rate, int ext_coding, int packing);
/*! Release a G.726 encode or decode context.
\param s The G.726 context.
\return 0 for OK. */
SPAN_DECLARE(int) g726_release(g726_state_t *s);
/*! Free a G.726 encode or decode context.
\param s The G.726 context.
\return 0 for OK. */
SPAN_DECLARE(int) g726_free(g726_state_t *s);
/*! Decode a buffer of G.726 ADPCM data to linear PCM, a-law or u-law.
\param s The G.726 context.
\param amp The audio sample buffer.
\param g726_data
\param g726_bytes
\return The number of samples returned. */
SPAN_DECLARE(int) g726_decode(g726_state_t *s,
int16_t amp[],
const uint8_t g726_data[],
int g726_bytes);
/*! Encode a buffer of linear PCM data to G.726 ADPCM.
\param s The G.726 context.
\param g726_data The G.726 data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of G.726 data produced. */
SPAN_DECLARE(int) g726_encode(g726_state_t *s,
uint8_t g726_data[],
const int16_t amp[],
int len);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,153 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* gsm0610.h - GSM 06.10 full rate speech codec.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: gsm0610.h,v 1.21 2009/02/10 13:06:47 steveu Exp $
*/
#if !defined(_SPANDSP_GSM0610_H_)
#define _SPANDSP_GSM0610_H_
/*! \page gsm0610_page GSM 06.10 encoding and decoding
\section gsm0610_page_sec_1 What does it do?
The GSM 06.10 module is an version of the widely used GSM FR codec software
available from http://kbs.cs.tu-berlin.de/~jutta/toast.html. This version
was produced since some versions of this codec are not bit exact, or not
very efficient on modern processors. This implementation can use MMX instructions
on Pentium class processors, or alternative methods on other processors. It
passes all the ETSI test vectors. That is, it is a tested bit exact implementation.
This implementation supports encoded data in one of three packing formats:
- Unpacked, with the 76 parameters of a GSM 06.10 code frame each occupying a
separate byte. (note that none of the parameters exceed 8 bits).
- Packed the the 33 byte per frame, used for VoIP, where 4 bits per frame are wasted.
- Packed in WAV49 format, where 2 frames are packed into 65 bytes.
\section gsm0610_page_sec_2 How does it work?
???.
*/
enum
{
GSM0610_PACKING_NONE,
GSM0610_PACKING_WAV49,
GSM0610_PACKING_VOIP
};
/*!
GSM 06.10 FR codec unpacked frame.
*/
typedef struct
{
int16_t LARc[8];
int16_t Nc[4];
int16_t bc[4];
int16_t Mc[4];
int16_t xmaxc[4];
int16_t xMc[4][13];
} gsm0610_frame_t;
/*!
GSM 06.10 FR codec state descriptor. This defines the state of
a single working instance of the GSM 06.10 FR encoder or decoder.
*/
typedef struct gsm0610_state_s gsm0610_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise a GSM 06.10 encode or decode context.
\param s The GSM 06.10 context
\param packing One of the GSM0610_PACKING_xxx options.
\return A pointer to the GSM 06.10 context, or NULL for error. */
SPAN_DECLARE(gsm0610_state_t *) gsm0610_init(gsm0610_state_t *s, int packing);
/*! Release a GSM 06.10 encode or decode context.
\param s The GSM 06.10 context
\return 0 for success, else -1. */
SPAN_DECLARE(int) gsm0610_release(gsm0610_state_t *s);
/*! Free a GSM 06.10 encode or decode context.
\param s The GSM 06.10 context
\return 0 for success, else -1. */
SPAN_DECLARE(int) gsm0610_free(gsm0610_state_t *s);
/*! Set the packing format for a GSM 06.10 encode or decode context.
\param s The GSM 06.10 context
\param packing One of the GSM0610_PACKING_xxx options.
\return 0 for success, else -1. */
SPAN_DECLARE(int) gsm0610_set_packing(gsm0610_state_t *s, int packing);
/*! Encode a buffer of linear PCM data to GSM 06.10.
\param s The GSM 06.10 context.
\param code The GSM 06.10 data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of GSM 06.10 data produced. */
SPAN_DECLARE(int) gsm0610_encode(gsm0610_state_t *s, uint8_t code[], const int16_t amp[], int len);
/*! Decode a buffer of GSM 06.10 data to linear PCM.
\param s The GSM 06.10 context.
\param amp The audio sample buffer.
\param code The GSM 06.10 data.
\param len The number of bytes of GSM 06.10 data to be decoded.
\return The number of samples returned. */
SPAN_DECLARE(int) gsm0610_decode(gsm0610_state_t *s, int16_t amp[], const uint8_t code[], int len);
SPAN_DECLARE(int) gsm0610_pack_none(uint8_t c[], const gsm0610_frame_t *s);
/*! Pack a pair of GSM 06.10 frames in the format used for wave files (wave type 49).
\param c The buffer for the packed data. This must be at least 65 bytes long.
\param s A pointer to the frames to be packed.
\return The number of bytes generated. */
SPAN_DECLARE(int) gsm0610_pack_wav49(uint8_t c[], const gsm0610_frame_t *s);
/*! Pack a GSM 06.10 frames in the format used for VoIP.
\param c The buffer for the packed data. This must be at least 33 bytes long.
\param s A pointer to the frame to be packed.
\return The number of bytes generated. */
SPAN_DECLARE(int) gsm0610_pack_voip(uint8_t c[], const gsm0610_frame_t *s);
SPAN_DECLARE(int) gsm0610_unpack_none(gsm0610_frame_t *s, const uint8_t c[]);
/*! Unpack a pair of GSM 06.10 frames from the format used for wave files (wave type 49).
\param s A pointer to a buffer into which the frames will be packed.
\param c The buffer containing the data to be unpacked. This must be at least 65 bytes long.
\return The number of bytes absorbed. */
SPAN_DECLARE(int) gsm0610_unpack_wav49(gsm0610_frame_t *s, const uint8_t c[]);
/*! Unpack a GSM 06.10 frame from the format used for VoIP.
\param s A pointer to a buffer into which the frame will be packed.
\param c The buffer containing the data to be unpacked. This must be at least 33 bytes long.
\return The number of bytes absorbed. */
SPAN_DECLARE(int) gsm0610_unpack_voip(gsm0610_frame_t *s, const uint8_t c[]);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of include ---------------------------------------------------------*/

View File

@ -0,0 +1,252 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* hdlc.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: hdlc.h,v 1.45 2009/06/02 16:03:56 steveu Exp $
*/
/*! \file */
/*! \page hdlc_page HDLC
\section hdlc_page_sec_1 What does it do?
The HDLC module provides bit stuffing, destuffing, framing and deframing,
according to the HDLC protocol. It also provides 16 and 32 bit CRC generation
and checking services for HDLC frames.
HDLC may not be a DSP function, but is needed to accompany several DSP components.
\section hdlc_page_sec_2 How does it work?
*/
#if !defined(_SPANDSP_HDLC_H_)
#define _SPANDSP_HDLC_H_
/*!
HDLC_MAXFRAME_LEN is the maximum length of a stuffed HDLC frame, excluding the CRC.
*/
#define HDLC_MAXFRAME_LEN 400
typedef void (*hdlc_frame_handler_t)(void *user_data, const uint8_t *pkt, int len, int ok);
typedef void (*hdlc_underflow_handler_t)(void *user_data);
/*!
HDLC receive descriptor. This contains all the state information for an HDLC receiver.
*/
typedef struct hdlc_rx_state_s hdlc_rx_state_t;
/*!
HDLC received data statistics.
*/
typedef struct
{
/*! \brief The number of bytes of good frames received (CRC not included). */
unsigned long int bytes;
/*! \brief The number of good frames received. */
unsigned long int good_frames;
/*! \brief The number of frames with CRC errors received. */
unsigned long int crc_errors;
/*! \brief The number of too short and too long frames received. */
unsigned long int length_errors;
/*! \brief The number of HDLC aborts received. */
unsigned long int aborts;
} hdlc_rx_stats_t;
/*!
HDLC transmit descriptor. This contains all the state information for an
HDLC transmitter.
*/
typedef struct hdlc_tx_state_s hdlc_tx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Initialise an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\param crc32 TRUE to use ITU CRC32. FALSE to use ITU CRC16.
\param report_bad_frames TRUE to request the reporting of bad frames.
\param framing_ok_threshold The number of back-to-back flags needed to
start the framing OK condition. This may be used where a series of
flag octets is used as a preamble, such as in the T.30 protocol.
\param handler The function to be called when a good HDLC frame is received.
\param user_data An opaque parameter for the callback routine.
\return A pointer to the HDLC receiver context.
*/
SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s,
int crc32,
int report_bad_frames,
int framing_ok_threshold,
hdlc_frame_handler_t handler,
void *user_data);
/*! Change the put_bit function associated with an HDLC receiver context.
\brief Change the put_bit function associated with an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\param handler The function to be called when a good HDLC frame is received.
\param user_data An opaque parameter for the callback routine.
*/
SPAN_DECLARE(void) hdlc_rx_set_frame_handler(hdlc_rx_state_t *s, hdlc_frame_handler_t handler, void *user_data);
/*! Change the status report function associated with an HDLC receiver context.
\brief Change the status report function associated with an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\param handler The callback routine used to report status changes.
\param user_data An opaque parameter for the callback routine.
*/
SPAN_DECLARE(void) hdlc_rx_set_status_handler(hdlc_rx_state_t *s, modem_rx_status_func_t handler, void *user_data);
/*! Release an HDLC receiver context.
\brief Release an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\return 0 for OK */
SPAN_DECLARE(int) hdlc_rx_release(hdlc_rx_state_t *s);
/*! Free an HDLC receiver context.
\brief Free an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\return 0 for OK */
SPAN_DECLARE(int) hdlc_rx_free(hdlc_rx_state_t *s);
/*! \brief Set the maximum frame length for an HDLC receiver context.
\param s A pointer to an HDLC receiver context.
\param max_len The maximum permitted length of a frame.
*/
SPAN_DECLARE(void) hdlc_rx_set_max_frame_len(hdlc_rx_state_t *s, size_t max_len);
/*! \brief Set the octet counting report interval.
\param s A pointer to an HDLC receiver context.
\param interval The interval, in octets.
*/
SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s,
int interval);
/*! \brief Get the current receive statistics.
\param s A pointer to an HDLC receiver context.
\param t A pointer to the buffer for the statistics.
\return 0 for OK, else -1.
*/
SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s,
hdlc_rx_stats_t *t);
/*! \brief Put a single bit of data to an HDLC receiver.
\param s A pointer to an HDLC receiver context.
\param new_bit The bit.
*/
SPAN_DECLARE_NONSTD(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit);
/*! \brief Put a byte of data to an HDLC receiver.
\param s A pointer to an HDLC receiver context.
\param new_byte The byte of data.
*/
SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
/*! \brief Put a series of bytes of data to an HDLC receiver.
\param s A pointer to an HDLC receiver context.
\param buf The buffer of data.
\param len The length of the data in the buffer.
*/
SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
/*! \brief Initialise an HDLC transmitter context.
\param s A pointer to an HDLC transmitter context.
\param crc32 TRUE to use ITU CRC32. FALSE to use ITU CRC16.
\param inter_frame_flags The minimum flag octets to insert between frames (usually one).
\param progressive TRUE if frame creation works in progressive mode.
\param handler The callback function called when the HDLC transmitter underflows.
\param user_data An opaque parameter for the callback routine.
\return A pointer to the HDLC transmitter context.
*/
SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s,
int crc32,
int inter_frame_flags,
int progressive,
hdlc_underflow_handler_t handler,
void *user_data);
SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s);
SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s);
/*! \brief Set the maximum frame length for an HDLC transmitter context.
\param s A pointer to an HDLC transmitter context.
\param max_len The maximum length.
*/
SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len);
/*! \brief Transmit a frame.
\param s A pointer to an HDLC transmitter context.
\param frame A pointer to the frame to be transmitted.
\param len The length of the frame to be transmitted.
\return 0 if the frame was accepted for transmission, else -1.
*/
SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len);
/*! \brief Corrupt the frame currently being transmitted, by giving it the wrong CRC.
\param s A pointer to an HDLC transmitter context.
\return 0 if the frame was corrupted, else -1.
*/
SPAN_DECLARE(int) hdlc_tx_corrupt_frame(hdlc_tx_state_t *s);
/*! \brief Transmit a specified quantity of flag octets, typically as a preamble.
\param s A pointer to an HDLC transmitter context.
\param len The length of the required period of flags, in flag octets. If len is zero this
requests that HDLC transmission be terminated when the buffers have fully
drained.
\return 0 if the flags were accepted for transmission, else -1.
*/
SPAN_DECLARE(int) hdlc_tx_flags(hdlc_tx_state_t *s, int len);
/*! \brief Send an abort.
\param s A pointer to an HDLC transmitter context.
\return 0 if the frame was aborted, else -1.
*/
SPAN_DECLARE(int) hdlc_tx_abort(hdlc_tx_state_t *s);
/*! \brief Get the next bit for transmission.
\param s A pointer to an HDLC transmitter context.
\return The next bit for transmission.
*/
SPAN_DECLARE_NONSTD(int) hdlc_tx_get_bit(hdlc_tx_state_t *s);
/*! \brief Get the next byte for transmission.
\param s A pointer to an HDLC transmitter context.
\return The next byte for transmission.
*/
SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
/*! \brief Get the next sequence of bytes for transmission.
\param s A pointer to an HDLC transmitter context.
\param buf The buffer for the data.
\param max_len The number of bytes to get.
\return The number of bytes actually got.
*/
SPAN_DECLARE_NONSTD(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,117 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* ima_adpcm.c - Conversion routines between linear 16 bit PCM data and
* IMA/DVI/Intel ADPCM format.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Based on a bit from here, a bit from there, eye of toad,
* ear of bat, etc - plus, of course, my own 2 cents.
*
* $Id: ima_adpcm.h,v 1.25 2009/04/11 18:11:19 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_IMA_ADPCM_H_)
#define _SPANDSP_IMA_ADPCM_H_
/*! \page ima_adpcm_page IMA/DVI/Intel ADPCM encoding and decoding
\section ima_adpcm_page_sec_1 What does it do?
IMA ADPCM offers a good balance of simplicity and quality at a rate of
32kbps.
\section ima_adpcm_page_sec_2 How does it work?
\section ima_adpcm_page_sec_3 How do I use it?
*/
enum
{
/*! IMA4 is the original IMA ADPCM variant */
IMA_ADPCM_IMA4 = 0,
/*! DVI4 is the IMA ADPCM variant defined in RFC3551 */
IMA_ADPCM_DVI4 = 1,
/*! VDVI is the variable bit rate IMA ADPCM variant defined in RFC3551 */
IMA_ADPCM_VDVI = 2
};
/*!
IMA (DVI/Intel) ADPCM conversion state descriptor. This defines the state of
a single working instance of the IMA ADPCM converter. This is used for
either linear to ADPCM or ADPCM to linear conversion.
*/
typedef struct ima_adpcm_state_s ima_adpcm_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an IMA ADPCM encode or decode context.
\param s The IMA ADPCM context.
\param variant IMA_ADPCM_IMA4, IMA_ADPCM_DVI4, or IMA_ADPCM_VDVI.
\param chunk_size The size of a chunk, in samples. A chunk size of
zero sample samples means treat each encode or decode operation
as a chunk.
\return A pointer to the IMA ADPCM context, or NULL for error. */
SPAN_DECLARE(ima_adpcm_state_t *) ima_adpcm_init(ima_adpcm_state_t *s,
int variant,
int chunk_size);
/*! Release an IMA ADPCM encode or decode context.
\param s The IMA ADPCM context.
\return 0 for OK. */
SPAN_DECLARE(int) ima_adpcm_release(ima_adpcm_state_t *s);
/*! Free an IMA ADPCM encode or decode context.
\param s The IMA ADPCM context.
\return 0 for OK. */
SPAN_DECLARE(int) ima_adpcm_free(ima_adpcm_state_t *s);
/*! Encode a buffer of linear PCM data to IMA ADPCM.
\param s The IMA ADPCM context.
\param ima_data The IMA ADPCM data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of IMA ADPCM data produced. */
SPAN_DECLARE(int) ima_adpcm_encode(ima_adpcm_state_t *s,
uint8_t ima_data[],
const int16_t amp[],
int len);
/*! Decode a buffer of IMA ADPCM data to linear PCM.
\param s The IMA ADPCM context.
\param amp The audio sample buffer.
\param ima_data The IMA ADPCM data
\param ima_bytes The number of bytes of IMA ADPCM data
\return The number of samples returned. */
SPAN_DECLARE(int) ima_adpcm_decode(ima_adpcm_state_t *s,
int16_t amp[],
const uint8_t ima_data[],
int ima_bytes);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,141 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* logging.h - definitions for error and debug logging.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: logging.h,v 1.20 2009/02/10 17:44:18 steveu Exp $
*/
/*! \file */
/*! \page logging_page Logging
\section logging_page_sec_1 What does it do?
???.
*/
#if !defined(_SPANDSP_LOGGING_H_)
#define _SPANDSP_LOGGING_H_
/*! General logging function for spandsp logging. */
typedef void (*message_handler_func_t)(int level, const char *text);
/*! Error logging function for spandsp logging. */
typedef void (*error_handler_func_t)(const char *text);
/* Logging elements */
enum
{
SPAN_LOG_SEVERITY_MASK = 0x00FF,
SPAN_LOG_SHOW_DATE = 0x0100,
SPAN_LOG_SHOW_SAMPLE_TIME = 0x0200,
SPAN_LOG_SHOW_SEVERITY = 0x0400,
SPAN_LOG_SHOW_PROTOCOL = 0x0800,
SPAN_LOG_SHOW_VARIANT = 0x1000,
SPAN_LOG_SHOW_TAG = 0x2000,
SPAN_LOG_SUPPRESS_LABELLING = 0x8000
};
/* Logging severity levels */
enum
{
SPAN_LOG_NONE = 0,
SPAN_LOG_ERROR = 1,
SPAN_LOG_WARNING = 2,
SPAN_LOG_PROTOCOL_ERROR = 3,
SPAN_LOG_PROTOCOL_WARNING = 4,
SPAN_LOG_FLOW = 5,
SPAN_LOG_FLOW_2 = 6,
SPAN_LOG_FLOW_3 = 7,
SPAN_LOG_DEBUG = 8,
SPAN_LOG_DEBUG_2 = 9,
SPAN_LOG_DEBUG_3 = 10
};
/*!
Logging descriptor. This defines the working state for a single instance of
the logging facility for spandsp.
*/
typedef struct logging_state_s logging_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Test if logging of a specified severity level is enabled.
\brief Test if logging of a specified severity level is enabled.
\param s The logging context.
\param level The severity level to be tested.
\return TRUE if logging is enable, else FALSE.
*/
SPAN_DECLARE(int) span_log_test(logging_state_t *s, int level);
/*! Generate a log entry.
\brief Generate a log entry.
\param s The logging context.
\param level The severity level of the entry.
\param format ???
\return 0 if no output generated, else 1.
*/
SPAN_DECLARE(int) span_log(logging_state_t *s, int level, const char *format, ...);
/*! Generate a log entry displaying the contents of a buffer.
\brief Generate a log entry displaying the contents of a buffer
\param s The logging context.
\param level The severity level of the entry.
\param tag A label for the log entry.
\param buf The buffer to be dumped to the log.
\param len The length of buf.
\return 0 if no output generated, else 1.
*/
SPAN_DECLARE(int) span_log_buf(logging_state_t *s, int level, const char *tag, const uint8_t *buf, int len);
SPAN_DECLARE(int) span_log_set_level(logging_state_t *s, int level);
SPAN_DECLARE(int) span_log_set_tag(logging_state_t *s, const char *tag);
SPAN_DECLARE(int) span_log_set_protocol(logging_state_t *s, const char *protocol);
SPAN_DECLARE(int) span_log_set_sample_rate(logging_state_t *s, int samples_per_second);
SPAN_DECLARE(int) span_log_bump_samples(logging_state_t *s, int samples);
SPAN_DECLARE(void) span_log_set_message_handler(logging_state_t *s, message_handler_func_t func);
SPAN_DECLARE(void) span_log_set_error_handler(logging_state_t *s, error_handler_func_t func);
SPAN_DECLARE(void) span_set_message_handler(message_handler_func_t func);
SPAN_DECLARE(void) span_set_error_handler(error_handler_func_t func);
SPAN_DECLARE(logging_state_t *) span_log_init(logging_state_t *s, int level, const char *tag);
SPAN_DECLARE(int) span_log_release(logging_state_t *s);
SPAN_DECLARE(int) span_log_free(logging_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,120 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* lpc10.h - LPC10 low bit rate speech codec.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: lpc10.h,v 1.22 2009/04/11 18:11:19 steveu Exp $
*/
#if !defined(_SPANDSP_LPC10_H_)
#define _SPANDSP_LPC10_H_
/*! \page lpc10_page LPC10 encoding and decoding
\section lpc10_page_sec_1 What does it do?
The LPC10 module implements the US Department of Defense LPC10
codec. This codec produces compressed data at 2400bps. At such
a low rate high fidelity cannot be expected. However, the speech
clarity is quite good, and this codec is unencumbered by patent
or other restrictions.
\section lpc10_page_sec_2 How does it work?
???.
*/
#define LPC10_SAMPLES_PER_FRAME 180
#define LPC10_BITS_IN_COMPRESSED_FRAME 54
/*!
LPC10 codec unpacked frame.
*/
typedef struct
{
/*! Pitch */
int32_t ipitch;
/*! Energy */
int32_t irms;
/*! Reflection coefficients */
int32_t irc[10];
} lpc10_frame_t;
/*!
LPC10 codec encoder state descriptor. This defines the state of
a single working instance of the LPC10 encoder.
*/
typedef struct lpc10_encode_state_s lpc10_encode_state_t;
/*!
LPC10 codec decoder state descriptor. This defines the state of
a single working instance of the LPC10 decoder.
*/
typedef struct lpc10_decode_state_s lpc10_decode_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an LPC10e encode context.
\param s The LPC10e context
\param error_correction ???
\return A pointer to the LPC10e context, or NULL for error. */
SPAN_DECLARE(lpc10_encode_state_t *) lpc10_encode_init(lpc10_encode_state_t *s, int error_correction);
SPAN_DECLARE(int) lpc10_encode_release(lpc10_encode_state_t *s);
SPAN_DECLARE(int) lpc10_encode_free(lpc10_encode_state_t *s);
/*! Encode a buffer of linear PCM data to LPC10e.
\param s The LPC10e context.
\param ima_data The LPC10e data produced.
\param amp The audio sample buffer.
\param len The number of samples in the buffer. This must be a multiple of 180, as
this is the number of samples on a frame.
\return The number of bytes of LPC10e data produced. */
SPAN_DECLARE(int) lpc10_encode(lpc10_encode_state_t *s, uint8_t code[], const int16_t amp[], int len);
/*! Initialise an LPC10e decode context.
\param s The LPC10e context
\param error_correction ???
\return A pointer to the LPC10e context, or NULL for error. */
SPAN_DECLARE(lpc10_decode_state_t *) lpc10_decode_init(lpc10_decode_state_t *st, int error_correction);
SPAN_DECLARE(int) lpc10_decode_release(lpc10_decode_state_t *s);
SPAN_DECLARE(int) lpc10_decode_free(lpc10_decode_state_t *s);
/*! Decode a buffer of LPC10e data to linear PCM.
\param s The LPC10e context.
\param amp The audio sample buffer.
\param code The LPC10e data.
\param len The number of bytes of LPC10e data to be decoded. This must be a multiple of 7,
as each frame is packed into 7 bytes.
\return The number of samples returned. */
SPAN_DECLARE(int) lpc10_decode(lpc10_decode_state_t *s, int16_t amp[], const uint8_t code[], int len);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of include ---------------------------------------------------------*/

View File

@ -0,0 +1,177 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* modem_connect_tones.c - Generation and detection of tones
* associated with modems calling and
* answering calls.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: modem_connect_tones.h,v 1.24 2009/06/02 16:03:56 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_MODEM_CONNECT_TONES_H_)
#define _SPANDSP_MODEM_CONNECT_TONES_H_
/*! \page modem_connect_tones_page Modem connect tone detection
\section modem_connect_tones_page_sec_1 What does it do?
Some telephony terminal equipment, such as modems, require a channel which is as
clear as possible. They use their own echo cancellation. If the network is also
performing echo cancellation the two cancellors can end up squabbling about the
nature of the channel, with bad results. A special tone is defined which should
cause the network to disable any echo cancellation processes. This is the echo
canceller disable tone.
The tone detector's design assumes the channel is free of any DC component.
\section modem_connect_tones_page_sec_2 How does it work?
A sharp notch filter is implemented as a single bi-quad section. The presence of
the 2100Hz disable tone is detected by comparing the notched filtered energy
with the unfiltered energy. If the notch filtered energy is much lower than the
unfiltered energy, then a large proportion of the energy must be at the notch
frequency. This type of detector may seem less intuitive than using a narrow
bandpass filter to isolate the energy at the notch freqency. However, a sharp
bandpass implemented as an IIR filter rings badly. The reciprocal notch filter
is very well behaved for our purpose.
*/
enum
{
/*! \brief This is reported when a tone stops. */
MODEM_CONNECT_TONES_NONE = 0,
/*! \brief CNG tone is a pure 1100Hz tone, in 0.5s bursts, with 3s silences in between. The
bursts repeat for as long as is required. */
MODEM_CONNECT_TONES_FAX_CNG = 1,
/*! \brief ANS tone is a pure continuous 2100Hz+-15Hz tone for 3.3s+-0.7s. */
MODEM_CONNECT_TONES_ANS = 2,
/*! \brief ANS with phase reversals tone is a 2100Hz+-15Hz tone for 3.3s+-0.7s, with a 180 degree
phase jump every 450ms+-25ms. */
MODEM_CONNECT_TONES_ANS_PR = 3,
/*! \brief The ANSam tone is a version of ANS with 20% of 15Hz+-0.1Hz AM modulation, as per V.8 */
MODEM_CONNECT_TONES_ANSAM = 4,
/*! \brief The ANSam with phase reversals tone is a version of ANS_PR with 20% of 15Hz+-0.1Hz AM
modulation, as per V.8 */
MODEM_CONNECT_TONES_ANSAM_PR = 5,
/*! \brief FAX preamble in a string of V.21 HDLC flag octets. */
MODEM_CONNECT_TONES_FAX_PREAMBLE = 6,
/*! \brief CED tone is the same as ANS tone. FAX preamble in a string of V.21 HDLC flag octets.
This is only valid as a tone type to receive. It is never reported as a detected tone
type. The report will either be for FAX preamble or CED/ANS tone. */
MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE = 7
};
/*! \brief FAX CED tone is the same as ANS tone. */
#define MODEM_CONNECT_TONES_FAX_CED MODEM_CONNECT_TONES_ANS
/*!
Modem connect tones generator descriptor. This defines the state
of a single working instance of the tone generator.
*/
typedef struct modem_connect_tones_tx_state_s modem_connect_tones_tx_state_t;
/*!
Modem connect tones receiver descriptor. This defines the state
of a single working instance of the tone detector.
*/
typedef struct modem_connect_tones_rx_state_s modem_connect_tones_rx_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! \brief Initialise an instance of the modem connect tones generator.
\param s The context.
*/
SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s,
int tone_type);
/*! \brief Release an instance of the modem connect tones generator.
\param s The context.
\return 0 for OK, else -1.
*/
SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t *s);
/*! \brief Free an instance of the modem connect tones generator.
\param s The context.
\return 0 for OK, else -1.
*/
SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s);
/*! \brief Generate a block of modem connect tones samples.
\param s The context.
\param amp An array of signal samples.
\param len The number of samples to generate.
\return The number of samples generated.
*/
SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
int16_t amp[],
int len);
/*! \brief Process a block of samples through an instance of the modem connect
tones detector.
\param s The context.
\param amp An array of signal samples.
\param len The number of samples in the array.
\return The number of unprocessed samples.
*/
SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
const int16_t amp[],
int len);
/*! \brief Test if a modem_connect tone has been detected.
\param s The context.
\return TRUE if tone is detected, else FALSE.
*/
SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s);
/*! \brief Initialise an instance of the modem connect tones detector.
\param s The context.
\param tone_type The type of connect tone being tested for.
\param tone_callback An optional callback routine, used to report tones
\param user_data An opaque pointer passed to the callback routine,
\return A pointer to the context.
*/
SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s,
int tone_type,
tone_report_func_t tone_callback,
void *user_data);
/*! \brief Release an instance of the modem connect tones detector.
\param s The context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t *s);
/*! \brief Free an instance of the modem connect tones detector.
\param s The context.
\return 0 for OK, else -1. */
SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s);
SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,129 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* modem_echo.h - An echo cancellor, suitable for electrical echos in GSTN modems
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001, 2004 Steve Underwood
*
* Based on a bit from here, a bit from there, eye of toad,
* ear of bat, etc - plus, of course, my own 2 cents.
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: modem_echo.h,v 1.14 2009/09/22 13:11:04 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_MODEM_ECHO_H_)
#define _SPANDSP_MODEM_ECHO_H_
/*! \page modem_echo_can_page Line echo cancellation for modems
\section modem_echo_can_page_sec_1 What does it do?
This module aims to cancel electrical echoes (e.g. from 2-4 wire hybrids)
in modem applications. It is not very suitable for speech applications, which
require additional refinements for satisfactory performance. It is, however, more
efficient and better suited to modem applications.
\section modem_echo_can_page_sec_2 How does it work?
The heart of the echo cancellor is an adaptive FIR filter. This is adapted to
match the impulse response of the environment being cancelled. It must be long
enough to adequately cover the duration of that impulse response. The signal
being transmitted into the environment being cancelled is passed through the
FIR filter. The resulting output is an estimate of the echo signal. This is
then subtracted from the received signal, and the result should be an estimate
of the signal which originates within the environment being cancelled (people
talking in the room, or the signal from the far end of a telephone line) free
from the echos of our own transmitted signal.
The FIR filter is adapted using the least mean squares (LMS) algorithm. This
algorithm is attributed to Widrow and Hoff, and was introduced in 1960. It is
the commonest form of filter adaption used in things like modem line equalisers
and line echo cancellers. It works very well if the signal level is constant,
which is true for a modem signal. To ensure good performa certain conditions must
be met:
- The transmitted signal has weak self-correlation.
- There is no signal being generated within the environment being cancelled.
The difficulty is that neither of these can be guaranteed. If the adaption is
performed while transmitting noise (or something fairly noise like, such as
voice) the adaption works very well. If the adaption is performed while
transmitting something highly correlative (e.g. tones, like DTMF), the adaption
can go seriously wrong. The reason is there is only one solution for the
adaption on a near random signal. For a repetitive signal, there are a number of
solutions which converge the adaption, and nothing guides the adaption to choose
the correct one.
\section modem_echo_can_page_sec_3 How do I use it?
The echo cancellor processes both the transmit and receive streams sample by
sample. The processing function is not declared inline. Unfortunately,
cancellation requires many operations per sample, so the call overhead is only a
minor burden.
*/
#include "fir.h"
/*!
Modem line echo canceller descriptor. This defines the working state for a line
echo canceller.
*/
typedef struct modem_echo_can_state_s modem_echo_can_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Create a modem echo canceller context.
\param len The length of the canceller, in samples.
eturn The new canceller context, or NULL if the canceller could not be created.
*/
SPAN_DECLARE(modem_echo_can_state_t *) modem_echo_can_create(int len);
/*! Free a modem echo canceller context.
\param ec The echo canceller context.
*/
SPAN_DECLARE(void) modem_echo_can_free(modem_echo_can_state_t *ec);
/*! Flush (reinitialise) a modem echo canceller context.
\param ec The echo canceller context.
*/
SPAN_DECLARE(void) modem_echo_can_flush(modem_echo_can_state_t *ec);
/*! Set the adaption mode of a modem echo canceller context.
\param ec The echo canceller context.
\param adapt The mode.
*/
SPAN_DECLARE(void) modem_echo_can_adaption_mode(modem_echo_can_state_t *ec, int adapt);
/*! Process a sample through a modem echo canceller.
\param ec The echo canceller context.
\param tx The transmitted audio sample.
\param rx The received audio sample.
eturn The clean (echo cancelled) received sample.
*/
SPAN_DECLARE(int16_t) modem_echo_can_update(modem_echo_can_state_t *ec, int16_t tx, int16_t rx);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,131 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* noise.h - A low complexity audio noise generator, suitable for
* real time generation (current just approx AWGN)
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: noise.h,v 1.17 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_NOISE_H_)
#define _SPANDSP_NOISE_H_
/*! \page noise_page Noise generation
\section noise_page_sec_1 What does it do?
It generates audio noise. Currently it only generates reasonable quality
AWGN. It is designed to be of sufficiently low complexity to generate large
volumes of reasonable quality noise, in real time.
Hoth noise is used to model indoor ambient noise when evaluating communications
systems such as telephones. It is named after D.F. Hoth, who made the first
systematic study of this. The official definition of Hoth noise is IEEE
standard 269-2001 (revised from 269-1992), "Draft Standard Methods for Measuring
Transmission Performance of Analog and Digital Telephone Sets, Handsets and Headsets."
The table below gives the spectral density of Hoth noise, adjusted in level to produce
a reading of 50 dBA.
Freq (Hz) Spectral Bandwidth Total power in
density 10 log_f each 1/3 octave band
(dB SPL/Hz) (dB) (dB SPL)
100 32.4 13.5 45.9
125 30.9 14.7 45.5
160 29.1 15.7 44.9
200 27.6 16.5 44.1
250 26.0 17.6 43.6
315 24.4 18.7 43.1
400 22.7 19.7 42.3
500 21.1 20.6 41.7
630 19.5 21.7 41.2
800 17.8 22.7 40.4
1000 16.2 23.5 39.7
1250 14.6 24.7 39.3
1600 12.9 25.7 38.7
2000 11.3 26.5 37.8
2500 9.6 27.6 37.2
3150 7.8 28.7 36.5
4000 5.4 29.7 34.8
5000 2.6 30.6 33.2
6300 -1.3 31.7 30.4
8000 -6.6 32.7 26.0
The tolerance for each 1/3rd octave band is ¡Ó3dB.
\section awgn_page_sec_2 How does it work?
The central limit theorem says if you add a few random numbers together,
the result starts to look Gaussian. In this case we sum 8 random numbers.
The result is fast, and perfectly good as a noise source for many purposes.
It should not be trusted as a high quality AWGN generator, for elaborate
modelling purposes.
*/
enum
{
NOISE_CLASS_AWGN = 1,
NOISE_CLASS_HOTH
};
/*!
Noise generator descriptor. This contains all the state information for an instance
of the noise generator.
*/
typedef struct noise_state_s noise_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an audio noise generator.
\brief Initialise an audio noise generator.
\param s The noise generator context.
\param seed A seed for the underlying random number generator.
\param level The noise power level in dBmO.
\param class_of_noise The class of noise (e.g. AWGN).
\param quality A parameter which permits speed and accuracy of the noise
generation to be adjusted.
\return A pointer to the noise generator context.
*/
SPAN_DECLARE(noise_state_t *) noise_init_dbm0(noise_state_t *s, int seed, float level, int class_of_noise, int quality);
SPAN_DECLARE(noise_state_t *) noise_init_dbov(noise_state_t *s, int seed, float level, int class_of_noise, int quality);
SPAN_DECLARE(int) noise_release(noise_state_t *s);
SPAN_DECLARE(int) noise_free(noise_state_t *s);
/*! Generate a sample of audio noise.
\brief Generate a sample of audio noise.
\param s The noise generator context.
\return The generated sample.
*/
SPAN_DECLARE(int16_t) noise(noise_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,104 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* oki_adpcm.h - Conversion routines between linear 16 bit PCM data and
* OKI (Dialogic) ADPCM format.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: oki_adpcm.h,v 1.24 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_OKI_ADPCM_H_)
#define _SPANDSP_OKI_ADPCM_H_
/*! \page okiadpcm_page OKI (Dialogic) ADPCM encoding and decoding
\section okiadpcm_page_sec_1 What does it do?
OKI ADPCM is widely used in the CTI industry because it is the principal format
supported by Dialogic. As the market leader, they tend to define "common
practice". It offers a good balance of simplicity and quality at rates of
24kbps or 32kbps. 32kbps is obtained by ADPCM compressing 8k samples/second linear
PCM. 24kbps is obtained by resampling to 6k samples/second and using the same ADPCM
compression algorithm on the slower samples.
The algorithms for this ADPCM codec can be found in "PC Telephony - The complete guide
to designing, building and programming systems using Dialogic and Related Hardware"
by Bob Edgar. pg 272-276. */
/*!
Oki (Dialogic) ADPCM conversion state descriptor. This defines the state of
a single working instance of the Oki ADPCM converter. This is used for
either linear to ADPCM or ADPCM to linear conversion.
*/
typedef struct oki_adpcm_state_s oki_adpcm_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise an Oki ADPCM encode or decode context.
\param s The Oki ADPCM context.
\param bit_rate The required bit rate for the ADPCM data.
The valid rates are 24000 and 32000.
\return A pointer to the Oki ADPCM context, or NULL for error. */
SPAN_DECLARE(oki_adpcm_state_t *) oki_adpcm_init(oki_adpcm_state_t *s,
int bit_rate);
/*! Release an Oki ADPCM encode or decode context.
\param s The Oki ADPCM context.
\return 0 for OK. */
SPAN_DECLARE(int) oki_adpcm_release(oki_adpcm_state_t *s);
/*! Free an Oki ADPCM encode or decode context.
\param s The Oki ADPCM context.
\return 0 for OK. */
SPAN_DECLARE(int) oki_adpcm_free(oki_adpcm_state_t *s);
/*! Decode a buffer of Oki ADPCM data to linear PCM.
\param s The Oki ADPCM context.
\param amp The audio sample buffer.
\param oki_data
\param oki_bytes
\return The number of samples returned. */
SPAN_DECLARE(int) oki_adpcm_decode(oki_adpcm_state_t *s,
int16_t amp[],
const uint8_t oki_data[],
int oki_bytes);
/*! Encode a buffer of linear PCM data to Oki ADPCM.
\param s The Oki ADPCM context.
\param oki_data The Oki ADPCM data produced
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of bytes of Oki ADPCM data produced. */
SPAN_DECLARE(int) oki_adpcm_encode(oki_adpcm_state_t *s,
uint8_t oki_data[],
const int16_t amp[],
int len);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,216 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* playout.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: playout.h,v 1.14 2009/02/10 13:06:47 steveu Exp $
*/
#if !defined(_SPANDSP_PLAYOUT_H_)
#define _SPANDSP_PLAYOUT_H_
/*! \page playout_page Play-out (jitter buffering)
\section playout_page_sec_1 What does it do?
The play-out module provides a static or dynamic length buffer for received frames of
audio or video data. It's goal is to maximise the receiver's tolerance of jitter in the
timing of the received frames.
Dynamic buffers are generally good for speech, since they adapt to provide the smallest delay
consistent with a low rate of packets arriving too late to be used. For things like FoIP and
MoIP, a static length of buffer is normally necessary. Any attempt to elastically change the
buffer length would wreck a modem's data flow.
*/
/* Return codes */
enum
{
PLAYOUT_OK = 0,
PLAYOUT_ERROR,
PLAYOUT_EMPTY,
PLAYOUT_NOFRAME,
PLAYOUT_FILLIN,
PLAYOUT_DROP
};
/* Frame types */
#define PLAYOUT_TYPE_CONTROL 0
#define PLAYOUT_TYPE_SILENCE 1
#define PLAYOUT_TYPE_SPEECH 2
typedef int timestamp_t;
typedef struct playout_frame_s
{
/*! The actual frame data */
void *data;
/*! The type of frame */
int type;
/*! The timestamp assigned by the sending end */
timestamp_t sender_stamp;
/*! The timespan covered by the data in this frame */
timestamp_t sender_len;
/*! The timestamp assigned by the receiving end */
timestamp_t receiver_stamp;
/*! Pointer to the next earlier frame */
struct playout_frame_s *earlier;
/*! Pointer to the next later frame */
struct playout_frame_s *later;
} playout_frame_t;
/*!
Playout (jitter buffer) descriptor. This defines the working state
for a single instance of playout buffering.
*/
typedef struct
{
/*! TRUE if the buffer is dynamically sized */
int dynamic;
/*! The minimum length (dynamic) or fixed length (static) of the buffer */
int min_length;
/*! The maximum length (dynamic) or fixed length (static) of the buffer */
int max_length;
/*! The target filter threshold for adjusting dynamic buffering. */
int dropable_threshold;
int start;
/*! The queued frame list */
playout_frame_t *first_frame;
playout_frame_t *last_frame;
/*! The free frame pool */
playout_frame_t *free_frames;
/*! The total frames input to the buffer, to date. */
int frames_in;
/*! The total frames output from the buffer, to date. */
int frames_out;
/*! The number of frames received out of sequence. */
int frames_oos;
/*! The number of frames which were discarded, due to late arrival. */
int frames_late;
/*! The number of frames which were never received. */
int frames_missing;
/*! The number of frames trimmed from the stream, due to buffer shrinkage. */
int frames_trimmed;
timestamp_t latest_expected;
/*! The present jitter adjustment */
timestamp_t current;
/*! The sender_stamp of the last speech frame */
timestamp_t last_speech_sender_stamp;
/*! The duration of the last speech frame */
timestamp_t last_speech_sender_len;
int not_first;
/*! The time since the target buffer length was last changed. */
timestamp_t since_last_step;
/*! Filter state for tracking the packets arriving just in time */
int32_t state_just_in_time;
/*! Filter state for tracking the packets arriving late */
int32_t state_late;
/*! The current target length of the buffer */
int target_buffer_length;
/*! The current actual length of the buffer, which may lag behind the target value */
int actual_buffer_length;
} playout_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Queue a frame
\param s The play-out context.
\param data The frame data.
\param sender_len Length of frame (for voice) in timestamp units.
\param sender_stamp Sending end's time stamp.
\param receiver_stamp Local time at which packet was received, in timestamp units.
\return One of
PLAYOUT_OK: Frame queued OK.
PLAYOUT_ERROR: Some problem occured - e.g. out of memory. */
SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestamp_t sender_len, timestamp_t sender_stamp, timestamp_t receiver_stamp);
/*! Get the next frame.
\param s The play-out context.
\param frame The frame.
\param sender_stamp The sender's timestamp.
\return One of
PLAYOUT_OK: Suitable frame found.
PLAYOUT_DROP: A frame which should be dropped was found (e.g. it arrived too late).
The caller should request the same time again when this occurs.
PLAYOUT_NOFRAME: There's no frame scheduled for this time.
PLAYOUT_FILLIN: Synthetic signal must be generated, as no real data is available for
this time (either we need to grow, or there was a lost frame).
PLAYOUT_EMPTY: The buffer is empty.
*/
SPAN_DECLARE(int) playout_get(playout_state_t *s, playout_frame_t *frame, timestamp_t sender_stamp);
/*! Unconditionally get the first buffered frame. This may be used to clear out the queue, and free
all its contents, before the context is freed.
\param s The play-out context.
\return The frame, or NULL is the queue is empty. */
SPAN_DECLARE(playout_frame_t *) playout_get_unconditional(playout_state_t *s);
/*! Find the current length of the buffer.
\param s The play-out context.
\return The length of the buffer. */
SPAN_DECLARE(timestamp_t) playout_current_length(playout_state_t *s);
/*! Find the time at which the next queued frame is due to play.
Note: This value may change backwards as freshly received out of order frames are
added to the buffer.
\param s The play-out context.
\return The next timestamp. */
SPAN_DECLARE(timestamp_t) playout_next_due(playout_state_t *s);
/*! Reset an instance of play-out buffering.
NOTE: The buffer should be empty before you call this function, otherwise
you will leak queued frames, and some internal structures
\param s The play-out context.
\param min_length Minimum length of the buffer, in samples.
\param max_length Maximum length of the buffer, in samples. If this equals min_length, static
length buffering is used. */
SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_length);
/*! Create a new instance of play-out buffering.
\param min_length Minimum length of the buffer, in samples.
\param max_length Maximum length of the buffer, in samples. If this equals min_length, static
length buffering is used.
\return The new context */
SPAN_DECLARE(playout_state_t *) playout_init(int min_length, int max_length);
/*! Release an instance of play-out buffering.
\param s The play-out context to be releaased
\return 0 if OK, else -1 */
SPAN_DECLARE(int) playout_release(playout_state_t *s);
/*! Free an instance of play-out buffering.
\param s The play-out context to be destroyed
\return 0 if OK, else -1 */
SPAN_DECLARE(int) playout_free(playout_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,173 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* plc.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: plc.h,v 1.21 2009/02/10 13:06:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PLC_H_)
#define _SPANDSP_PLC_H_
/*! \page plc_page Packet loss concealment
\section plc_page_sec_1 What does it do?
The packet loss concealment module provides a synthetic fill-in signal, to minimise
the audible effect of lost packets in VoIP applications. It is not tied to any
particular codec, and could be used with almost any codec which does not
specify its own procedure for packet loss concealment.
Where a codec specific concealment procedure exists, that algorithm is usually built
around knowledge of the characteristics of the particular codec. It will, therefore,
generally give better results for that particular codec than this generic concealer will.
The PLC code implements an algorithm similar to the one described in Appendix 1 of G.711.
However, the G.711 algorithm is optimised for 10ms packets. Few people use such small
packets. 20ms is a much more common value, and longer packets are also quite common. The
algorithm has been adjusted with this in mind. Also, the G.711 approach causes an
algorithmic delay, and requires significant buffer manipulation when there is no packet
loss. The algorithm used here avoids this. It causes no delay, and achieves comparable
quality with normal speech.
Note that both this algorithm, and the one in G.711 are optimised for speech. For most kinds
of music a much slower decay on bursts of lost packets give better results.
\section plc_page_sec_2 How does it work?
While good packets are being received, the plc_rx() routine keeps a record of the trailing
section of the known speech signal. If a packet is missed, plc_fillin() is called to produce
a synthetic replacement for the real speech signal. The average mean difference function
(AMDF) is applied to the last known good signal, to determine its effective pitch.
Based on this, the last pitch period of signal is saved. Essentially, this cycle of speech
will be repeated over and over until the real speech resumes. However, several refinements
are needed to obtain smooth pleasant sounding results.
- The two ends of the stored cycle of speech will not always fit together smoothly. This can
cause roughness, or even clicks, at the joins between cycles. To soften this, the
1/4 pitch period of real speech preceeding the cycle to be repeated is blended with the last
1/4 pitch period of the cycle to be repeated, using an overlap-add (OLA) technique (i.e.
in total, the last 5/4 pitch periods of real speech are used).
- The start of the synthetic speech will not always fit together smoothly with the tail of
real speech passed on before the erasure was identified. Ideally, we would like to modify
the last 1/4 pitch period of the real speech, to blend it into the synthetic speech. However,
it is too late for that. We could have delayed the real speech a little, but that would
require more buffer manipulation, and hurt the efficiency of the no-lost-packets case
(which we hope is the dominant case). Instead we use a degenerate form of OLA to modify
the start of the synthetic data. The last 1/4 pitch period of real speech is time reversed,
and OLA is used to blend it with the first 1/4 pitch period of synthetic speech. The result
seems quite acceptable.
- As we progress into the erasure, the chances of the synthetic signal being anything like
correct steadily fall. Therefore, the volume of the synthesized signal is made to decay
linearly, such that after 50ms of missing audio it is reduced to silence.
- When real speech resumes, an extra 1/4 pitch period of synthetic speech is blended with the
start of the real speech. If the erasure is small, this smoothes the transition. If the erasure
is long, and the synthetic signal has faded to zero, the blending softens the start up of the
real signal, avoiding a kind of "click" or "pop" effect that might occur with a sudden onset.
\section plc_page_sec_3 How do I use it?
Before audio is processed, call plc_init() to create an instance of the packet loss
concealer. For each received audio packet that is acceptable (i.e. not including those being
dropped for being too late) call plc_rx() to record the content of the packet. Note this may
modify the packet a little after a period of packet loss, to blend real synthetic data smoothly.
When a real packet is not available in time, call plc_fillin() to create a sythetic substitute.
That's it!
*/
/*! Minimum allowed pitch (66 Hz) */
#define PLC_PITCH_MIN 120
/*! Maximum allowed pitch (200 Hz) */
#define PLC_PITCH_MAX 40
/*! Maximum pitch OLA window */
#define PLC_PITCH_OVERLAP_MAX (PLC_PITCH_MIN >> 2)
/*! The length over which the AMDF function looks for similarity (20 ms) */
#define CORRELATION_SPAN 160
/*! History buffer length. The buffer much also be at leat 1.25 times
PLC_PITCH_MIN, but that is much smaller than the buffer needs to be for
the pitch assessment. */
#define PLC_HISTORY_LEN (CORRELATION_SPAN + PLC_PITCH_MIN)
/*!
The generic packet loss concealer context.
*/
typedef struct
{
/*! Consecutive erased samples */
int missing_samples;
/*! Current offset into pitch period */
int pitch_offset;
/*! Pitch estimate */
int pitch;
/*! Buffer for a cycle of speech */
float pitchbuf[PLC_PITCH_MIN];
/*! History buffer */
int16_t history[PLC_HISTORY_LEN];
/*! Current pointer into the history buffer */
int buf_ptr;
} plc_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Process a block of received audio samples for PLC.
\brief Process a block of received audio samples for PLC.
\param s The packet loss concealer context.
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples in the buffer. */
SPAN_DECLARE(int) plc_rx(plc_state_t *s, int16_t amp[], int len);
/*! Fill-in a block of missing audio samples.
\brief Fill-in a block of missing audio samples.
\param s The packet loss concealer context.
\param amp The audio sample buffer.
\param len The number of samples to be synthesised.
\return The number of samples synthesized. */
SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len);
/*! Initialise a packet loss concealer context.
\brief Initialise a PLC context.
\param s The packet loss concealer context.
\return A pointer to the the packet loss concealer context. */
SPAN_DECLARE(plc_state_t *) plc_init(plc_state_t *s);
/*! Release a packet loss concealer context.
\param s The packet loss concealer context.
\return 0 for OK. */
SPAN_DECLARE(int) plc_release(plc_state_t *s);
/*! Free a packet loss concealer context.
\param s The packet loss concealer context.
\return 0 for OK. */
SPAN_DECLARE(int) plc_free(plc_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,154 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* power_meter.h
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: power_meter.h,v 1.19 2009/05/19 14:15:09 steveu Exp $
*/
#if !defined(_POWER_METER_H_)
#define _POWER_METER_H_
/*! \page power_meter_page Power metering
\section power_meter_page_sec_1 What does it do?
The power metering module implements a simple IIR type running power meter. The damping
factor of the IIR is selectable when the meter instance is created.
Note that the definition of dBOv is quite vague in most places - is it peak since wave,
peak square wave, etc.? This code is based on the well defined wording in RFC3389:
"For example, in the case of a u-law system, the reference would be a square wave with
values +/-8031, and this square wave represents 0dBov. This translates into 6.18dBm0".
\section power_meter_page_sec_2 How does it work?
*/
/*!
Power meter descriptor. This defines the working state for a
single instance of a power measurement device.
*/
typedef struct
{
/*! The shift factor, which controls the damping of the power meter. */
int shift;
/*! The current power reading. */
int32_t reading;
} power_meter_t;
typedef struct
{
power_meter_t short_term;
power_meter_t medium_term;
int signal_present;
int32_t surge;
int32_t sag;
int32_t min;
} power_surge_detector_state_t;
#if defined(__cplusplus)
extern "C"
{
#endif
/*! Initialise a power meter context.
\brief Initialise a power meter context.
\param s The power meter context.
\param shift The shift to be used by the IIR filter.
\return The power meter context. */
SPAN_DECLARE(power_meter_t *) power_meter_init(power_meter_t *s, int shift);
SPAN_DECLARE(int) power_meter_release(power_meter_t *s);
SPAN_DECLARE(int) power_meter_free(power_meter_t *s);
/*! Change the damping factor of a power meter context.
\brief Change the damping factor of a power meter context.
\param s The power meter context.
\param shift The new shift to be used by the IIR filter.
\return The power meter context. */
SPAN_DECLARE(power_meter_t *) power_meter_damping(power_meter_t *s, int shift);
/*! Update a power meter.
\brief Update a power meter.
\param s The power meter context.
\param amp The amplitude of the new audio sample.
\return The current power meter reading. */
SPAN_DECLARE(int32_t) power_meter_update(power_meter_t *s, int16_t amp);
/*! Get the current power meter reading.
\brief Get the current power meter reading.
\param s The power meter context.
\return The current power meter reading. */
SPAN_DECLARE(int32_t) power_meter_current(power_meter_t *s);
/*! Get the current power meter reading, in dBm0.
\brief Get the current power meter reading, in dBm0.
\param s The power meter context.
\return The current power meter reading, in dBm0. */
SPAN_DECLARE(float) power_meter_current_dbm0(power_meter_t *s);
/*! Get the current power meter reading, in dBOv.
\brief Get the current power meter reading, in dBOv.
\param s The power meter context.
\return The current power meter reading, in dBOv. */
SPAN_DECLARE(float) power_meter_current_dbov(power_meter_t *s);
/*! Get the power meter reading which represents a specified power level in dBm0.
\brief Get the current power meter reading, in dBm0.
\param level A power level, in dB0m.
\return The equivalent power meter reading. */
SPAN_DECLARE(int32_t) power_meter_level_dbm0(float level);
/*! Get the power meter reading which represents a specified power level in dBOv.
\brief Get the current power meter reading, in dBOv.
\param level A power level, in dBOv.
\return The equivalent power meter reading. */
SPAN_DECLARE(int32_t) power_meter_level_dbov(float level);
SPAN_DECLARE(int32_t) power_surge_detector(power_surge_detector_state_t *s, int16_t amp);
/*! Get the current surge detector short term meter reading, in dBm0.
\brief Get the current surge detector meter reading, in dBm0.
\param s The power surge detector context.
\return The current power surge detector power reading, in dBm0. */
SPAN_DECLARE(float) power_surge_detector_current_dbm0(power_surge_detector_state_t *s);
/*! Get the current surge detector short term meter reading, in dBOv.
\brief Get the current surge detector meter reading, in dBOv.
\param s The power surge detector context.
\return The current power surge detector power reading, in dBOv. */
SPAN_DECLARE(float) power_surge_detector_current_dbov(power_surge_detector_state_t *s);
SPAN_DECLARE(power_surge_detector_state_t *) power_surge_detector_init(power_surge_detector_state_t *s, float min, float surge);
SPAN_DECLARE(int) power_surge_detector_release(power_surge_detector_state_t *s);
SPAN_DECLARE(int) power_surge_detector_free(power_surge_detector_state_t *s);
#if defined(__cplusplus)
}
#endif
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,3 @@
The header files in this directory should only be used by code tightly integrating itself with the
spandsp library to maximise performance. To maximise compatibility with futures revisions of spandsp,
most users should avoid using these headers, or probing into the spandsp data structures in other ways.

View File

@ -0,0 +1,120 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/adsi.h - Analogue display services interface and other call ID related handling.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: adsi.h,v 1.4 2009/04/12 04:20:01 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_ADSI_H_)
#define _SPANDSP_PRIVATE_ADSI_H_
/*!
ADSI transmitter descriptor. This contains all the state information for an ADSI
(caller ID, CLASS, CLIP, ACLIP) transmit channel.
*/
struct adsi_tx_state_s
{
/*! */
int standard;
/*! */
tone_gen_descriptor_t alert_tone_desc;
/*! */
tone_gen_state_t alert_tone_gen;
/*! */
fsk_tx_state_t fsktx;
/*! */
dtmf_tx_state_t dtmftx;
/*! */
async_tx_state_t asynctx;
/*! */
int tx_signal_on;
/*! */
int byte_no;
/*! */
int bit_pos;
/*! */
int bit_no;
/*! */
uint8_t msg[256];
/*! */
int msg_len;
/*! */
int preamble_len;
/*! */
int preamble_ones_len;
/*! */
int postamble_ones_len;
/*! */
int stop_bits;
/*! */
int baudot_shift;
/*! */
logging_state_t logging;
};
/*!
ADSI receiver descriptor. This contains all the state information for an ADSI
(caller ID, CLASS, CLIP, ACLIP, JCLIP) receive channel.
*/
struct adsi_rx_state_s
{
/*! */
int standard;
/*! */
put_msg_func_t put_msg;
/*! */
void *user_data;
/*! */
fsk_rx_state_t fskrx;
/*! */
dtmf_rx_state_t dtmfrx;
/*! */
int consecutive_ones;
/*! */
int bit_pos;
/*! */
int in_progress;
/*! */
uint8_t msg[256];
/*! */
int msg_len;
/*! */
int baudot_shift;
/*! A count of the framing errors. */
int framing_errors;
/*! */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,91 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/async.h - Asynchronous serial bit stream encoding and decoding
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: async.h,v 1.1 2008/11/30 10:17:31 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_ASYNC_H_)
#define _SPANDSP_PRIVATE_ASYNC_H_
/*!
Asynchronous data transmit descriptor. This defines the state of a single
working instance of a byte to asynchronous serial converter, for use
in FSK modems.
*/
struct async_tx_state_s
{
/*! \brief The number of data bits per character. */
int data_bits;
/*! \brief The type of parity. */
int parity;
/*! \brief The number of stop bits per character. */
int stop_bits;
/*! \brief A pointer to the callback routine used to get characters to be transmitted. */
get_byte_func_t get_byte;
/*! \brief An opaque pointer passed when calling get_byte. */
void *user_data;
/*! \brief A current, partially transmitted, character. */
int byte_in_progress;
/*! \brief The current bit position within a partially transmitted character. */
int bitpos;
/*! \brief Parity bit. */
int parity_bit;
};
/*!
Asynchronous data receive descriptor. This defines the state of a single
working instance of an asynchronous serial to byte converter, for use
in FSK modems.
*/
struct async_rx_state_s
{
/*! \brief The number of data bits per character. */
int data_bits;
/*! \brief The type of parity. */
int parity;
/*! \brief The number of stop bits per character. */
int stop_bits;
/*! \brief TRUE if V.14 rate adaption processing should be performed. */
int use_v14;
/*! \brief A pointer to the callback routine used to handle received characters. */
put_byte_func_t put_byte;
/*! \brief An opaque pointer passed when calling put_byte. */
void *user_data;
/*! \brief A current, partially complete, character. */
int byte_in_progress;
/*! \brief The current bit position within a partially complete character. */
int bitpos;
/*! \brief Parity bit. */
int parity_bit;
/*! A count of the number of parity errors seen. */
int parity_errors;
/*! A count of the number of character framing errors seen. */
int framing_errors;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,130 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/at_interpreter.h - AT command interpreter to V.251, V.252, V.253, T.31 and the 3GPP specs.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004, 2005, 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: at_interpreter.h,v 1.1 2008/11/30 05:43:37 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_AT_INTERPRETER_H_)
#define _SPANDSP_PRIVATE_AT_INTERPRETER_H_
typedef struct at_call_id_s at_call_id_t;
struct at_call_id_s
{
char *id;
char *value;
at_call_id_t *next;
};
/*!
AT descriptor. This defines the working state for a single instance of
the AT interpreter.
*/
struct at_state_s
{
at_profile_t p;
/*! Value set by +GCI */
int country_of_installation;
/*! Value set by +FIT */
int dte_inactivity_timeout;
/*! Value set by +FIT */
int dte_inactivity_action;
/*! Value set by L */
int speaker_volume;
/*! Value set by M */
int speaker_mode;
/*! This is no real DTE rate. This variable is for compatibility this serially
connected modems. */
/*! Value set by +IPR/+FPR */
int dte_rate;
/*! Value set by +ICF */
int dte_char_format;
/*! Value set by +ICF */
int dte_parity;
/*! Value set by &C */
int rlsd_behaviour;
/*! Value set by &D */
int dtr_behaviour;
/*! Value set by +FCL */
int carrier_loss_timeout;
/*! Value set by X */
int result_code_mode;
/*! Value set by +IDSR */
int dsr_option;
/*! Value set by +ILSD */
int long_space_disconnect_option;
/*! Value set by +ICLOK */
int sync_tx_clock_source;
/*! Value set by +EWIND */
int rx_window;
/*! Value set by +EWIND */
int tx_window;
int v8bis_signal;
int v8bis_1st_message;
int v8bis_2nd_message;
int v8bis_sig_en;
int v8bis_msg_en;
int v8bis_supp_delay;
uint8_t rx_data[256];
int rx_data_bytes;
int display_call_info;
int call_info_displayed;
at_call_id_t *call_id;
char *local_id;
/*! The currently select FAX modem class. 0 = data modem mode. */
int fclass_mode;
int at_rx_mode;
int rings_indicated;
int do_hangup;
int silent_dial;
int command_dial;
int ok_is_pending;
int dte_is_waiting;
/*! \brief TRUE if a carrier is presnt. Otherwise FALSE. */
int rx_signal_present;
/*! \brief TRUE if a modem has trained, Otherwise FALSE. */
int rx_trained;
int transmit;
char line[256];
int line_ptr;
at_modem_control_handler_t *modem_control_handler;
void *modem_control_user_data;
at_tx_handler_t *at_tx_handler;
void *at_tx_user_data;
at_class1_handler_t *class1_handler;
void *class1_user_data;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,46 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/awgn.h - An additive Gaussian white noise generator
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: awgn.h,v 1.1 2008/11/30 12:38:27 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_AWGN_H_)
#define _SPANDSP_PRIVATE_AWGN_H_
/*!
AWGN generator descriptor. This contains all the state information for an AWGN generator.
*/
struct awgn_state_s
{
double rms;
long int ix1;
long int ix2;
long int ix3;
double r[98];
double gset;
int iset;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,104 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* bell_r2_mf.h - Bell MF and MFC/R2 tone generation and detection.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bell_r2_mf.h,v 1.2 2008/10/13 14:19:18 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_BELL_R2_MF_H_)
#define _SPANDSP_PRIVATE_BELL_R2_MF_H_
/*!
Bell MF generator state descriptor. This defines the state of a single
working instance of a Bell MF generator.
*/
struct bell_mf_tx_state_s
{
/*! The tone generator. */
tone_gen_state_t tones;
int current_sample;
union
{
queue_state_t queue;
uint8_t buf[QUEUE_STATE_T_SIZE(MAX_BELL_MF_DIGITS)];
} queue;
};
/*!
Bell MF digit detector descriptor.
*/
struct bell_mf_rx_state_s
{
/*! Optional callback funcion to deliver received digits. */
digits_rx_callback_t digits_callback;
/*! An opaque pointer passed to the callback function. */
void *digits_callback_data;
/*! Tone detector working states */
goertzel_state_t out[6];
/*! Short term history of results from the tone detection, using in persistence checking */
uint8_t hits[5];
/*! The current sample number within a processing block. */
int current_sample;
/*! The number of digits which have been lost due to buffer overflows. */
int lost_digits;
/*! The number of digits currently in the digit buffer. */
int current_digits;
/*! The received digits buffer. This is a NULL terminated string. */
char digits[MAX_BELL_MF_DIGITS + 1];
};
/*!
MFC/R2 tone detector descriptor.
*/
struct r2_mf_tx_state_s
{
/*! The tone generator. */
tone_gen_state_t tone;
/*! TRUE if generating forward tones, otherwise generating reverse tones. */
int fwd;
/*! The current digit being generated. */
int digit;
};
/*!
MFC/R2 tone detector descriptor.
*/
struct r2_mf_rx_state_s
{
/*! Optional callback funcion to deliver received digits. */
tone_report_func_t callback;
/*! An opaque pointer passed to the callback function. */
void *callback_data;
/*! TRUE is we are detecting forward tones. FALSE if we are detecting backward tones */
int fwd;
/*! Tone detector working states */
goertzel_state_t out[6];
/*! The current sample number within a processing block. */
int current_sample;
/*! The currently detected digit. */
int current_digit;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,92 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/bert.h - Bit error rate tests.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2004 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bert.h,v 1.2 2009/04/14 16:04:54 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_BERT_H_)
#define _SPANDSP_PRIVATE_BERT_H_
typedef struct
{
uint32_t reg;
int step;
int step_bit;
int bits;
int zeros;
} bert_tx_state_t;
typedef struct
{
uint32_t reg;
uint32_t ref_reg;
uint32_t master_reg;
int step;
int step_bit;
int resync;
int bits;
int zeros;
int resync_len;
int resync_percent;
int resync_bad_bits;
int resync_cnt;
int report_countdown;
int measurement_step;
} bert_rx_state_t;
/*!
Bit error rate tester (BERT) descriptor. This defines the working state for a
single instance of the BERT.
*/
struct bert_state_s
{
int pattern;
int pattern_class;
bert_report_func_t reporter;
void *user_data;
int report_frequency;
int limit;
uint32_t mask;
int shift;
int shift2;
int max_zeros;
int invert;
int resync_time;
int decade_ptr[9];
int decade_bad[9][10];
int error_rate;
bert_tx_state_t tx;
bert_rx_state_t rx;
bert_results_t results;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,44 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/bitstream.h - Bitstream composition and decomposition routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2006 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: bitstream.h,v 1.1.4.1 2009/12/28 12:20:47 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_BITSTREAM_H_)
#define _SPANDSP_PRIVATE_BITSTREAM_H_
/*! Bitstream handler state */
struct bitstream_state_s
{
/*! The bit stream. */
uint32_t bitstream;
/*! The residual bits in bitstream. */
int residue;
/*! TRUE if the stream is LSB first, else MSB first */
int lsb_first;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,111 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/dtmf.h - DTMF tone generation and detection
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001, 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dtmf.h,v 1.1 2008/10/13 13:14:01 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_DTMF_H_)
#define _SPANDSP_PRIVATE_DTMF_H_
/*!
DTMF generator state descriptor. This defines the state of a single
working instance of a DTMF generator.
*/
struct dtmf_tx_state_s
{
tone_gen_state_t tones;
float low_level;
float high_level;
int on_time;
int off_time;
union
{
queue_state_t queue;
uint8_t buf[QUEUE_STATE_T_SIZE(MAX_DTMF_DIGITS)];
} queue;
};
/*!
DTMF digit detector descriptor.
*/
struct dtmf_rx_state_s
{
/*! Optional callback funcion to deliver received digits. */
digits_rx_callback_t digits_callback;
/*! An opaque pointer passed to the callback function. */
void *digits_callback_data;
/*! Optional callback funcion to deliver real time digit state changes. */
tone_report_func_t realtime_callback;
/*! An opaque pointer passed to the real time callback function. */
void *realtime_callback_data;
/*! TRUE if dialtone should be filtered before processing */
int filter_dialtone;
#if defined(SPANDSP_USE_FIXED_POINT)
/*! 350Hz filter state for the optional dialtone filter. */
float z350[2];
/*! 440Hz filter state for the optional dialtone filter. */
float z440[2];
/*! Maximum acceptable "normal" (lower bigger than higher) twist ratio. */
float normal_twist;
/*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio. */
float reverse_twist;
/*! Minimum acceptable tone level for detection. */
int32_t threshold;
/*! The accumlating total energy on the same period over which the Goertzels work. */
int32_t energy;
#else
/*! 350Hz filter state for the optional dialtone filter. */
float z350[2];
/*! 440Hz filter state for the optional dialtone filter. */
float z440[2];
/*! Maximum acceptable "normal" (lower bigger than higher) twist ratio. */
float normal_twist;
/*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio. */
float reverse_twist;
/*! Minimum acceptable tone level for detection. */
float threshold;
/*! The accumlating total energy on the same period over which the Goertzels work. */
float energy;
#endif
/*! Tone detector working states for the row tones. */
goertzel_state_t row_out[4];
/*! Tone detector working states for the column tones. */
goertzel_state_t col_out[4];
/*! The result of the last tone analysis. */
uint8_t last_hit;
/*! The confirmed digit we are currently receiving */
uint8_t in_digit;
/*! The current sample number within a processing block. */
int current_sample;
/*! The number of digits which have been lost due to buffer overflows. */
int lost_digits;
/*! The number of digits currently in the digit buffer. */
int current_digits;
/*! The received digits buffer. This is a NULL terminated string. */
char digits[MAX_DTMF_DIGITS + 1];
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,94 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/echo.h - An echo cancellor, suitable for electrical and acoustic
* cancellation. This code does not currently comply with
* any relevant standards (e.g. G.164/5/7/8).
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: echo.h,v 1.1 2009/09/22 13:11:04 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_ECHO_H_)
#define _SPANDSP_PRIVATE_ECHO_H_
/*!
G.168 echo canceller descriptor. This defines the working state for a line
echo canceller.
*/
struct echo_can_state_s
{
int tx_power[4];
int rx_power[3];
int clean_rx_power;
int rx_power_threshold;
int nonupdate_dwell;
int curr_pos;
int taps;
int tap_mask;
int adaption_mode;
int32_t supp_test1;
int32_t supp_test2;
int32_t supp1;
int32_t supp2;
int vad;
int cng;
int16_t geigel_max;
int geigel_lag;
int dtd_onset;
int tap_set;
int tap_rotate_counter;
int32_t latest_correction; /* Indication of the magnitude of the latest
adaption, or a code to indicate why adaption
was skipped, for test purposes */
int32_t last_acf[28];
int narrowband_count;
int narrowband_score;
fir16_state_t fir_state;
/*! Echo FIR taps (16 bit version) */
int16_t *fir_taps16[4];
/*! Echo FIR taps (32 bit version) */
int32_t *fir_taps32;
/* DC and near DC blocking filter states */
int32_t tx_hpf[2];
int32_t rx_hpf[2];
/* Parameters for the optional Hoth noise generator */
int cng_level;
int cng_rndnum;
int cng_filter;
/* Snapshot sample of coeffs used for development */
int16_t *snapshot;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,50 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/fax.h - private definitions for analogue line ITU T.30 fax processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2005 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax.h,v 1.1 2008/10/13 13:14:01 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_FAX_H_)
#define _SPANDSP_PRIVATE_FAX_H_
/*!
Analogue line T.30 FAX channel descriptor. This defines the state of a single working
instance of an analogue line soft-FAX machine.
*/
struct fax_state_s
{
/*! \brief The T.30 back-end */
t30_state_t t30;
/*! \brief The analogue modem front-end */
fax_modems_state_t modems;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,127 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/fax_modems.h - definitions for the analogue modem set for fax processing
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2008 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fax_modems.h,v 1.4 2009/09/04 14:38:47 steveu Exp $
*/
/*! \file */
#if !defined(_SPANDSP_PRIVATE_FAX_MODEMS_H_)
#define _SPANDSP_PRIVATE_FAX_MODEMS_H_
/*!
The set of modems needed for FAX, plus the auxilliary stuff, like tone generation.
*/
struct fax_modems_state_s
{
/*! TRUE is talker echo protection should be sent for the image modems */
int use_tep;
/*! If TRUE, transmit silence when there is nothing else to transmit. If FALSE return only
the actual generated audio. Note that this only affects untimed silences. Timed silences
(e.g. the 75ms silence between V.21 and a high speed modem) will alway be transmitted as
silent audio. */
int transmit_on_idle;
/*! \brief An HDLC context used when transmitting HDLC messages. */
hdlc_tx_state_t hdlc_tx;
/*! \brief An HDLC context used when receiving HDLC messages. */
hdlc_rx_state_t hdlc_rx;
/*! \brief A V.21 FSK modem context used when transmitting HDLC over V.21
messages. */
fsk_tx_state_t v21_tx;
/*! \brief A V.21 FSK modem context used when receiving HDLC over V.21
messages. */
fsk_rx_state_t v21_rx;
/*! \brief A V.17 modem context used when sending FAXes at 7200bps, 9600bps
12000bps or 14400bps */
v17_tx_state_t v17_tx;
/*! \brief A V.29 modem context used when receiving FAXes at 7200bps, 9600bps
12000bps or 14400bps */
v17_rx_state_t v17_rx;
/*! \brief A V.29 modem context used when sending FAXes at 7200bps or
9600bps */
v29_tx_state_t v29_tx;
/*! \brief A V.29 modem context used when receiving FAXes at 7200bps or
9600bps */
v29_rx_state_t v29_rx;
/*! \brief A V.27ter modem context used when sending FAXes at 2400bps or
4800bps */
v27ter_tx_state_t v27ter_tx;
/*! \brief A V.27ter modem context used when receiving FAXes at 2400bps or
4800bps */
v27ter_rx_state_t v27ter_rx;
/*! \brief Used to insert timed silences. */
silence_gen_state_t silence_gen;
/*! \brief CED or CNG generator */
modem_connect_tones_tx_state_t connect_tx;
/*! \brief CED or CNG detector */
modem_connect_tones_rx_state_t connect_rx;
/*! \brief */
dc_restore_state_t dc_restore;
/*! \brief The currently select receiver type */
int current_rx_type;
/*! \brief The currently select transmitter type */
int current_tx_type;
/*! \brief TRUE if a carrier is present. Otherwise FALSE. */
int rx_signal_present;
/*! \brief TRUE if a modem has trained correctly. */
int rx_trained;
/*! \brief TRUE if an HDLC frame has been received correctly. */
int rx_frame_received;
/*! The current receive signal handler */
span_rx_handler_t *rx_handler;
/*! The current receive missing signal fill-in handler */
span_rx_fillin_handler_t *rx_fillin_handler;
void *rx_user_data;
/*! The current transmit signal handler */
span_tx_handler_t *tx_handler;
void *tx_user_data;
/*! The next transmit signal handler, for two stage transmit operations.
E.g. a short silence followed by a modem signal. */
span_tx_handler_t *next_tx_handler;
void *next_tx_user_data;
/*! The current bit rate of the transmitter. */
int tx_bit_rate;
/*! The current bit rate of the receiver. */
int rx_bit_rate;
/*! If TRUE, transmission is in progress */
int transmit;
/*! \brief Audio logging file handle for received audio. */
int audio_rx_log;
/*! \brief Audio logging file handle for transmitted audio. */
int audio_tx_log;
/*! \brief Error and flow logging control */
logging_state_t logging;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,100 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/fsk.h - FSK modem transmit and receive parts
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: fsk.h,v 1.5 2009/04/01 13:22:40 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_FSK_H_)
#define _SPANDSP_PRIVATE_FSK_H_
/*!
FSK modem transmit descriptor. This defines the state of a single working
instance of an FSK modem transmitter.
*/
struct fsk_tx_state_s
{
int baud_rate;
/*! \brief The callback function used to get the next bit to be transmitted. */
get_bit_func_t get_bit;
/*! \brief A user specified opaque pointer passed to the get_bit function. */
void *get_bit_user_data;
/*! \brief The callback function used to report modem status changes. */
modem_tx_status_func_t status_handler;
/*! \brief A user specified opaque pointer passed to the status function. */
void *status_user_data;
int32_t phase_rates[2];
int16_t scaling;
int32_t current_phase_rate;
uint32_t phase_acc;
int baud_frac;
int shutdown;
};
/*!
FSK modem receive descriptor. This defines the state of a single working
instance of an FSK modem receiver.
*/
struct fsk_rx_state_s
{
int baud_rate;
/*! \brief Synchronous/asynchronous framing control */
int framing_mode;
/*! \brief The callback function used to put each bit received. */
put_bit_func_t put_bit;
/*! \brief A user specified opaque pointer passed to the put_bit routine. */
void *put_bit_user_data;
/*! \brief The callback function used to report modem status changes. */
modem_tx_status_func_t status_handler;
/*! \brief A user specified opaque pointer passed to the status function. */
void *status_user_data;
int32_t carrier_on_power;
int32_t carrier_off_power;
power_meter_t power;
/*! \brief The value of the last signal sample, using the a simple HPF for signal power estimation. */
int16_t last_sample;
/*! \brief >0 if a signal above the minimum is present. It may or may not be a V.29 signal. */
int signal_present;
int32_t phase_rate[2];
uint32_t phase_acc[2];
int correlation_span;
complexi32_t window[2][FSK_MAX_WINDOW_LEN];
complexi32_t dot[2];
int buf_ptr;
int frame_state;
int frame_bits;
int baud_phase;
int last_bit;
int scaling_shift;
};
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -0,0 +1,41 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* private/g711.h - In line A-law and u-law conversion routines
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2001 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: g711.h,v 1.2 2009/04/12 09:12:11 steveu Exp $
*/
#if !defined(_SPANDSP_PRIVATE_G711_H_)
#define _SPANDSP_PRIVATE_G711_H_
/*!
G.711 state
*/
struct g711_state_s
{
/*! One of the G.711_xxx options */
int mode;
};
#endif
/*- End of file ------------------------------------------------------------*/

Some files were not shown because too many files have changed in this diff Show More