WIRELESS INSTANT VOICE MESSAGING USING THE INTERNET
By
CARLOS A. RIVERA-CINTRON
A THESIS PRESENTED TO THE GRADUATE SCHOOLOF THE UNIVERSITY OF FLORIDA IN PARTIAL FULFILLMENT
OF THE REQUIREMENTS FOR THE DEGREE OFMASTER OF SCIENCE
UNIVERSITY OF FLORIDA
2000
I dedicate this work to my loving wife, Odemaris, our daughter Adriana Maria,
our soon to be born child, and my relatives in Puerto Rico. Thanks for your patience,
and understanding (Los Amo!).
iii
ACKNOWLEDGMENTS
Above all, I thank God for providing me the resources, health, courage and
strength necessary to start and complete this work.
Also, my deepest gratitude goes to my managers and colleagues at Motorola for
their financial and technical support.
iv
TABLE OF CONTENTS
ACKNOWLEDGMENTS..............................................................................................iii
ABSTRACT..................................................................................................................vii
CHAPTERS
1 THESIS INTRODUCTION AND MOTIVATION .................................................... 1
1.1 Voice Messaging Introduction .............................................................................. 11.2 Voice Messaging Systems..................................................................................... 1
1.2.1 History of Paging............................................................................................ 11.2.2 The Messaging Device ................................................................................... 3
1.3 Voice Messaging Using The Internet .................................................................... 51.4 Wireless Voice Messaging – Thesis Motivation................................................... 61.5 Wireless Voice Messaging Components............................................................... 71.6 System Requirements .......................................................................................... 10
2 TRANSMITTING VOICE OVER AN INTERNET BASED NETWORK.............. 13
2.1 Voice Into The Computer.................................................................................... 132.2 Classes Of Codecs............................................................................................... 14
2.2.1 Waveform Codecs ........................................................................................ 142.2.2 Source Codecs .............................................................................................. 152.2.3 Hybrid Codecs.............................................................................................. 16
2.3 Codec Intelligibility Vs Naturalness ................................................................... 172.4 Voice Over IP Version 6 ..................................................................................... 19
2.4.1 Mobility support - AutoConfiguration ......................................................... 202.4.2 Quality of Service (QoS) - Multimedia features .......................................... 212.4.3 IPv6 Header.................................................................................................. 21
2.5 H.323................................................................................................................... 232.6 Quality Of Service Issues For Voice Over Packet Networks .............................. 25
2.6.1 Delay ............................................................................................................ 252.6.2 Jitter.............................................................................................................. 262.6.3 Lost Packets.................................................................................................. 27
2.7 Summary ............................................................................................................. 28
3 VOICE MESSAGING CLIENT ............................................................................... 30
3.1 Introduction ......................................................................................................... 303.2 Voice Messaging Client Software – The OS....................................................... 313.3 Voice Messaging Client Software – The Application......................................... 32
v
3.4 COM and ATL .................................................................................................... 333.4.1 Voice Messaging Client Software Explained with COM ............................ 413.4.2 Voice Messaging Client Software Events .................................................... 47
3.5 Summary ............................................................................................................. 48
4 WIRELINE TO WIRELESS INTERNET GATEWAY ........................................... 50
4.1 Introduction ......................................................................................................... 504.2 Mobile IP............................................................................................................. 514.3 iDEN Overview and Architecture ....................................................................... 544.4 GPRS Overview and Architecture ...................................................................... 564.5 Summary ............................................................................................................. 57
5 WIRELESS INTERNET VOICE MESSENGER ..................................................... 59
5.1 Introduction ......................................................................................................... 595.2 Wireless Voice Messenger Server – The OS ...................................................... 605.3 Wireless Voice Messenger Server – The Application Software ......................... 615.4 Wireless IP Network Interface - RF Modem....................................................... 68
5.4.1 PPP and IP address publication via a Mobile IP capable RF modem .......... 735.4.2 PPP and IP address publication via a GPRS capable RF modem ................ 75
5.5 Summary ............................................................................................................. 76
6 SYSTEM IMPLEMENTATION AND PERFORMANCE ANALYSIS.................. 77
6.1 Introduction ......................................................................................................... 776.2 Software Components ......................................................................................... 77
6.2.1 Instant Voice Messaging Client ................................................................... 776.2.2 Instant Voice Messaging Server................................................................... 82
6.3 Hardware/System Components ........................................................................... 856.3.1 Instant Voice Messaging Client Hardware/Systems .................................... 856.3.2 Instant Voice Messaging Server Hardware/Systems.................................... 85
6.4 Performance Analysis.......................................................................................... 866.5 Summary ............................................................................................................. 93
7 FURTHER WORK ................................................................................................... 95
7.1 Introduction ......................................................................................................... 957.2 Reverse Channel.................................................................................................. 95
7.2.1 Requirements................................................................................................ 967.2.2 Implementation Details for Server ............................................................... 96
7.3 Alternative to Real Time IP Telephony............................................................... 977.4 High Compression Codec.................................................................................... 98
8 CONCLUSION ....................................................................................................... 100
vi
APPENDICES
A SCREEN CAPTURES OF VMC AND VMS .................................................................... 102
B VOICE MESSAGING CLIENT AND VOICE MESSAGING SERVER SOURCE CODE.......... 111
B.1 Voice Messaging Client Source Code .............................................................. 111B.1.1 Gui Dll ....................................................................................................... 111B.1.2 Record Dll.................................................................................................. 125B.1.3 VoiceSender Dll ........................................................................................ 178
B.2 Voice Messaging Server Source Code.............................................................. 186B.2.1 VmsConsole Exe ....................................................................................... 186B.2.2 Playback Dll............................................................................................... 192
C EXPERIMENTS RESULTS............................................................................................ 245
C.1 Ping Performance In Drive Experiment............................................................ 245C.2 Boynton (client) Boynton (server), 50kB file transfer using 576 byte buffer... 246C.3 Boynton (client) Gainesville (server) 25kB file transfer, at 1 byte per chunk.. 250
REFERENCES............................................................................................................ 259
BIOGRAPHICAL SKETCH....................................................................................... 262
vii
Abstract of Thesis Presented to the Graduate SchoolOf the University of Florida in Partial Fulfillment of the
Requirements for the Degree of Master of Science
WIRELESS INSTANT VOICE MESSAGING USING THE INTERNET
By
Carlos A. Rivera-Cintron
May 2000
Chairman: Dr. Haniph LatchmanMajor Department: Electrical and Computer Engineering
"Communication is the successful transfer of information" - Dr. Haniph Latchman
If communication is the successful transfer of information then one of the most
effective and efficient ways of transferring the information must be the human voice.
When talking, human beings show an emotion in the voice, which is hardly reproducible
by any electronic or mechanical device. In our fast moving society the need for
information acquisition has fueled the development of mobile communication devices
which use the human voice as the medium to communicate. With the fast spread of the
Internet and the World Wide Web, for which the number of computers in US households
growing at 15% per year, and Internet access growing 100% per year (source,
International Engineering Consortium), it is obvious why voice communications have
merged with the Internet. New wireless systems to be deployed in the year 2000 will be
packet based, relying solely on an IP packet network mode which will not be circuit
viii
switched but purely packet switched. These mobile devices will have their own IP
address no matter where the device is linked to the Internet, so applications that perform
server functions will be able to run in these mobile servers. One such application is a
wireless IP voice messenger, where a message can be sent to the IP address of a mobile
user, without having to access a 3rd server in charge of looking up the mobile server, and
while the user is using the device in a data call connected to the WWW.
This thesis work presents the study of the systems used to transfer instant voice
messages from a wireline Internet network to a wireless Internet device, using wireless IP
technology. Because the voice message has to be digitized, packetized, entered and
delivered via the Internet, Voice Over IP (VoIP) systems are presented as a model of
study and reference for the design of the messaging system. We also look at the current
voice compression technology. Once the voice message is on the Internet it has to be
transmitted over the air to the receiving device, so a description of the interface between
the wireline and wireless Internet networks is included.
The wireless, packet based IP system is compared to a commercially available,
user name based messaging system over a dial-up circuit switched connection. The
system developed permits sending instant voice messages to wireline or wireless servers,
with fixed or dynamic IP addresses. Several performance measurements are performed to
analyze the packet transfer and ping performance over the wireless interface.
1
CHAPTER 1THESIS INTRODUCTION AND MOTIVATION
1.1 Voice Messaging Introduction
Two different types of messaging applications have been introduced: text and
voice paging. Voice messaging has some advantages, in most applications, over
conventional data only messaging: voice communicates messages most naturally, is
easiest for message sender to use, might identify sender, and voice tone can convey
urgency (or lack of) [1].
To better understand the current state of the art in voice messaging, this chapter
will present a historical background into voice messaging applications and its origins. It
will also introduce the theoretical components of a modern voice messaging system
solution, along with the requirements to be researched and developed in this thesis.
1.2 Voice Messaging Systems
1.2.1 History of Paging
The voice messaging industry can trace its origins to the 1st half of the 20th
century, when police departments, government agencies and the armed forces in the USA
used voice based land-mobile radio systems to broadcast 1 way voice. These systems
used powerful transmitters to broadcast (every so many minutes) the voice messages from
2
a base station to the mobile units. An operator was used to receive all the incoming
messages, which were taped, put in a queue, and transmitted at the scheduled time. All
the subscribed units to that network were to tune in at the specified time to listen to all the
messages in queue and check if a message was intended for him. This mechanism, also
called non-selective operator assisted paging, wasted airtime and did not provide privacy
to the subscriber, although it sufficed the intended application. The second generation of
paging involved selective operator assisted paging [1]. Here tone messages are
transmitted to a specific subscriber unit to let it know that there is a recorded message
waiting in the system.
Until the 1970s, operators were required to record and playback the voice
messages, because pagers were designed to decode its identification number but not the
actual message. When pagers became feature rich (with the advent of more memory and
faster processors), automatic paging became the next step in the paging industry. Now,
pagers were designed to decode its address and a voice message. This brought changes to
the message entry point. A phone number was assigned to the subscriber unit, and the
paging terminal could prompt the user for the voice message input. The message is
relayed to the actual unit, which in turn would alert then playback the message (between
10 and 20 seconds of voice) [1]. The advantages of this system were that the user gets
voice message with alert, and that there was no need to make a telephone call to get
message. From this point, pagers evolved to more memory and the message that arrived
could be stored and playback later.
The original protocol used for transferring the voice message over the air was 5/6
tone, a combination of analog and FM modulation with a frequency carrier range from 30
3
MHz to 512 MHz [2]. A series of combined audio tones are used to identify each pager.
This voice paging protocol also supports a battery-saver option, which by time sharing
page reception to groups of pagers; it can accommodate up to a 1 million pagers in a
system [1].
The current state of the technology in voice messaging is the InFLEXion™ digital
protocol, which works nationwide on the 900MHz NPCS (narrowband PCS) frequency
band with 25kHz channels. It is also a 2 way (acknowledge only) with guaranteed
message delivery. By allowing the subscriber unit to register itself into the geographic
zone it is currently located, InFLEXion™ protocol enables the infrastructure system to
send the messages to the unit via its closest transmitter, saving precious bandwidth.
Modern message entry systems require that the user call the paging service
provider through the POTS system and enter the pager's identification number and the
intended message. Using DTMF tones, the service provider software deciphers the pager
address. A wireline to over the air system takes the message and the identification
number and send them over the air. It can be seen that with the use of a cellular phone,
the service provider’s message entry point is accessible from virtually any major city in
the world (assuming satellite coverage is available).
1.2.2 The Messaging Device
The simplest form of messaging is for a mobile user to carry a small wireless
device (about palm size), which is programmed with an identification number. These
devices have been commonly known as beepers and pagers. Beeper because the typical
alert given to the user is of the form of an audible, high frequency sound. The name
4
pager was used because the devices were commonly used to “page” or call doctors or
other professionals.
A contemporary two-way pager contains the circuitry shown in figure 1.1 [3]:
The transceiver section is designed to up convert a baseband signal to RF output, and to
down convert RF input into a baseband signal. The receiver section of the transceiver is
typically a dual conversion RF demodulator with an operation similar to the
superheterodyne receiver of figure 4-29 in reference [4]. The transmitter section of the
transceiver is similar to the one shown in figure 1.2 [4,5].
Transceiver Decoder Host
Signal
Control
InterfacingAPI
Fig. 1.1 Pager system block diagram
RF driverand poweramp
Referenceoscillator
Synthesizer
Fig. 1.2 Transceiver system block diagram
Data fromdecoder
Voltagecontrolledoscillator
5
The decoder subsystem consists of a microcontroller that controls all the
processing of the paging protocol. The host subsystem is in charge of interfacing to the
user via a set of peripherals (screen, buttons, etc.).
1.3 Voice Messaging Using The Internet
It was mentioned in the last section that with the growth and widespread use of
cellular phones, the message entry point for paging systems has expanded. A question
one would ask, what if we want to send voice messages to the cell phone user? It is well
known that voice and text messaging are preferred for most users. The European cellular
telephony standard GSM and its Short Message Service (SMS) feature, among others,
attempt to fill the need for a voice and text message mobile device. SMS allows a
cellular service subscriber to receive text messages to the wireless device. Voice usage is
only available via the circuit switched system, which is expensive for voice messaging. It
is also known that a very practical and popular usage of cellular phones is to do dialup
connections to the Internet via an Internet Service Provider. So the next question one
would ask is, how can voice messages be sent to a cell phone user via a packet based
network, where billing is based on amount of data received not on the time while the call
is in progress? Of course, we would like to do this while leveraging on the success of
previous technologies (such as IP). IP based voice messaging compared to user name
voice messaging (as it is used in most commercial applications like: ICQ, Yahoo!, AOL)
is more efficient in terms of network resources required to complete the message transfer,
because it only involves the computer sending the message and the computer receiving it
6
plus the routers required to transfer the IP packets. In user name based applications, a
third computer is needed, namely the Resource Location Protocol (RLP) server, where
both the client and message receiver have to be connected to prior to any messages being
transferred. In IP based messaging, the client (namely the message sender) and server
(message receiver) do not have to be connected to a common server or even connected to
the Internet via a common ISP.
The technology that will allow these IP address interactions to be executed
seamlessly is the wireless Internet.
1.4 Wireless Voice Messaging – Thesis Motivation
Several technologies exist today that bring the Internet to wireless; for example,
Cellular Digital Packet Data (CDPD) which uses unused radio channels over the analog
cellular telephone system in the USA, and cellular circuit switched data which involves
the placing of a cellular telephone call to a dial-up access server. In CDPD, a permanent
IP address to be used over the entire CDPD network is assigned to the subscriber. The
billing mode in CDPD is per packet transmitted and received. In cellular circuit switched
data, where billing is on a per minute basis, the cellular phone works as a RF modem
(physical layer) for a TCP/IP/PPP (session/network/link layers) stack where the IP
address is dynamically assigned to the IP layer on each dial-up connection (a PPP
negotiated address). Also, more recent technologies being prepared to be deployed in the
year 2000 and beyond are the General Packet Radio Services (GPRS) for GSM, and
UMTS2000. These technologies promise the user higher connection speeds and per
7
packet billing. For more information on 3G cellular protocols and their applications to
multimedia services, see Sanchez [6].
The work to be developed in this thesis leverages on the next generation wireless
packet data protocols like GPRS and Mobile IP to demonstrate how the Internet is a great
(in terms of widespread and economical) medium to merge voice and data messaging for
wireless devices. Because the Internet already supports data messaging protocols (in the
form e-mail and WWW browsing), the thesis is focused on the voice messaging part.
1.5 Wireless Voice Messaging Components
The system that delivers voice messages via the Internet to a wireless device
requires the minimum number of components shown in figure 1.3:
8
Voice MessagingClient (VMC)
Wireline to WirelessInternetGateway(WiWls)
WirelineInternetVoice Messaging
Server (VMS)
Figure 1.3 Voice Messaging Components
The functionality of each component is described as:
1. VMC = a computer system connected to the Internet which allows a user to send voice
messages to a wireless voice device (which will be known in this thesis as voice
messaging server). The VMC is referred to as a client because it solicits the service of
voice playback from the server device. The basic components of a VMC are:
- VMC Software = provides user interface, high-level network access (via TCP
another or session layer protocol), subscriber units database management (IP
9
address), voice compression/decompression to send/receive over IP,
diagnostics for system checks.
- Network Operating System = provides peripheral resource allocation to VMC
software, low-level network access, file and database access. Provides the
software drivers for the presentation, session, transport and the network layers
of the ISO/OSI computer networks model [7].
- Voice Capture Device = sound to electrical signal conversion device used to
allow the analog real world message to enter the VMS software.
- Network Interface Card = provides the network, data link control, and physical
layers of the ISO/OSI computer networks model [7].
- NDIS (Network Device Interface Specification) = software mechanism to
allow communication between the NIC and the Network Operating System
[8].
2. Wireline to Wireless Gateway (WiWls) = a computer system connected to the wireline
Internet on one side, and to a wireless Internet on another. It receives digitized voice
messages from a wireline Internet client and sends them to a wireless device via a
wireless Internet network. The basic components of a VMC are:
- WiWls Software = provides the mechanism to receive the voice packets from
the NIC, queue them and send them to the VMT using the wireless Internet
protocol.
- RF transceiver = over the air transceiver for a wireless Internet network.
Receives packets from the WiWls software and sends them over the air, at a
specified radiated power level. The radiated power level is a directly
10
proportional to the coverage area. It implements the physical layer of the
wireless Internet protocol.
3. Wireless Voice Messaging Server = addressable, portable, wireless communication
device capable of receiving a message over the air, processing and displaying it in the
form of voice. This device is known as a voice messaging server, because it provides the
service of voice playback for a client originated voice message.
1.6 System Requirements
In the scenario proposed, a wireless device (cellular telephone) is connected to a
wireless Internet network (with higher layer protocols from PPP all the way to TCP
provided by a high power controller), which makes it capable of receiving any type of
packetized data (including packetized voice!). The following are the
functional/operational requirements:
- Robust, reliable TCP oriented transport protocol, over a packet based,
economical IP
- Low bit rate (small voice file) to allow short session times and reduce power
consumption in the mobile device
- Synchronous, fast air interface that minimizes transmitter key up, and reduce
power consumption
- Modular, component based software architecture in client (message sender)
and server (message receiver) to allow for easier development and
maintenance
11
- Target platform for software shall be a common and popular one
The low level usage requirements are defined as:
- Human interface to VMC computer (operator speaking to subscriber) with a
push to talk button
- After the push to talk button is pressed, the message is digitized using a codec
method
- Digital audio message transmission on the Internet interface
- Wireless Internet gateway to IP interface software needs to find the mobile
user and route the packets to the final destination.
- Wireless IP device transceiver interface - using a wireless modem or smart
phone (IP transceiver interface), the device software is of the server type. It is
waiting for a connection from the client (the VMC) to store and playback
later, a voice message.
- GUI interface to wireless device user to indicate status of messages received.
Now that we have laid down the work to be presented, we need to start answering
a few questions to get the system up and running. How does a voice message gets
packaged to be sent via the Internet? What are the different codecs available, and which
one suites best for a messaging (non real-time) application? Chapter 2 explains how to
transmit voice over data networks, concentrating on different issues and solutions
surrounding the different components of the system (voice capture to transmission to
playback).
12
Chapter 3 describes in detail the Voice Messaging Client (VMC) and its
components. In Chapter 4, it is presented an in- depth look at a wireline to wireless
Internet gateway and how mobiles are found in the network and how packets are routed to
and from it. Chapter 5 presents the inner workings and operation of the wireless Internet
messengers (the wireless device). Finally, Chapter 6 presents the specifications a dial-up
(circuit switched) messaging systems which uses IP over a cellular network. Chapters 7
to 8 present further works suggested, and conclusion remarks on the proposed solutions.
13
CHAPTER 2TRANSMITTING VOICE OVER AN INTERNET BASED NETWORK
2.1 Voice Into The Computer
In Chapter 1 it was presented that the interface to the wireless voice-messaging
client needed a voice capture device. Voice is an analog (continuous) entity and to allow
a sample to be transmitted via a packetized network such as the Internet, it must be
digitally processed with a special hardware/software system called a codec. A codec is
made up of a voice encoder and a voice decoder. The voice encoder resides in the voice
capture device and is in charge of sampling the analog voice into digital samples that can
be stored and transmitted inside a computer. The voice capture device uses elementary
hardware such as a microphone transducer to convert the human generated voice into an
analog electrical signal. On the other side, the voice decoder resides in the voice
playback device, and is in charge of decoding the digital samples while attempting to
reproduce the original voice sample. The voice playback device uses a speaker
transducer to convert the reproduced electrical signal into human hearable form.
Let's study a numerical example to determine the computing requirements for a
codec system. To digitally capture a human voice sample, the Plain Old Telephone
System (a.k.a. POTS) uses a bandwidth of 4kHz [9]. The Nyquist sampling rate of 2B
(where B=4kHz is the maximum frequency component of the speech waveform) has been
proven to be the minimum sampling rate allowed for reconstructing an analog waveform
14
from its digital samples. Consequently, for human speech a sampling rate of 8kHz is
used. Now, with how much digital data should a voice sample be represented with?
Larkin [9] explains that, typically, voice is quantized with 8 bits of data, creating a
transfer bit rate of 64kbps. Due to this massive size of digital audio data, and because
certain network communications pipes (like modems) get "clogged" at higher bit tares,
codecs usually involve more complex levels of compression to reduce the bit rate
required for a certain Quality of Service (QoS). Depending on the compression
implemented, codecs are classified as waveform, source, or hybrid. In the next section
we will explain the operation of these codecs.
2.2 Classes Of Codecs
2.2.1 Waveform Codecs
Waveform codecs attempt to gather enough data about the original sound wave so
as to reproduce it with high quality. Any sound (speech and music, among others) can be
recorded and played back because these codecs sample and store the actual data. Also,
because most of the information is contained in the sampled audio, the algorithm is not as
complex, and a dedicated processor is not required to implement the codec [10].
The PCM codec in the Microsoft Windows 98/NT systems is one of the waveform
codecs. Pulse Code Modulation (PCM) was developed by Alec H. Reeves in the mid
1930's [11]. It was developed to seek a modulation technique for the newly developed
microwave links, but its use has spread to digital speech processing. The Microsoft
Windows NT/95/98 PCM Codec is configurable for sampling rates ranging from 8kHz to
15
44.1 kHz, and 8 to 16 bits of sample size. The PCM process is divided into 3 major
steps: sampling, quantizing and encoding. After the sampling is complete, the sampled
word is quantized (mapped) into the closest, predetermined step. This quantizing
operation produces "quantization noise,” which can be considered as a round-off error
[5]. The encoding operation then assigns a code to each quantized value. The main
disadvantage of using the PCM codec for voice transmission over a packetized network is
the high bandwidth requirement. Couch [5] shows that the bandwidth of the PCM signal
is larger, by a factor of twice the number of bits in the PCM word, that the one of the
original speech waveform.
2.2.2 Source Codecs
Source codecs sample the speech waveform, and then attempt to create a
representation (model) of how the sound was generated. During playback, the sound
model, not the original sampled waveform data, is used to reconstruct the original speech.
In fact, source codecs discard the original sampled waveform data completely. Source
codecs use electrical excitations that are then modified by a linear filter, which is a simple
and effective way of modeling the human voice system [9]. Vocoders, which are used
extensively in digital cellular telephony (like the GSM vocoder implemented by Troy
[12]), are the most common of the source codecs. The Code Division Multiple Access
(CDMA) cellular protocol uses a variable rate vocoder. The actual bit rate used is
determined via adaptive thresholds. By using a voice detection mechanism, the
thresholds are used to assign the higher vocoder rates for the phone user speech, even
when the background is noisy. CDMA can vary their bit rate from full to 1/2, 1/4, and
16
1/8 of the available rate. The full rate for a rate 1 system is an 8kbps vocoder, operating
in a 9.6kbps data channel [13]. The main advantage of the vocoder is that, because they
save a small portion of the original message characteristics, they produce small voice
message sizes so a lower bit rate can be achieved. On the other hand, the main
disadvantage to using vocoders is that the excitations are based on pre-programmed
human voice patterns, so the output tends to be artificial, and it does not work well on
anything else but human speech. In a later section we will explore what is currently being
done to improve speech naturalness and intelligibility.
2.2.3 Hybrid Codecs
The last type of codec to study here is the hybrid codec. As the name implies,
these are codecs that use elements of waveform and source codecs to attempt to
synthesize (like in vocoders) the human voice by selecting a preprogrammed electrical
excitation based on the actual speech waveform (which, like in PCM, is not immediately
discarded). Hybrid (also called stochastic) codecs are more complex and with less
reproduction quality than waveform codecs, but they are simpler and with better quality
than vocoders [10]. The hybrid codec contains 3 main components that carry out these
functions [12]:
1. Synthesis filter = shaping filter which maps a speech sample into a
comparable signal.
2. Encoder = feeds potential excitation signals until the output has the minimal
error compared to the output of the synthesis filter. The excitation signals are
17
stored in a codebook. The address of the excitation vector in the codebook is
sent to the next element, the decoder.
3. Decoder = contains the identical codebook as the encoder. Receives the
excitation vector codebook address, and looks up the actual excitation signal
required to recreate the original speech.
The Code Excitation LP (CELP) codecs are the most commonly used hybrid
codecs [12]. They use a Vector Quantization scheme, which is the method of sending
over the air the address of the excitation signal instead of the actual voice sample. The
excitation signal is stored in a codebook in the encoder and in the decoder. Several types
of codebooks exist, among them: overlapped, sparse excitation, lattice and trained. See
[12] for a more thorough description of these.
The Glottal Excitation LP (GELP) algorithm for codecs is intended to improve
speech naturalness by using a model that interacts between the voice source and the filter
that simulates the voice tract. It is currently being researched by Charoenruengkit [14] for
usage in real-time voice communications. The next section shows the issue of speech
naturalness and intelligibility.
2.3 Codec Intelligibility Vs Naturalness
Recent advancements in codec development have made them well suited for all
type of voice processing applications. However, the ever-present challenge of
representing the human voice in a natural, accurate and intelligible manner is pushing
research to understand and improve the intelligibility and naturalness of speech
18
processing systems. Roy [12] mentioned that in the CELP codecs, the adaptive and
stochastic codebooks are used to time shift the excitation waveform, which in turn
provides the right "pitch" for the voice sample. One research being conducted by
Childers and Wong [15] attempts to improve speech naturalness by creating a speech
model where the vocal source and the vocal tract interact. Naturalness is believed to
depend on the characteristics of the excitation waveform to reproduce voice sounds,
which will be dependent on the codec ability to store the proper amount of excitation
codes in the codebooks. The researches work proves that the lack of naturalness is due to
the fact that the speech synthesizers of today model the vocal folds open, and this will
cause the phase of the signal to be changed when it passes through the filter modeling the
tract. Also, in real human speech there are two types of excitations, the primary being
when the vocal folds close and a second one when they open [15]. Knowing this fact,
Childers and Wong showed in this research that the main reason for the lack of
naturalness is due to the fact that speech synthesizers do not model the interaction
between the vocal tract (represented by a filter) and the glottal source. The glottal source
is where voice and unvoiced sound is created. To achieve a better accuracy, a speech
model that captures the interaction between the filter and the source will produce a more
natural voice. In [15] the researchers show how a simple model of excitation adds
formant "ripple" (noise) to the speech waveform generated, producing a "skewed"
waveform, thereby improving speech naturalness.
The proper reproduction of the formants determines how intelligible speech is.
Good speech intelligibility depends on the codecs proper reproduction of the formant
bandwidth and transitions, where stops and other transient sounds are better understood.
19
The current state of the codec technology used in most digital phones provides good
intelligibility (at rates as low as 2kbps [12]), but not so good naturalness.
It is worth noting that, in most applications like digital cellular telephony, the user
community is used to these imprecise codec techniques. The author believes that the
successful application of the new research being conducted will provide new avenues to
improve service and revenues (similar to the High Definition TV (HDTV) for today's TV
signals and sets).
2.4 Voice Over IP Version 6
With the popularity of the Internet, the IP backbone is running out of room to
accommodate so many users and appliances. Several techniques exist today to increase
the address space of the current IP version 4, among them the Classless InterDomain
Routing (CIDR). Projections done to estimate the availability of IP address, considering
CIDR, account for sufficient, globally unique IPv4 addresses that extend beyond the year
2010 [16]. The growth of Internet addresses is directly proportional to the emerging
network intelligent devices, such as Personal Digital Assistants (PDAs), mobile phones
offering voice over IP, over the air Web access, among others. All of these devices
require IP addresses and enhanced multimedia services. There is an effort on the way, by
the Internet Engineering Task Force (IETF), and being backed by companies such as
Cisco and Sun, studying the upgrade for the current version of the IP protocol version 4
(IPv4) to version 6 (IPv6). IPv6 is an improved protocol based on the lessons learned
from IPv4 which will allow a redefinition of IPv4 features into IPv6 features that address
20
specific issues for what the future holds for Internet traffic, data, audio and video
transmissions.
IPv6 has the following improvements over IPv4:
- 128 bits of address space, with lifetime identifier (valid, deprecated,
invalid) which allows for easier reassignment.
- improved multicast routing (no broadcasting)
- use of anycast address to allow better node traffic flow
- simplified header to improve bandwidth and processing cost
- quality of service (QoS) capabilities
- extensions for authentication and confidentiality.
This research is interested in the enhanced IPv6 features for quality of service
(QoS), and mobility support. Several of these IPv6 features are further explained.
2.4.1 Mobility support - AutoConfiguration
This is similar to the concept of plug-and-play, and basically it will allow a host to
connect to the network without having a geographic or subnet dependency. Once a host
has been configured to work with a network, it can be physically moved to a different
location, and with minimal configuration, still access the network with the same
parameters. An obvious application of this feature is the use of mobile devices (wireless)
used to access the Internet or receive content from it. This process is done via an address
discovery phase, which allows hosts to learn their IP address from a local router. Also,
the protocol includes an algorithm for automatic forwarding of the information packets so
that mobile hosts can receive packets seamlessly, even if they are in a different network.
21
In a later section, we will discuss how the Mobile IP protocol implements this feature in
the Motorola's iDEN® network.
2.4.2 Quality of Service (QoS) - Multimedia features
IPv6 provides several techniques used to guarantee bandwidth and latency of
packet arrival, which enable the application of the Internet to deliver audio, video, and
other real-time data. Namely:
- multicasting = function used to deliver messages to all users that had register to
receive it, thus reducing bandwidth by not broadcasting to the entire network.
- bandwidth reservation = by using the RSVP protocol developed by the IETF for
the current TCP/IP networks, a network host can make bandwidth reservation for the
packets sent from source to destination.
- packet priority = similar to the service type field of IPv4, a priority assigned to
certain packets.
- jumbograms = packet size of up to 4 billion bytes, which attempts to utilize all
of the available and reserved bandwidth.
2.4.3 IPv6 Header
Figure 2.1 shows the proposed header for IPv6. The header for the existing IP
consists of 32 bit wide fields. Much has been discussed of IPv4 (see [17] for more
details), so we will go straight into IPv6 without attempting to compare both protocol
formats.
22
- Version is a 4-bit field indicating the version of the protocol, which is number 6.
- The 8-bit Priority field (also known as Traffic Class [18]) is used by source or
forwarding nodes to set priorities to the packets being transmitted.
- Flow label consists of 20-bits that allow a source of packets to assign special handling
labels such as "real-time" or QoS mode, to a sequence of packets.
- Sixteen (16) bits of payload length field specify, in octets, the length of the IPv6 packets
following the header, (which include the new IPv6 extensions. See [18] for an IPv6
extension description).
- Payload type is 8-bit wide used to designate the type of header following this header.
The values used are identical to the IPv4 protocol field.
- The hop limit 8-bit field is used tell every node that is a hop to a packet (not intended
for that node) to decrement the field by 1, such that when the field reaches 0, the packet is
discarded. Consequently any packet can be "hopped" a maximum of 255 times.
Version Flow label
Payload length Payloadtype
Hop limit
Source address
Destination address
Priority
Figure 2.1 IP version 6 header format
23
- Both the source and destination address fields are made of four (4) 32 bit wide fields, so
the total address number of address bits is 128 bits. They contain the address of the
packet originator, and the intended packet destination (which might not be the final one
for special routing packets), respectively. The larger number of address bits allows for
15% of current addresses assigned and 85% is left for improvement over the years [10].
2.5 H.323
The H.323 standard is a collection of protocols adopted by the International
Telecommunications Union (ITU) which address the transmission of videoconferencing
data (audio and video) via packet switched networks. The standard and its components
apply to multipoint and point-to-point sessions and can be applied to wireless networks.
One of the components of the H.323 standard is the codec standard G.723, which
supports bit rates of 5.3kbps and 6.3 kbps. A high pass filter is used to condition the
input speech by removing any DC bias noise. Using an LPC (Linear Predictive Coding)
speech model, the filtered signal provides the source for a series of speech parameters.
This process is similar to the Vector Quantization method explained in [12]. In DSP
(Digital Signal Processing) jargon, the term quantization is used for the process that
digitizes an analog waveform with a limited number of bits [19]. An input sample vector
is compared to the entries in a codebook (table of quantization vectors) and by checking
the error between the sample and the table entries, a match is found in the codebook and
is chosen to represent the input sample. As we saw earlier, the speech encoder and the
decoder have identical codebooks in memory, so only the index into the codebook is
24
transmitted over the communication line between both, thus reducing the bit rate required
to represent a speech sample. The idea of using parameters to identify a waveform
instead of using the data points extracted from the waveform is analogous to representing
a sine wave with a frequency, amplitude and phase shift [19]. The system receiving the
parameters knows how to build a sine wave so it only needs the correct parameters to be
able to reproduce it. Mathematically speaking, the encoder is represented with a transfer
function implemented using digital filtering techniques, and the decoder uses the
parameters represented by the codebook entry to generate a digital filter that implements
the inverse transfer function of the encoder.
Another feature of the G.723 codec is that it uses pitch estimation of the input
speech. Pitch is one of the largest contributors to the speech frequency spectrum because
it is the element that provides periodicity to the waveform. The protocol attempts to
identify the major contributors to the characteristics of the signal, then it removes them
from it and sends them to the decoder in a separate format. The vector components are
weighted against the information collected from the LPC parameter estimation. The three
components that are quantized and transmitted to the decoder as indices in the codebook
are: speech model parameters, pitch parameters, and the remaining non-periodic
components.
25
The implementation of a software compression technique that uses Microsoft
Windows NT/95/98 G.723.1 codec is limited by the audio hardware. Current
implementations of this codec in Windows require hardware that supports it, and standard
audio hardware in most PCs, do not support this codec.
2.6 Quality Of Service Issues For Voice Over Packet Networks
With the current state of the technology for packet networks (ATM, IP, frame
relay), transmitting voice data (essentially a real time process if used in a two-way
network) has several problems. Some of these problems are mitigated with state of the
art Digital Signal Processing techniques using digital signal processors or other types of
embedded, real time processors. Other problems have been addressed at the protocol
layer (see the previous section on IPv6). In this section we will discuss what are the
hurdles to pass in any voice over IP system.
2.6.1 Delay
There are 3 types of delay:
1. Accumulation delay (also known as algorithmic delay) which is the time it
takes to process a voice sample in the voice encoder. The ITU-T standard
G.723 codec provides about 30ms of accumulation delay [20]. Assuming
comparable processor speeds, in vector quantization codecs this delay is larger
in the encoder because the decoder is only finding the vector in the codebook,
and reproducing the signal.
26
2. Processing delay is a function of the processor speed, and the algorithm used
to convert the speech sample into data packets ready to be sent over the
communication line.
3. Network delay is inversely proportional to the speed, and capacity of the
network used to transfer the message from source to destination. This delay is
the one that the application developer does not have too much control off. It is
a function of network usage, network reliability, and distance.
All of these delays produce echo and talker overlap. Echo, which is the reflection
of the speaker's voice from the listener equipment, becomes a major cause of problem
when the round trip delay between sender and receiver is greater than 50ms [20]. In a full
duplex system, talker overlap is a major problem after the round trip delay is greater than
250ms [20]. Talker overlap manifests in a talker stepping into a speech segment that
another talker has voiced some time before.
In the voice messaging application being studied, these problems are not a major
issue because the message is delivered (i.e. playback) only after the destination host
(either the messaging client or the wireless device) has received all packets.
2.6.2 Jitter
Jitter is the error introduced by the variable transmission delays in the underlying
network, where packets are received out of order, which is essentially the interpacket
arrival time. To remove jitter error, the receiver has to queue up all the packets (within a
certain time window) until a predetermined number of slow packets have been received.
27
The receiver has to then reorganize the packets in the right order, and then playback the
packets. The waiting for slow packets and reordering of packets causes an additional
delay. Typically, jitter buffers add a fixed delay that is used to remove the variant packet
network delay (which could be up to several seconds for the Internet [20]). These brings
a trade-off to the system, namely to minimize the delay while maximizing the amount of
packets queued up (which reduces lost packets).
Several adaptive techniques have been introduced to work around the delay-
packet recovery trade-off. One approach, which works best in consistent jitter
performance networks like ATM [20], is to dynamically (over time) measure the amount
of packets in the jitter buffer, and dynamically sizing up the buffer accordingly to allow
more or less packets. A second technique that is better suited for highly variable jitter
networks like IP [20], is to count the amount of packets arriving after the jitter buffer
capture time window has closed (packets that arrive late). A ratio of this number versus
the number of packets that arrive on time is calculated, and the jitter buffer is adjusted to
maintain a predetermined ratio.
2.6.3 Lost Packets
Today's packet networks experience packet loss especially under heavy network
usage. A voice over IP system has to be able to cope with this problem to allow a
consistent QoS, and to make sure that all important voice message packets do not get lost.
Lost packets are the products of network queues overflow in routers and hops. Also, we
saw in section 2.4, that the IPv6 packet header contains a maximum number of hops
allowed, so packets can be trashed, as requested by the packet sender, after the number of
28
hops have elapsed. Because IP systems treat all voice packets as data packets, both
packets can be discarded with equal probability. Lost data packets, not being time-
sensitive, can be corrected by re-transmission techniques. Lost voice packets, have a time
dependency, so re-transmission techniques are not very useful once a packet has been
discarded (the speaker will have to be requested to repeat the packet segment which was
lost in the network!).
An approach used in voice over IP systems used to fill the gap of a lost voice
packet is to playback the previous voice packet in the time slot of the packet that got lost.
This technique will cause only a minor nuisance when the incidence of lost packets is
infrequent [20]. Another technique, which a takes a proactive approach to packet loss (at
the price of bandwidth usage), is for the sender to include the previous packet information
in the current packet, under the same header. This will allow the receiver to playback the
redundant previous packet in the case it was lost. The downside of this approach is that
not only it uses precious bandwidth for an already bandwidth intensive application, but it
also introduces delay to process the additional packet information. Using low bit rate
voice codecs with this technique reduces the bandwidth required, but the delay element
remains.
2.7 Summary
In this chapter we have seen how special techniques are needed to send voice
information over the Internet or any other packet data network. A numerical example
was computed to show that the amount of data needed to send a voice message is rather
29
large, and that special voice codecs (like the ITU-T standard G.723) are used to compress
or synthesize the speech instead of sending over the network the entire digitized speech.
These codecs allow for a low bit rate (less than 8kbs) voice data packet transmission,
which efficiently use the network, also reducing the session time. A discussion on the
naturalness Vs intelligibility of these codecs demonstrated how the current codec
technique model do not accurately model the interaction between the vocal tract and the
glottal source, therefore the technology produces highly intelligible but unnatural voice.
The glottal source is where voice and unvoiced sound is created. A technique called
GELP, which is being studied by Charoenruengkit [14], attempts to simulate this
interaction to achieve better naturalness. IPv6 was discussed in section 2.4 and the
features used to improve multimedia applications were explained. The ITU-T H.323
standard G.723 component was discussed in terms of its vector quantization process. In
the last section, we discussed that delay, jitter, and lost packet compensation are the
number 1 enemies of a voice over packet network system.
As was mentioned in a previous chapter, the messaging client contains several
components (including software and hardware) which have to accept user inputs, perform
voice processing, and session and network layer access. In the next chapter, we will
discuss the design philosophy, implementation constraints, and behavior and for a
component based software architecture that uses graphical user interface, recording
hardware, and network resources.
30
CHAPTER 3VOICE MESSAGING CLIENT
3.1 Introduction
The previous chapters have presented an overview of the history of messaging and
its evolution to the current state of the start. It was made clear how the message entry
point and the messaging device have evolved and both have merged with the Internet.
Chapter 2 also expanded in detail the different issues surrounding the transmission of
time sensitive data (like voice), via a network that does not guarantee timely delivery, like
the Internet. However, up this point we have not covered how to actually implement a
system (namely a voice messaging client (VMC)) that is able to capture voice messages
and transfer them to a wireless Internet appliance. Chapter 3 will focus on the design,
implementation, and behavior aspects of an IP based voice messaging client. The concept
of a wireline voice client and wireless voice server is being introduced, and will be
developed in later sections.
As seen in chapter 1, the VMC is a computer system connected to a wireline
Internet, which will enable a user to transmit voice messages to a mobile or portable,
wireless Internet device. In this chapter, the VMC software is broken down into 3 major
components, namely: user interface, recording, and packet transfer.
31
3.2 Voice Messaging Client Software – The OS
The high level requirements for the voice messaging client can be summarized as:
- Receive user inputs (IP address, push to talk, send message)
- Record voice messages
- Send voice messages to an Internet IP address
Because the client software requires access to the computer's audio hardware
resources, the author researched several different target platforms. Most operating
systems provide a hardware abstraction layer (in the form of API calls) for audio
hardware access, but due to the lack of software tools that link these APIs between
different operating systems and for the sake of simplicity, one platform had to be chosen.
Unix systems are very common, but hardware is expensive. Linux systems are cheaper
than Unix and run in a PC, but the software is not yet commonly used in home or office
PCs. The Windows 9x and Windows NT operating systems are the most common and
popular operating systems because all the software and hardware available for them.
Among those hardware components available for these systems, is a very extensive list of
audio capture and playback devices. Also, Microsoft has provided in every Windows 9x
and NT package a bundle of voice compression codecs (PCM, GSM, G.723.1, etc.) and a
set of API calls (Audio Compression Manager, DirectX audio, etc.) for accessing the
audio hardware abstraction layer. For these reasons, Windows 9x and Windows NT were
chosen to implement the voice messaging client. Another powerful reason to design the
system for a Windows client, is the strong support for network sockets in the TCP/IP
software stack of Windows.
32
3.3 Voice Messaging Client Software – The Application
If one studies the usage scenario for messaging applications, it can be noted that,
typically, wireline connected computers use a Word Wide Web browser to connect and
access the Internet. Because of the circuit switched nature of the Internet connection for
most home PCs, many home PC users pay for every minute their computer is connected
to their Internet Service Provider (ISP). In order to minimize the connection time, the ISP
dialer software is tied to the Internet access program and not the operating system startup
sequence. For example, in the Microsoft Windows world, when the Internet Explorer
browser is accessed, it detects if the computer is currently connected to the Internet. If no
connection is present, the Internet Explorer browser automatically fires a dialup session
using the Dial-Up Networking component.
In the voice messaging client application, leverage on this integration provided by
the Windows operating system is an important requirement. To this effect the client
software shall be started from inside a Web browser in order to allow a seamless and fast
connectivity to the Internet. A type of software application called a control (specifically a
Microsoft Internet Explorer control) was chosen to perform this functionality nicely by
being tightly coupled to the Internet Explorer. The Internet Explorer controls are built
using Microsoft Component Object Model (COM) with a set of high level template based
libraries called ATL. In the next section we will provide an overview of components and
controls in the context of ATL and COM.
33
3.4 COM and ATL
In this section, we will divert from the subject of wireless voice messaging to
demonstrate how the COM and ATL technologies can be used to connect a wireline
Internet client application to a mobile server.
With the advent of the Internet and the fact that the networking capabilities of
computers are becoming the major reason for their popularity, software development and
maintenance for this type of networking applications is getting increasingly complicated.
Many applications, including the voice messaging client discussed in this chapter, are
designed to reuse software components that exist in other processes. Also, the popularity
of client/server architectures have added a layer of complexity to software development,
because not only does a software product depends on user inputs, it also depends on what
is happening in another software product running in a different machine. There have
been many efforts in the industry and academia to create and/or enforce the use of
common programming languages which will minimize the compatibility issues between
applications (Java inside a sandbox, C/C++, etc.), but these efforts are hard if not
impossible to attain. The difficulty in attaining these goals are mostly due to the human
nature of the software development cycle and the fact that different programming
languages are better suited for different applications. When software is being reused at
the development level, it requires multiple files to be kept in synchronization among
spatially separated developer groups. This synchronization is hard to maintain during the
busiest times of the software lifecycle (just prior to shipping and during user
maintenance). In the voice messaging client application discussed here, it is important to:
34
reuse and leverage from software components which contain interfaces to the Internet
Explorer, and to minimize the changes to the voice recording (and/or voice transfer) part
of the software while the user interface is being optimized, and viceversa. Also, from the
point of view of software maintenance and enhancements, it is important that the
recording part of the voice messaging client software be reused (at runtime) for other
applications which use voice communication over the Internet (example, two-way voice).
In the Microsoft Windows platform, the Component Object Model (COM) is a
technology capable of introducing software reuse at the binary level and of reducing the
amount of compile time dependencies.
Microsoft Corporation created their Windows 9x and NT operating systems (and
most of their applications) using the Component Object Model. COM is a language-
neutral, distributed, object oriented system for creating binary software components that
are able to interact [21]. COM uses the concept of component servers and clients, where
a component server is a Dynamic Link Library (DLL), static library (LIB) or executable
(EXE) which provides services (by means of software interfaces) to clients. Component
clients are software entities (which can also be COM components) which access and use
the interfaces exposed by a server. COM servers register their name and interfaces
supported into the operating system registry. COM clients check the registry for a
component name, then query the component for the requested interface. COM servers
and clients can reside in the process in the same machine, in the machine in different
processes, or across the network in different machines.
Because the concepts of COM require more expertise than the average Windows
software developer would have, ATL is used to simplify the process of using COM. ATL
35
is the Active Template Library, which is a set of C++ high level classes that can be used
to create small and modular COM software components. The relationship between ATL
and COM can be compared to a C cross-compiler for an Assembly language, where ATL
is like the C language and COM is the Assembly. The fundamental points of COM to
which ATL provides special support are interfaces, interface reference counting and
interface query, marshaling, and aggregation among others. Another interesting feature
supported by COM and ATL is the connection point concept. Connection points allow
servers to communicate to the client (or viceversa) when a specific event has occurred by
calling a specific interface, which handles the actual event.
The IUnknown interface is the only required interface that every COM object (or
component) has to implement in order for it to be COM compatible. The component’s
implementation of IUnknown allows it to manage its own lifetime, and for other client
code to query the component interfaces. The basic functionality provided by IUnknown,
plus other features used in this application, are:
- Interfaces
Way in which a COM server object allows a client to access its
functionality. The interface is implemented in C++ as a virtual table of
pointers to functions, and the pointer to the table represents it. Methods (also
commonly known as functions) provide the actual implementation of the
functionality, whereas the virtual table is the means used to allow other
components to call these methods. See figure 3.1 [22]
36
Figure 3.1 Interfaces in COM
&FunctionA()
&FunctionB()
Virtual table pointerInterface pointer
&FunctionC()
FunctionA()
FunctionB()
FunctionC()
The Interface
Virtual function table Methods implemented
- Interface query
Mechanism provided by IUnknown, which allow clients to determine,
at runtime, if a specific component supports the interface that it desires. The
IUnknown method QueryInterface() is implemented by the server component
and called by the client.
- Interface reference counting
This is the feature that allows server components to manage their own
lifetime and optimize memory and hardware resources usage. Server
components keep track of the number of clients accessing its interfaces so that
when there are no clients using its interfaces, the object can unload itself from
memory. The IUnknown methods AddRef() and QueryInterface(), called by
clients, cause the reference count to the interface to be incremented. At some
point in time the client will no longer need the interface so to decrement the
reference count, clients call the IUnknown Release() method. When all
references have been released, the component can remove itself from memory.
37
- Marshaling
Process by which the Windows OS allows a client to call a method
from an interface in a COM server that is outside of the process space of the
client. The technique is used to package the parameters of the method called,
and unpack them at the receiving server side. It also supports the packing and
unpacking of the method’s return. A proxy-stub pair is created in between the
client and server, respectively. The proxy provides packaging of the method
parameters at the client, and the stub does the unpacking at the server. Figure
3.2 shows the parts of the interprocess communications model used by COM,
assuming both client and servers are EXEs. The COM library/channel layer
provides buffering for the marshaled parameters to interface with the
parameter transfer mechanism. In the current implementation of COM the
parameter transfer is done via Remote Procedure Call (RPC) protocol, but
other protocols are used as well in Windows 98 (sockets, NetBIOS,
Distributed COM to name a few).
38
Client
Proxy
Server
Stub
Interprocess boundary
Figure 3.2 Interprocess Communications
COMlibrary
Channel
COMlibrary
Channel
- Containment and Aggregation
These are the two primary mechanisms for component reuse.
Containment allows an outer component to have as a member variable some
or all of the interfaces of an inner component. See figure 3.3.
Inner
IInnerIInnerWrapper
IOuter
IUnknown
Figure 3.3 Containment
39
Calls from the client to a contained object interface are relayed to the inner
object by means of an interface wrapper. Aggregation, on the other hand,
allows an outer component to expose directly (without wrappers) the inner
object’s interfaces, consequently providing clients more efficient access to
the interfaces of the inner object. Containment requires knowledge of the
inner object by the outer component designer but the method allows for
components to be aggregated across processes and/or machines.
Aggregation does not require knowledge of the inner object by the outer
component designer, but it requires that the inner component support
aggregation by implementing a set of CComCreator classes. These classes
provide knowledge of which type of instance is required (contained or
aggregated).
- Connection points
Similarly to the callback mechanism used in the Win32 system, a
thread of execution passes the pointer of a function to another thread. The
thread receiving the function pointer can invoke the function when a
certain event happens. Callbacks can only be used when the threads of
execution are in the same process whereas connection points can be called
across machines and processes. Connection points have two interfaces;
namely event source and event sink interfaces. Figure 3.4 explains this.
40
Sink Source
Figure 3.4 Connection
ISink IIncoming
Informs source of the function pointerto execute, for a specific event.
When desired event happens,function is called on the sink.
The event sink passes to the event source the function pointer. This is
done via a SINK_MAP and each advisable event will have IIncoming
interface, so the sink knows which one to map into the SINK_MAP. A
server component that supports connection points must implement the
IConnectionPointContainer interface for the IIncoming interface, which
indicates the existence of outgoing interfaces. To implement an outgoing
path to the client, the server component must implement the
IConnectionPoint interface, which is linked to the ISink in the client by
means of the COM Invoke() method.
In the next section these concepts will be explained from the point of view of the
voice messaging client software components. The reader is advised to review the
references [22] and [23] to further explore the wide world of COM and ATL.
41
3.4.1 Voice Messaging Client Software Explained with COM
The Figure 3.5 shows a software architecture diagram with the components of the
messaging client, and their interactions.
The application is divided in three main dynamic link libraries (DLLs), namely:
Gui, Record, and VoiceSender. The ICQ Client is used to map a user supplied ICQ
number to the current IP address used by that number, which becomes useful when the
intended message receiver does not connect to the Internet with a fixed IP address. It is
important to note that in the voice messaging client application, no proxies-stub or across
process marshaling is used because all COM servers have been implemented as DLLs. In
this case, simple function calls between DLLs are used, but the very important fact of
SoundCaptureHw
Networkinterfacecard orDialUp
VoiceSenderWindowssocket(CLIENT)
RecordingApplication(MS COM)
GUI (insideweb browser,MS COM)
codec plug-inMS AudioCompressionManager API
WirelineInternet
ICQClient
Figure 3.5 Voice Messaging Client Software Architecture
42
location transparency remains, as the application is 100% compatible with a COM server
being located in a different process in a different machine.
The lollipop diagram in Figure 3.6 shows the Talker component of the
VoiceSender DLL.
TalkerITalker
IUnknown
Figure 3.6 Talker component
1. VoiceSender
DLL COM server containing the Talker component, which uses the
Windows socket API (WinSock) to implement a socket client that sends
digitized voice files to a listening socket server. Talker will open a voice file
and transfer it to the destination socket. The interface exposed by Talker
component is called ITalker with the following functionality (methods):
- Talk()
Starts a TCP session with a listening socket to transfer the voice
file.
- SetListenerAddress()
43
Initializes the component for the address and socket port number of
the listening socket.
- SetVoiceFilename()
Initialize the component for the name and fully quantified path of
the voice file to transfer
- SetPacketSize()
Enter the size of the socket message size queue.
2. Record
DLL COM server that contains the Recorder component (see Figure 3.7).
Recorder
ISpeechRecorder
ISpeechCompresor
IUnknown
Figure 3.7 Recorder component class
ISpeechMessenger
IRecorder
_IRecorderEvents(event source)
Talker
ITalker
44
Recorder implements the audio compression manager API calls to allow
the access to the voice capture hardware and convert speech into a voice file with
the specified codec plugin format. It also contains the interfaces of Talker (thus
making it a client of Talker) to allow the transfer of the voice file to a destination
IP address. Because events happening in the Record are time dependent (based on
user voice inputs) it also implements a source connection point interface. This
interface is used by clients connecting to it to get reports from events happening
regardless if the client is waiting for the events or not. The server component
“sources” events to clients. Typically, a codec plugin can be entered into the
application using the API so that different compression schemes can be used. The
interfaces of the Recorder component are:
- ISpeechRecorder
Provides the functionality required to start and stop recording. The
methods are:
A. StartRecording(). Calls the ACM functions to create a new
voice file, initialize the recording audio and start recording.
When the recording system is ready, it fires the events required
by a connected client.
B. StopRecording(). Calls the ACM functions to stop the current
recording session, and releases the recording audio hardware.
- ISpeechCompressor
Compress and uncompress the voice message after it has been captured.
- ISpeechMessenger
45
Provides the voice file transfer functionality, by accessing the Talker
component ITalker interface. The method supported is:
A. Send(). Calls the methods of the ITalker interface to initiate
and complete the voice file transfer.
- IRecorder
Implemented by the DispatchImpl class of the CRecorder coclass.
- _IRecorderEvents
Provides the IConnectionPointContainer implementation, which
allows clients to determine that this component has connection points. This
interface supports the following events: OnReadyToRecord,
OnDoneRecording, and OnDoneCompressing. The CProxy_IRecorderEvents
class provides the implementation of the outgoing interface to the clients. The
methods used to fire the events are:
A. Fire_OnReadyToRecord(). This method is called by the code
handling the start recording event.
B. Fire_OnDoneRecording(). This method is called by the code
handling the stop recording event.
C. Fire_OnDoneCompressing(). This method is called by the
code handling the compressing event.
46
3. Gui
COM server DLL with the IEGui Internet explorer control, which
implements the standard interfaces required to be contained in IE (see figure
3.8).
IEGui
_IRecordingEvents(sink)
IRecordingListener
IUnknown
Figure 3.8 IEGui component class
Recorder
The interfaces are designed into the operating system and they just
have to be invoked and exposed by the control (the author did not have to
implement these). The mechanism by which these interfaces to the IE are
used in the IEGui control is called inheritance. Inheritance is a term used
in object oriented design, which defines the ability of a subclass to become
part of the class it is based on, and uses its attributes and interfaces. For
more information on object oriented design and inheritance see [24]. A
member attribute of the CIEGui class is the CStringDlg, which is a COM
47
based class, implements the user dialog box to control the entire voice
messaging client. IEGui is also a COM client and a connection point sink
(receives events from a connection point source) for the Recorder
component. IEGui uses the recording and file transfer services of the
Record application and receives notifications of events happening. This
way the IEGui can inform the user when the hardware is ready to start
recording. The IEGui uses containment (as explained in the previous
section) to feature the Recorder component functionality.
4. Audio Compression Manager
Set of API calls provided by the Windows operating system which
provide a hardware abstraction layer so that the audio software design
works for multiple (but supported) audio hardware. It provides functions
to open, play, record, and close audio hardware and also features to
manage WAV type files.
3.4.2 Voice Messaging Client Software Events
See Figure 3.9. The GUI queries the user to enter the IP address of the destination
device and press a button to enter a voice message. The ICQ client is used to map an ICQ
number to the current IP address of that user. This will trigger the rest of the recording
application to access the Audio Control Manager (ACM) API (provided by Microsoft) to
capture an audio message. The ACM allows for hardware independent recording and
playback of audio samples. The voice samples are captured using PCM samples at
48
64kbps. When the message has been captured, the application will make a Windows
socket connection to the voice messenger server (wireless device) and send the voice
information to it.
3.5 Summary
In this chapter was presented the COM and ATL principles used in the
development of the software. COM provided a very important reuse level, because the
components plugged in nicely with Internet Explorer (IEGui), and took advantage of
connection points for event notification (Recorder to IEGui).
So far, we have discussed how to get the voice message inside the application, and
how to route it to the destination. In the next chapter the wireline to wireless IP gateway
will be presented which is the key element required to route the IP packets to the final
destination.
49
START(1) User startsInternet Explorer(IEGui.html)
(2) InternetExplorerconnects to theInternet
IEGui
Internet Explorer
DialUpNetworking
(3) Internetconnectioncompleted
Recorder
CProxy_IRecorderEvents
Talker(5) StartRecording()
CStringDlg
(4) User enters IP addressor ICQ number, then hitsPush To Talk ( OnPtt() )
(8) Fire_OnStartRecording()(15)Fire_OnDoneRecording()
(9) OnReady()(16) OnReady()
(10) Displaymessage to user
(11) User speaksinto microphonethen hits StopTalking( OnCancel() )
ACM
(6) mciSendString(“record”)(13) mciSendString(“stop”)
(7) Mmsyserr_noerror(14) Mmsyserr_noerror
(12) StopRecording()
(17) Send()
(18) Talk()
(19) S_OK
(20) S_OK
END(21) User notified ifmessage was sent
Figure 3.9 Voice Messaging Client Event Diagram
ICQ client
(5) If ICQ #, Fetch IP
50
CHAPTER 4WIRELINE TO WIRELESS INTERNET GATEWAY
4.1 Introduction
In the previous chapter, we have studied the operation and implementation of the
Voice Messaging Client. Once the message packets are sent over the wireline Internet,
they will arrive at a gateway that will convert them to the over the air interface so that
they can reach the mobile, wireless voice playback server. Because the wireless voice
playback server is mobile in nature, the system needs to be able find the server and send
the voice packets to it. Chapter 4 focuses on describing the operation of two systems
designed to send packetized data over an air interface to an IP address enabled device.
The wireless systems studied in this chapter as applied to transmission of voice packets
are the Motorola Integrated Dispatch Enhanced Network (iDEN) packet data using
Mobile IP, and the GSM General Packet Radio Service (GPRS). These two systems were
studied as the network element developed in our application, because they support fixed
IP address mobile nodes, which is an essential element of finding a mobile server without
using 3rd party servers dedicated to finding users. The routing algorithms of Mobile IP
and GPRS systems and air interface protocols will be studied. Because Mobile IP is such
a powerful protocol used for locating servers or otherwise mobile nodes in the Internet,
the next section will introduce the concept.
51
4.2 Mobile IP
Mobile IP [25] [26], is a network layer protocol solution that attempts to solve the
issue of node mobility on the Internet, by maintaining the appropriate IP address routing
tables, regardless of the physical layer access point to the network. Mobile IP is the
foundation of iDEN packet data to perform wireless IP routing. Existing link layer
protocols used for solving the problem of node mobility (like CDPD) depend on the
physical media over which the protocol is running (in the case of CDPD, it is the AMPS
cellular network). Mobile IP has four major design elements:
1. Mobile nodes are able to communicate with other nodes, possibly mobile also, after
changing the link layer connection geographically or by type (wired to wireless)
2. Mobile nodes accomplish the first requirements using one and only one IP address
permanently assigned to each node
3. Mobile IP nodes allow communications between Mobile IP and non-Mobile IP
enabled nodes
4. Nodes connected to the Internet using mobile IP over wired or wireless links have
identical security features so that security threats are not different than ones on fixed
non-mobile IP nodes.
The mobile IP functionality is implemented in 3 components of the Internet, namely:
mobile nodes, home and foreign agents (routers). The next section will discuss these and
other mobile IP terms, before describing the operation of a mobile node being wirelessly
linked to a foreign agent.
52
1. Mobile Node (MN) = known also as Mobile Station (MS). Can change its point of
attachment to the same network via different links, while always using its permanent
IP address.
2. Care Of Address (COA) = temporarily used by MN as an IP tunnel exit point address
when MN is in foreign agent
3. IP Tunnel = technique used to encapsulate an IP packet inside the payload of an
outermost IP packet
4. Foreign Agent (FA) = router to which the MN does not belong (different IP address
network prefix). When the MN is visiting a FA, it provides the COA to the MN. The
MN will register this COA with its home agent
5. Home Agent (HA) = router to which the MN IP address network prefix belongs to.
Typically is the next routing hop for MN outgoing packets when in its home network.
When the MN is outside its home network, MN registers its COA. HA “tunnels”
packets destined to MN via the care-of-address (COA)
6. Agent Discovery = process by which the MN searches and determines if it is being
serviced by its HA or a FA
7. Agent Advertisement = message sent by agents (via an Internet Control Message
Protocol header) to allow MNs to determine their location in the network
8. Agent Solicitation = message sent by MNs to request a forced agent advertisement
from all agents on the link the node is currently connected to
9. Registration = process by which the MN detects that its link connection to the IP
network has changed or that its current link is about to expire. The MN will request
53
routing services from the foreign agent, and will proceed to send the assigned COA to
its home agent so those IP packets can be tunneled properly.
Figure 4.1 [26] shows a simplified diagram of the relationships between the components.
In this section we will explain the Mobile IP process for a mobile node visiting in
a foreign agent.
1. Home and foreign agents send Agent Advertisement messages on their links
using multicasting of broadcasting.
2. Mobile nodes, which are programmed with a specific IP address, are listening
for the Agent Advertisement messages to detect if the link currently being
used is a home or foreign link.
3. If the link is a home link, the mobile node behaves with regular, non-mobile
IP functionality.
4. By means of agent advertisement, the mobile node detects it is in a foreign
link and fetches the COA from one of the advertisement fields. The MN
Home Agent
Mobile Node(at home)
Home LinkNetwork
ForeignAgent
Foreign Link
ForeignAgent
Mobile Node(visiting)
Figure 4.1 Mobile IP Simplified Diagram
54
detects the foreign agent via one of: lifetime parameter or comparing the
network prefix of the IP source address in the advertisement message. If no
advertisements are detected, agent solicitation messages are sent by the mobile
node to a DHCP server to request a collocated COA. Also, the MS can sniff
all packets being sent in that link and comparing the network prefix of those
with its own.
5. After acquiring the COA or collocated COA address, the MN registers to its
home agent. The home agent will serve as proxy for the traveling mobile
node, so that when packets are destined to the node, they are tunneled to the
COA.
6. When mobile node packets arrive to the foreign agent, they are extracted out
of the COA tunnel, and forwarded to the visiting node. If a collocated COA is
being used, the MN does the de-tunneling itself.
4.3 iDEN Overview and Architecture
The Motorola® Integrated Dispatch Enhanced Network (iDEN) is a complete
communications system that combines circuit switched voice, digital dispatch, and packet
data access to the Internet using the Mobile IP protocol. As seen in the previous section,
Mobile IP is an IETF standard that specifies the Layer 3 of the ISO/OSI model to allow
nodes to connect to the Internet regardless of where they access it, using the same IP
address.
55
iDEN was designed using a proprietary modulation technology (called M16-
QAM) which allows the combination of digital dispatch radio, digital cellular, packet
switched data, and text messaging into the same system and mobile stations (handsets).
The protocol uses a gross bit rate of approximately 64kbit/s and operates in the 806 to
821 MHz and in the 851 to 866 MHz bands (for uplink and downlink channels), with
base carriers spaced by 25kHz. The TDMA protocol implementation, similar to GSM,
divides the RF carrier into time slots of 15ms. Each slot contains not only the normal
voice and data traffic but also auxiliary data for signaling support. The inbound (or
uplink) channel access uses a reservation protocol. In the packet data protocol, an iDEN
data channel is shared between multiple, concurrent users that compete for channel access
when data frames are to be transmitted.
The iDEN network elements are also similar in functionality to the GSM digital
cellular network. The RF section of the system consists of an Enhanced Base Transceiver
Station (EBTS), which is managed by a Base Site Controller. A BSC manages multiple
EBTSs. Each EBTS consists of one or more packet data channels. In an iDEN system,
packet data calls are service by a Mobile IP enabled router (Home or foreign agents, as
seen in the previous section).
In the modulation scheme used in the RF interface, a special speech compression
technique (Vector Sum Excited Linear Predicting) encodes three to six communication
paths into one 25kHz channel. The M16-QAM modulation technique used in the iDEN
system is a linear technique that provides a good combination of modulation efficiency,
channel sensitivity, C/I ratio and adjacent channel interference.
56
4.4 GPRS Overview and Architecture
GPRS is an ETSI standard, which defines a high-speed packet data protocol for
the GSM cellular network. The protocol supports packet data transfers in Point-To-Point
(connection and connectionless modes) and Point-To-Multipoint. GPRS uses IP
addresses to interface the cellular IP enabled mobile node to the outside public packet
data network (IP based Internet and X.25 networks). The IP address is mapped to the
International Mobile Subscriber Identity (IMSI) by the GGSN network component.
Depending on the subscription agreement with the service provider, the IP address
assigned to the mobile is fixed (so that a mobile server application can use it) or dynamic
(assigned by the system to the mobile when a packet service is requested by the mobile).
To achieve a high data rate, the system uses a TDMA access scheme, where a user can be
assigned from 1 to 8 timeslots, which at 21 kbits/s per slot will improve the data rate to
171kbits/s. In reality the limitations of mobile phones transmitters will limit the number
of slots it can use to send data. For this reason, asymmetric connections (where the
mobile uses 2 or more slots on the downlink and a smaller number in the uplink) will be
very common.
The radio interface of GPRS is independent of the packet data stack and has been
maintained compatible with the GSM core network. This modularity will allow
improvements to the air interface (EDGE) to achieve up to 350 kbits/s. The rest of the
GPRS network coexist with the existing GSM modules, except that the Serving GPRS
Support Node (SGSN) and Gateway GPRS Support Node (GGSN) have been added into
the system to control the routing and interworking functions required in a IP based data
57
network. Both of these components are connected to each other via an IP backbone
network, which is used to transfer data and signaling messages. Depending on the
reliability of the message being sent the packets are transferred using TCP or UDP, with a
GPRS Tunneling Protocol on top. Let us now discuss the SGSN and GGSN nodes.
1. GGSN = this is the interworking node which interfaces the GSM PLMN to the
outside packet data network, and connects to the all the SGSNs in the GPRS
network. The GGSN receives a packet from an outside source, to send to a
mobile inside the GPRS network, and tunnels the packet to the SGSN serving
the mobile. Mobile originated packets transmitted from inside the GPRS
network are forwarded to the external Internet by the GGSN.
2. SGSN = using a Frame Relay interface this component is connected to the
radio interface equipment and provides ciphering and authentication services
for the mobile. This node also participates in the routing of IP packets by
forwarding MO packets to the GGSN and serving as the tunnel exit point for
the packets that are MT sent from the GGSN.
4.5 Summary
In this chapter we have presented the applications of mobile IP and GPRS to the
problem of mobile node mobility management. As presented in this work, a mobile
wireless server requires a fixed IP address or means of finding a dynamic one. The
systems discussed here, namely GPRS and mobile IP, provide components dedicated to
the mobility management of nodes. In Mobile IP, the foreign agent is in charge of
58
allocating a care-of-address to a visiting node, and providing de-tunneling capabilities to
MT packets. The home agent, receives registration requests from the mobile being
serviced by a foreign agent, and provides tunneling capabilities to send MT packets via
the foreign agent. In mobile IP, as implemented in the iDEN protocol the handset is
allocated one IP address that can be used throughout the network. In GPRS, which can
assign dynamic or static IP addresses, the SGSNs and the GGSN perform the routing and
mobility capabilities. The SGSN and GGSN communicate via an IP tunneling interface.
The IMSI number in the handset is mapped to the IP address.
Up to this point, we have studied how the instant voice message gets into the
client application and how it is forwarded. The next chapter will present the functionality
of the wireless instant messaging server, which receives the voice message and plays it
back.
59
CHAPTER 5WIRELESS INTERNET VOICE MESSENGER
5.1 Introduction
In chapter 3 it was presented the design and operation of the voice messaging
client (VMC), while chapter 4 attempted to explain the wireless Internet gateway which
converts the landline originated, digitized voice packets to a wireless medium. The VMC
software was designed to capture and deliver a voice message to a listening server, using
an IP address. Chapter 5 will study one specific type of voice message receiver server,
namely the wireless Internet voice messenger server. The wireless Internet voice
messenger server consists of a mobile phone, which supports packet data processing, and
a portable computer connected to the phone. This chapter will focus on: what is the
architecture of the Voice Messaging Software (VMS), how the server possesses a
permanent IP address or how it publishes a dynamic one (so that clients can find it), how
the user is able to browse the Web at the same time that a voice message is received, and
what is the functionality of the software components in the phone and portable computer
that allows them to communicate.
Recall that, as seen in Chapter 1, the wireless Internet voice messenger (WIVM) is
mobile or portable in nature. In this context, mobile means that it can be moving between
areas of coverage while the device is in use, and portable means that it is allowed to
receive service in different areas but not while it is in use. It is important to note here that
60
the term server is used, as explained in Chapter 1, to indicate the fact that the voice
message receiver accepts connections from and provides the service of message playback
to a voice message originated by a client. The server user connects to the Internet with an
IP address, and enables or disables voice message reception by starting or closing the
server application.
5.2 Wireless Voice Messenger Server – The OS
As seen in the VMC chapter, choosing an OS to implement the VMS software is
the 1st step to determine software development complexity and feature support. To
choose an operating system for the voice server application, the author considered the
following requirements:
- OS support of mobile/portable devices (like laptops and palmtops computers),
- WWW browser available to allow the user seamless connectivity to the
networking software,
- support of COM platform to leverage on the lessons learned during the VMC
development,
- support of a wide range of voice playback hardware with a common API,
- robust support of TCP/IP networking software.
The Windows 98/95 and NT software platform was chosen because it meets all of
these categories. Another very important reason is that most commercial messaging
packages (Yahoo!, ICQ) have been designed to work with Windows. With this platform,
61
it should be relatively easy to setup a test system for multiple configurations of the VMS
package and the other commercial packages. This will be discussed more in depth in
chapter 6. The support of the TCP/IP networking software is also very important because
the VMS software requires access to different types of phones (GPRS Vs iDEN,
Motorola Vs Qualcom, etc.), and the Dial-Up Networking component of Windows can be
well tailored for these different scenarios, while minimizing the changes to the VMS
application.
5.3 Wireless Voice Messenger Server – The Application Software
The usage scenario for a mobile, voice messaging receiving application consists
of a portable computer user with a cellular phone accessing the wireless data network
(WWW) and voice messaging reception enabled (by starting the VMS application). The
data capable cellular phone is used to access the Web in the absence of a landline modem.
With the phone having a permanent IP address (achieved with Mobile IP and GPRS), the
VMS application user can publish this IP into business cards so that clients, colleagues
and family can instantly send voice messages (assuming they have the voice messaging
client with a Web browser, as explained in chapter 3). Because the voice message is
digitized, it is received by the VMS application while the phone is connected via a data
call, thus allowing the message to be playback instantly. This feature is also commonly
known as instant voice messaging but, unlike existing popular messaging applications, it
does not require the VMS user to log-on to a separate server so that messaging clients can
find him or her (typically using the Internet Resource Locator protocol). Also, existing
62
commercial cellular networks like Sprint PCS and Omnipoint allow users to receive voice
mail if the phone is busy but message retrieval has to wait until the current data or voice
call is completed. The VMS application shall be able to bridge voice messaging while
the phone is busy in a data call.
Because of the packet switched nature (billing is per packet sent and received) of
the Internet connection for the mobile user with Mobile IP or GPRS, the user is able to
leave the connection to its Internet Service Provider (ISP) for longer periods of time
(although at the expense of battery life). This avoids the lengthy dial up process and the
possibility of missing messages while connection setup is being completed. The effect of
long term connections to the Internet on the battery life is out of the scope of this
investigation, but we will be analyzing in chapter 7 several experiments carried out with
to determine the length of time it takes to deliver the voice message, as it directly impatcs
handset battery life. The requirements for the VMS application are summarized as:
- Application started by the user once connection to the Internet has been
established
- Application should allow browsing the Web at the same time that an instant
voice message is received and playback
- Application separate from Internet Explorer because voice messaging
reception is not always desired while browsing the Web
- Voice message reception software shall implement a TCP/IP server socket
scheme to allow clients to stream a voice file into the server
- When a voice message is received, voice file shall stored in a file and the user
will be notified
63
- Messages received are not acknowledged back to the sender as to whether they
have been playback. Only delivery confirmation is available
- Voice playback software independent of voice playback hardware (using
Audio Compression Manager) which allows operation in different types of
hardware
- Modular, component based software (separation of voice playback and voice
transfer software) to allow for easier debugging and maximum reuse.
As can be inferred from these requirements, a design with COM components (see
Chapter 3 for more information on COM) and the Microsoft Audio Compression manager
(ACM), is very suitable for the VMS application. These requirements evolved into the
software architecture diagram shown in Figure 5.1.
64
The ICQ client is used when the user desires to be located via the ICQ system, which
maps its current IP address to a fixed ICQ number. The components of the WIVM server
software are:
1. Playback
DLL COM server, which controls the entire Audio Compression Manager
(ACM) functions for the application’s voice playback requirements. For this purpose,
this DLL implements the SpeechPlayer component and its interfaces (see Figure 5.2).
Figure 5.1 Wireless Internet Voice Messaging Server Software Architecture
SoundplaybackHw
WirelessModeminterface
Windowssocket(SERVER)
PlaybackApplication(MS COM)
VmsConsole(GUI)
codec plug-inMS AudioCompression ManagerAPI
Antenna
Hard disk ICQ client
65
This component has been designed to open a voice file (with a certain compression
scheme) and stream it to the sound processor hardware for immediate playback.
SpeechPlayer
ISpeechUncompressor
ISpeechPlayer
IUnknown
Figure 5.2 SpeechPlayer component class
- ISpeechPlayer
Interface designed to allow the start and stop of the voice message
playback.
A. StartPlayback(). Calls the ACM functions to open a voice file, and
send it to the audio hardware for playback.
B. StopPlayback(). This is convenience method provided in the interface
to allow the voice playback to be aborted.
- ISpeechUncompressor
The ISpeechUncompressor is required to uncompress the voice file
before it is played back.
66
2. VmsConsole
Console application used for initializing the Windows Socket interface,
starting a socket server at a specific port number, receiving and binding a voice file
connection from a client and saving the file locally, then informing the user that a
voice message has arrived. VmsConsole is a COM client for the SpeechPlayer
component of the Playback DLL. When the file is received and the user has accepted
playback, VmsConsole access the voice playback capabilities of SpeechPlayer.
It is important to note that because the server application is monitoring a specific
socket port number, voice packets are received only from the VMC client software and
not the typical WWW or FTP socket port number. This provides some level of security
and privacy because only the authorized VMC client application knows what this port
number is.
67
VmsConsole.exe
Web browser(Internet Explorer orNetscape)
START(1) User connectsto the Internet
DialUpNetworking(DUN)
RF modemdata protocolstack
(7) User enables voicemessaging
Main() func
WinSock
(14) Inform user voicemessage was received
VmcS.wavVoice file(15) User chooses
message playback
SpeechPlayer
ACM
Figure 5.3 Wireless Voice Server Software Events
(2) Web browserconnects to theInternet viawireless modem
(3) Setup thephone for datacall
(4) Data callproceeds, pass IPaddress to DUN
(5) DUN initialized
(6) Web can bebrowsed
(8) Initialize TCP socketserver, port 6400
(9) TCP socket serverinitialized, and listening.(12) Voice message data
(10) Voice messagereceived
(11) Socket reads indata
(13) Voice messagedata stored in file
(16) StartPlayback()
(18) mciSendString(“play”)
(19) Mmsyserr_noerror
(17) Read file
END(20) Voice messageplayback to user
68
5.4 Wireless IP Network Interface - RF Modem
In the previous sections and chapters we have studied the operation of the
application software required in the voice message client (sender) and the voice message
server (receiver), while also discussing the protocols used in the different interfaces of the
entire system. However, most of the focus of this thesis evolves around the mobile phone
and the widespread availability of the air interface, which enables the user to be
connected anywhere to the WWW and Internet, while simultaneously allowing the
reception of instant voice messages.
In chapter 4, we have studied the operation of the Wireless Internet Gateway
(system component responsible for finding the mobile phone, converting all landline
originated data packets to the over the air interface, and delivering each and every packet)
with emphasis in GPRS and Mobile IP. This section deals with the software interfaces of
the phone to allow packet data calls, and the interconnecting components that make the
phone look like an extension of the mobile server (the actual laptop computer) TCP/IP
protocol stack.
In order to understand the networking functions used by the server and mobile
station, let's first review the ISO/OSI protocol model for computer communications.
Figure 5.4 shows the Open Systems Interconnect (OSI) reference model for two
computers connected via a physical medium. In this theoretical model, an application
that wishes to communicate to another in a different computer does so by using a network
protocol stack. The protocol stack is made of layers with each layer providing certain
procedures and functions that are understood and decoded by the respective layer in the
69
stack of the receiving computer, while also providing services to the layer above it in the
stack. The idea of modularizing these protocol layers is intended to facilitate the
incorporation of improvements to a specific layer without affecting the other layers. A
brief description of the functionality of each layer follows, with emphasis in the lower
four layers, which are relevant to our study:
- Physical = it is the wire (electrical and mechanical specifications), plus the
overhead required to move the "raw" data bits between sender and destination.
As data is transferred between computers, multiple physical interfaces could
be used. This layer is also concerned with bit rate, and voltages. For
example: RS-232.
- Link = it provides the transfer mechanism to move data frames between
neighboring computers on the same link. Frames consist of packets generated
at the network layer plus the header added in the link layer. The link layer
also provides access control to links that are shared between multiple talkers
and listeners, and ensures the successful transfer of the frames in that link.
For example: PPP.
- Network = generates packets from the bit streams generated at the transport
layer and, using the network address, ensures that packets are delivered across
multiple links. This layer is used by nodes as well as routers, and defines how
devices in the network discover each other and how are packets to traverse the
network to reach their final destination. For example: IP.
- Transport = provides reliability to the network layer by ensuring all bit streams
are received to the final destination. With some exceptions (like UDP), this
70
layer defines methods for detecting and correcting errors in the transmission of
this streams to the final destination. This layer typically does not exist in
routers, and is only concerned with the end-to-end nodes. For example: TCP.
- Session = provides application oriented features (like file transfer retries) to
ensure user data is successfully transferred to the final destination.
- Presentation = provides encoding of the user data to prepare it for transmission
through the network.
- Application = defines a data transfer high level interface to the specific
program used to transfer the data. For example: a Web browser.
Physical
Application
Presentation
Session
Transport
Network
Link
Physical
Application
Presentation
Session
Transport
Network
Link
ApplicationProgram X
ApplicationProgram Y
Computer 1 Computer 2
Figure 5.4 ISO/OSI Reference Model for Computer Communications
Network
Link 1 Link 2Physical 1 Physical 2
A note should be added to emphasize that because Figure 5.4 is a theoretical
model used as a reference, it is not immune to certain challenges such as the
interdependencies between the layers that are caused by efficiency improvements [26].
71
For this reason, real world applications, including the one developed in this research, will
not strictly follow the model.
In the three wireless IP access scenarios discussed (Mobile IP over iDEN, GPRS,
and circuit-switched over CDMA) a PPP link layer connection is made between the
mobile computer and the Internet Service Provider (ISP) using the mobile phone as a
modem. All of the mobile phones support the AT command set, which allow to setup
data calls to access the PPP services of a dial-up server. PPP is the Point-to-Point
protocol defined in RFC 1661 [27], and proposes a standard method of transporting
packets in order, between two topologically adjacent peers (share the same physical, full
duplex link). The wireless link, be it GPRS, CDMA, or iDEN is well suited to this type
of protocol. PPP supports link quality reports and control information compression, such
as Van-Jacobson TCP/IP header compression negotiation, protocol-field and address-
control field compression. In a mobile, wireless link, compression achieves better battery
performance, and quality reports allow us to monitor the link
The different implementations of the PPP process for the three wireless IP access
scenarios considered require special considerations, but one common aspect is that the
mobile voice playback server application require a permanent IP address (or a method of
publishing a dynamically assigned one) so that Web clients can connect to the server to
send the voice messages. The next few sections will explore how PPP can be used to
achieve this requirement for the Mobile IP and GPRS cases, but first we will discuss the
PPP procedure for a landline connected computer, which dynamically requests an IP
address to an ISP:
72
- Dial-up networking software uses the modem to connect to the ISP using AT
commands.
- Once the connection is made, PPP starts the link-establishment phase [27].
This phase includes negotiation for quality, compression, packet size, and
authentication protocol.
- Then the PPP authentication phase begins. In this phase either the PPP
password authentication protocol [28], or some stronger authentication
method (like CHAP [29]) is used.
- Then the PPP begins the Network Control Protocol where both ends negotiate
parameters used for the IP layer. This is done using the Internet protocol
control protocol (IPCP) [30] to negotiate the TCP/IP header compression,
DNS [31], and IP address [30]. In this case, the PPP protocol is configured to
request an IP address from the peer, which then assigns one to the remotely
connected computer.
- To publish this dynamically allocated IP address so that a Web client can use
it, the server can usually logon to a second server and push its user name and
IP address into this server. A Web client looking for the mobile server can
lookup the IP address based on the user name. The commercially available
ICQ client and the dynamic IP address lookup work performed by Sanchez
[6], present two alternatives to this problem. The author used the ICQ
mechanism for finding the dynamic IP address.
The next two sections present the approach taken by the GPRS and Mobile IP
configurations discussed.
73
5.4.1 PPP and IP address publication via a Mobile IP capable RF modem
The Mobile IP approach to fixed IP addresses was discussed in chapter 4, but in
this section we will discuss the phone specific behavior, as related to the networking
protocol stack. In this approach, because the IP address is fixed and the mobility
management is part of the Mobile IP infrastructure (routers as foreign and home agents),
the voice messaging mobile server user can publish its phone/computer IP address the
same way he/she would publish its mobile phone number (business card, etc.).
In Table 5.1 it is shown a theoretical protocol stack description between the
Mobile IP radio (in this case a Motorola iDEN radio) and the mobile server.
Table 5.1 Voice Mobile Server and iDEN phone protocol stacks
Voice Mobile server iDEN Phone
TCP [NA]
IP IP
PPP PPP<>iLLP
RS-232 RS-232<>iRF
As discussed in the previous section, notice the use of the PPP link to establish the
connection to the Internet and to exchange IP packets between the phone and the server.
The PPP procedure for a connection to a foreign agent can be described as:
74
- Mobile server establishes a PPP connection to the iDEN phone, requesting an
IP address assignment. The Windows DialUp networking software uses an
iDEN phone modem driver to perform this operation.
- Because the phone has a valid, permanent IP address it assigns this to the
mobile server address request, and proceeds to communicate to the iDEN
infrastructure to register in the foreign area, as explained in chapter 4.
Once the PPP and Mobile IP registration procedures are complete, the voice
messaging server is ready to receive messages. Between the phone and the Internet, the
phone uses the Motorola proprietary iLLP (iDEN Link Layer Protocol). When a message
is being addressed to the server, the iDEN infrastructure pages the mobile phone, in a
control channel being monitored by the phone, to indicate that packets are destined to it.
This will trigger an IP packet transfer between the phone and mobile server. When the
mobile server has packets to send (due to the TCP layer being controlled by the VMS
application in the server) the iLLP and the lower iRF (iDEN RF interface) use the Queued
Contiguous Reservation Aloha (QCRA) [26], which can be summarized as:
- An IP packet is sent between mobile server and phone, phone then sends a
short reservation request, which include the phone's link layer address, to the
iDEN wireless IP infrastructure.
- The wireless IP infrastructure equipment uses a scheduling policy to grant
access to the packet data channel to the sending device. This equipment needs
to arbitrate requests from multiple phones, so it sends over a broadcast
channel the link layer address of the phone to which packet transfer has been
75
granted. This is done so that all devices in the link learn who's turn it is to
transmit packets over the shared packet data channel.
- The requesting phone notices its own link layer address in the access grant
received over the broadcast channel, so its sends the packet, and proceed to
requests another grant if more packets are pending.
5.4.2 PPP and IP address publication via a GPRS capable RF modem
In GPRS, the connection mechanism between the mobile phone and the server is
similar to the connection with the Mobile IP phone. The major difference is related to
how the IP address is kept constant in the GPRS network. When a user connects the
phone to the GPRS network, it gets assigned a permanent IP address, which is maintained
in the phone and in the GGSN. When a packet arrives from the landline network to the
GPRS phone/server, the GGSN finds the IMSI (International Mobile Subscriber
Identification) which correlates to the IP address of the packets, and forwards the
information to the SGSN serving that IMSI. At the GGSN, the IMSI/IP address is
packaged using the GTP protocol discussed in the previous chapter. The SGSN sends a
message to the BTS to page the unit on the PPCH. After the phone starts receiving
packets, it alerts the PPP software between the server and the phone to receive PPP
packets. From this point, the packet transfer scenario is similar the Mobile IP case. In
GPRS, dynamic IP addresses can be used but there is currently no mechanism in that
network, known to the author, to have a client find the dynamically IP address of an IMSI
as requested by an external network client.
76
5.5 Summary
A discussion on the wireless voice messenger (mobile server) was presented in
this chapter. It was shown how the mobile server application allows the user to receive
instant voice messages while connected to an ISP via a data call and browsing the Web at
the same time. The software architecture using Microsoft COM was used to develop the
application while reusing components of the voice messaging client application. To
receive a general understanding of the link between the mobile computer and the mobile
phone, chapter 5 also presented the OSI model for computer communications, focusing in
the lower layers, namely: physical, link and network. With this understanding, the PPP
protocol was presented as it is being used for Mobile IP and GPRS.
77
CHAPTER 6SYSTEM IMPLEMENTATION AND PERFORMANCE ANALYSIS
6.1 Introduction
In previous chapters we have shown the theoretical and implementation concepts
behind the instant voice messaging client/server developed. The goal of this chapter is to
present a final system specification for the system implemented. Also, several
experiments were conducted using standard Windows networking tools (ping, tracert, and
Windump [32]). Appendix B shows the source code for the entire client and server
application and Appendix C shows the results from the performance tests.
6.2 Software Components
6.2.1 Instant Voice Messaging Client
The software components of the Instant Voice Messaging Client are shown in
Figure 3.5. Following is a description of each software source code module.
6.2.1.1 GUI
1. Gui.dsw = project file for the Gui Internet Explorer Control
2. Gui.def = Declares the module parameters for the Gui.dll
3. Gui.idl = Interface definition file
4. Gui.rc = defines the dialog resources used
78
5. Gui.cpp = dll entry point provided
6. IEGui.cpp = C++ class implementation for the IEGui coclass
7. Stdafx.cpp = provided by MS Visual C++ to include default header files
8. IEGui.h = header file for IEGui.cpp
9. Resource.h = defines the Ids for the dialog box controls
10. Stdafx.h = header file for the Stdafx.cpp
11. StringDlg.h = main program for the dialog box of the messaging client
6.2.1.2 ICQ Client
The following software modules from the ICQ API are available for free from the
http://www.icq.com website. The .h and .lib files are needed to build the Gui.dll
project; the .dll file is needed at run time.
1. ICQAPINotifications.h
2. ICQAPICalls.h
3. ICQAPIData.hICQAPIInterface.h
4. ICQMAPI.lib, dll
6.2.1.3 Record
1. Record.dsw = project file for the Record COM server DLL
2. Record.def = Declares the module parameters for the Record.dll
3. Record.idl = Interface definition file
4. Record.rc = defines the dialog resources used
5. Record.cpp == DLL entry point
79
6. Recorder.cpp = main recorder file with all methods for CRecorder and the
AcmApp functions
7. RecorderCP.h = contains the connection point methods OnFire_…() used to
notify an event sink (the COM client)
8. StdAfx.cpp = standard includes for the application
9. AcmApp.h = includes all the multimedia overhead
10. Recorder.h = header file for the CRecorder class
11. Resource.h = windows resources used by the Recorder.dll
6.2.1.4 Recorder algorithm
External event: CRecorder coclass is loaded by a client request of an interface,
which makes the Microsoft COM libraries call FinalConstruct().
- FinalConstruct() calls AcmAppInit() to initialize the recording HW
- AcmAppInit() creates the target file (AppFileNew()) (C:\Vmc.wav)
- Initialize the recording commands (AcmAppPlayRecordInitCommands())
External event: User clicks Push To Talk on the GUI (Windows calls OnPtt())
- StartRecording() is called by the OnPtt(). Initialize the target file
(AppFileNew()), open the audio hardware for recording
(acmAppPlayRecordOpen()), check the status of the open for recording
request (AcmAppPlayRecordStatus()), start recording
(AcmAppPlayRecordRecord()), check status of the recording request
(AcmAppPlayRecordStatus())
External event: User clicks Stop Talking on the GUI (Windows calls OnCancel())
80
- StopRecording() is called by OnCancel(). Stop the recording process
(AcmAppPlayRecordStop()),check status of the stop recording request
(AcmAppPlayRecordStatus()), close the audio hardware and set its state to
idle (AcmAppPlayRecordClose()), check the to make sure that the
C:\Vmc.wav file was properly written.
- Send() is called by OnCancel(). Initialize with the destination IP address/
socket/filename the ITalker interface of the VoiceSender.dll. Call the
compression mechanism (CompressSpeech()), trigger the ITalker interface to
send the file (Talk()), remove the file when done.
6.2.1.5 VoiceSender
1. VoiceSender.dsw = project file for the VoiceSender COM server DLL
2. StdAfx.cpp, .h = standard COM server includes
3. Talker.cpp, .h = main code for TCP socket client
4. VoiceSender.cpp == DLL entry point
5. VoiceSender.def = Declares the module parameters for the VoiceSender.dll
6. VoiceSender.idl = Interface definition file
7. VoiceSender.rc = defines the dialog resources used
8. Resource.h = windows resources used by the VoiceSender.dll
6.2.1.5 Client Software Installation
1. Verify that the Atl.dll and winsock.dll files exist in the machine. If these files
are not found, they can be downloaded from the Microsoft Web Site. Atl.dll
81
needs to be registered by using the regsvr32.exe program that can also be
downloaded from Micrsoft.com
2. Create a C:\Vmc directory
3. Copy the ICQMAPI.dll, IEGui.htm, Gui.dll, Record.dll and VoiceSender.dll
into the Vmc directory. Also copy the ICQMAPI.dll in the
/windows/system32 directory.
4. Run the regsvr32.exe to register VoiceSender.dll, Record.dll and Gui.dll (in
that specific order)
5. The software detects the presence of the ICQ client and will operate properly
in IP address mode if ICQ is not running. If ICQ is required, start the ICQ
client (download it for free from http://www.icq.com), and register as a user.
Add to the Contacts list of the ICQ client the ICQ id of the person that will be
receiving voice messages
6. By starting Internet Explorer 4.0 or above (the software has not been tested
with previous versions), open the IEGui.htm file. The software is now ready
to be used
6.2.1.6 Client Software Known Defects
1. The software might fail to record a message, and a TMP file is copied in the
machine desktop. An “Error recording” message appears. Remove the TMP
file from the desktop, close the Gui and Internet Explorer and run again.
2. When using ICQ and the contact person has gone offline and back online, the
ICQ API will always return the last IP address, even though the new IP
82
address is shown in the Contacts user’s details. The only way I found to fix
this problem was by resetting the computer. As harsh as it sounds, restarting
Internet Explorer, ICQ and the IEGui do not fix it. ICQ Tech support was
informed of this issue, and is looking into it.
3. When the “Send pre-recorded voice file” button is used, the last message that
appears in the message box does not get updated until the file has been sent.
6.2.2 Instant Voice Messaging Server
The software components of the Instant Voice Messaging Server are shown in
Figure 5.1. Following is a description of each software source code module.
6.2.2.1 Playback
1. Playback.dsw = project file for the Playback COM server DLL
2. Playback.cpp = DLL entry point
3. Playback.def = Declares the module parameters for the Playback.dll
4. Playback.idl = Interface definition file
5. Playback.rc = defines the dialog resources used
6. SpeechPlayer.cpp, .h = main playback with all methods for CSpeechPlayer
and the AcmApp functions
7. StdAfx.cpp, .h = standard COM server includes
8. Resource.h = windows resources used by the Playback.dll
83
6.2.2.2 SpeechPlayer algorithm
External event: SpeechPlayer coclass is loaded by a COM client request of an
interface, which makes the Microsoft COM libraries call FinalConstruct().
- FinalConstruct() calls AcmAppInit() to initialize the playback HW
- Initialize the recording commands (AcmAppPlayRecordInitCommands())
- AppFileOpen() opens the voice/sound file received, open the audio hardware
for playback (acmAppPlayRecordOpen()), check the status of the open for
playback request (AcmAppPlayRecordStatus())
External event: User accepts the voice message received, which call
StartPlayback().
- StarPlayback() calls
- AcmAppPlayRecordPlay() to start the playback process.
- A subsequent call to AcmAppPlayRecordStatus() is done to verify the
playback status of the hw.
- Calculate how long the playback takes so as not to release object before it
is done
6.2.2.3 VmsConsole
1. VmsConsole.dsw = project file for the console application
2. Main.cpp = main file that creates the socket server, and calls the playback
component
84
6.2.2.4 VmsConsole algorithm
- Create server socket
- Wait for client connection
- Accept client connection
- Read 6 bytes for voice file length
- Read all voice file contents 1 byte at a time.
- Store the voice file in c:\Vms.wav
- Close client socket
- Prompt user that message has arrived (Playback, Wait for another, Quit)
- User accepts playback
- connect to the smart pointer on the SpeechPlayer and playback the voice
file.
- User accepts wait for another connection
- The socket server goes back to listening mode
- User accepts quit
- Connection to the SpeechPlayer COM interface is released and program
terminates
6.2.2.5 Server Software Installation
1. Verify that the Atl.dll and Winsock.dll files exist in the machine. If these files
are not found, they can be downloaded from the Microsoft Web Site. Atl.dll
needs to be registered by using the regsvr32.exe program that can also be
downloaded from Micrsoft.com
85
2. Create a C:\VmS directory
3. Copy the VmsConsole.exe and Playback.dll into the VmS directory
4. Run the regsvr32.exe to register Playback.dll
5. The software will work properly without the ICQ client, but if the user desires
to be found on the Internet via ICQ (because of a dynamic IP address), start
the ICQ client. ICQ can be downloaded from http://www.icq.com.
6. Start the VmsConsole.exe and wait for a voice message to arrive.
6.2.2.6 Server Software Known Defects
As of this writing, there are no known defects in the software.
6.3 Hardware/System Components
6.3.1 Instant Voice Messaging Client Hardware/Systems
1. Compaq Presario 5716 desktop running Windows 98, Internet Explorer 5.0,
with integrated sound card
2. Lucent 56k (V.90) internal modem connected to a landline wall jack (PSTN)
3. FreeI.net Internet Service Provider
6.3.2 Instant Voice Messaging Server Hardware/Systems
1. Dell Latitude CP laptop running Windows NT 4.0 (service pak 4), with
internal sound card
2. Data ready Qualcomm QCP-2700 CDMA cellular phone and serial cable
(connected to laptop COM1)
86
3. Sprint PCS Wireless Web access, which includes the drivers for Qualcomm
phone dialing software
4. Bellsouth.net Internet Service Provider, dialed up using Windows Dial Up
networking
6.4 Performance Analysis
This section will explain the results of the experiments carried out between the
instant voice messenger server and the instant voice messaging client.
1. Drive experiment
- Description
Ping performance for the server connected to the local Bellsouth.net
ISP and client connected to local FreeI.net ISP. The experiment consisted of
sending 50 ping requests, every 2 minutes for a period of 20 minutes, from the
client to the server, while the server was being driven between different cells.
- Goals
This experiment was performed to study the performance of the
wireless-to-wireline interface, and what type of delays are being encountered
while the server was being handed-off between different cells while the test
was in progress. “mobile” around several cells. The data is included in
Appendix C.
- Results Summary
Minimum: 895 ms, Average Minimum: 1020.4 ms
Maximum: 5415 ms, Average Maximum: 2928.1 ms
87
Average: 1559.2 ms
Packet loss: 5 out of 500 = 1%
- Comments
In this experiment, we have seen that the wireless server (running at
14.4kbps in the wireless interface, and 19.2kbps PPP to the laptop) has a fairly
high ping echo return, when compared to a wireline to wireline ping
performance. The routing inside the cellular network of mobile originated and
mobile terminated IP packets, as well as the slow dialup interface on both the
client and server will contribute to the sub-optimal ping performance. The
lost packets show the unreliable nature of the wireless interface in the absence
of a TCP layer, as interference and holes in the cellular coverage will cause
packet loss.
2. Local message transfer performance experiment
- Description
Perform packets count, ping, and tracert for both machines connected
to the Motorola corporate network. In this experiment, two constant size pre-
recorded WAV files (25kB and 50kB) were sent from the client to the server,
while varying the size of the message transfer unit (number of bytes queued up
by the TCP stream socket client). The Windump program [32] was used to
capture the TCP frames and IP packets transferred between both machines,
along with transfer time and number of packets used in the transfer. The
actual results are shown in Appendix C. Trace route and ping was captured to
88
analyze the performance of the connection. NOTE: The IP addresses in this
section have been removed from the results because they belong to the
Motorola internal network. They have been replaced with the words
CLIENT.port_number and SERVER.6300. Because the client closes the
connection to the socket server every time a transfer is complete, a different
port number appears in the CLIENT for every different transfer. The TCP
software assigns this port number. The socket SERVER port number is fixed
to 6300.
- Goals
The goal of the experiment was to use the Windump program to learn
the packet transfer performance, when the wireline client and mobile wireless
server are connected to the same network.
- Results summary
Tracert output
1 259 ms 209 ms 244 ms t_il01_e.corp.mot.com [SERVER]
2 244 ms 399 ms * t-il01-ab-e0.corp.mot.com [SERVER]
3 1344 ms 1600 ms 1604 ms t-il01-ab-port2.corp.mot.com
[SERVER]
Ping output
Minimum: 780 ms
Maximum: 2959 ms
Average: 1270 ms
Packet loss: 0 out of 50 = 0%
89
Table 6.1 Message transfer time (in seconds) and packet size for varying transfer
size (in bytes)
Message transfer size (in bytes)
1 byte 576 bytes 1152 bytes 12.5k bytes
25kB file 26.08 seconds 26.07 seconds 26.54 seconds 30.1 seconds
# of packets 111 126 123 107
50kB file 49.76 seconds 45.33 seconds 45.77 seconds 51.41 seconds
# of packets 222 247 224 222
- Comments
As can be seen by the tracert output, 2 hops link the server and the
client, but even though the ping performance is slightly better than the first
case, it is still not so great. Ping performance between wireline machines in
the same network is typically less than 1 second. From the Table 6.1, and by
looking at the Windump output data in Appendix C, we see that the variation
between the transfer of the 25kB file and the 50kB file is fairly constant. As
expected, the 50kB file takes almost as double the number of packets and the
time it takes the 25kB file. The average effective ratio of number of bytes
transferred by unit of time (bit rate) is fairly constant across all transfers.
Because the socket used is of the stream type, which does not have any
boundaries on the data, the chunking of the data transfer to 1 byte does not
have an effect in the IP layer packet. By inspecting the Windump output files
in Appendix C, it can be appreciated that all IP packets have the same size
90
(590 bytes, although for clarity not all are shown). The acks from the
SERVER are completed way after the CLIENT has completed sending all
packets, which can be explained because the mechanism used to receive
packet on the server is 1 byte at a time.
3. Remote message transfer performance experiment
- Description
This experiment is similar to the experiment in section 6.4.2, except
that the wireline client is connected to the Internet via a local exchange ISP
(FreeI.net) in West Palm Beach and the mobile server is connected to a
Gainesville area code ISP (Bellsouth.net).
- Goals
The goal of the experiment was to use the Windump program to learn
the packet transfer performance, when the wireline client and mobile wireless
server are connected to relatively remote networks.
- Results summary
Tracert output
1 147 ms 145 ms 145 ms usr59-2.mix2.Atlanta.cw.net
[166.62.49.81]
2 141 ms 145 ms 144 ms 166.62.49.65
3 153 ms 145 ms 140 ms core2-fddi-0.Atlanta.cw.net
[204.70.86.49]
4 144 ms 145 ms 145 ms core9.Atlanta.cw.net [204.70.9.97]
91
5 144 ms 150 ms 150 ms ast-uunet-nap.Atlanta.cw.net
[206.157.77.114]
6 145 ms 145 ms 139 ms 104.ATM2-
0.XR2.ATL1.ALTER.NET
7 153 ms 149 ms 150 ms 194.ATM10-0-
0.GW1.ORL1.ALTER.NET
8 158 ms 156 ms 155 ms bs-orlando-
gw.customer.ALTER.NET
9 154 ms 156 ms 155 ms 205.152.111.204
10 158 ms 159 ms 158 ms 205.152.48.90
11 159 ms 159 ms 156 ms 205.152.46.222
12 161 ms 160 ms 160 ms 209.215.248.3
13 1370 ms 1290 ms 1810 ms host-216-78-85-
19.gnv.bellsouth.net
Ping output
Minimum: 941 ms
Maximum: 1405 ms
Average: 1251 ms
Packet loss: 0 out of 20 = 0%
92
Table 6.2 Message transfer time (in seconds) and packet size for varying transfer
size (in bytes)
Message transfer size (in bytes)
1 byte 536 bytes 1152 bytes
25kB file (1st) 28.06 seconds (110
packets)
28.18 seconds (109
packets)
29.14 seconds (113
packets)
- Comments
As seen in the ping performance, there is no big difference between the
results of the previous two experiments shown in sections 6.4.1 and 6.4.2. A
major difference is the tracert output that shows 12 hops between the wireline
client and the wireless server. This number of hops did not affect the
performance of the ping.
To better understand the Windump output as shown in Appendix C, a hex
editor/viewer was used to look at the contents of the 25kB file and find these in
the Windump output file. These contents are marked to show how the TCP/IP
stack in Windows allocates the data. From table 6.2 and the results, it can be
appreciated how packets smaller than the standard packet size of 590 bytes are
sent, and that there is no noticeable difference by chunking the data sent to the
TCP layer.
93
6.5 Summary
In this chapter we have shown a description of all the source files for both the
client and server. All of the code was developed, compiled and tested using the
Microsoft Visual C++ compiler in Windows NT and Windows 98 systems. The list of all
the equipment used for the system implementation was also shown. The software in the
client is called from the Internet Explorer in Windows, and the server software is a
console application. In the later sections of the chapter, it was discussed the experiments
performed with the system using the Windump program, which is available free of charge
from http://netgroup-serv.polito.it/windump/. As seen in the results from Appendix C,
the TCP packets set the message segment size (mss) flag to 536 bytes, and the PUSH flag
is used. As stated in RFC793 [33], when these flags are used, the client application
indicates in each SEND call whether the data in that call (and any preceding calls) should
be immediately pushed through to the receiving user by the setting of the PUSH flag. The
client TCP stack is buffering data from the application SEND calls and sending that data
in segments at its own convenience. Thus the MTU parameter in the main client window
does not have a direct effect in the TCP layer, except one of how much the data is being
parsed and buffered.
It can be inferred from the experiments results that the wireless air interface,
although slow (compared to wireline connection rates), is fairly reliable when used in a
connection oriented (TCP) framework. The TCP layer suppresses the susceptibility to RF
interference, although the throughput is effectively reduced. These experiments were
performed in South Florida, where the CDMA cellular data network coverage used is
94
relatively good (as shown in the phone signal strength indicator). The system was also
tested in the Laboratory for Information Systems Technology (LIST) in the University of
FL, Gainesville. Contrary to the situation in South Florida, the signal strength in the
LIST lab was less than optimal, so voice messages took longer to arrive to the wireless
server.
One caveat of the 2G CDMA data network utilized is that, being circuit switched,
billing is on a per minute basis. With this model, the wireless server usage model is not
very feasible economically for the wireless server user because a server is designed to
stay online for long periods of time waiting for connections from clients. A better
consumer-oriented approach is the packet data network proposed by GPRS or iDEN™.
In both of these the consumer is billed by the amount of data transferred, not by the length
of time of the connection. With these packet switched model unlimited data rates can be
offered to the consumer because when no data is being transferred by a particular device,
the air interface channel is reused by other devices.
The ICQ hook in the client/server application was introduced as a powerful bridge
to allow dynamic and fixed IP addresses (like Mobile IP) to be destination servers for the
voice messaging application. The ICQ server, by means of running the ICQ client in the
instant voice messaging client and server, provides our application an IP address lookup
mechanism for dialup servers that get a dynamic address assigned at every dialup session.
In the next chapter, we will describe future enhancements to the instant wireless
voice messaging application.
95
CHAPTER 7FURTHER WORK
7.1 Introduction
This chapter will present suggested future work required to enhance the features
of the instant voice messaging application. Each section is divided into Requirements
and Implementation.
7.2 Reverse Channel
An interesting and relatively uncomplicated feature is to add a reverse channel so
that the user that receives the voice message has the option of returning a reply to the
sender. Because of the component technology used in the current version, a lot of reuse
of these components is expected if this feature is added. In the context of this new
feature, the voice messaging client will be known as the caller and the voice messaging
server will become the called.
For this feature, it will be simpler if the VmsConsole is converted to a COM
based project using Visual C++ 6.0, but can also be done manually by an experienced
COM programmer.
96
7.2.1 Requirements
1. Both caller and called execute the VmsConsole.exe/Playback.dll and
IEGui.htm /Gui.dll/Record.dll/ VoiceSender.dll packages.
2. Convert the VmsConsole.exe to COM based so that a new interface
(IConnectingIP) can be created and exposed for the connecting IP address.
The IP address is initialized when the accept() (socket server) function
returns.
3. Provide a GUI control to allow the called to generate a message reply to the
caller. Upon clicking this control, the GUI will fetch the connecting IP
address from the VmsConsole.exe component.
4. Save the voice message in a file named Vmc_r.wav.
7.2.2 Implementation Details for Server
Requirements/Design implementation details are shown to give the future work
designer a reference on the existing design. This section does not necessarily show the
optimal implementation approach, although a lot of effort was given to this.
1. (For Req 3) In the Gui.dll Stringdlg.h file, add a “Send Reply” button, and an
OnSendReply() method. This method will connect to the VmsConsole (via
the new COM interface IConnectingIP) to fetch the IP address of the last voice
file received, and put it in the IP control.
2. (For Req 2) In the VmsConsole, create a new COM interface
(IConnectingClient) so that, the when a voice file is received, the IP address of
the connecting client is set.
97
7.3 Alternative to Real Time IP Telephony
In this scenario, a QoS based mechanism (via a packet counter using Windump,
and ping echo return performance) can be devised to choose between a real time voice
call over the Internet or a voice messaging approach in case the Internet is congested.
The solution proposed requires that the caller and called have access to the Internet
telephony software (like DialPad) and the Vmc/Vms software described in section 7.2.
Figure 7.1 shows the architecture diagram proposed.
Basically, the QoSApp will perform a ping echo return analysis on the user
supplied IP address (or via ICQ # resolution to IP address). Once the performance of the
QoSApp
ICQClient
ICQClient
Vms/Vmc
IPTelephonyApp
Vms/Vmc
IPTelephonyApp
Caller CalledInternet
Ping echo
Windump
UserICQ #or IP
Figure 7.1 QoSApp architecture
98
network linking both machines has been measured, the QoSApp will launch the
Vmc/Vms app (for high network latency) or the IP telephony app (for low network
latency). The network performance criteria to choose which application is launched can
be determined by experiments.
The QoSApp can be a implemented in a Perl script that calls functions from other
executables (ping and Windump), checks the results, and calls another program
depending on the executable output. An equivalent application is needed in the called
party so that when a decision has been made in the caller of which application to use,
both can synchronize to the same application.
7.4 High Compression Codec
The software on the Vmc and Vms was designed to be easily expandable to
improve on the voice file transfer rate by installing a high compression codec. In the
voice messaging client, the compress interface is in the Recorder coclass in the Record.dll
COM server, and has been defined and merged into the code. In the voice messaging
server, the uncompress interface is in the SpeechPlayer coclass in the Playback.dll COM
server, and is the equivalent method used to uncompress the WAV file.
99
For the client, the developer has to implement in the
ISpeechCompressor.CompressSpeech() method a codec that converts a PCM 8kHz/8 bits
WAV file into another format. This method is called by the CRecorder::Send() before the
voice message is sent over the TCP socket. For the server, the
ISpeechUncompressor.UncompressSpeech() needs to implement the reverse of the
compression performed in CompressSpeech(). The UncompressSpeech() method is
called by the CSpeechPlayer::FinalConstruct() before the voice message is sent to the
audio hardware for playback.
100
CHAPTER 8CONCLUSION
The author has been working in the messaging industry for more than 7 years, and
has seen a dramatic increase in the need time-challenged people have for messaging
applications, and the way the devices that enable messaging have evolved. First simple
pagers, then cellular SMS, now Internet based messaging that follows the user even when
there is not a single traditional phone line available. With such busy lifestyles, these
people can benefit from not loosing messages while they are connected to the Internet.
One area of research is unified messaging, where users can log on to a messaging
provider (for example, http://www.messageclick.com) and use a single phone number for
all messaging needs (fax, email, voicemail, etc.). The application developed here, with
the enhancements shown in sections 7.2 and 7.3, can be used in multi-mode (real-time
telephony or voice chat or voice mail). Using the technique of TCP socket ports,
different messaging client/server apps can communicate allowing TCP/IP based
messaging. The extension of Internet messaging applications to the wireless world shall
also include consideration of the underlying transport and network layers. The TCP layer
is not optimized for wireless due to the slow-start feature of the protocol (see Section
13.1.4 in [26]), and several techniques need to be developed to minimize wireless handset
battery consumption while messaging applications are being delivered. This work shall
serve as a development platform for the research of these initiatives.
101
In this work we have presented a model of wireless servers, which is a different
paradigm than the traditional client (mobile)/server (static) approach. Our intention was
to demonstrate one use for such model, which is enabled by the application of Mobile IP
to packet data networks, GPRS, and user name lookup techniques (like ICQ). The
computing power required by these wireless messaging servers can and will be exploited
by the mobile phone/laptop computer combination approach. The number of fast and full
applications used in laptops, and the fast air interfaces promised by the CDMA HDR,
GPRS EDGE, etc; will permit users to keep this same usage model until PDAs begin to
replace laptops.
102
APPENDIX ASCREEN CAPTURES OF VMC AND VMS
Figure A.1 Default Instant Voice Message Client When ICQ is Not Running
103
Figure A.2 Default Instant Voice Message Client GUI When ICQ Is Running
104
Figure A.3 Instant Voice Message Client GUI After Entering Fields, And “Push To Talk”Is Clicked
105
Figure A.4 Instant Voice Message Client GUI After Clicking On “Send Pre-RecordedMessage”
106
Figure A.5 Instant Voice Message Client GUI After Message Has Been Successfully Sent
107
Figure A.6 Instant Voice Message Server Console Waiting For A Connecting Client
108
Figure A.7 Instant Voice Message Server Console Receiving A Voice File From A Client
109
Figure A.8 Instant Voice Message Server Console After A Voice File Has Been Received
110
Figure A.9 Instant Voice Message Server Console While A Voice File Is Being Playback
111
APPENDIX BVOICE MESSAGING CLIENT AND VOICE MESSAGING SERVER SOURCE CODE
B.1 Voice Messaging Client Source Code
B.1.1 Gui Dll
<! IEGUI.htm = This is the html file used to load the GUI inside INternet Explorer ><HTML><HEAD><TITLE>ATL 3.0 test page for object IEGui</TITLE></HEAD><BODY><OBJECT ID="IEGui" CLASSID="CLSID:19A2966E-5122-11D3-BD2C-828A6439BC24"></OBJECT></BODY></HTML>
//*****************************************************// IEGui.h : Declaration of the CIEGui//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. Changes made by the author to the// file are marked by 'Comment by CR:'.// This is the header file implementation of the CIEGui class.// CIEGui is the C++ dependent implementation of the IEGui coclass.//-----------------------------------------------------
#ifndef __IEGUI_H_#define __IEGUI_H_
#include "resource.h" // main symbols#include <atlctl.h>
// Comment by CR: This is the header file for the client dialog box definition#include "stringdlg.h"
/////////////////////////////////////////////////////////////////////////////// CIEGui// Comment by CR: CIEGui definition with all of the Internet Explorer required interfacesclass ATL_NO_VTABLE CIEGui :
public CComObjectRootEx<CComSingleThreadModel>,public IDispatchImpl<IRecordingListener, &IID_IRecordingListener, &LIBID_GUILib>,public CComControl<CIEGui>,public IPersistStreamInitImpl<CIEGui>,
112
public IOleControlImpl<CIEGui>,public IOleObjectImpl<CIEGui>,public IOleInPlaceActiveObjectImpl<CIEGui>,public IViewObjectExImpl<CIEGui>,public IOleInPlaceObjectWindowlessImpl<CIEGui>,public IPersistStorageImpl<CIEGui>,public ISpecifyPropertyPagesImpl<CIEGui>,public IQuickActivateImpl<CIEGui>,public IDataObjectImpl<CIEGui>,public IProvideClassInfo2Impl<&CLSID_IEGui, NULL, &LIBID_GUILib>,public CComCoClass<CIEGui, &CLSID_IEGui>
{public:CIEGui()
{m_rc.left = 0;m_rc.top = 0;m_rc.right = 25;m_rc.bottom = 25;
}
DECLARE_REGISTRY_RESOURCEID(IDR_IEGUI)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CIEGui)COM_INTERFACE_ENTRY(IRecordingListener)COM_INTERFACE_ENTRY2(IDispatch, IRecordingListener)COM_INTERFACE_ENTRY(IViewObjectEx)COM_INTERFACE_ENTRY(IViewObject2)COM_INTERFACE_ENTRY(IViewObject)COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)COM_INTERFACE_ENTRY(IOleInPlaceObject)COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)COM_INTERFACE_ENTRY(IOleControl)COM_INTERFACE_ENTRY(IOleObject)COM_INTERFACE_ENTRY(IPersistStreamInit)COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)COM_INTERFACE_ENTRY(ISpecifyPropertyPages)COM_INTERFACE_ENTRY(IQuickActivate)COM_INTERFACE_ENTRY(IPersistStorage)COM_INTERFACE_ENTRY(IDataObject)COM_INTERFACE_ENTRY(IProvideClassInfo)COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP()
BEGIN_PROP_MAP(CIEGui)PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)// Example entries// PROP_ENTRY("Property Description", dispid, clsid)// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()
BEGIN_MSG_MAP(CIEGui)CHAIN_MSG_MAP(CComControl<CIEGui>)DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
// Handler prototypes:// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
// IViewObjectExDECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
// IIEGuipublic:
113
HRESULT OnDraw(ATL_DRAWINFO& di){
return S_OK;}
HRESULT InPlaceActivate( LONG iVerb, const RECT* prcPosRect);
private:RECT m_rc;
// Comment by CR: This is the Dialog class used by the CIEGui to implement all the necessary dialog// controls (buttons, edit boxes, etc.)CStringDlg m_CVmcDialog;
};
#endif //__IEGUI_H_
//*****************************************************// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently,// but are changed infrequently//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. No changes were made by the author.//-----------------------------------------------------
#if !defined(AFX_STDAFX_H__19A29664_5122_11D3_BD2C_828A6439BC24__INCLUDED_)#define AFX_STDAFX_H__19A29664_5122_11D3_BD2C_828A6439BC24__INCLUDED_
#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000
#define STRICT#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define _ATL_APARTMENT_THREADED
#include <atlbase.h>//You may derive a class from CComModule and use it if you want to override//something, but do not change the name of _Moduleextern CComModule _Module;#include <atlcom.h>#include <atlctl.h>
//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__19A29664_5122_11D3_BD2C_828A6439BC24__INCLUDED)
114
//*****************************************************// stringdlg.h//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file is the main voice messaging client window.// It implements a dialog box class with controls to record// cancel, and send messages. Provides input to the user// for the IP address or ICQ number of the destination// machine. The ICQ api is used to convert an ICQ number to// an IP address.//-----------------------------------------------------
// Comment by CR: This include provides COM definitions for the controls inside// the dialog. This software DOES NOT use MFC, so AtlControls.h is the// answer to use buttons, combo boxes, etc. in a dialog#include <AtlControls.h>#include <math.h>#include <time.h>
// Comments by CR: These are the ICQ APIs defines. These defines are// implemented in the#include "ICQAPINotifications.h"#include "ICQAPICalls.h"#include "ICQAPIData.h"#include "ICQAPIInterface.h"
#pragma once#include "resource.h"
// Comment by CR: Record.tlb is the type library that contains the Recorder// component and the ISpeechRecorder interface.#import "Record.tlb" raw_interfaces_only, no_namespace, named_guids#define lengthof(rg) (sizeof(rg)/sizeof(*rg))
#define IDLE 0#define RECORDING 1
void __stdcall OnReady();
class CStringDlg; //forward declaration, allows the next line to compile properly// Comment by CR: typedef for the IDispEventImpl<> ATL template to support connection points on// this class event sink maptypedef IDispEventImpl<0, CStringDlg, &DIID__IRecorderEvents, &LIBID_RECORDLib, 1, 0> IEventSink;
// Comment by CR: CStringDlg class which implements an instance of an ATL CDialogImpl// template class. This is the dialog box that implements the IDD_DIALOG1 dialog// resource of Gui. Also implements the behavior of an event sink to receive// 'Done recording' messages from the Recorder component.class CStringDlg : public CDialogImpl<CStringDlg>,
public IEventSink //CR.{public:
// Comment by CR: Constructor initializes all member attributes CStringDlg() {
*m_sz = 0;m_nStatus=IDLE;m_lpszIPAddress = new char [16];memset(m_lpszIPAddress,16,NULL);m_nIcqApiVersion=-1;
115
}
// Comment by CR: The sink map defines the interface that fires the event on the source (Recorder)// and the method (OnReady) to be called from this class (sink)BEGIN_SINK_MAP(CStringDlg)
SINK_ENTRY_EX(0, DIID__IRecorderEvents, 1, OnReady)END_SINK_MAP()
// Comment by CR: Message map defines method calls when a message is handled by WindowsBEGIN_MSG_MAP(CStringDlg) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDOK, OnOK) // Comment by CR: When clicking Close button COMMAND_ID_HANDLER(IDCANCEL, OnCancel) // Comment by CR: When clicking Stop Talking COMMAND_ID_HANDLER(IDC_PTT, OnPtt) // Comment by CR: When clicking Push to Talk COMMAND_ID_HANDLER(IDC_ABORT, OnAbort) // Comment by CR: When clicking Abort COMMAND_ID_HANDLER(IDC_SEND_PRERECORDED, OnSendPrerecorded) // Comment by CR: When clicking Send pre-recordedEND_MSG_MAP()
enum { IDD = IDD_DIALOG1 }; TCHAR m_sz[64];
// Comment by CR: This is the event sink method is called by the event source (Recorder) // when a certain event is completed in the source. The events handled are the start // and stop talking events, to allow for the voice message to be transfered properly. void __stdcall OnReady() {
USES_CONVERSION;
char szMessageString[256];memset(szMessageString,256,NULL);sprintf(szMessageString,"Recorder completed start/stop/compress operation!");
m_Edit.SetWindowText(szMessageString); }
private: // Comment by CR: when first time, Gui initializes all smart pointers. If not first time // it will use these smart pointers, as they have been init already. This permits the Gui // to be hidden minimized without having to recreate the poiters to the COM server. BOOL m_bFirstTime; // Comment by CR: These are the smart pointers used to access the interfaces in the // Record DLL. CComQIPtr<ISpeechRecorder> m_spSR; CComQIPtr<ISpeechMessenger> m_spSM;
// Comment by CR: Method called when the Gui is loaded in the Internet Explorer LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&) {
// Comment by CR: Initialize the ICQ library. Enter here a new name, password and IDICQAPICall_SetLicenseKey("LicenseeName","LicenseePassword","LicenseNumber");// Comment by CR: If the password and License key worked okICQAPICall_GetVersion(m_nIcqApiVersion);
CenterWindow();
// Comment by CR: Assign the IDD_DIALOG1 controls to the IEGui dialog m_Edit.Attach(GetDlgItem(IDC_EDIT1));
m_IP.Attach(GetDlgItem(IDC_IPADDRESS1));m_IcqNumberCombo.Attach(GetDlgItem(IDC_ICQCOMBO));
m_MtuSize.Attach(GetDlgItem(IDC_MTU_COMBO));m_PrerecordedFileName.Attach(GetDlgItem(IDC_PRERECORDED_COMBO));
// Comment by CR: Initialize all the dialog controlsm_IP.ClearAddress();m_MtuSize.AddString("1");m_MtuSize.AddString("288");
116
m_MtuSize.AddString("576");m_MtuSize.AddString("1152");m_PrerecordedFileName.AddString("c:\\Vmc_pr_25k.wav");m_PrerecordedFileName.AddString("c:\\Vmc_pr_50k.wav");
// Comment by CR: Notify user if ICQ not runningif ( m_nIcqApiVersion == -1 ){
m_IcqNumberCombo.AddString("NO ICQ ready!");m_Edit.SetWindowText("No ICQ. System will only work with IP address.");
}else{ // Comment by CR: These are default ICQ number used to test the system
m_IcqNumberCombo.AddString("60960293");m_IcqNumberCombo.AddString("60964539");
}
LRESULT hr=0;// Comment by CR: If this is the 1st the Gui is loaded initialize the connection// to the Recorder ISpeechRecorder interface by creating/init the smart pointerif ( m_bFirstTime ){
m_bFirstTime = FALSE;
// Comment by CR: Get the ISpeechRecorder from the Record.dllhr = (LRESULT) m_spSR.CoCreateInstance (__uuidof(Recorder));// Comment by CR: Once the pointer is initialized and pointing the created// instance to the Recoder component, it can be used to query other interfaces,// in this case the ISpeechMessenger.m_spSR->QueryInterface(reinterpret_cast<ISpeechMessenger **> (&m_spSM));
if (SUCCEEDED(hr)){
// Comment by CR: Check that the source has been initialized. Init is done by// the constructor of the _IDispEvent class and means that the connection point// can be connected and disconnected from the sinkif ( IEventSink::m_dwEventCookie != 0xFEFEFEFE )
DisconnectServer();
try{
// Comment by CR: Check the IRecorderEvents interface (event source)// interface is validhr = IEventSink::DispEventAdvise( m_spSR, & DIID__IRecorderEvents);if (FAILED(hr))
_com_issue_error(hr);}catch (_com_error e){
ATLTRACE(_T("Cannot create server, %x"), e.Error());return e.Error();
}}
}
// Comment by CR: Set the default recording status to idlem_nStatus = IDLE;
return 1; // Let dialog manager set initial focus }
LRESULT OnSendPrerecorded(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) //CR. {
char szWavFileName[256];
m_Edit.SetWindowText("Sending pre-recorded file ..."); if ( m_nStatus == IDLE )
117
{ if ( this->FetchIPAddress() == TRUE ) {
memset(szWavFileName,NULL,sizeof(szWavFileName)); m_PrerecordedFileName.GetWindowText(szWavFileName,255);
if ( strlen(szWavFileName) ) {
if ( m_spSM->SetWavFileName(szWavFileName) == S_OK ) this->SendMsg();
else {
m_Edit.SetWindowText("Wav file was not found or could not be opened!"); return ( ! S_OK );
} } else
m_Edit.SetWindowText("No Wav file name was specified ! Try again.");
return S_OK; } else
return ( ! S_OK ); } else {
m_Edit.SetWindowText("PTT was pressed first! Abort or Stop Talking before attempting to send file"); return ( ! S_OK );
} }
// Comment by CR: When clicking Push to Talk, Windows calls this method LRESULT OnPtt(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) //CR. { if ( this->FetchIPAddress() == TRUE )
{ m_Edit.SetWindowText("Wait for signal to start talking ...");
// Comment by CR: Connect to the StartRecording method of the ISpeechRecorder interface // When is completed, StartRecording fires an event which the the CStringDlg::OnReady() // method if ( m_spSR->StartRecording() != S_OK ) {
m_Edit.SetWindowText("Error in Voice Capture hardware. Close application!"); return ( ! S_OK );
}
// Comment by CR: Update the status attribute so that the Gui knows what the recorder is // doing m_nStatus = RECORDING; return S_OK;
} else
return ( ! S_OK ); }
// Comment by CR: Called when user click on Stop Talking LRESULT OnCancel(WORD, UINT, HWND, BOOL&) { // Comment by CR: Check if recording. Can only stop if recording not if idle.
if ( m_nStatus == RECORDING ){
m_Edit.SetWindowText("Ready to stop recording.");
// Comment by CR: Stop recording and let the message be sent to the userif ( m_spSR->StopRecording() != S_OK ){
m_Edit.SetWindowText("Error in Voice Capture hardware. Close application!");
118
return 0;}
// Comment by CR: Using the ISpeechMessenger interface, send the message to the// final IP addressthis->SendMsg();// Comment by CR: System is now ready to record againm_nStatus = IDLE;
}else
m_Edit.SetWindowText("No message. Press Push To Talk first.");
return 0; }
// Comment by CR: When clickin Close, release the handles to the interfaces in Record.dll // so that OS can free up the DLL. Also close the Window, which will require reload to get // Gui to start again LRESULT OnOK(WORD, UINT, HWND, BOOL&) {
m_spSR.Release();m_spSM.Release();
CWindow::DestroyWindow(); return 0; }
// Comment by CR: When clickin Abort, if user does not want to send message LRESULT OnAbort(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) //CR. {
if ( m_nStatus == RECORDING ){
m_Edit.SetWindowText("Ready to Abort recording.");// Comment by CR: StopRecording and set the state to IDLEif ( m_spSR->StopRecording() != S_OK ){
m_Edit.SetWindowText("Error in Voice Capture hardware. Close application!");return 0;
}m_nStatus = IDLE;m_Edit.SetWindowText("Ready to record.");
}else
m_Edit.SetWindowText("Not recording. Press Push To Talk first.");
return 0; }
private:
// Comment by CR: These are the private attributes of the class int m_nStatus; ATLControls::CIPAddressCtrl m_IP; ATLControls::CEdit m_Edit; ATLControls::CComboBox m_IcqNumberCombo; ATLControls::CComboBox m_MtuSize; ATLControls::CComboBox m_PrerecordedFileName; LPTSTR m_lpszIPAddress; UINT m_SocketPort; int m_nIcqApiVersion;
// Comment by CR: This method is used to disconnect from the connection point // event source (IRecorderEvents interface) void DisconnectServer() {
if (IEventSink::m_dwEventCookie)
119
IEventSink::DispEventUnadvise( m_spSR, & DIID__IRecorderEvents);
IEventSink::m_dwEventCookie = 0xFEFEFEFE; }
void SendMsg() //CR. {
// Comment by CR: Using the ISpeechMessenger interface, send the message to the // final IP address
char szMtuSize[256]; UINT nPacketSize = 576; memset(szMtuSize,NULL,sizeof(szMtuSize));
m_MtuSize.GetWindowText(szMtuSize,255);
// Comments by CR: modify the default, only if a value has been chosen if ( strlen(szMtuSize) )
sscanf(szMtuSize,"%d",&nPacketSize);
// COmments by CR: Measure the elapsed time while transmitting char szMessage[256]; memset(szMessage,NULL,sizeof(szMessage));
clock_t startTime = 0; clock_t endTime = 0; double elapsedTime = 0.0;
startTime = clock(); if ( m_spSM->Send( m_lpszIPAddress, nPacketSize) != S_OK ) {
endTime = clock(); elapsedTime = (double) (endTime-startTime)/CLOCKS_PER_SEC; sprintf(szMessage,"Error Sending message! Elapsed time = %3.3f",elapsedTime); m_Edit.SetWindowText(szMessage);
} else {
endTime = clock(); elapsedTime = (double) (endTime-startTime)/CLOCKS_PER_SEC; sprintf(szMessage,"Done. Elapsed time = %3.3f. Ready for another.",elapsedTime); m_Edit.SetWindowText(szMessage);
} }
BOOL FetchIPAddress() {
char szIcqNumber[256]; DWORD dwAddress= 0; BSICQAPI_User bsiIcqUser;
// Comment by CR: Initialize the array and ICQ user struct memset(szIcqNumber,NULL,sizeof(szIcqNumber)); memset(&bsiIcqUser,0,sizeof(bsiIcqUser));
// Comment by CR: Accept ICQ number only if ICQ is running if ( m_nIcqApiVersion != -1 )
m_IcqNumberCombo.GetWindowText(szIcqNumber,255);
// Comment by CR: ICQ number has precedence, so check if it is there if ( !strlen(szIcqNumber) && m_IP.IsBlank() == TRUE ) {
// Comment by CR: At least an IP or ICQ number needs to be present if ( m_nIcqApiVersion != -1 )
m_Edit.SetWindowText("Please enter valid ICQ number OR IP address first."); else
m_Edit.SetWindowText("Please enter valid IP address first (ICQ is not running)."); return FALSE;
} else if ( strlen(szIcqNumber) )
120
{ // Comment by CR: ICQ number found, clear the IP address field and store the // ICQ number in the ICQ data structure m_IP.ClearAddress(); sscanf(szIcqNumber,"%d", &bsiIcqUser.m_iUIN);
// Comment by CR: Call the ICQ API to get the IP address of the ICQ number ICQAPICall_GetFullUserData(& bsiIcqUser,m_nIcqApiVersion); // Comment by CR: IP address returns in nondot format, convert it to dot format; which // is most significant first DWORD field0, field1, field2, field3; field0 = 0; field1 = 0; field2 = 0; field3 = 0;
sprintf(m_lpszIPAddress,"%u.%u.%u.%u",(field0=(bsiIcqUser.m_iIP)&0x000000FF),
(field1=((bsiIcqUser.m_iIP)&0x0000FF00)/0x000000FF),
(field2=((bsiIcqUser.m_iIP)&0x00FF0000)/0x0000FFFF),
(field3=((bsiIcqUser.m_iIP)&0xFF000000)/0x00FFFFFF)); // Comment by CR: Print the found IP address into the IP control. First need to convert // it most significant last. ICQ returns the IP address backwards from the way our IP control // requires it. dwAddress = (field0*0x01000000) +
(field1*0x00010000) + (field2*0x00000100) + field3;
m_IP.SetAddress( dwAddress );
// Comment by CR: Release the ICQ structure. This is done so that if user details change // ( user goes offline back online), the Gui grabs the latest information. ICQAPIUtil_FreeUser( & bsiIcqUser ); return TRUE;
} else // Comment by CR: Fetch the IP address from the control not ICQ {
// Comment by CR: An ICQ number is not found, then use the IP address entered m_IP.GetAddress(&dwAddress); // Comment by CR: Conver the number to dot format, which is least significant first sprintf(m_lpszIPAddress,"%u.%u.%u.%u",(dwAddress&0xFF000000)/0x00FFFFFF,
(dwAddress&0x00FF0000)/0x0000FFFF,
(dwAddress&0x0000FF00)/0x000000FF,
dwAddress&0x000000FF); return TRUE;
} }};
//******************************************************// Gui.cpp : Implementation of DLL Exports.// Note: Proxy/Stub Information// To build a separate proxy/stub DLL,// run nmake -f Guips.mk in the project directory.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000
121
//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. No changes were made to the// automatically generated version.// Gui.dll is the COM server DLL that provides the interfaces// required to be loaded into an Internet Explorer control.//-----------------------------------------------------
#include "stdafx.h"#include "resource.h"#include <initguid.h>#include "Gui.h"
#include "Gui_i.c"#include "IEGui.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)OBJECT_ENTRY(CLSID_IEGui, CIEGui)END_OBJECT_MAP()
/////////////////////////////////////////////////////////////////////////////// DLL Entry Point
extern "C"BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/){ if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance, &LIBID_GUILib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok}
/////////////////////////////////////////////////////////////////////////////// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void){ return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;}
/////////////////////////////////////////////////////////////////////////////// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){ return _Module.GetClassObject(rclsid, riid, ppv);}
/////////////////////////////////////////////////////////////////////////////// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void){ // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE);}
/////////////////////////////////////////////////////////////////////////////// DllUnregisterServer - Removes entries from the system registry
122
STDAPI DllUnregisterServer(void){ return _Module.UnregisterServer(TRUE);}
//*****************************************************// Gui.idl : IDL source for Gui.dll//
// This file will be processed by the MIDL tool to// produce the type library (Gui.tlb) and marshalling code.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. Changes made by the author to the// file are marked by 'Carlos:'.// Gui.dll is the COM server DLL that provides the interfaces// required to be loaded into an Internet Explorer control.// This file provides the interface definition language (idl)// for the interfaces exposed by coclasses in the Gui.dll.//-----------------------------------------------------
import "oaidl.idl";import "ocidl.idl";#include "olectl.h"
// IRecordingListener Interface// Comments by CR: The IRecordingListener dispatch interface is to be implemented by the// DispatchImpl class of the IEGui coclass. Internet Explorer compatible components// (like IEGui) require a Dispatch interface. No methods are implemented because this// interface is being provided for compatibility with IE.[
object,uuid(CDE1DA20-53F5-11d3-BD2C-F437BEA48224),dual,helpstring("IRecordingListener Interface"),pointer_default(unique)
]interface IRecordingListener : IDispatch{};
[uuid(19A29661-5122-11D3-BD2C-828A6439BC24),version(1.0),helpstring("Gui 1.0 Type Library")
]library GUILib{
importlib("stdole32.tlb");importlib("stdole2.tlb");// Carlos: Because the Gui is a COM client of the Recorder component// defined in the Record.dll, include the type library to allow smart// pointers to access the interfaces in the Recorder compoenent.importlib("..\Record\Record.tlb");
// Carlos: The IEGui coclass is the actual component of the Gui.dll that implements// an Internet Explorer compatible control.
123
[uuid(19A2966E-5122-11D3-BD2C-828A6439BC24),helpstring("IEGui Class")
]coclass IEGui{
[default] interface IRecordingListener;// Carlos: This is the connection point sink (connection point receiver)// to the Recorder component connection point source (connection point trigger).dispinterface _IRecorderEvents;
};};
//*****************************************************// IEGui.cpp : Implementation of CIEGui//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. Changes made by the author to the// file are marked by 'Carlos:'.// This is the implementation of the CIEGui class. CIEGui// the C++ dependent implementation of the IEGui coclass.//-----------------------------------------------------#include "stdafx.h"#include "Gui.h"#include "IEGui.h"
/////////////////////////////////////////////////////////////////////////////// CIEGui// Comment by CR: This method is called when the component is being loaded in the// parent window. It calls the base class InPlaceActivate() then prepares the// Voice Messaging Client (CVmcDialog) to be presented in the parent window// (Internet Explorer)HRESULT CIEGui::InPlaceActivate( LONG iVerb, const RECT* prcPosRect){
HRESULT hr=0;
hr = CComControlBase::InPlaceActivate(iVerb, prcPosRect);
// Comment by CR: create the m_CVmcDialog window, then show it inside the parentm_CVmcDialog.Create( ::GetActiveWindow(), m_rc, NULL );m_CVmcDialog.EnableWindow(TRUE);m_CVmcDialog.ShowWindow(TRUE);
return hr;}
//*****************************************************// stdafx.cpp : source file that includes just the standard includes// stdafx.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron
124
// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Gui.dll workspace. No changes were made by the author.// Gui.dll is the COM server DLL that provides the interfaces// required to be loaded into an Internet Explorer control.//-----------------------------------------------------#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY#include <statreg.h>#include <statreg.cpp>#endif
#include <atlimpl.cpp>
125
B.1.2 Record Dll
//*****************************************************// AcmApp.h = Includes all the necessary ovrhead for the// Audio Control Manager (ACM) and the Media Control Interface// (MCI)//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was adapted from the AcmApp application in the// Microsoft Developer's network library.//-----------------------------------------------------
#include <windows.h>#include <mmsystem.h>#include <mmreg.h>#include <msacm.h>
#define _tcstoul strtoul
#ifndef INLINE #define INLINE __inline#endif
#ifndef SIZEOF #ifdef UNICODE #define SIZEOF(x) (sizeof(x)/sizeof(WCHAR)) #else #define SIZEOF(x) sizeof(x) #endif#endif
//// ACMAPPINST.fdwState flags//#define ACMAPPFILEDESC_STATEF_MODIFIED 0x80000000L
#define APP_MAX_FILE_PATH_CHARS 144#define APP_MAX_FILE_TITLE_CHARS APP_MAX_FILE_PATH_CHARS#define APP_MAX_STRING_CHARS 128#define APP_MAX_APP_NAME_CHARS 30#define APP_MAX_EXT_DEFAULT_CHARS 4#define APP_MAX_EXT_FILTER_CHARS 256#define APP_MAX_STRING_RC_CHARS 512#define APP_MAX_STRING_ERROR_CHARS 512#define APP_OPTIONSF_DEBUGLOG 0x0004#define APP_OPTIONSF_AUTOOPEN 0x0001
#define AAPLAYRECORD_MAX_MCI_COMMAND_CHARS 255#define AAPLAYRECORD_STATUS_NOT_OPEN (UINT)-1#define AAPLAYRECORD_STATUS_NOT_READY 0#define AAPLAYRECORD_STATUS_PAUSED 1#define AAPLAYRECORD_STATUS_PLAYING 2#define AAPLAYRECORD_STATUS_STOPPED 3#define AAPLAYRECORD_STATUS_RECORDING 4#define AAPLAYRECORD_TIMER_RESOLUTION 54#define AAPLAYRECORD_STATUS_SEEKING 5
#define WIOERR_BASE (0)#define WIOERR_NOERROR (0)
126
#define WIOERR_ERROR (WIOERR_BASE+1)#define WIOERR_BADHANDLE (WIOERR_BASE+2)#define WIOERR_BADFLAGS (WIOERR_BASE+3)#define WIOERR_BADPARAM (WIOERR_BASE+4)#define WIOERR_BADSIZE (WIOERR_BASE+5)#define WIOERR_FILEERROR (WIOERR_BASE+6)#define WIOERR_NOMEM (WIOERR_BASE+7)#define WIOERR_BADFILE (WIOERR_BASE+8)#define WIOERR_NODEVICE (WIOERR_BASE+9)#define WIOERR_BADFORMAT (WIOERR_BASE+10)#define WIOERR_ALLOCATED (WIOERR_BASE+11)#define WIOERR_NOTSUPPORTED (WIOERR_BASE+12)
#ifndef SIZEOF_WAVEFORMATEX#define SIZEOF_WAVEFORMATEX(pwfx) ((WAVE_FORMAT_PCM==(pwfx)->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX)+(pwfx)->cbSize))#endif
//// ACMAPPINST.fdwState flags//#define ACMAPPFILEDESC_STATEF_MODIFIED 0x80000000L
//// fuFlags for AppGetFileName()...//#define APP_GETFILENAMEF_OPEN 0x0000#define APP_GETFILENAMEF_SAVE 0x0001
#define IDS_OFN_EXT_DEF 125#define IDS_OFN_EXT_FILTER 126//// the main window control id's...//#define IDD_ACMAPP_EDIT_DISPLAY 200
#define IDM_FILE_NEW 1100#define IDM_FILE_OPEN 1101#define IDM_FILE_SAVE 1102#define IDM_FILE_SAVEAS 1103#define IDM_FILE_SNDPLAYSOUND_PLAY 1104#define IDM_FILE_SNDPLAYSOUND_STOP 1105#define IDM_FILE_CONVERT 1106#define IDM_FILE_CONVERT_ALL 1107#define IDM_FILE_ABOUT 1109#define IDM_FILE_EXIT 1110
#define IDM_VIEW_SYSTEMINFO 1300#define IDM_VIEW_ACM_DRIVERS 1301#define IDM_OPTIONS_WAVEINDEVICE 1500#define IDM_OPTIONS_WAVEOUTDEVICE 1501#define IDM_OPTIONS_AUTOOPEN 1505#define IDM_OPTIONS_DEBUGLOG 1506#define IDM_OPTIONS_FONT 1509#define IDM_PLAYRECORD 1400
#define IDD_AAPLAYRECORD_BTN_PLAY 100#define IDD_AAPLAYRECORD_BTN_RECORD 105#define IDD_AAPLAYRECORD_BTN_STOP 102
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;//////////- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
//
127
//////typedef UINT WIOERR;
typedef struct tACMAPPFILEDESC{ DWORD fdwState;
TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
DWORD cbFileSize; UINT uDosChangeDate; UINT uDosChangeTime; DWORD fdwFileAttributes;
LPWAVEFORMATEX pwfx; UINT cbwfx;
DWORD dwDataBytes; DWORD dwDataSamples;
} ACMAPPFILEDESC, *PACMAPPFILEDESC;
typedef struct tWAVEIOCB{ DWORD dwFlags; HMMIO hmmio;
DWORD dwDataOffset; DWORD dwDataBytes; DWORD dwDataSamples;
LPWAVEFORMATEX pwfx;
#if 0 HWAVEOUT hwo; DWORD dwBytesLeft; DWORD dwBytesPerBuffer;
DISP FAR * pDisp; INFOCHUNK FAR * pInfo;#endif
} WAVEIOCB, *PWAVEIOCB, FAR *LPWAVEIOCB;
//*****************************************************// RecordCP.h : RecorderEvents "fire" methods.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the IRecorderEvents connection points. No changes were made by// the author. THis is the code that calls the event sink when// events happen.//-----------------------------------------------------#ifndef _RECORDCP_H_#define _RECORDCP_H_
128
template <class T>class CProxy_IRecorderEvents : public IConnectionPointImpl<T, &DIID__IRecorderEvents, CComDynamicUnkArray>{
//Warning this class may be recreated by the wizard.public:
HRESULT Fire_OnReadyToRecord(){
CComVariant varResult;T* pT = static_cast<T*>(this);int nConnectionIndex;int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++){
pT->Lock();CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);pT->Unlock();IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);if (pDispatch != NULL){
VariantClear(&varResult);DISPPARAMS disp = { NULL, NULL, 0, 0 };pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &disp, &varResult, NULL, NULL);}
}return varResult.scode;
}HRESULT Fire_OnDoneRecording(){
CComVariant varResult;T* pT = static_cast<T*>(this);int nConnectionIndex;int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++){
pT->Lock();CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);pT->Unlock();IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);if (pDispatch != NULL){
VariantClear(&varResult);DISPPARAMS disp = { NULL, NULL, 0, 0 };pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &disp, &varResult, NULL, NULL);}
}return varResult.scode;
}};#endif
//*****************************************************// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently,// but are changed infrequently//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//
129
// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace. No changes were made by the author.//-----------------------------------------------------#if !defined(AFX_STDAFX_H__6BFBE224_4F94_11D3_BD2C_B7B20D959A24__INCLUDED_)#define AFX_STDAFX_H__6BFBE224_4F94_11D3_BD2C_B7B20D959A24__INCLUDED_
#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000
#define STRICT#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define _ATL_APARTMENT_THREADED
#include <atlbase.h>//You may derive a class from CComModule and use it if you want to override//something, but do not change the name of _Moduleextern CComModule _Module;#include <atlcom.h>
//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__6BFBE224_4F94_11D3_BD2C_B7B20D959A24__INCLUDED)
//*****************************************************//{{NO_DEPENDENCIES}}// Microsoft Developer Studio generated include file.// Used by Record.rc////-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace.//-----------------------------------------------------#define IDS_PROJNAME 100#define IDR_RECORDER 101
// Next default values for new objects//#ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE 201#define _APS_NEXT_COMMAND_VALUE 32768#define _APS_NEXT_CONTROL_VALUE 201#define _APS_NEXT_SYMED_VALUE 102#endif#endif
//*****************************************************// Record.cpp : Implementation of DLL Exports.
130
//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace. No changes were made to the// automatically generated version.// Record.dll is the COM server DLL that provides the interfaces// required to record a voice/sound by using the Microsoft Audio// Control manager.//-----------------------------------------------------
// Note: Proxy/Stub Information// To build a separate proxy/stub DLL,// run nmake -f Recordps.mk in the project directory.
#include "stdafx.h"#include "resource.h"#include <initguid.h>#include "Record.h"
#include "Record_i.c"#include "Recorder.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)OBJECT_ENTRY(CLSID_Recorder, CRecorder)END_OBJECT_MAP()
/////////////////////////////////////////////////////////////////////////////// DLL Entry Point
extern "C"BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/){ if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance, &LIBID_RECORDLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok}
/////////////////////////////////////////////////////////////////////////////// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void){ return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;}
/////////////////////////////////////////////////////////////////////////////// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){ return _Module.GetClassObject(rclsid, riid, ppv);}
131
/////////////////////////////////////////////////////////////////////////////// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void){ // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE);}
/////////////////////////////////////////////////////////////////////////////// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void){ return _Module.UnregisterServer(TRUE);}
//*****************************************************// Record.idl : IDL source for Record.dll//
// This file will be processed by the MIDL tool to// produce the type library (Record.tlb) and marshalling code.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace. Changes made by the author to the// file are marked by 'Carlos:'.// Record.dll is the COM server DLL that provides the interfaces// required to record a voice/sound.// This file provides the interface definition language (idl)// for the interfaces exposed by coclasses in the Record.dll.//-----------------------------------------------------
import "oaidl.idl";import "ocidl.idl";
// Comments by CR: The ISpeechRecorder provides the methods required to// record the voice/sound message[
object,uuid(6BFBE22D-4F94-11D3-BD2C-B7B20D959A24),
helpstring("ISpeechRecorder Interface"),pointer_default(unique)
]interface ISpeechRecorder : IUnknown{
[helpstring("method StartRecording")] HRESULT StartRecording();[helpstring("method StopRecording")] HRESULT StopRecording();
};
// Comments by CR: The ISpeechCompressor is required to compress and uncompress the// after it has been captured. This interface is not currently implemented, but its// methods are stubbed and should be called from the COM client to permit future// compatibility.[
132
object,uuid(5E136C20-4F9C-11d3-BD2C-B7B20D959A24),
helpstring("ISpeechCompressor Interface"),pointer_default(unique)
]interface ISpeechCompressor : IUnknown{
[helpstring("method CompressSpeech")] HRESULT CompressSpeech(LPSTR pFileName);};
// Comments by CR: The ISpeechMessenger interface implements the functions// require to package the voice/sound message and send it to an IP network// aware component[
object,uuid(0BCC20E0-76BD-11d3-BD2C-C7F3F4028924),
helpstring("ISpeechMessenger Interface"),pointer_default(unique)
]interface ISpeechMessenger : IUnknown{
[helpstring("method Send")] HRESULT Send(LPSTR pServerAddress, UINT nPacketSize);[helpstring("method Set Wav File name")] HRESULT SetWavFileName(LPSTR pFileName);
};
// Comments by CR: The IRecorder dispatch interface is to be implemented by the// DispatchImpl class of the CRecorder coclass. No methods are implemented because this// interface is being provided for compatibility with automation objects (such as VB).[
object,uuid(A0277400-53E6-11d3-BD2C-A692173F4C2A),
helpstring("IRecorder Interface"),pointer_default(unique)
]interface IRecorder : IDispatch{};
[uuid(6BFBE221-4F94-11D3-BD2C-B7B20D959A24),version(1.0),helpstring("Record 1.0 Type Library")
]library RECORDLib{
importlib("stdole32.tlb");importlib("stdole2.tlb");
// Comments by CR: The _IRecorderEvents is the source interface for the connections// points events fired by this component[
uuid(6BFBE22F-4F94-11D3-BD2C-B7B20D959A24),helpstring("_IRecorderEvents Interface")
]dispinterface _IRecorderEvents{
properties:methods:[id(1), helpstring("method OnReadyToRecord")] HRESULT OnReadyToRecord();[id(2), helpstring("method OnDoneRecording")] HRESULT OnDoneRecording();[id(3), helpstring("method OnDoneCompressing")] HRESULT OnDoneCompressing();
};
// Comments by CR: The Recorder coclass is the actual component that implements// and supports all the interfaces.
133
[uuid(6BFBE22E-4F94-11D3-BD2C-B7B20D959A24),helpstring("Recorder Class")
]coclass Recorder{
interface IRecorder;[default] interface ISpeechRecorder;interface ISpeechCompressor;[default, source] dispinterface _IRecorderEvents;interface ISpeechMessenger;
};};
//*****************************************************// Recorder.cpp : Implementation of CRecorder//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// This is the implementation of the CRecorder class. CRecorder// the C++ dependent implementation of the Recorder coclass.//// Recorder is a COM component that permits the user to record a// PCM WAV file, compress it, and send it to a TCP/IP enabled COM// component (Talker) so that it can be sent to a listenning socket// server.//// REUSE NOTE: This file contains code adapted and modified by the// author, from Microsoft's AcmApp application found in the// Developer's Network Library.//-----------------------------------------------------#include "stdafx.h"#include "Record.h"#include "Recorder.h"
// Comments by CR: This define is used to conditionally compile the section of// code that permits introducing a high compression codec into the software.//#define DEBUGGING_COMPRESSION 0
/////////////////////////////////////////////////////////////////////////////// CRecorder
STDMETHODIMP CRecorder::SetWavFileName(LPSTR pFileName){
if ( pFileName ){
// Comment by CR: OPen and close the file to check for its existence. OPenFile()// with the OF_EXIST parameter will open and close the file immediately.
134
OFSTRUCT ofs;if ( OpenFile(pFileName,&ofs,OF_EXIST) == HFILE_ERROR )
return ( !S_OK );
strcpy(m_szWavFileName,pFileName);}
return S_OK;}
//******************************************************************************// Comments by CR: THe send method receives the IP address of the destination// IP computer, and calls the Talk method of the ITalker interface to route// the message//-----------------------------------------------------------------------------STDMETHODIMP CRecorder::Send(LPSTR pAddress, UINT nPacketSize){
// Comments by CR: set the packet size for the transferm_spTalkerClient->SetPacketSize(nPacketSize);// Comments by CR: set the address to the predetermined listening port// on the serverm_spTalkerClient->SetListenerAddress(pAddress,VOICE_MESSENGER_PORT_NUM);char szVoiceFilePath[256];
// Comments by CR: Check if the file to transfer is different than the default,// then send that one. m_szWavFileName is initialized to NULLif ( strlen(m_szWavFileName) )
strcpy(szVoiceFilePath,m_szWavFileName);else
sprintf(szVoiceFilePath,"%s%s",VOICE_FILE_PATH,VOICE_FILE_NAME);
// Comments by CR: if required, compress the speech to save bandwidth when transmitting.// CompressSpeech() will expect to compress a PCM wav file named VOICE_FILE_PATH/VOICE_FILE_NAME,// and save it under the same name// Note: Compression is turned on by adding the compressing code, not selectable at runtime.//
//// Comments by CR: This conditionally compiled section is used to when debugging the introduction// of a PCM-to-X codec into this system. Two files are created so that the original file is// kept and can be analyzed with the Microsoft Sound /Recorder Player. When the code is debugged,// remove the DEBUGGING_COMPRESSION sections.//
#if DEBUGGING_COMPRESSION// Comments by CR: Remove this section when done debugging compression//// Speech will expect to compress a PCM wav file named VOICE_FILE_PATH/VOICE_FILE_NAME,// and save it under the name VOICE_FILE_PATH/COMPRESSED_VOICE_FILE_NAMEchar szCompressedVoiceFilePath[256];sprintf(szCompressedVoiceFilePath,"%s%s",VOICE_FILE_PATH,COMPRESSED_VOICE_FILE_NAME);this->CompressSpeech(szCompressedVoiceFilePath);// Comments by CR: set the compressed voice filenamem_spTalkerClient->SetVoiceFilename(szCompressedVoiceFilePath);
#elsethis->CompressSpeech(szVoiceFilePath);// Comments by CR: set the voice filenamem_spTalkerClient->SetVoiceFilename(szVoiceFilePath);
#endif// Comments by CR: tell the talker to start sending the messageHRESULT hr = m_spTalkerClient->Talk();
#if DEBUGGING_COMPRESSION// Comments by CR: when completed, remove the file(s) to avoid sharing conflicts// NOTE: The compressed file could or could not be there depending if the codec is// installed or not. Try to delete the file for compatibility, and if it is not there// it fails but that is ok.DeleteFile(szCompressedVoiceFilePath);
#endif
135
// Comments by CR: when completed, remove the file(s) to avoid sharing conflicts// At least the WAV file should be there! Get rid of it.// BUT, do not delete the file if the message is being sent from a pre-recorded file.// If a pre-recorded message is being sent, just initialize the string.BOOL bStatus=FALSE;if ( strlen(m_szWavFileName) )
memset(m_szWavFileName,NULL,sizeof(m_szWavFileName));else{
bStatus = DeleteFile(szVoiceFilePath);if ( ! bStatus ){
DWORD dError = GetLastError();hr = ! S_OK; // CR. could not delete file
}}return ( hr );
}
//******************************************************************************// Comments by CR: THe StarRecording method calls the AcmApp modules to init the// audio hardware, and puts the hardware in a recording mode//-----------------------------------------------------------------------------STDMETHODIMP CRecorder::StartRecording(){ // Comments by CR: Create the media (WAV) file
if ( AppFileNew(TRUE) == FALSE )return ( !S_OK );
// Comments by CR: OPen the hwif ( this->AcmAppPlayRecordOpen() == FALSE )
return ( !S_OK );
this->AcmAppPlayRecordStatus();
// Comments by CR: Init hw for recordingif ( this->AcmAppPlayRecordRecord() == FALSE )
return ( !S_OK );
this->AcmAppPlayRecordStatus();
// Comments by CR: when hw is ready, inform the client by firing the event!Fire_OnReadyToRecord();
return S_OK;}
//******************************************************************************// Comments by CR: THe StopRecording method calls the AcmApp modules to put the// audio record hardware in an idle mode//-----------------------------------------------------------------------------STDMETHODIMP CRecorder::StopRecording(){
if ( this->AcmAppPlayRecordStop() == FALSE )return ( !S_OK );
this->AcmAppPlayRecordStatus();
if ( this->AcmAppPlayRecordClose() == FALSE )return ( !S_OK );
m_fFileOpen = FALSE;
// Comments by CR: This section was added because the application is having some// problems synchronizing the media file. So before we let the file go, check// if recording was ok, so as not to send an empry file to the Voice Messaging Server{
Sleep(1000); //this is to allow file to close properly before checking its size
136
//*CR. Open the file to check the sizeHANDLE hf;char szVoiceFilePath[256];sprintf(szVoiceFilePath,"%s%s",VOICE_FILE_PATH,VOICE_FILE_NAME);hf = CreateFile(szVoiceFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == hf)return( !S_OK );
if ( GetFileSize((HANDLE)hf, NULL) ){
CloseHandle(hf);// Comments by CR: when hw is ready, inform the COM client using the connection pointFire_OnDoneRecording();return S_OK;
}else{
CloseHandle(hf);BOOL bStatus = DeleteFile(szVoiceFilePath);if ( ! bStatus )
DWORD dError = GetLastError();
return (! S_OK);}
}}
//******************************************************************************// Comments by CR: This is convenience method provided in the interface for future use// This method shall convert a UNcompressed PCM wav file named VOICE_FILE_PATH/// VOICE_FILE_NAME into a compressed wav file named VOICE_FILE_PATH/COMPRESSED_VOICE_FILE_NAME// THe compression used is determined by the code that gets called, so this is NOT the// compression code, but the entry point to the compression code.//-----------------------------------------------------------------------------STDMETHODIMP CRecorder::CompressSpeech(LPSTR pFileName){
// Comments by CR: Todo; call the compress routines from here
return S_OK;}
//==========================================================================;//////////==========================================================================;//******************************************************************************// Comments by CR: Following is the code adapted from the Microsoft's AcmApp. A lot// of code overhead was removed (user confirmation dialogs, compatiblity with Win16,// and others). This code contains the algorithms used to access the Microsoft's// Audio Compression Manager (ACM) to: create, open, store, and manage media WAV files,// using the Media Control Interface (mci).//-----------------------------------------------------------------------------
//--------------------------------------------------------------------------;//// BOOL AppFileSave//// Description:// This function handles the IDM_FILE_SAVE[AS] messages. It is// responsible for saving the current file. If a file name needs// to be specified then the save file dialog is displayed.//// Arguments:
137
// HWND hwnd: Handle to application window.//// PACMAPPFILEDESC m_paafd: Pointer to current file descriptor.//// BOOL fSaveAs: TRUE if the save file chooser should be displayed// before saving the file. FALSE if should operate like File.Save.//// Return (BOOL):// The return value is TRUE if the file was saved. It is FALSE if the// user canceled the operation or the file does not need saved.////--------------------------------------------------------------------------;
BOOL CRecorder:: AppFileSave( HWND hwnd, PACMAPPFILEDESC m_paafd, BOOL fSaveAs){ TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; BOOL f;
// // // lstrcpy(szFilePath, m_paafd->szFilePath); lstrcpy(szFileTitle, m_paafd->szFileTitle);
// // check if we should bring up the save file chooser dialog... // if (fSaveAs || (0 == lstrcmp(m_paafd->szFileTitle, m_szFileUntitled))) { // // get the file name for saving the data to into temporary // buffers (so if we fail to save it we can back out cleanly). // f = AppGetFileName(szFilePath, szFileTitle, APP_GETFILENAMEF_SAVE);//*CR. if (!f) return (FALSE); }
// // save the file... // f = AcmAppFileSave(hwnd, m_paafd, szFilePath, szFileTitle, 0); if (f) { // // changes have been saved, so clear the modified bit... // m_paafd->fdwState &= ~ACMAPPFILEDESC_STATEF_MODIFIED;
AppTitle(m_paafd->szFileTitle);
AcmAppDisplayFileProperties();//*CR. }
return (f);} // AppFileSave()
//--------------------------------------------------------------------------;//// BOOL AppGetFileName//
138
// Description:// This function is a wrapper for the Get[Open/Save]FileName commdlg// chooser dialogs. Based on the fuFlags argument, this function will// display the appropriate chooser dialog and return the result.//// Arguments:// HWND hwnd: Handle to parent window for chooser dialog.//// PTSTR pszFilePath: Pointer to buffer to receive the file path.//// PTSTR pszFileTitle: Pointer to buffer to receive the file title.// This argument may be NULL, in which case no title will be returned.//// UINT fuFlags://// Return (BOOL):// The return value is TRUE if a file was chosen. It is FALSE if the// user canceled the operation.//////--------------------------------------------------------------------------;
BOOL CRecorder:: AppGetFileName( PTSTR pszFilePath, PTSTR pszFileTitle, UINT fuFlags){ #define APP_OFN_FLAGS_SAVE (OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT) #define APP_OFN_FLAGS_OPEN (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST)
TCHAR szExtDefault[APP_MAX_EXT_DEFAULT_CHARS]; TCHAR szExtFilter[APP_MAX_EXT_FILTER_CHARS]; OPENFILENAME ofn; BOOL f; PTCHAR pch;
// // NOTE! building the filter string for the OPENFILENAME structure // is a bit more difficult when dealing with Unicode and C8's new // optimizer. it joyfully removes literal '\0' characters from // strings that are concatted together. if you try making each // string separate (array of pointers to strings), the compiler // will dword align them... etc, etc. // // if you can think of a better way to build the silly filter string // for common dialogs and still work in Win 16 and Win 32 [Unicode] // i'd sure like to hear about it... // for (pch = &szExtFilter[0]; '\0' != *pch; pch++) { if ('!' == *pch) *pch = '\0'; }
// // initialize the OPENFILENAME members // memset(&ofn, 0, sizeof(OPENFILENAME));
pszFilePath[0] = '\0'; if (pszFileTitle) pszFileTitle[0] = '\0';
ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFilter = szExtFilter; ofn.lpstrCustomFilter = NULL;
139
ofn.nMaxCustFilter = 0L; ofn.nFilterIndex = 1L; ofn.lpstrFile = pszFilePath; ofn.nMaxFile = APP_MAX_FILE_PATH_CHARS; ofn.lpstrFileTitle = pszFileTitle; ofn.nMaxFileTitle = pszFileTitle ? APP_MAX_FILE_TITLE_CHARS : 0; if (fuFlags & APP_GETFILENAMEF_SAVE) { ofn.lpstrInitialDir = m_szInitialDirSave; } else { ofn.lpstrInitialDir = m_szInitialDirOpen; } ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = szExtDefault;
// // if the fuFlags.APP_GETFILENAMEF_SAVE bit is set, then call // GetSaveFileName() otherwise call GetOpenFileName(). why commdlg was // designed with two separate functions for save and open only clark // knows. // if (fuFlags & APP_GETFILENAMEF_SAVE) { ofn.Flags = APP_OFN_FLAGS_SAVE; f = GetSaveFileName(&ofn); if (f) { if (NULL != pszFilePath) { lstrcpy(m_szInitialDirSave, pszFilePath);
pch = &m_szInitialDirSave[lstrlen(m_szInitialDirSave) - 1]; for ( ; m_szInitialDirSave != pch; pch--) { if ('\\' == *pch) { *pch = '\0'; break; } } } } } else { ofn.Flags = APP_OFN_FLAGS_OPEN; f = GetOpenFileName(&ofn); if (f) { if (NULL != pszFilePath) { lstrcpy(m_szInitialDirOpen, pszFilePath);
pch = &m_szInitialDirOpen[lstrlen(m_szInitialDirOpen) - 1]; for ( ; m_szInitialDirOpen != pch; pch--) { if ('\\' == *pch) { *pch = '\0'; break; } } } } }
140
return (f);} // AppGetFileName()
//--------------------------------------------------------------------------;//// BOOL AppTitle//// Description:// This function formats and sets the title text of the application's// window.//// Arguments:// HWND hwnd: Handle to application window to set title text for.//// PTSTR pszFileTitle: Pointer to file title to display.//// Return (BOOL):// The return value is always TRUE.//////--------------------------------------------------------------------------;
BOOL CRecorder:: AppTitle( PTSTR pszFileTitle){ static TCHAR szFormatTitle[] = TEXT("%s - %s");
TCHAR ach[APP_MAX_FILE_PATH_CHARS];
// // format the title text as 'AppName - FileTitle' // wsprintf(ach, szFormatTitle, (LPSTR)m_szAppName, (LPSTR)pszFileTitle);
return (TRUE);} // AppTitle()
//--------------------------------------------------------------------------;//// BOOL AcmAppDisplayFileProperties//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppDisplayFileProperties(){ static TCHAR szInvalidWaveFile[] = TEXT("No File"); static TCHAR szDisplayTitle[] = TEXT("[Wave File Format Properties]\r\n");
MMRESULT mmr; TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; TCHAR ach[APP_MAX_STRING_CHARS]; DWORD dw;
141
LPWAVEFORMATEX pwfx; HWND hedit=NULL; BOOL fCanPlayRecord; BOOL f;
// // clear the display // AppHourGlass(TRUE);
MEditPrintF(hedit, NULL);
// // // MEditPrintF(hedit, szDisplayTitle);
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Title"), (LPTSTR)m_paafd->szFileTitle); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Full Path"), (LPTSTR)m_paafd->szFilePath);
AppFormatBigNumber(ach, m_paafd->cbFileSize); MEditPrintF(hedit, TEXT("%25s: %s bytes"), (LPTSTR)TEXT("Total File Size"), (LPTSTR)ach);
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Last Change Date/Time"), (LPTSTR)ach);
dw = m_paafd->fdwFileAttributes; MEditPrintF(hedit, TEXT("%25s: %c %c%c%c%c %c%c%c%c (%.08lXh)"), (LPTSTR)TEXT("Attributes"), (dw & FILE_ATTRIBUTE_TEMPORARY) ? 't' : '-', (dw & FILE_ATTRIBUTE_NORMAL) ? 'n' : '-', (dw & 0x00000040) ? '?' : '-', (dw & FILE_ATTRIBUTE_ARCHIVE) ? 'a' : '-', (dw & FILE_ATTRIBUTE_DIRECTORY) ? 'd' : '-', (dw & 0x00000008) ? '?' : '-', (dw & FILE_ATTRIBUTE_SYSTEM) ? 's' : '-', (dw & FILE_ATTRIBUTE_HIDDEN) ? 'h' : '-', (dw & FILE_ATTRIBUTE_READONLY) ? 'r' : '-', dw);
pwfx = m_paafd->pwfx; if (NULL == pwfx) { fCanPlayRecord = FALSE;
// Comments by CR: Believe it or not, THIS IS Microsoft code!!! goto AA_Display_File_Properties_Exit; }
// // // // f = AcmAppGetFormatDescription(pwfx, szFormatTag, ach); MEditPrintF(hedit, TEXT("\r\n%25s: %s%s"), (LPTSTR)TEXT("Format"), f ? (LPTSTR)m_szNull : (LPTSTR)TEXT("*"), (LPTSTR)szFormatTag); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Attributes"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataBytes); MEditPrintF(hedit, TEXT("\r\n%25s: %s bytes"), (LPTSTR)TEXT("Data Size"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataBytes / pwfx->nAvgBytesPerSec); dw = m_paafd->dwDataBytes % pwfx->nAvgBytesPerSec; dw = (dw * 1000) / pwfx->nAvgBytesPerSec; MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (avg bytes)"), (LPTSTR)ach, dw);
142
AppFormatBigNumber(ach, m_paafd->dwDataSamples); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Total Samples"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataSamples / pwfx->nSamplesPerSec); dw = m_paafd->dwDataSamples % pwfx->nSamplesPerSec; dw = (dw * 1000) / pwfx->nSamplesPerSec; MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (samples)"), (LPTSTR)ach, dw);
// // // MEditPrintF(hedit, TEXT("\r\n%25s: %u"), (LPTSTR)TEXT("Format Tag"), pwfx->wFormatTag); MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Channels"), pwfx->nChannels);
AppFormatBigNumber(ach, pwfx->nSamplesPerSec); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Samples Per Second"), (LPTSTR)ach);
AppFormatBigNumber(ach, pwfx->nAvgBytesPerSec); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Avg Bytes Per Second"), (LPTSTR)ach);
AppFormatBigNumber(ach, pwfx->nBlockAlign); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Block Alignment"), (LPTSTR)ach);
MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Bits Per Sample"), pwfx->wBitsPerSample);
if (WAVE_FORMAT_PCM != pwfx->wFormatTag) { AppFormatBigNumber(ach, pwfx->cbSize); MEditPrintF(hedit, TEXT("%25s: %s bytes\r\n"), (LPTSTR)TEXT("Extra Format Information"), (LPTSTR)ach);
AcmAppDumpExtraHeaderData(hedit, pwfx); }
// // note that we do NOT set the 'WAVE_ALLOWSYNC' bit on queries because // the player/recorder dialog uses MCIWAVE--which cannot work with // SYNC devices. // mmr = waveOutOpen(NULL, m_uWaveOutId,#if (WINVER < 0x0400) (LPWAVEFORMAT)pwfx,#else pwfx,#endif 0L, 0L, WAVE_FORMAT_QUERY);
fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
if (!fCanPlayRecord) { // // this situation can happen with the 'preferred' device settings // for the Sound Mapper. // mmr = waveInOpen(NULL, m_uWaveInId,#if (WINVER < 0x0400) (LPWAVEFORMAT)pwfx,#else pwfx,#endif 0L, 0L, WAVE_FORMAT_QUERY);
fCanPlayRecord = (MMSYSERR_NOERROR == mmr); }
143
AA_Display_File_Properties_Exit: return (fCanPlayRecord);} // AcmAppDisplayFileProperties()
//--------------------------------------------------------------------------;//// void AppHourGlass//// Description:// This function changes the cursor to that of the hour glass or// back to the previous cursor.//// This function can be called recursively.//// Arguments:// BOOL fHourGlass: TRUE if we need the hour glass. FALSE if we need// the arrow back.//// Return (void):// On return, the cursor will be what was requested.////--------------------------------------------------------------------------;
void CRecorder:: AppHourGlass( BOOL fHourGlass){ static HCURSOR hcur; static UINT uWaiting = 0;
if (fHourGlass) { if (!uWaiting) { ShowCursor(TRUE); }
uWaiting++; } else { --uWaiting;
if (!uWaiting) { ShowCursor(FALSE); SetCursor(hcur); } }} // AppHourGlass()
//--------------------------------------------------------------------------;//// BOOL AppFormatBigNumber//// Description:////// Arguments:// LPTSTR pszNumber://// DWORD dw://// Return (BOOL)://
144
//--------------------------------------------------------------------------;
BOOL CRecorder:: AppFormatBigNumber( LPTSTR pszNumber, DWORD dw){
// Comments by CR: Believe it or not, THIS IS Microsoft code (+ comments)!!! // // this is ugly... // // if (dw >= 1000000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"), (WORD)(dw / 1000000000L), (WORD)((dw % 1000000000L) / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u"), (WORD)(dw / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000) { wsprintf(pszNumber, TEXT("%u,%03u"), (WORD)(dw / 1000), (WORD)(dw % 1000)); } else { wsprintf(pszNumber, TEXT("%lu"), dw); }
return (TRUE);} // AppFormatBigNumber()
//--------------------------------------------------------------------------;//// BOOL AppFormatDosDateTime//// Description:////// Arguments:// LPTSTR pszDateTime://// UINT uDosDate://// UINT uDosTime://// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CRecorder:: AppFormatDosDateTime( LPTSTR pszDateTime, UINT uDosDate, UINT uDosTime
145
){ static TCHAR szFormatDateTime[] = TEXT("%.02u/%.02u/%.02u %.02u:%.02u:%.02u");
UINT uDateMonth; UINT uDateDay; UINT uDateYear; UINT uTimeHour; UINT uTimeMinute; UINT uTimeSecond;
// // // uTimeHour = uDosTime >> 11; uTimeMinute = (uDosTime & 0x07E0) >> 5; uTimeSecond = (uDosTime & 0x001F) << 1;
uDateMonth = (uDosDate & 0x01E0) >> 5; uDateDay = (uDosDate & 0x001F); uDateYear = (uDosDate >> 9) + 80;
// // // // wsprintf(pszDateTime, szFormatDateTime, uDateMonth, uDateDay, uDateYear, uTimeHour, uTimeMinute, uTimeSecond);
return (TRUE);} // AppFormatDosDateTime()
//--------------------------------------------------------------------------;//// BOOL AcmAppGetFormatDescription//// Description:////// Arguments:// LPWAVEFORMATEX pwfx://// LPSTR pszFormatTag://// LPSTR pszFormat://// Return (BOOL)://////--------------------------------------------------------------------------;
TCHAR gszIntl[] = TEXT("Intl");TCHAR gszIntlList[] = TEXT("sList");TCHAR gszIntlDecimal[] = TEXT("sDecimal");TCHAR gchIntlList = ',';TCHAR gchIntlDecimal = '.';
BOOL CRecorder:: AcmAppGetFormatDescription( LPWAVEFORMATEX pwfx, LPTSTR pszFormatTag, LPTSTR pszFormat)
146
{ MMRESULT mmr; BOOL f;
f = TRUE;
// // get the name for the format tag of the specified format // if (NULL != pszFormatTag) { ACMFORMATTAGDETAILS aftd;
// // initialize all unused members of the ACMFORMATTAGDETAILS // structure to zero // memset(&aftd, 0, sizeof(aftd));
// // fill in the required members of the ACMFORMATTAGDETAILS // structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query // aftd.cbStruct = sizeof(aftd); aftd.dwFormatTag = pwfx->wFormatTag;
// // ask the ACM to find the first available driver that // supports the specified format tag // mmr = acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG); if (MMSYSERR_NOERROR == mmr) { // // copy the format tag name into the caller's buffer // lstrcpy(pszFormatTag, aftd.szFormatTag); } else { PTSTR psz;
// // no ACM driver is available that supports the // specified format tag //
f = FALSE; psz = NULL;
// // the following stuff if proof that the world does NOT need // yet another ADPCM algorithm!! // switch (pwfx->wFormatTag) { case WAVE_FORMAT_UNKNOWN: psz = TEXT("** RESERVED INVALID TAG **"); break;
case WAVE_FORMAT_PCM: psz = TEXT("PCM"); break;
case WAVE_FORMAT_ADPCM: psz = TEXT("Microsoft ADPCM");
147
break;
case 0x0003: psz = TEXT("MV's *UNREGISTERED* ADPCM"); break;
case WAVE_FORMAT_IBM_CVSD: psz = TEXT("IBM CVSD"); break;
case WAVE_FORMAT_ALAW: psz = TEXT("A-Law"); break;
case WAVE_FORMAT_MULAW: psz = TEXT("u-Law"); break;
case WAVE_FORMAT_OKI_ADPCM: psz = TEXT("OKI ADPCM"); break;
case WAVE_FORMAT_IMA_ADPCM: psz = TEXT("IMA/DVI ADPCM"); break;
case WAVE_FORMAT_DIGISTD: psz = TEXT("DIGI STD"); break;
case WAVE_FORMAT_DIGIFIX: psz = TEXT("DIGI FIX"); break;
case WAVE_FORMAT_YAMAHA_ADPCM: psz = TEXT("Yamaha ADPCM"); break;
case WAVE_FORMAT_SONARC: psz = TEXT("Sonarc"); break;
case WAVE_FORMAT_DSPGROUP_TRUESPEECH: psz = TEXT("DSP Group TrueSpeech"); break;
case WAVE_FORMAT_ECHOSC1: psz = TEXT("Echo SC1"); break;
case WAVE_FORMAT_AUDIOFILE_AF36: psz = TEXT("Audiofile AF36"); break;
case WAVE_FORMAT_CREATIVE_ADPCM: psz = TEXT("Creative Labs ADPCM"); break;
case WAVE_FORMAT_APTX: psz = TEXT("APTX"); break;
case WAVE_FORMAT_AUDIOFILE_AF10: psz = TEXT("Audiofile AF10"); break;
case WAVE_FORMAT_DOLBY_AC2: psz = TEXT("Dolby AC2");
148
break;
case WAVE_FORMAT_MEDIASPACE_ADPCM: psz = TEXT("Media Space ADPCM"); break;
case WAVE_FORMAT_SIERRA_ADPCM: psz = TEXT("Sierra ADPCM"); break;
case WAVE_FORMAT_G723_ADPCM: psz = TEXT("CCITT G.723 ADPCM"); break;
case WAVE_FORMAT_GSM610: psz = TEXT("GSM 6.10"); break;
case WAVE_FORMAT_G721_ADPCM: psz = TEXT("CCITT G.721 ADPCM"); break;
case WAVE_FORMAT_DEVELOPMENT: psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **"); break;
default: wsprintf(pszFormatTag, TEXT("[%u] (unknown)"), pwfx->wFormatTag); break; }
if (NULL != psz) { lstrcpy(pszFormatTag, psz); } } }
// // get the description of the attributes for the specified // format // if (NULL != pszFormat) { ACMFORMATDETAILS afd;
// // initialize all unused members of the ACMFORMATDETAILS // structure to zero // memset(&afd, 0, sizeof(afd));
// // fill in the required members of the ACMFORMATDETAILS // structure for the ACM_FORMATDETAILSF_FORMAT query // afd.cbStruct = sizeof(afd); afd.dwFormatTag = pwfx->wFormatTag; afd.pwfx = pwfx;
// // the cbwfx member must be initialized to the total size // in bytes needed for the specified format. for a PCM // format, the cbSize member of the WAVEFORMATEX structure // is not valid. // if (WAVE_FORMAT_PCM == pwfx->wFormatTag) {
149
afd.cbwfx = sizeof(PCMWAVEFORMAT); } else { afd.cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize; }
// // ask the ACM to find the first available driver that // supports the specified format // mmr = acmFormatDetails(NULL, &afd, ACM_FORMATDETAILSF_FORMAT); if (MMSYSERR_NOERROR == mmr) { // // copy the format attributes description into the caller's // buffer // lstrcpy(pszFormat, afd.szFormat); } else { TCHAR ach[2]; TCHAR szChannels[24]; UINT cBits;
// // no ACM driver is available that supports the // specified format //
f = FALSE;
// // // ach[0] = gchIntlList; ach[1] = '\0';
gchIntlList = ach[0];
ach[0] = gchIntlDecimal; ach[1] = '\0';
gchIntlDecimal = ach[0];
// // compute the bit depth--this _should_ be the same as // wBitsPerSample, but isn't always... // cBits = (UINT)(pwfx->nAvgBytesPerSec * 8 / pwfx->nSamplesPerSec / pwfx->nChannels);
if ((1 == pwfx->nChannels) || (2 == pwfx->nChannels)) { if (1 == pwfx->nChannels) lstrcpy(szChannels, TEXT("Mono")); else lstrcpy(szChannels, TEXT("Stereo"));
wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %s"), pwfx->nSamplesPerSec / 1000, gchIntlDecimal, (UINT)(pwfx->nSamplesPerSec % 1000), gchIntlList, cBits,
150
gchIntlList, (LPTSTR)szChannels); } else { wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %u Channels"), pwfx->nSamplesPerSec / 1000, gchIntlDecimal, (UINT)(pwfx->nSamplesPerSec % 1000), gchIntlList, cBits, gchIntlList, pwfx->nChannels); } } }
// // // return (f);} // AcmAppGetFormatDescription()
//--------------------------------------------------------------------------;//// BOOL AcmAppDumpExtraHeaderData//// Description:////// Arguments:// HWND hedit://// LPWAVEFORMATEX pwfx://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppDumpExtraHeaderData( HWND hedit, LPWAVEFORMATEX pwfx){ static TCHAR szDisplayTitle[] = TEXT("Offset Data Bytes");
if ((WAVE_FORMAT_PCM == pwfx->wFormatTag) || (0 == pwfx->cbSize)) return (TRUE);
MEditPrintF(hedit, szDisplayTitle); MEditPrintF(hedit, TEXT("------ -----------------------------------------------"));
// Comments by CR: Believe it or not, THIS IS Microsoft code (+ comments) !!! // // !!! this is really horrible code !!! //{ #define ACMAPP_DUMP_BYTES_PER_LINE 16
UINT u; UINT v;
for (u = 0; u < pwfx->cbSize; u += ACMAPP_DUMP_BYTES_PER_LINE) {
151
MEditPrintF(hedit, TEXT("~0x%.04X"), u);
for (v = 0; v < ACMAPP_DUMP_BYTES_PER_LINE; v++) { if ((u + v) >= pwfx->cbSize) break;
MEditPrintF(hedit, TEXT("~ %.02X"), ((LPBYTE)(pwfx + 1))[u + v]); }
MEditPrintF(hedit, m_szNull); }
#undef ACMAPP_DUMP_BYTES_PER_LINE}
return (TRUE);} // AcmAppDumpExtraHeaderData()
//--------------------------------------------------------------------------;//// BOOL AcmAppFileSave//// Description:// This function saves the file to the specified file.//// NOTE! This function does NOT bring up a save file chooser dialog// if the file path is invalid. The calling function is responsible// for making sure the file path is valid before calling this function.//// This function also does NOT modify the 'modified' bit of the file// descriptor. This is up to the calling function.//// Arguments:// HWND hwnd: Handle to main window.//// PACMAPPFILEDESC m_paafd: Pointer to file descriptor.//// Return (BOOL):// The return value is TRUE if the function is successful. It is FALSE// if an error occurred. If an error does occur, then the contents// of the file descriptor was not saved.////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppFileSave( HWND hwnd, PACMAPPFILEDESC m_paafd, PTSTR pszFilePath, PTSTR pszFileTitle, UINT fuSave){
return (FALSE);} // AcmAppFileSave()
//--------------------------------------------------------------------------;//// int MEditPrintF//// Description:// This function is used to print formatted text into a Multiline// Edit Control as if it were a standard console display. This is// a very easy way to display small amounts of text information// that can be scrolled and copied to the clip-board.//
152
// Arguments:// HWND hedit: Handle to a Multiline Edit control.//// PTSTR pszFormat: Pointer to any valid format for wsprintf. If// this argument is NULL, then the Multiline Edit Control is cleared// of all text.////// Return (int):// Returns the number of characters written into the edit control.//// Notes:// The pszFormat string can contain combinations of escapes that// modify the default behaviour of this function. Escapes are single// character codes placed at the _beginning_ of the format string.//// Current escapes defined are://// ~ : Suppresses the default CR/LF added to the end of the// printed line. Since the most common use of this function// is to output a whole line of text with a CR/LF, that is// the default.//// ` : Suppresses logging to the debug terminal (regardless of// the global debug log options flag).//////--------------------------------------------------------------------------;
int CRecorder:: MEditPrintF( HWND hedit, PTSTR pszFormat, ...){ static TCHAR szCRLF[] = TEXT("\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_RC_CHARS]; int n; BOOL fCRLF; BOOL fDebugLog;
// // default the escapes // fCRLF = TRUE; fDebugLog = TRUE;
// // if the pszFormat argument is NULL. // if (NULL == pszFormat) { AcmAppDebugLog(NULL);
return (0); }
// // format and display the string in the window... first search for // escapes to modify default behaviour. // for (;;) { switch (*pszFormat)
153
{ case '~': fCRLF = FALSE; pszFormat++; continue;
case '`': fDebugLog = FALSE; pszFormat++; continue; }
break; }
va_start(va, pszFormat);#ifdef WIN32 n = wvsprintf(ach, pszFormat, va);#else n = wvsprintf(ach, pszFormat, (LPSTR)va);#endif va_end(va);
if (fDebugLog) { AcmAppDebugLog(ach); }
if (fCRLF) { if (fDebugLog) { AcmAppDebugLog(szCRLF); } }
return (n);} // MEditPrintF()
//--------------------------------------------------------------------------;//// void AcmAppDebugLog//// Description:// This function logs information to the debugger if the Debug Log// option is set. You can then run DBWin (or something similar)// to redirect the output whereever you want. Very useful for debugging// ACM drivers.//// Arguments:// PTSTR pszFormat: Pointer to any valid format for wsprintf.//// Return (void):// None.////--------------------------------------------------------------------------;
void CRecorder:: AcmAppDebugLog( PTSTR pszFormat, ...){ static TCHAR szDebugLogSeparator[] =TEXT("=============================================================================\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
154
// // !!! UNICODE !!! // // if (0 != (APP_OPTIONSF_DEBUGLOG & m_fuAppOptions)) { if (NULL == pszFormat) { OutputDebugString(szDebugLogSeparator); return; }
// // format and display the string in a message box... // va_start(va, pszFormat);#ifdef WIN32 wvsprintf(ach, pszFormat, va);#else wvsprintf(ach, pszFormat, (LPSTR)va);#endif va_end(va);
OutputDebugString(ach); }} // AcmAppDebugLog()
//--------------------------------------------------------------------------;//// BOOL AcmAppFileNew//// Description://// Arguments:// HWND hwnd: Handle to main window.//// PACMAPPFILEDESC m_paafd: Pointer to file descriptor.//// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppFileNew(){ TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; MMRESULT mmr; LPWAVEFORMATEX pwfx; DWORD cbwfx; BOOL f; ACMFORMATCHOOSE afc; HMMIO hmmio; MMCKINFO ckRIFF; MMCKINFO ck; DWORD cSamples;
if (!m_fAcmAvailable) { return (FALSE); }
//
155
// get a filename // szFileTitle[0] = '\0'; szFilePath[0] = '\0';
strcpy(szFileTitle,m_szInitialFileTitle);//*CR.sprintf(szFilePath,"%s%s",m_szInitialDirSave,m_szInitialFileTitle);//*CR.
// // // // // // mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfx); if (MMSYSERR_NOERROR != mmr) { return (FALSE); }
pwfx = NULL;//*CR.pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX [cbwfx]; //*CR.
if (NULL == pwfx) { return (FALSE); }
// // // // f = FALSE;
// // initialize the ACMFORMATCHOOSE members // memset(&afc, 0, sizeof(afc));
afc.cbStruct = sizeof(afc); afc.fdwStyle = ACMFORMATCHOOSE_STYLEF_SHOWHELP; afc.pwfx = pwfx; afc.cbwfx = cbwfx; afc.pszTitle = TEXT("ACM App: New Format Choice");
afc.szFormatTag[0] = '\0'; afc.szFormat[0] = '\0'; afc.pszName = NULL; afc.cchName = 0;
afc.fdwEnum = 0; afc.pwfxEnum = NULL;
afc.hInstance = NULL; afc.pszTemplateName = NULL; afc.lCustData = 0L; afc.pfnHook = NULL;
// // //
// Comments by CR: This where the WAV file parameters (sample rate, etc) is setuppwfx->wFormatTag = PCM_FORMAT_TAG;pwfx->nChannels = PCM_CHANNELS;pwfx->nSamplesPerSec = PCM_SAMPLES_PER_SEC;
156
pwfx->nAvgBytesPerSec = PCM_AVERAGE_BYTES_PER_SEC;pwfx->nBlockAlign = PCM_BLOCK_ALIGN;pwfx->wBitsPerSample = PCM_BITS_PER_SAMPLE;pwfx->cbSize = PCM_SIZE;
//
if (MMSYSERR_NOERROR != mmr) { return (FALSE); }
// // // hmmio = mmioOpen(szFilePath, NULL, MMIO_CREATE | MMIO_WRITE | MMIO_DENYNONE | MMIO_ALLOCBUF);
if (NULL == hmmio) { return (FALSE); }
// // create the RIFF chunk of form type 'WAVE' // ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); ckRIFF.cksize = 0L; mmioCreateChunk(hmmio, &ckRIFF, MMIO_CREATERIFF);
// // now create the destination fmt, fact, and data chunks _in that order_ // // hmmio is now descended into the 'RIFF' chunk--create the format chunk // and write the format header into it // cbwfx = SIZEOF_WAVEFORMATEX(pwfx);
ck.ckid = mmioFOURCC('f', 'm', 't', ' '); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0);
mmioWrite(hmmio, (HPSTR)pwfx, cbwfx); mmioAscend(hmmio, &ck, 0);
// // create the 'fact' chunk (not necessary for PCM--but is nice to have) // since we are not writing any data to this file (yet), we set the // samples contained in the file to 0.. // ck.ckid = mmioFOURCC('f', 'a', 'c', 't'); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0);
cSamples = 0L; mmioWrite(hmmio, (HPSTR)&cSamples, sizeof(DWORD)); mmioAscend(hmmio, &ck, 0);
// // create the data chunk with no data.. // ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0);
157
mmioAscend(hmmio, &ck, 0);
mmioAscend(hmmio, &ckRIFF, 0);
MMRESULT mmResult = 0;//Comments by CR: Added !mmResult = mmioClose(hmmio, 0);
// // //
delete [] pwfx;//Comments by CR: Added !
lstrcpy(m_paafd->szFilePath, szFilePath); lstrcpy(m_paafd->szFileTitle, szFileTitle);
return (AcmAppFileOpen());//Comments by CR: Added !
// // success // return (TRUE);} // AcmAppFileNew()
//--------------------------------------------------------------------------;//// BOOL AcmAppFileOpen//// Description:// This function opens the specified file and get the important info// from it.//// NOTE! This function does NOT check for a modified file! It is// assumed that the calling function took care of everything before// calling this function.//// Arguments:// HWND hwnd: Handle to main window.//// PACMAPPFILEDESC m_paafd: Pointer to file descriptor.//// Return (BOOL):// The return value is TRUE if the function is successful. It is FALSE// if an error occurred. If an error does occur, then the contents// of the file descriptor will remain unchanged.//////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppFileOpen(){ WAVEIOCB wio; WIOERR werr;
#ifdef WIN32 HANDLE hf;#else #define SEEK_SET 0 // flags for _lseek #define SEEK_CUR 1 #define SEEK_END 2
HFILE hf; OFSTRUCT of; DWORD dw;#endif
158
DWORD cbFileSize; BOOL fReturn;
// // blow previous stuff... // if (NULL != m_paafd->pwfx) { m_paafd->pwfx = NULL; m_paafd->cbwfx = 0; }
m_paafd->fdwState = 0L; m_paafd->cbFileSize = 0L; m_paafd->uDosChangeDate = 0; m_paafd->uDosChangeTime = 0; m_paafd->fdwFileAttributes = 0L; m_paafd->dwDataBytes = 0L; m_paafd->dwDataSamples = 0L;
// // open the file for reading.. //#ifdef WIN32 hf = CreateFile(m_paafd->szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (INVALID_HANDLE_VALUE == hf) return (FALSE);#else of.cBytes = sizeof(of); hf = OpenFile(m_paafd->szFilePath, &of, OF_READ); if (HFILE_ERROR == hf) return (FALSE);#endif
// // assume the worst // fReturn = FALSE;
// // determine the length in _bytes_ of the file //#ifdef WIN32 cbFileSize = GetFileSize((HANDLE)hf, NULL);#else cbFileSize = _llseek(hf, 0L, SEEK_END); _llseek(hf, 0L, SEEK_SET);#endif
// // // // m_paafd->cbFileSize = cbFileSize;
#ifdef WIN32{ BY_HANDLE_FILE_INFORMATION bhfi; WORD wDosChangeDate; WORD wDosChangeTime;
GetFileInformationByHandle(hf, &bhfi);
159
m_paafd->fdwFileAttributes = bhfi.dwFileAttributes;
FileTimeToDosDateTime(&bhfi.ftLastWriteTime, &wDosChangeDate, &wDosChangeTime);
m_paafd->uDosChangeDate = (UINT)wDosChangeDate; m_paafd->uDosChangeTime = (UINT)wDosChangeTime;}#else m_paafd->fdwFileAttributes = DosGetFileAttributes(m_paafd->szFilePath);
dw = DosGetDateTime(hf); m_paafd->uDosChangeDate = LOWORD(dw); m_paafd->uDosChangeTime = HIWORD(dw);#endif
// // now return the fully qualified path and title for the file //#ifndef WIN32 lstrcpy(m_paafd->szFilePath, of.szPathName);#endif AppGetFileTitle(m_paafd->szFilePath, m_paafd->szFileTitle);
#ifdef WIN32 CloseHandle(hf);#else _lclose(hf);#endif
// // // // werr = wioFileOpen(&wio, m_paafd->szFilePath, 0L); if (WIOERR_NOERROR == werr) { UINT cbwfx;
cbwfx = SIZEOF_WAVEFORMATEX(wio.pwfx);
m_paafd->pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX [cbwfx];//*CR. if (NULL != m_paafd->pwfx) {
memcpy(m_paafd->pwfx, wio.pwfx, cbwfx);//*CR.
m_paafd->cbwfx = cbwfx;
m_paafd->dwDataBytes = wio.dwDataBytes; m_paafd->dwDataSamples = wio.dwDataSamples;
fReturn = TRUE; }
wioFileClose(&wio, 0L); }
return (fReturn);} // AcmAppFileOpen()
//--------------------------------------------------------------------------;//// BOOL AppGetFileTitle//// Description:
160
// This function extracts the file title from a file path and returns// it in the caller's specified buffer.//// Arguments:// PTSTR pszFilePath: Pointer to null terminated file path.//// PTSTR pszFileTitle: Pointer to buffer to receive the file title.//// Return (BOOL):// Always returns TRUE. But should return FALSE if this function// checked for bogus values, etc.//////--------------------------------------------------------------------------;
BOOL CRecorder:: AppGetFileTitle( PTSTR pszFilePath, PTSTR pszFileTitle){ #define IS_SLASH(c) ('/' == (c) || '\\' == (c))
PTSTR pch;
// // scan to the end of the file path string.. // for (pch = pszFilePath; '\0' != *pch; pch++) ;
// // now scan back toward the beginning of the string until a slash (\), // colon, or start of the string is encountered. // while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch)) { pch--; }
// // finally, copy the 'title' into the destination buffer.. skip ahead // one char since the above loop steps back one too many chars... // lstrcpy(pszFileTitle, ++pch);
return (TRUE);} // AppGetFileTitle()
//--------------------------------------------------------------------------;//// WIOERR wioFileOpen//// Description:////// Arguments:// LPWAVEIOCB pwio://// LPCTSTR pszFilePath://// DWORD fdwOpen://// Return (WIOERR)://////--------------------------------------------------------------------------;
161
WIOERR CRecorder:: wioFileOpen( LPWAVEIOCB pwio, LPCTSTR pszFilePath, DWORD fdwOpen){ WIOERR werr; HMMIO hmmio; MMCKINFO ckRIFF; MMCKINFO ck; DWORD dw;
// // validate a couple of things... // if (NULL == pwio) return (WIOERR_BADPARAM);
// // default our error return (assume the worst) //
memset(pwio, 0, sizeof(*pwio));//*CR. werr = WIOERR_FILEERROR;
pwio->dwFlags = fdwOpen;
// // first try to open the file, etc.. open the given file for reading // using buffered I/O // hmmio = mmioOpen((LPTSTR)pszFilePath, NULL, MMIO_READ | MMIO_ALLOCBUF); if (NULL == hmmio) goto wio_Open_Error;
pwio->hmmio = hmmio;
// // locate a 'WAVE' form type... // ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hmmio, &ckRIFF, NULL, MMIO_FINDRIFF)) goto wio_Open_Error;
// // we found a WAVE chunk--now go through and get all subchunks that // we know how to deal with... // pwio->dwDataSamples = (DWORD)-1L;
#if 0 if (lrt=riffInitINFO(&wio.pInfo)) { lr=lrt; goto wio_Open_Error; }#endif
// // // while (MMSYSERR_NOERROR == mmioDescend(hmmio, &ck, &ckRIFF, 0)) { // // quickly check for corrupt RIFF file--don't ascend past end! // if ((ck.dwDataOffset + ck.cksize) > (ckRIFF.dwDataOffset + ckRIFF.cksize))
162
{// Comments by CR: Believe it or not, THIS IS Microsoft's code !!!werr = WIOERR_BADFILE;
goto wio_Open_Error; }
switch (ck.ckid) { case mmioFOURCC('L', 'I', 'S', 'T'): if (ck.fccType == mmioFOURCC('I', 'N', 'F', 'O')) {#if 0 if(lrt=riffReadINFO(hmmio, &ck, wio.pInfo)) { lr=lrt; goto wio_Open_Error; }#endif } break;
case mmioFOURCC('D', 'I', 'S', 'P'):#if 0 riffReadDISP(hmmio, &ck, &(wio.pDisp));#endif break;
case mmioFOURCC('f', 'm', 't', ' '): // // !?! another format chunk !?! // if (NULL != pwio->pwfx) break;
// // get size of the format chunk, allocate and lock memory // for it. we always alloc a complete extended format header // (even for PCM headers that do not have the cbSize field // defined--we just set it to zero). // dw = ck.cksize; if (dw < sizeof(WAVEFORMATEX)) dw = sizeof(WAVEFORMATEX);
pwio->pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX[dw]; if (NULL == pwio->pwfx) { werr = WIOERR_NOMEM; goto wio_Open_Error; }
// // read the format chunk // werr = WIOERR_FILEERROR; dw = ck.cksize; if (mmioRead(hmmio, (HPSTR)pwio->pwfx, dw) != (LONG)dw) goto wio_Open_Error; break;
case mmioFOURCC('d', 'a', 't', 'a'): // // !?! multiple data chunks !?! // if (0L != pwio->dwDataBytes) break;
163
// // just hang on to the total length in bytes of this data // chunk.. and the offset to the start of the data // pwio->dwDataBytes = ck.cksize; pwio->dwDataOffset = ck.dwDataOffset; break;
case mmioFOURCC('f', 'a', 'c', 't'): // // !?! multiple fact chunks !?! // if (-1L != pwio->dwDataSamples) break;
// // read the first dword in the fact chunk--it's the only // info we need (and is currently the only info defined for // the fact chunk...) // // if this fails, dwDataSamples will remain -1 so we will // deal with it later... // mmioRead(hmmio, (HPSTR)&pwio->dwDataSamples, sizeof(DWORD)); break; }
// // step up to prepare for next chunk.. // mmioAscend(hmmio, &ck, 0); }
// // if no fmt chunk was found, then die! // if (NULL == pwio->pwfx) { werr = WIOERR_ERROR; goto wio_Open_Error; }
// // all wave files other than PCM are _REQUIRED_ to have a fact chunk // telling the number of samples that are contained in the file. it // is optional for PCM (and if not present, we compute it here). // // if the file is not PCM and the fact chunk is not found, then fail! // if (-1L == pwio->dwDataSamples) { if (WAVE_FORMAT_PCM == pwio->pwfx->wFormatTag) { pwio->dwDataSamples = pwio->dwDataBytes / pwio->pwfx->nBlockAlign; } else {
// Comments by CR: Believe it or not, THIS IS Microsoft's code (+ comments) !!! // // !!! HACK HACK HACK !!! // // although this should be considered an invalid wave file, we // will bring up a message box describing the error--hopefully // people will start realizing that something is missing??? // werr = WIOERR_BADFILE; goto wio_Open_Error;
164
// // !!! need to hack stuff in here !!! // pwio->dwDataSamples = 0L; } }
// // cool! no problems.. // return (WIOERR_NOERROR);
// // return error (after minor cleanup) //wio_Open_Error:
wioFileClose(pwio, 0L); return (werr);} // wioFileOpen()
//--------------------------------------------------------------------------;//// WIOERR wioFileClose//// Description:////// Arguments:// LPWAVEIOCB pwio://// DWORD fdwClose://// Return (WIOERR):////--------------------------------------------------------------------------;
WIOERR CRecorder:: wioFileClose( LPWAVEIOCB pwio, DWORD fdwClose){ // // validate a couple of things... // if (NULL == pwio) return (WIOERR_BADPARAM);
// // get rid of stuff... //// wioStopWave(pwio);
if (NULL != pwio->hmmio) { mmioClose(pwio->hmmio, 0); }
// FreeWaveHeaders(lpwio);
#if 0 if (pwio->pInfo) riffFreeINFO(&(lpwio->pInfo));
165
if (pwio->pDisp) riffFreeDISP(&(lpwio->pDisp));#endif
return (WIOERR_NOERROR);} // wioFileClose()
//--------------------------------------------------------------------------;//// BOOL AppFileNew//// Description:// This function is called to handle the IDM_FILE_NEW message. It is// responsible for clearing the working area for a new unnamed file.//// Arguments:// HWND hwnd: Handle to application window.//// PACMAPPFILEDESC m_paafd: Pointer to current file descriptor.//// Return (BOOL):// The return value is TRUE if the working area was cleared and is// ready for new stuff. The return value is FALSE if the user canceled// the operation.////--------------------------------------------------------------------------;
BOOL CRecorder:: AppFileNew( BOOL fCreate){ BOOL f;
if (fCreate) { f = AcmAppFileNew();//*CR. if (!f) return (FALSE); } else { // // if there is currently a file path, then we have to do some real // work... // if ('\0' != m_paafd->szFilePath[0]) {
f = AcmAppFileNew();//*CR. if (!f) return (FALSE); }
// // blow away the old file path and title; set the window title // and return success // lstrcpy(m_paafd->szFilePath, m_szFileUntitled); lstrcpy(m_paafd->szFileTitle, m_szFileUntitled); }
AppTitle(m_paafd->szFileTitle);
return (TRUE);} // AppFileNew()
//--------------------------------------------------------------------------;//
166
// BOOL AppFileOpen//// Description:// This function handles the IDM_FILE_OPEN message. It is responsible// for getting a new file name from the user and opening that file// if possible.//// Arguments:// HWND hwnd: Handle to application window.//// PACMAPPFILEDESC m_paafd: Pointer to current file descriptor.//// Return (BOOL):// The return value is TRUE if a new file was selected and opened.// It is FALSE if the user canceled the operation.////--------------------------------------------------------------------------;
BOOL CRecorder:: AppFileOpen( HWND hwnd, PACMAPPFILEDESC m_paafd){ TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; BOOL f;
// // get the file name of the new file into temporary buffers (so // if we fail to open it we can back out cleanly). // f = AppGetFileName(szFilePath, szFileTitle, APP_GETFILENAMEF_OPEN);// Comments by CR: Added if (!f) return (FALSE);
//!!! // read the new file... // lstrcpy(m_paafd->szFilePath, szFilePath); lstrcpy(m_paafd->szFileTitle, szFileTitle);
f = AcmAppFileOpen();// Comments by CR: Added if (f) { // // set the window title text... //
// Comments by CR: Added AppTitle(szFileTitle); AcmAppDisplayFileProperties(); }
return (f);} // AppFileOpen()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordStatus//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd:
167
//// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordStatus(){ TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS]; TCHAR szMode[40]; TCHAR szPosition[40]; TCHAR szLength[40]; TCHAR szFormat[40]; MCIERROR mcierr; UINT uStatus; BOOL fStartTimer; BOOL fPlay; BOOL fPause; BOOL fStop; BOOL fStart; BOOL fEnd; BOOL fRecord; BOOL fCommand; UINT uIdFocus; DWORD dwLength; DWORD dwPosition;
// // // if (AAPLAYRECORD_STATUS_NOT_OPEN != m_uPlayRecordStatus) {
mcierr = AcmPlayRecordSendCommand(TEXT("status mode"), szMode, SIZEOF(szMode), TRUE);//*CR. if (MMSYSERR_NOERROR != mcierr) { m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN; } }
// // assume all buttons disabled // fStartTimer = FALSE; fPlay = FALSE; fPause = FALSE; fStop = FALSE; fStart = FALSE; fEnd = FALSE; fRecord = FALSE; fCommand = TRUE; uIdFocus = IDOK; dwPosition = 0L; dwLength = 0L; lstrcpy(szFormat, TEXT("???"));
// // // if (AAPLAYRECORD_STATUS_NOT_OPEN == m_uPlayRecordStatus) { lstrcpy(szMode, TEXT("not open")); } else if (0 == lstrcmpi(TEXT("not ready"), szMode)) { uStatus = AAPLAYRECORD_STATUS_NOT_READY;
168
fStartTimer = TRUE; } else if (0 == lstrcmpi(TEXT("paused"), szMode)) { uStatus = AAPLAYRECORD_STATUS_PAUSED;
fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("playing"), szMode)) { uStatus = AAPLAYRECORD_STATUS_PLAYING;
fStartTimer = TRUE; fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("stopped"), szMode)) { uStatus = AAPLAYRECORD_STATUS_STOPPED;
fPlay = TRUE; fStart = TRUE; fEnd = TRUE; fRecord = TRUE; } else if (0 == lstrcmpi(TEXT("recording"), szMode)) { uStatus = AAPLAYRECORD_STATUS_RECORDING;
fStartTimer = TRUE; fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("seeking"), szMode)) { uStatus = AAPLAYRECORD_STATUS_SEEKING;
fStartTimer = TRUE; fStop = TRUE; }
// // // // // if (fStartTimer) { if (!m_fTimerGoing) {
SetTimer(NULL, 1, AAPLAYRECORD_TIMER_RESOLUTION, NULL);//*CR. m_fTimerGoing = TRUE; } } else if (m_fTimerGoing) {
KillTimer(NULL, 1);//*CR. m_fTimerGoing = FALSE; }
// // // //
169
if (AAPLAYRECORD_STATUS_NOT_OPEN != m_uPlayRecordStatus) { // // //
mcierr = AcmPlayRecordSendCommand(TEXT("status position"), szPosition, SIZEOF(szPosition), TRUE);//Comments by CR: Added if (MMSYSERR_NOERROR == mcierr) { dwPosition = _tcstoul(szPosition, NULL, 10); }
mcierr = AcmPlayRecordSendCommand(TEXT("status length"), szLength, SIZEOF(szLength), TRUE);//Comments by CR: Added if (MMSYSERR_NOERROR == mcierr) { dwLength = _tcstoul(szLength, NULL, 10); }
mcierr = AcmPlayRecordSendCommand(TEXT("status time format"), szFormat, SIZEOF(szFormat),TRUE);// Comments by CR: Added }
// // // // if (uStatus != m_uPlayRecordStatus) { m_uPlayRecordStatus = uStatus; }
// // // AppFormatBigNumber(szPosition, dwPosition); AppFormatBigNumber(szLength, dwLength);
wsprintf(ach, TEXT("%s: %14s (%s) %s"), (LPSTR)szMode, (LPSTR)szPosition, (LPSTR)szLength, (LPSTR)szFormat);
// // // // return (TRUE);} // AcmAppPlayRecordStatus()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordPlay//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
170
BOOL CRecorder:: AcmAppPlayRecordPlay( HWND hwnd, PACMAPPFILEDESC m_paafd){ MCIERROR mcierr; TCHAR szPosition[40]; TCHAR szLength[40];
mcierr = AcmPlayRecordSendCommand(TEXT("status position"), szPosition, SIZEOF(szPosition), TRUE);// Commentsby CR: Added if (MMSYSERR_NOERROR != mcierr) { return (FALSE); }
mcierr = AcmPlayRecordSendCommand(TEXT("status length"), szLength, SIZEOF(szLength), TRUE);// Comments byCR: Added if (MMSYSERR_NOERROR != mcierr) { return (FALSE); }
if (0 == lstrcmp(szPosition, szLength)) {
AcmPlayRecordSendCommand(TEXT("seek to start"), NULL, 0, TRUE);// Comments by CR: Added }
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("play"), NULL, 0, TRUE);// Comments by CR: Added
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordPlay()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordStop//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordStop(){ MCIERROR mcierr;
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("stop"), NULL, 0, TRUE);// Comments by CR: Added
171
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordStop()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordRecord//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordRecord(){ MCIERROR mcierr;
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("record insert"), NULL, 0, TRUE);// Comments by CR: Added if (MMSYSERR_NOERROR == mcierr) { m_fDirty = TRUE; }
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordRecord()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordClose//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordClose(){ MCIERROR mcierr;
if (m_fDirty) {
mcierr = AcmPlayRecordSendCommand(TEXT("save"), NULL, 0, TRUE);// Comments by CR: Added }
mcierr = AcmPlayRecordSendCommand(TEXT("close"), NULL, 0, TRUE);// Comments by CR: Added
172
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordClose()
//--------------------------------------------------------------------------;//// MCIERROR AcmPlayRecordSendCommand//// Description:// The string is of the form "verb params" our device name is inserted// after the verb and send to the device.//// Arguments:// HWND hwnd://// PSTR pszCommand://// PSTR pszReturn://// UINT cbReturn://// BOOL fErrorBox://// Return (MCIERROR)://////--------------------------------------------------------------------------;
MCIERROR CRecorder:: AcmPlayRecordSendCommand( PTSTR pszCommand, PTSTR pszReturn, UINT cbReturn, BOOL fErrorBox){ MCIERROR mcierr; TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS * 2]; TCHAR *pch; PTSTR psz;
pch = pszCommand;
while (('\t' == *pch) || (' ' == *pch)) { pch++; }
if (0 == lstrlen(pch)) { return (MMSYSERR_NOERROR); }
pch = ach; psz = pszCommand; while (('\0' != *psz) && (' ' != *psz)) { *pch++ = *psz++; }
*pch++ = ' ';
lstrcpy(pch, m_szAlias); lstrcat(pch, psz);
mcierr = mciSendString(ach, pszReturn, cbReturn, NULL);// Comments by CR: Changed the hwnd to NULL if (MMSYSERR_NOERROR != mcierr) { if (fErrorBox)
173
{ int n;
n = wsprintf(ach, TEXT("Command: '%s'\n\nMCI Wave Error (%lu): "), (LPTSTR)pszCommand, mcierr);
mciGetErrorString(mcierr, &ach[n], SIZEOF(ach) - n);}
}
return (mcierr);} // AcmPlayRecordSendCommand()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordInitCommands//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordInitCommands(){ static PTSTR pszCommands[] = { TEXT("play"), TEXT("play to Y"), TEXT("play from X to Y"),
TEXT(""), TEXT("capability can eject"), TEXT("capability can play"), TEXT("capability can record"), TEXT("capability can save"), TEXT("capability compound device"), TEXT("capability device type"), TEXT("capability has audio"), TEXT("capability has video"), TEXT("capability inputs"), TEXT("capability outputs"), TEXT("capability uses files"),
TEXT(""), TEXT("cue input !"), TEXT("cue output !"),
TEXT(""), TEXT("delete to Y !"), TEXT("delete from X to Y !"),
TEXT(""), TEXT("info input"), TEXT("info file"), TEXT("info output"), TEXT("info product"),
TEXT(""),
174
TEXT("pause"),
TEXT(""), TEXT("record insert !"), TEXT("record overwrite !"), TEXT("record to Y !"), TEXT("record from X to Y !"),
TEXT(""), TEXT("resume"),
TEXT(""), TEXT("save"), TEXT("save FILENAME"),
TEXT(""), TEXT("seek to Y"), TEXT("seek to start"), TEXT("seek to end"),
TEXT(""), TEXT("set alignment X"), TEXT("set any input"), TEXT("set any output"), TEXT("set audio all off"), TEXT("set audio all on"), TEXT("set audio left off"), TEXT("set audio left on"), TEXT("set audio right off"), TEXT("set audio right on"), TEXT("set bitspersample X"), TEXT("set bytespersec X"), TEXT("set channels X"), TEXT("set format tag X"), TEXT("set format tag pcm"), TEXT("set input X"), TEXT("set output X"), TEXT("set samplespersec X"), TEXT("set time format bytes"), TEXT("set time format milliseconds"), TEXT("set time format samples"),
TEXT(""), TEXT("status alignment"), TEXT("status bitspersample"), TEXT("status bytespersec"), TEXT("status channels"), TEXT("status current track"), TEXT("status format tag"), TEXT("status input"), TEXT("status length"), TEXT("status length track X"), TEXT("status level"), TEXT("status media present"), TEXT("status mode"), TEXT("status number of tracks"), TEXT("status output"), TEXT("status position"), TEXT("status position track X"), TEXT("status ready"), TEXT("status samplespersec"), TEXT("status start position"), TEXT("status time format"),
TEXT(""), TEXT("stop"), NULL };
175
// // // return (TRUE);} // AcmAppPlayRecordInitCommands()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordOpen//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppPlayRecordOpen(){ TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS]; MCIERROR mcierr;
m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN;
m_fTimerGoing = FALSE; m_fFileOpen = FALSE;
m_fDirty = FALSE;
if (NULL == m_paafd->pwfx) { return (FALSE); }
wsprintf(ach, TEXT("open \"%s\" alias %s"), (LPSTR)m_paafd->szFilePath, (LPSTR)m_szAlias);
mcierr = mciSendString(ach, NULL, 0, NULL); if (MMSYSERR_NOERROR != mcierr) { mciGetErrorString(mcierr, ach, SIZEOF(ach));
return (FALSE); }
m_fFileOpen = TRUE; m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_READY;
mcierr = AcmPlayRecordSendCommand(TEXT("set time format samples"), NULL, 0, TRUE); // Comments by CR: Removedhwnd param
if (WAVE_MAPPER != m_uWaveInId) { wsprintf(ach, TEXT("set input %u"), m_uWaveInId); mcierr = AcmPlayRecordSendCommand(ach, NULL, 0, TRUE);// Comments by CR: Added }
if (WAVE_MAPPER != m_uWaveOutId) { wsprintf(ach, TEXT("set output %u"), m_uWaveOutId);
176
mcierr = AcmPlayRecordSendCommand(ach, NULL, 0, TRUE);// Comments by CR: Added }
return (TRUE);} // AcmAppPlayRecordOpen()
//--------------------------------------------------------------------------;//// BOOL AcmAppInit//// Description:////// Arguments:////// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CRecorder:: AcmAppInit(){ DWORD dwVersion;
dwVersion = acmGetVersion(); if (0x0200 <= HIWORD(dwVersion)) { m_fAcmAvailable = TRUE;// Comments by CR: Added } else { m_fAcmAvailable = FALSE; }
AppFileNew(FALSE);
return (m_fAcmAvailable);} // AcmAppInit()
//*****************************************************// stdafx.cpp : source file that includes just the standard includes// stdafx.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Record.dll workspace. No changes were made by the author.//-----------------------------------------------------
#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY#include <statreg.h>
177
#include <statreg.cpp>#endif
#include <atlimpl.cpp>
178
B.1.3 VoiceSender Dll
// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently,// but are changed infrequently
#if !defined(AFX_STDAFX_H__10EE1611_6899_11D3_BD2C_D37A0AEB8424__INCLUDED_)#define AFX_STDAFX_H__10EE1611_6899_11D3_BD2C_D37A0AEB8424__INCLUDED_
#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000
#define STRICT#ifndef _WIN32_WINNT#define _WIN32_WINNT 0x0400#endif#define _ATL_APARTMENT_THREADED
#include <atlbase.h>//You may derive a class from CComModule and use it if you want to override//something, but do not change the name of _Moduleextern CComModule _Module;#include <atlcom.h>
//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__10EE1611_6899_11D3_BD2C_D37A0AEB8424__INCLUDED)
//*****************************************************// Talker.h : Declaration of the CTalker//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the VoiceSender.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// This is the header file of the CTalker class. CTalker is// the C++ dependent implementation of the Talker coclass.////-----------------------------------------------------#ifndef __TALKER_H_#define __TALKER_H_
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////// CTalkerclass ATL_NO_VTABLE CTalker :
public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CTalker, &CLSID_Talker>,public ITalker
{public:
// Comments by CR: for m_nPakcetSize// The voice/sound file is sent in chunks ranging from:// 1 to 576 bytes. 576 bytes is the minimum MTU required by all IPv4
179
// implementations. This size can be varied to arrive at different, to// determine the one that allows the best delivery time performance.CTalker():m_pVoiceDataBuffer(0),m_clientSocket(INVALID_SOCKET),m_nPacketSize(576){
memset(m_szVoiceFilename,NULL,256);}
HRESULT FinalConstruct(){
int status;
/* initialize the Windows Socket DLL */status=WSAStartup(MAKEWORD(1, 1), &m_Data);if ( status )
return( !S_OK);
/* zero the sockaddr_in structure */memset(&m_serverSockAddr, 0,sizeof(m_serverSockAddr));
return(S_OK);}
void FinalRelease(){
WSACleanup();}
DECLARE_REGISTRY_RESOURCEID(IDR_TALKER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CTalker)COM_INTERFACE_ENTRY(ITalker)
END_COM_MAP()
// ITalkerprivate:
WSADATA m_Data;SOCKADDR_IN m_serverSockAddr;SOCKET m_clientSocket;char m_szVoiceFilename[256];char *m_pVoiceDataBuffer;
UINT m_nPacketSize;// Comments by CR: Socket cleanup is a convenience function used to close the socket after it has been// usedvoid SocketCleanup(void);
public:STDMETHOD(SetVoiceFilename)(LPSTR filename);STDMETHOD(SetListenerAddress)(LPSTR pServerSockAddr, LPSTR pServerSockPort);STDMETHOD(Talk)();STDMETHOD(SetPacketSize)(UINT nPacketSize);
};
#endif //__TALKER_H_
180
//*****************************************************// stdafx.cpp : source file that includes just the standard includes// stdafx.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the VoiceSender.dll workspace. No changes were made by the author.//-----------------------------------------------------
#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY#include <statreg.h>#include <statreg.cpp>#endif
#include <atlimpl.cpp>
//*****************************************************// Talker.cpp : Implementation of CTalker//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the VoiceSender.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// CTalker the C++ dependent implementation of the Talker coclass.//// Talker is a COM component that implements a TCP socket client to// send a voice/sound file to a TCP socket server.// It uses the WinSock 2.0 API.//-----------------------------------------------------#include "stdafx.h"#include "VoiceSender.h"#include "Talker.h"
/////////////////////////////////////////////////////////////////////////////// CTalker
// Comments by CR: This is the Set method the COM client calls for the telling the// Talker which IP address and socket number it is to send the voice/sound file to.//STDMETHODIMP CTalker::SetListenerAddress(LPSTR pServerSockAddr, LPSTR pServerSockPort){
u_short listenerPort;
sscanf(pServerSockPort,"%d",&listenerPort);
m_serverSockAddr.sin_addr.s_addr=inet_addr(pServerSockAddr);m_serverSockAddr.sin_port=htons(listenerPort);
181
// Comments by CR: specify the address family as Internet//m_serverSockAddr.sin_family=AF_INET;
return S_OK;}
// Comments by CR: This is the Set method the COM client calls for the telling the// Talker the name of the file voice/sound file it will send.//STDMETHODIMP CTalker::SetVoiceFilename(LPSTR pFilename){
strcpy(m_szVoiceFilename,pFilename);return S_OK;
}
STDMETHODIMP CTalker::SetPacketSize(UINT nPacketSize){
// Comments by CR: ONly change the packet size if the value is valid, else leave the default// which is initialized in the constructor method.if ( nPacketSize > 0 )
this->m_nPacketSize = nPacketSize;
return S_OK;}
// Comments by CR: Talk() is called by the COM client to trigger the socket client to// connect to the socket server, and transmit the voice/sound file.// The file transfer uses the following protocol:// Client sends [number of bytes in file (6 bytes)]// Server acks// Client sends [file data chunks (X bytes)]// Server acks each chunk, and client//STDMETHODIMP CTalker::Talk(){
int status = 0;
// Comments by CR: make sure that sockets have been intialized first//if ( m_serverSockAddr.sin_port && m_serverSockAddr.sin_addr.s_addr ){
// Comments by CR: Open the file and read it in buffer//
HANDLE hf;hf = CreateFile(m_szVoiceFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == hf)return( !S_OK );
DWORD cbFileSize = GetFileSize((HANDLE)hf, NULL);
m_pVoiceDataBuffer = new char [cbFileSize+1];// Comments by CR: check if the memory was allocated properly, if not failif ( ! m_pVoiceDataBuffer )
return( !S_OK );
memset(m_pVoiceDataBuffer,NULL,cbFileSize+1);
DWORD nNumberOfBytesRead=0;
if ( ReadFile(hf,(LPVOID) m_pVoiceDataBuffer,cbFileSize,&nNumberOfBytesRead,NULL) != TRUE ){
delete [] m_pVoiceDataBuffer;m_pVoiceDataBuffer = NULL;return( !S_OK );
}
182
if ( cbFileSize != nNumberOfBytesRead ){
delete [] m_pVoiceDataBuffer;m_pVoiceDataBuffer = NULL;return( !S_OK );
}
CloseHandle(hf);
// Comments by CR: create a client socket//m_clientSocket=socket(AF_INET, SOCK_STREAM, 0);if (m_clientSocket == INVALID_SOCKET){
delete [] m_pVoiceDataBuffer;m_pVoiceDataBuffer = NULL;return( !S_OK );
}
// Comments by CR: Initialize socket parameters//SOCKADDR_IN clientSockAddr;clientSockAddr.sin_family = AF_INET;clientSockAddr.sin_port = 0;clientSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Comments by CR: Bind the client socket to the client address//status = bind(m_clientSocket,(LPSOCKADDR) &clientSockAddr,sizeof(clientSockAddr));if ( status == SOCKET_ERROR ){
this->SocketCleanup();return( !S_OK );
}
// Comments by CR: Connect the client socket to the server socket//status = connect( m_clientSocket, (LPSOCKADDR) &m_serverSockAddr, sizeof(m_serverSockAddr) );if ( status == SOCKET_ERROR ){
this->SocketCleanup();return( !S_OK );
}
// Comments by CR: Transfer file in chunkschar szFileSize[7];memset(szFileSize,NULL,7);sprintf(szFileSize,"%06X",nNumberOfBytesRead);status = send (m_clientSocket,szFileSize,6,0); //CR. 1st send the file size
// Comments by CR: Send the file contents, using a predertmined chunk size,// or setup from the COM client (as permissible by the min IPv4 MTU size).if ( nNumberOfBytesRead > (this->m_nPacketSize) ){
// Comments by CR: the file size is larger than the chunk size, so send the// file in chunks.for (int i=0; (DWORD) i<nNumberOfBytesRead;i+=(this->m_nPacketSize)){
// Comments by CR: Check if the number of bytes left is less than the// chunk, then send those leftif ( (nNumberOfBytesRead-i) < (this->m_nPacketSize) )
status =send(m_clientSocket,&m_pVoiceDataBuffer[i],nNumberOfBytesRead-i,0);
elsestatus = send(m_clientSocket,&m_pVoiceDataBuffer[i],this-
>m_nPacketSize,0);}
183
}else
// Comments by CR: the file size is less or equal to the chunk size so send it in// one shotstatus = send(m_clientSocket,m_pVoiceDataBuffer,nNumberOfBytesRead,0);
// Comments by CR: Status will contain the number of bytes sent, and if error, closesocket// and fail the transferif ( status == SOCKET_ERROR ){
this->SocketCleanup();return( !S_OK );
}
// Comments by CR: Clean up socket, and return okthis->SocketCleanup();return ( S_OK );
}return( !S_OK );
}
// Comments by CR: Socket cleanup convenience method. It deallocates the voice data// buffer and disconnects from the server.void CTalker::SocketCleanup(void){
// Comments by CR: Make sure all dynamic data is deallocatedif (m_pVoiceDataBuffer){
delete [] m_pVoiceDataBuffer;m_pVoiceDataBuffer = NULL;
}// Comments by CR: shutodwn the connection to the client, and return errorshutdown(m_clientSocket,SD_BOTH);closesocket(m_clientSocket);
}
//*****************************************************// VoiceSender.cpp : Implementation of DLL Exports.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the VoiceSender.dll workspace. No changes were made to the// automatically generated version.// VoiceSender.dll is the COM server DLL that provides the interfaces// required to transfer a voice/sound file to a TCP socket server.// It implements a TCP socket client, using the Winsock 2.0 API.//-----------------------------------------------------
// Note: Proxy/Stub Information// To build a separate proxy/stub DLL,// run nmake -f VoiceSenderps.mk in the project directory.
#include "stdafx.h"#include "resource.h"#include <initguid.h>#include "VoiceSender.h"
184
#include "VoiceSender_i.c"#include "Talker.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)OBJECT_ENTRY(CLSID_Talker, CTalker)END_OBJECT_MAP()
/////////////////////////////////////////////////////////////////////////////// DLL Entry Point
extern "C"BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/){ if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance, &LIBID_VOICESENDERLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok}
/////////////////////////////////////////////////////////////////////////////// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void){ return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;}
/////////////////////////////////////////////////////////////////////////////// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){ return _Module.GetClassObject(rclsid, riid, ppv);}
/////////////////////////////////////////////////////////////////////////////// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void){ // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE);}
/////////////////////////////////////////////////////////////////////////////// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void){ return _Module.UnregisterServer(TRUE);}
//*****************************************************// VoiceSender.idl : IDL source for VoiceSender.dll//
// This file will be processed by the MIDL tool to// produce the type library (VoiceSender.tlb) and marshalling code.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet
185
// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the VoiceSender.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// VoiceSender.dll is the COM server DLL that provides the interfaces// required to transfer the voice/sound file from the client to the server.// This file provides the interface definition language (idl)// for the interfaces exposed by coclasses in the VoiceSender.dll.//-----------------------------------------------------
import "oaidl.idl";import "ocidl.idl";
// Comments by CR: ITalker is the main interface which receives the socket server IP and socket,// along with the voice/sound file name.[
object,uuid(10EE161B-6899-11D3-BD2C-D37A0AEB8424),
helpstring("ITalker Interface"),pointer_default(unique)
]interface ITalker : IUnknown{
[helpstring("method Talk")] HRESULT Talk();[helpstring("method SetListenerAddress")] HRESULT SetListenerAddress(LPSTR pServerSockAddr, LPSTR
pServerSockPort);[helpstring("method SetVoiceFilename")] HRESULT SetVoiceFilename(LPSTR filename);[helpstring("method SetPacketSize")] HRESULT SetPacketSize(UINT nPacketSize);
};
[uuid(10EE160E-6899-11D3-BD2C-D37A0AEB8424),version(1.0),helpstring("VoiceSender 1.0 Type Library")
]library VOICESENDERLib{
importlib("stdole32.tlb");importlib("stdole2.tlb");[
uuid(10EE161C-6899-11D3-BD2C-D37A0AEB8424),helpstring("Talker Class")
]
// Comments by CR: The Talker coclass exposes the ITalker interfacecoclass Talker{
[default] interface ITalker;};
};
186
B.2 Voice Messaging Server Source Code
B.2.1 VmsConsole Exe
//*****************************************************// Main.cpp : Main for the VmsConsole application//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This is the source code of the VmsConsole app. It implements// a Windows TCP socket server via port PORT. Also, it uses// a simple but powerful mechanism to notifies the user when// an instant voice message has arrived, and routes the message to// the COM client it uses for message playback.//-----------------------------------------------------#include "resource.h" // main symbols#include <winsock.h> //*CR. WinSock API#include <atlbase.h> //CR. COM support#include <time.h>
// Comments by CR: Import the library of the SpeechPlayer component#import "Playback.tlb" raw_interfaces_only, no_namespace, named_guids
#define PORT (u_short) 6300 //CR.#define NUM_COUNT_CHARACTERS 6#define NO_FLAGS_SET 0
// Comments by CR: Socket parameters. GLobals, but that is ok. Who's counting?WSADATA m_Data;SOCKADDR_IN m_serverSockAddr;SOCKADDR_IN m_clientSockAddr;SOCKET m_serverSocket;SOCKET m_clientSocket;
// Function prototypesint initSocketServer(void);int waitForClientConnection(void);int talkToClient(void);
//CR: main() : main function that implements the socket server, and uses the SpeechPlayer component// for playing back the message. The software is designed to work with a message queue of ONE, so// everytime a new message arrives it overwrites the previous one. When a message arrives, the user// is prompted to enter:// P for message playback,// Q for quit application (no more messages will be received),// W for waiting for another message. If W is selected before selecting P, the received// message is ignored and will be lost.// Because this implements a TCP socket server to receive instant// voice messages, it is not far fetched to attempt to implement this for a Windows CE device.// Sections of the code have been marked as code compatible with Windows CE.//int main(void){
printf("2.2.1 - 4/21/2000\nStarted VmsApp. This a demo interface for an instant voice messaging over IPplayback.\nPlease send your comments to [email protected]. Thanks.\n");
HRESULT hr = CoInitialize(NULL); // For CE, use CoInitializeEx()if ( hr != S_OK )
187
return (hr);
int status = 0;/* initialize the Windows Socket DLL */status=WSAStartup(MAKEWORD(1, 1), &m_Data); //Supported in CE!if ( status )
return(FALSE);
//CR. Infinite loop until app is killed, and there is no error with statuswhile(TRUE && !status ){
// Init socket serverprintf("InitSocketServer\n");status = initSocketServer();if ( status )
printf("Broke after iniSocketServer. Status = %d.\n",status);
//CR. wait for socket connection, if fails print error message and abortprintf("\n\nWaiting for client connection\n");status = waitForClientConnection();if ( status ){
printf("Broke after waiting for connection. Status = %d.\n",status);break;
}
// Connection was accepted by the server, now receive the dataprintf("Talking to client\n");
char szMessage[256];memset(szMessage,NULL,sizeof(szMessage));
clock_t startTime = 0; clock_t endTime = 0; double elapsedTime = 0.0;
startTime = clock();status = talkToClient();if (status ){
printf("Broke after talking to client. Status = %d.\n",status);break;
}
// When entire message is received, shutdown the socket connectionprintf("\t\tMessage received. Shutdown client connection\n");status=shutdown(m_clientSocket, 2); //Supported in CE!if (status == SOCKET_ERROR){
printf("Broke after shutdown socket. Status = %d.\n",status);break;
}
/* close the socket */status=closesocket(m_clientSocket); //Supported in CE!if (status == SOCKET_ERROR){
printf("Broke after closing socket. Status = %d.\n",status);break;
}
//CR. Break servershutdown(m_serverSocket, 2); //Supported in CE!closesocket(m_serverSocket); //Supported in CE!
endTime = clock();elapsedTime = (double) (endTime-startTime)/CLOCKS_PER_SEC;printf("\nMessage reception time = %3.3f.\n",elapsedTime);
188
//CR. Prompt the user that message arrivedchar line[256];do{
memset(line,NULL,sizeof(line));printf( "Voice message was received, Want to Playback or Wait for another or Quit? (P, W, Quit): "
);gets( line );
if (line[0] == 'P' || line[0] == 'p' ){
// CR: User accepts to playback the message, now connect to the SpeechPlayerCComQIPtr<ISpeechPlayer> m_spSpeechPlayer; //Supported in CE! >= 2.0hr = (LRESULT) m_spSpeechPlayer.CoCreateInstance (__uuidof(SpeechPlayer));
//Supported in CE! >= 2.0if ( hr == S_OK ){
printf( "\nMessage is being played back\n" );m_spSpeechPlayer->StartPlayback();m_spSpeechPlayer.Release();
}else{
printf( "\nError accessing voice player. Error code is %d. Exiting\n",hr );line[0] = 'Q'; //CR. force it to bail outbreak;
}}
} while (line[0] == 'P' || line[0] == 'p' );
if (line[0] == 'Q' || line[0] == 'q' )break;
else if ( line[0] == 'W' || line[0] == 'w' )continue;
}
WSACleanup(); //Supported in CE! >= 2.0
CoUninitialize(); //Supported in CE! >= 2.0
return (0);}
// CR: INitialize the server socket to the port, and addressint initSocketServer(){
int status=0;
/* zero the sockaddr_in structure */memset(&m_serverSockAddr, 0,sizeof(m_serverSockAddr));/* specify the port portion of the address */m_serverSockAddr.sin_port=htons(PORT);/* specify the address family as Internet */m_serverSockAddr.sin_family=AF_INET;/* specify that the address does not matter */m_serverSockAddr.sin_addr.s_addr=htonl(INADDR_ANY);
/* create a socket */m_serverSocket=socket(AF_INET, SOCK_STREAM, 0); //Supported in CE!if (m_serverSocket == INVALID_SOCKET){
int nError = WSAGetLastError();printf("Broke after creating socket. WSAGetLastError returns = %d.\n",nError);switch (nError){
case WSANOTINITIALISED:printf("\tWSANOTINITIALISED\n");
189
break;case WSAENETDOWN:
printf("\tWSAENETDOWN\n");break;
case WSAEAFNOSUPPORT:printf("\tWSAEAFNOSUPPORT\n");break;
case WSAEINPROGRESS:printf("\tWSAEINPROGRESS\n");break;
case WSAEMFILE:printf("\tWSAEMFILE\n");break;
case WSAENOBUFS:printf("\tWSAENOBUFS\n");break;
case WSAEPROTONOSUPPORT:printf("\tWSAEPROTONOSUPPORT\n");break;
case WSAEPROTOTYPE:printf("\tWSAEPROTOTYPE\n");break;
case WSAESOCKTNOSUPPORT:printf("\tWSAESOCKTNOSUPPORT\n");break;
default:printf("\tUnknown error\n");
}return (nError);
}/* associate the socket with the address */status=bind(m_serverSocket,(LPSOCKADDR) &m_serverSockAddr,sizeof(m_serverSockAddr)); //Supported in CE!if ( status ){
int nError = WSAGetLastError();printf("Broke after binding. WSAGetLastError returns = %d.\n",nError);switch (nError){
case WSANOTINITIALISED:printf("\tWSANOTINITIALISED\n");break;
case WSAENETDOWN:printf("\tWSAENETDOWN\n");break;
case WSAEADDRINUSE:printf("\tWSAEADDRINUSE \n");break;
case WSAEADDRNOTAVAIL:printf("\tWSAEADDRNOTAVAIL\n");break;
case WSAEFAULT:printf("\tWSAEFAULT\n");break;
case WSAEINPROGRESS:printf("\tWSAEINPROGRESS\n");break;
case WSAEINVAL:printf("\tWSAEINVAL\n");break;
case WSAENOBUFS:printf("\tWSAENOBUFS\n");break;
case WSAENOTSOCK:printf("\tWSAENOTSOCK\n");break;
default:printf("\tUnknown error\n");
}
190
return (nError);}
return (status);}
// CR: When the socket has been setup, wait here until a connection from a client is receivedint waitForClientConnection(){
int status=0;
int addrLen=sizeof(SOCKADDR_IN);
/* WAIT HERE to allow the socket to take connections */status=listen(m_serverSocket, 1); //Supported in CE!if (status == SOCKET_ERROR){
int nError = WSAGetLastError();printf("Broke after listening. WSAGetLastError returns = %d.\n",nError);switch (nError){
case WSANOTINITIALISED:printf("\tA successful WSAStartup must occur before using this function\n");break;
case WSAENETDOWN:printf("\tThe network subsystem has failed.\n");break;
case WSAEINPROGRESS:printf("\tWSAEINPROGRESS\n");break;
case WSAEINVAL:printf("\tWSAEINVAL\n");break;
case WSAEISCONN:printf("\tWSAEISCONN\n");break;
case WSAEMFILE:printf("\tWSAEMFILE\n");break;
case WSAENOBUFS:printf("\tWSAENOBUFS\n");break;
case WSAENOTSOCK:printf("\tWSAENOTSOCK\n");break;
case WSAEOPNOTSUPP:printf("\tWSAEOPNOTSUPP\n");break;
default:printf("\tUnknown error\n");
}return(status);
}
/* accept the connection request when one is received */m_clientSocket=accept(m_serverSocket,(LPSOCKADDR) &m_clientSockAddr,&addrLen); //Supported in CE!if (m_clientSocket == INVALID_SOCKET){
printf("Broke after accepting. WSAGetLastError returns = %d.\n",WSAGetLastError());return(INVALID_SOCKET);
}
return (status);}
// CR: Once a connection from a socket client has been received, read the number of bytes. The data is// read 1 byte at a time to provide a simple solution to the problem that the client can be sending the// data in different chunks which can be greater or equal to 2 bytes/chunk.
191
//int talkToClient(){
char *pBuffer=NULL;pBuffer = new char [NUM_COUNT_CHARACTERS+1];memset(pBuffer,NULL,NUM_COUNT_CHARACTERS+1);
int numrcv=0;int i=0, numOfChars=0;// Read the number of characters first (the 1st two chars of the data)for (i=0;i < NUM_COUNT_CHARACTERS; i++){
numrcv=recv(m_clientSocket,pBuffer+i,1,NO_FLAGS_SET); //Supported in CE!}sscanf(pBuffer,"%X",&numOfChars);if (pBuffer)
delete [] pBuffer;pBuffer=NULL;pBuffer = new char [numOfChars+1];memset(pBuffer,NULL,numOfChars+1);// Read the number data bytesnumrcv=0;for (i=0;i<numOfChars; i++){//Supported in CE!
numrcv+=recv(m_clientSocket,pBuffer+i,1,NO_FLAGS_SET); //CR. increment the count for every bytereceived
}if ((numrcv != numOfChars) || (numrcv == SOCKET_ERROR))
return (numrcv);
//*CR. Save the file.HANDLE hf=0;DWORD nNumberOfBytesWritten=0;hf = CreateFile("c:\\VmcS.wav", GENERIC_WRITE, 0, NULL,CREATE_ALWAYS, 0, 0); //Supported in CE!WriteFile(hf,(LPVOID) pBuffer,numOfChars,&nNumberOfBytesWritten,NULL);CloseHandle(hf);if (pBuffer)
delete [] pBuffer;
if ( nNumberOfBytesWritten != (DWORD) numOfChars )return (nNumberOfBytesWritten); //CR. Failed writing file
elsereturn (0); //CR. Written successfully
} /* end talkToClient () */
192
B.2.2 Playback Dll
//*****************************************************// AcmApp.h : Declaration of the CSpeechPlayer//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// REUSE NOTE: This file contains code adapted and modified by the// author, from Microsoft's AcmApp application found in the// Developer's Network Library.//-----------------------------------------------------#include <windows.h>#include <mmsystem.h>#include <mmreg.h>#include <msacm.h>
#define _tcstoul strtoul
#ifndef INLINE #define INLINE __inline#endif
#ifndef SIZEOF #ifdef UNICODE #define SIZEOF(x) (sizeof(x)/sizeof(WCHAR)) #else #define SIZEOF(x) sizeof(x) #endif#endif
//// ACMAPPINST.fdwState flags//#define ACMAPPFILEDESC_STATEF_MODIFIED 0x80000000L
#define APP_MAX_FILE_PATH_CHARS 144#define APP_MAX_FILE_TITLE_CHARS APP_MAX_FILE_PATH_CHARS#define APP_MAX_STRING_CHARS 128#define APP_MAX_APP_NAME_CHARS 30#define APP_MAX_EXT_DEFAULT_CHARS 4#define APP_MAX_EXT_FILTER_CHARS 256#define APP_MAX_STRING_RC_CHARS 512#define APP_MAX_STRING_ERROR_CHARS 512#define APP_OPTIONSF_DEBUGLOG 0x0004#define APP_OPTIONSF_AUTOOPEN 0x0001
#define AAPLAYRECORD_MAX_MCI_COMMAND_CHARS 255#define AAPLAYRECORD_STATUS_NOT_OPEN (UINT)-1#define AAPLAYRECORD_STATUS_NOT_READY 0#define AAPLAYRECORD_STATUS_PAUSED 1#define AAPLAYRECORD_STATUS_PLAYING 2#define AAPLAYRECORD_STATUS_STOPPED 3#define AAPLAYRECORD_STATUS_RECORDING 4#define AAPLAYRECORD_TIMER_RESOLUTION 54#define AAPLAYRECORD_STATUS_SEEKING 5
#define WIOERR_BASE (0)#define WIOERR_NOERROR (0)#define WIOERR_ERROR (WIOERR_BASE+1)
193
#define WIOERR_BADHANDLE (WIOERR_BASE+2)#define WIOERR_BADFLAGS (WIOERR_BASE+3)#define WIOERR_BADPARAM (WIOERR_BASE+4)#define WIOERR_BADSIZE (WIOERR_BASE+5)#define WIOERR_FILEERROR (WIOERR_BASE+6)#define WIOERR_NOMEM (WIOERR_BASE+7)#define WIOERR_BADFILE (WIOERR_BASE+8)#define WIOERR_NODEVICE (WIOERR_BASE+9)#define WIOERR_BADFORMAT (WIOERR_BASE+10)#define WIOERR_ALLOCATED (WIOERR_BASE+11)#define WIOERR_NOTSUPPORTED (WIOERR_BASE+12)
#ifndef SIZEOF_WAVEFORMATEX#define SIZEOF_WAVEFORMATEX(pwfx) ((WAVE_FORMAT_PCM==(pwfx)->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX)+(pwfx)->cbSize))#endif
//// ACMAPPINST.fdwState flags//#define ACMAPPFILEDESC_STATEF_MODIFIED 0x80000000L
//// fuFlags for AppGetFileName()...//#define APP_GETFILENAMEF_OPEN 0x0000#define APP_GETFILENAMEF_SAVE 0x0001
#define IDS_OFN_EXT_DEF 125#define IDS_OFN_EXT_FILTER 126//// the main window control id's...//#define IDD_ACMAPP_EDIT_DISPLAY 200
#define IDM_FILE_NEW 1100#define IDM_FILE_OPEN 1101#define IDM_FILE_SAVE 1102#define IDM_FILE_SAVEAS 1103#define IDM_FILE_SNDPLAYSOUND_PLAY 1104#define IDM_FILE_SNDPLAYSOUND_STOP 1105#define IDM_FILE_CONVERT 1106#define IDM_FILE_CONVERT_ALL 1107#define IDM_FILE_ABOUT 1109#define IDM_FILE_EXIT 1110
#define IDM_VIEW_SYSTEMINFO 1300#define IDM_VIEW_ACM_DRIVERS 1301#define IDM_OPTIONS_WAVEINDEVICE 1500#define IDM_OPTIONS_WAVEOUTDEVICE 1501#define IDM_OPTIONS_AUTOOPEN 1505#define IDM_OPTIONS_DEBUGLOG 1506#define IDM_OPTIONS_FONT 1509#define IDM_PLAYRECORD 1400
#define IDD_AAPLAYRECORD_BTN_PLAY 100#define IDD_AAPLAYRECORD_BTN_RECORD 105#define IDD_AAPLAYRECORD_BTN_STOP 102
//*CR.#if 0
//globalsHINSTANCE ghinst;TCHAR gszInitialDirSave[APP_MAX_FILE_PATH_CHARS];TCHAR gszInitialDirOpen[APP_MAX_FILE_PATH_CHARS];TCHAR gszAppName[APP_MAX_APP_NAME_CHARS];TCHAR gszFileUntitled[APP_MAX_FILE_TITLE_CHARS];
194
UINT gfuAppOptions = APP_OPTIONSF_AUTOOPEN;TCHAR gszNull[] = TEXT("");UINT guWaveOutId = (UINT)WAVE_MAPPER;UINT guWaveInId = (UINT)WAVE_MAPPER;BOOL gfAcmAvailable;BOOL gfFileOpen;BOOL gfTimerGoing;BOOL gfDirty;UINT guPlayRecordStatus;TCHAR gszAlias[] = TEXT("zyzthing");#endif//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;//////////- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
////////typedef UINT WIOERR;
typedef struct tACMAPPFILEDESC{ DWORD fdwState;
TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
DWORD cbFileSize; UINT uDosChangeDate; UINT uDosChangeTime; DWORD fdwFileAttributes;
LPWAVEFORMATEX pwfx; UINT cbwfx;
DWORD dwDataBytes; DWORD dwDataSamples;
} ACMAPPFILEDESC, *PACMAPPFILEDESC;
//CR. ACMAPPFILEDESC gaafd;
typedef struct tWAVEIOCB{ DWORD dwFlags; HMMIO hmmio;
DWORD dwDataOffset; DWORD dwDataBytes; DWORD dwDataSamples;
LPWAVEFORMATEX pwfx;
#if 0 HWAVEOUT hwo; DWORD dwBytesLeft; DWORD dwBytesPerBuffer;
DISP FAR * pDisp; INFOCHUNK FAR * pInfo;#endif
} WAVEIOCB, *PWAVEIOCB, FAR *LPWAVEIOCB;
195
//*CR.#if 0//// Function protosBOOL FNGLOBAL AcmAppFileSaveModified( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNGLOBAL AcmAppFileSave( HWND hwnd, PACMAPPFILEDESC paafd, PTSTR pszFilePath, PTSTR pszFileTitle, UINT fuSave);
BOOL FNGLOBAL AppFileSave( HWND hwnd, PACMAPPFILEDESC paafd, BOOL fSaveAs);
BOOL FNGLOBAL AppGetFileName( HWND hwnd, PTSTR pszFilePath, PTSTR pszFileTitle, UINT fuFlags);
BOOL FNGLOBAL AppTitle( HWND hwnd, PTSTR pszFileTitle);
BOOL FNGLOBAL AcmAppDisplayFileProperties( HWND hwnd, PACMAPPFILEDESC paafd);
void FNGLOBAL AppHourGlass( BOOL fHourGlass);
BOOL FNGLOBAL AppFormatBigNumber( LPTSTR pszNumber, DWORD dw);
BOOL FNGLOBAL AppFormatDosDateTime( LPTSTR pszDateTime, UINT uDosDate, UINT uDosTime);
BOOL FNGLOBAL AcmAppGetFormatDescription( LPWAVEFORMATEX pwfx, LPTSTR pszFormatTag,
196
LPTSTR pszFormat);
BOOL FNLOCAL AcmAppDumpExtraHeaderData( HWND hedit, LPWAVEFORMATEX pwfx);
int FNCGLOBAL AppMsgBox( HWND hwnd, UINT fuStyle, PTSTR pszFormat, ...);
int FNCGLOBAL MEditPrintF( HWND hedit, PTSTR pszFormat, ...);
void FNCGLOBAL AcmAppDebugLog( PTSTR pszFormat, ...);
BOOL FNGLOBAL AcmAppFileNew( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNGLOBAL AcmAppFileOpen( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNGLOBAL AppGetFileTitle( PTSTR pszFilePath, PTSTR pszFileTitle);
WIOERR WIOAPI wioFileOpen( LPWAVEIOCB pwio, LPCTSTR pszFilePath, DWORD fdwOpen);
WIOERR WIOAPI wioFileClose( LPWAVEIOCB pwio, DWORD fdwClose);
LRESULT FNLOCAL AppCommand( HWND hwnd, int nId, HWND hwndCtl, UINT uCode);
197
BOOL FNGLOBAL AppFileNew( HWND hwnd, PACMAPPFILEDESC paafd, BOOL fCreate);
BOOL FNLOCAL AppFileOpen( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNEXPORT AcmAppPlayRecord( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL FNLOCAL AcmAppPlayRecordStatus( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNLOCAL AcmAppPlayRecordPlay( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNLOCAL AcmAppPlayRecordStop( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNLOCAL AcmAppPlayRecordRecord( HWND hwnd, PACMAPPFILEDESC paafd);
BOOL FNLOCAL AcmAppPlayRecordClose( HWND hwnd, PACMAPPFILEDESC paafd);
MCIERROR FNLOCAL AcmPlayRecordSendCommand( HWND hwnd, PTSTR pszCommand, PTSTR pszReturn, UINT cbReturn, BOOL fErrorBox);
INLINE DWORD MulDivRN(DWORD a,DWORD b,DWORD c){ _asm mov eax,dword ptr a // mov eax, a _asm mov ebx,dword ptr b // mov ebx, b _asm mov ecx,dword ptr c // mov ecx, c _asm mul ebx // mul ebx _asm mov ebx,ecx // mov ebx,ecx
198
_asm shr ebx,1 // sar ebx,1 _asm add eax,ebx // add eax,ebx _asm adc edx,0 // adc edx,0 _asm div ecx // div ecx _asm shld edx, eax, 16 // shld edx, eax, 16
} // MulDiv32()#endif
199
//*****************************************************// SpeechPlayer.h : Declaration of the CSpeechPlayer//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// This is the header file for the implementation of the CSpeechPlayer// class.//// REUSE NOTE: This file contains code adapted and modified by the// author, from Microsoft's AcmApp application found in the// Developer's Network Library.//-----------------------------------------------------
#ifndef __SPEECHPLAYER_H_#define __SPEECHPLAYER_H_
#include "resource.h" // main symbols
// Comments by CR: This is the include of required ACM and MCI APIs#include "AcmApp.h"
#define LIBRARY_MAJOR 1#define LIBRARY_MINOR 0
#define VOICE_FILE_PATH "\\"#define VOICE_FILE_NAME "VmcS.wav"#define UNCOMPRESSED_VOICE_FILE_NAME "VmcS_ucp.wav"
// Comments by CR: PCM paramters definition// Ranges:// PCM_SAMPLES_PER_SEC = 8,000 or 22,050// PCM_AVERAGE_BYTES_PER_SEC = 8,000 or 22,050//#define PCM_FORMAT_TAG 1#define PCM_CHANNELS 1#define PCM_SAMPLES_PER_SEC 8000#define PCM_AVERAGE_BYTES_PER_SEC 8000#define PCM_BLOCK_ALIGN 1#define PCM_BITS_PER_SAMPLE 8#define PCM_SIZE 0
// Comments by CR: This define is used to conditionally compile the section of// code that permits introducing uncompression codec into the software.//#define DEBUGGING_COMPRESSION 0
/////////////////////////////////////////////////////////////////////////////// CSpeechPlayerclass ATL_NO_VTABLE CSpeechPlayer :
public CComObjectRootEx<CComSingleThreadModel>,public CComCoClass<CSpeechPlayer, &CLSID_SpeechPlayer>,public ISpeechPlayer,public ISpeechUncompressor
{public:
CSpeechPlayer(): m_fuAppOptions(APP_OPTIONSF_AUTOOPEN), m_uWaveOutId(WAVE_MAPPER),m_uWaveInId(WAVE_MAPPER),
200
m_fAcmAvailable(FALSE), m_fFileOpen(FALSE), m_fTimerGoing(FALSE),m_fDirty(TRUE),
m_uPlayRecordStatus(AAPLAYRECORD_STATUS_NOT_OPEN){
strcpy(m_szNull,TEXT(""));strcpy(m_szAlias,TEXT("zyzthing"));
//init the file descriptionm_aafd.fdwState = 0;strcpy(m_aafd.szFileTitle,"");strcpy(m_aafd.szFilePath,"");m_aafd.cbFileSize = 0;m_aafd.uDosChangeDate = 0;m_aafd.uDosChangeTime = 0;m_aafd.fdwFileAttributes = 0;m_aafd.pwfx = NULL;m_aafd.cbwfx = 0;m_aafd.dwDataBytes = 0;m_aafd.dwDataSamples = 0;
m_paafd = NULL;
strcpy(m_szInitialDirSave,VOICE_FILE_PATH);strcpy(m_szInitialFileTitle,VOICE_FILE_NAME);strcpy(m_szInitialDirOpen,"");strcpy(m_szAppName,"");strcpy(m_szFileUntitled,"(Untitled)");
}
// Comments by CR: Because this coclass is created when the message is already// stored, FinalConstruct() will uncompress the file receivedHRESULT FinalConstruct(){
m_paafd = & m_aafd;
if ( this->AcmAppInit() == FALSE )return (! S_OK);
this->AcmAppPlayRecordInitCommands();
// Comments by CR: if required, uncompress the speech if it was sent with compression.// UncompressSpeech() will expect to uncompress a compressed wav file named
VOICE_FILE_PATH/VOICE_FILE_NAME,// and save it under the same name// Note: Uncompression is turned on by adding the uncompressing code, not selectable at runtime.//
//// Comments by CR: This conditionally compiled section is used to when debugging the introduction// of a X-to-PCM codec into this system. Two files are created so that the original file is// kept and can be analyzed with the Microsoft Sound /Recorder Player. When the code is debugged,// remove the DEBUGGING_COMPRESSION sections.//
#if DEBUGGING_COMPRESSIONchar szUncompressedVoiceFilePath[256];
sprintf(szUncompressedVoiceFilePath,"%s%s",m_szInitialDirSave,UNCOMPRESSED_VOICE_FILE_NAME);// Comments by CR: set the uncompressed voice filenamestrcpy(m_szInitialFileTitle,szUncompressedVoiceFilePath);this->UncompressSpeech(szUncompressedVoiceFilePath);
#elsechar szVoiceFilePath[256];// Comments by CR: set the uncompressed voice filenamesprintf(szVoiceFilePath,"%s%s",m_szInitialDirSave,m_szInitialFileTitle);this->UncompressSpeech(szVoiceFilePath);
#endif
201
if ( this->AppFileOpen() == FALSE )return (! S_OK);
if ( this->AcmAppPlayRecordOpen() == FALSE )return (! S_OK );
if ( this->AcmAppPlayRecordStatus() == FALSE )return (! S_OK );
return S_OK;}
void FinalRelease(){
if ( m_fFileOpen ){
this->AcmAppPlayRecordStop();this->AcmAppPlayRecordStatus();this->AcmAppPlayRecordClose();
}}
DECLARE_REGISTRY_RESOURCEID(IDR_SPEECHPLAYER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CSpeechPlayer)COM_INTERFACE_ENTRY(ISpeechPlayer)COM_INTERFACE_ENTRY(ISpeechUncompressor)
END_COM_MAP()
// ISpeechPlayerpublic:
STDMETHOD(StopPlayback)();STDMETHOD(StartPlayback)();
// ISpeechUncompressorSTDMETHOD(UncompressSpeech)(LPSTR pFileName);
private:// Comments by CR: ACM app adapted attributesACMAPPFILEDESC m_aafd;PACMAPPFILEDESC m_paafd;//*CR. Pointer to ACMAPPFILEDESC
TCHAR m_szInitialDirSave[APP_MAX_FILE_PATH_CHARS];TCHAR m_szInitialDirOpen[APP_MAX_FILE_PATH_CHARS];TCHAR m_szInitialFileTitle[256];TCHAR m_szAppName[APP_MAX_APP_NAME_CHARS];TCHAR m_szFileUntitled[APP_MAX_FILE_TITLE_CHARS];UINT m_fuAppOptions;TCHAR m_szNull[256];UINT m_uWaveOutId;UINT m_uWaveInId;BOOL m_fAcmAvailable;BOOL m_fFileOpen;BOOL m_fTimerGoing;BOOL m_fDirty;UINT m_uPlayRecordStatus;TCHAR m_szAlias[256];
// Comments by CR: ACMApp adapted methods.BOOL AcmAppPlayRecordInitCommands();
BOOL AcmAppPlayRecordOpen();
BOOL AppGetFileName(
PTSTR pszFilePath,
202
PTSTR pszFileTitle,UINT fuFlags
);
BOOL AppTitle(
PTSTR pszFileTitle);
BOOL AcmAppDisplayFileProperties();
void AppHourGlass(
BOOL fHourGlass);
BOOL AppFormatBigNumber(
LPTSTR pszNumber,DWORD dw
);
BOOL AppFormatDosDateTime(
LPTSTR pszDateTime,UINT uDosDate,UINT uDosTime
);
BOOL AcmAppGetFormatDescription(
LPWAVEFORMATEX pwfx,LPTSTR pszFormatTag,LPTSTR pszFormat
);
BOOL AcmAppDumpExtraHeaderData(
HWND hedit,LPWAVEFORMATEX pwfx
);
int MEditPrintF(
HWND hedit,PTSTR pszFormat,...
);
void AcmAppDebugLog(
PTSTR pszFormat,...
);
BOOL AcmAppFileNew();
BOOL AcmAppFileOpen();
BOOL AppGetFileTitle(
PTSTR pszFilePath,PTSTR pszFileTitle
);
WIOERR wioFileOpen(
LPWAVEIOCB pwio,
203
LPCTSTR pszFilePath,DWORD fdwOpen
);
WIOERR wioFileClose(
LPWAVEIOCB pwio,DWORD fdwClose
);
BOOL AppFileNew(
BOOL fCreate);
BOOL AppFileOpen();
BOOL AcmAppPlayRecordStatus();
BOOL AcmAppPlayRecordPlay();
BOOL AcmAppPlayRecordStop();
BOOL AcmAppPlayRecordRecord();
BOOL AcmAppPlayRecordClose();
MCIERROR AcmPlayRecordSendCommand(
PTSTR pszCommand,PTSTR pszReturn,UINT cbReturn,BOOL fErrorBox
);
BOOL AcmAppInit();
};
#endif //__SPEECHPLAYER_H_
//*****************************************************// stdafx.h : include file for standard system include files,// or project specific include files that are used frequently,// but are changed infrequently//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace.//-----------------------------------------------------#if !defined(AFX_STDAFX_H__EBBB8876_7B2D_11D3_841E_00C04F776696__INCLUDED_)#define AFX_STDAFX_H__EBBB8876_7B2D_11D3_841E_00C04F776696__INCLUDED_
#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000
204
#define STRICT#define _ATL_APARTMENT_THREADED
#include <atlbase.h>//You may derive a class from CComModule and use it if you want to override//something, but do not change the name of _Moduleextern CComModule _Module;#include <atlcom.h>
//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__EBBB8876_7B2D_11D3_841E_00C04F776696__INCLUDED)
205
//******************************************************// Playback.cpp : Implementation of DLL Exports.// Note: Proxy/Stub Information// To build a separate proxy/stub DLL,// run nmake -f Playbackps.mk in the project directory.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace. No changes were made to the// automatically generated version.// Playback.dll is the COM server DLL that provides the interfaces// required to playback a PCM wav file.//-----------------------------------------------------
#include "stdafx.h"#include "resource.h"#include <initguid.h>#include "Playback.h"
#include "Playback_i.c"#include "SpeechPlayer.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)OBJECT_ENTRY(CLSID_SpeechPlayer, CSpeechPlayer)END_OBJECT_MAP()
/////////////////////////////////////////////////////////////////////////////// DLL Entry Point
extern "C"BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/){ if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance, &LIBID_PLAYBACKLib); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok}
/////////////////////////////////////////////////////////////////////////////// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void){ return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;}
/////////////////////////////////////////////////////////////////////////////// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){ return _Module.GetClassObject(rclsid, riid, ppv);
206
}
/////////////////////////////////////////////////////////////////////////////// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void){ // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE);}
/////////////////////////////////////////////////////////////////////////////// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void){ return _Module.UnregisterServer(TRUE);}
//*****************************************************// Playback.idl : IDL source for Playback.dll//
// This file will be processed by the MIDL tool to// produce the type library (Playback.tlb) and marshalling code.//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// Playback.dll is the COM server DLL that provides the interfaces// required to playback a PCM wav voice/sound file .// This file provides the interface definition language (idl)// for the interfaces exposed by coclasses in the Playback.dll.//-----------------------------------------------------
import "oaidl.idl";import "ocidl.idl";
[object,uuid(EBBB887F-7B2D-11D3-841E-00C04F776696),
helpstring("ISpeechPlayer Interface"),pointer_default(unique)
]// Comments by CR: The ISpeechPlayer provides the methods required to// play the voice/sound messageinterface ISpeechPlayer : IUnknown{
[helpstring("method StartPlayback")] HRESULT StartPlayback();[helpstring("method StopPlayback")] HRESULT StopPlayback();
};
[object,uuid(2412DD30-7B39-11d3-841E-00C04F776696),
helpstring("ISpeechUncompressor Interface"),pointer_default(unique)
207
]// Comments by CR: The ISpeechUncompressor is required to uncompress the voice file// before it is played back. This interface is not currently implemented, but its// methods are stubbed and should be called from the COM client to permit future// compatibility.interface ISpeechUncompressor : IUnknown{
[helpstring("method UncompressSpeech")] HRESULT UncompressSpeech(LPSTR pFileName);};
[uuid(EBBB8873-7B2D-11D3-841E-00C04F776696),version(1.0),helpstring("Playback 1.0 Type Library")
]library PLAYBACKLib{
importlib("stdole32.tlb");importlib("stdole2.tlb");
[uuid(EBBB8880-7B2D-11D3-841E-00C04F776696),helpstring("SpeechPlayer Class")
]// Comments by CR: The SpeechPlayer coclass is the actual component that implements// and supports all the interfaces.coclass SpeechPlayer{
[default] interface ISpeechPlayer;interface ISpeechUncompressor;
};};
//*****************************************************// SpeechPlayer.cpp : Implementation of CSpeechPlayer//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace. Changes made by the author to the// file are marked by 'Comments by CR:'.// This is the implementation of the CSpeechPlayer class. CSpeechPlayer// the C++ dependent implementation of the Recorder coclass.//// SpeechPlayer is a COM component that permits the user to compress a// PCM WAV file, and playback.//// REUSE NOTE: This file contains code adapted and modified by the// author, from Microsoft's AcmApp application found in the// Developer's Network Library.//-----------------------------------------------------
#include "stdafx.h"#include <stdio.h> // added for min dependencies#include "Playback.h"#include "SpeechPlayer.h"
/////////////////////////////////////////////////////////////////////////////// CSpeechPlayer
208
// Comments by CR: This is the method called by the COM client when the message is// ready to be played back.//STDMETHODIMP CSpeechPlayer::StartPlayback(){
// Comments by CR: Start the playbackthis->AcmAppPlayRecordPlay();this->AcmAppPlayRecordStatus();
// Comments by CR: to determine the time to playback before releasing objectdouble dTimeToPlaybackMs = (double) 1000* (m_paafd->dwDataBytes) / ((m_paafd->pwfx)->nAvgBytesPerSec);Sleep( (DWORD) dTimeToPlaybackMs );return S_OK;
}
//******************************************************************************// Comments by CR: This is convenience method provided in the interface to allow// the voice playback to be aborted.//-----------------------------------------------------------------------------STDMETHODIMP CSpeechPlayer::StopPlayback(){
if ( this->AcmAppPlayRecordStop() == FALSE )return ( !S_OK );
this->AcmAppPlayRecordStatus();
if ( this->AcmAppPlayRecordClose() == FALSE )return ( !S_OK );
m_fFileOpen = FALSE;
return S_OK;}
//******************************************************************************// Comments by CR: This is convenience method provided in the interface for future use// This method shall convert a compressed wav file named pFileName, into a PCM// wav file named pFileName//-----------------------------------------------------------------------------STDMETHODIMP CSpeechPlayer::UncompressSpeech(LPSTR pFileName){
// TODO: Add your implementation code here
return S_OK;}
//==========================================================================;//////////==========================================================================;//******************************************************************************// Comments by CR: Following is the code adapted from the Microsoft's AcmApp. A lot// of code overhead was removed (user confirmation dialogs, compatiblity with Win16,// and others). This code contains the algorithms used to access the Microsoft's// Audio Compression Manager (ACM) to: open, and manage media WAV files, via the// Media Control Interface (mci).//-----------------------------------------------------------------------------
//--------------------------------------------------------------------------;//// BOOL AppTitle//// Description:// This function formats and sets the title text of the application's
209
// window.//// Arguments:// HWND hwnd: Handle to application window to set title text for.//// PTSTR pszFileTitle: Pointer to file title to display.//// Return (BOOL):// The return value is always TRUE.//////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppTitle( PTSTR pszFileTitle){ static TCHAR szFormatTitle[] = TEXT("%s - %s");
TCHAR ach[APP_MAX_FILE_PATH_CHARS];
// // format the title text as 'AppName - FileTitle' // wsprintf(ach, szFormatTitle, (LPSTR)m_szAppName, (LPSTR)pszFileTitle);
return (TRUE);} // AppTitle()
//--------------------------------------------------------------------------;//// BOOL AcmAppDisplayFileProperties//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppDisplayFileProperties(){ static TCHAR szInvalidWaveFile[] = TEXT("No File"); static TCHAR szDisplayTitle[] = TEXT("[Wave File Format Properties]\r\n");
MMRESULT mmr; TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS]; TCHAR ach[APP_MAX_STRING_CHARS]; DWORD dw; LPWAVEFORMATEX pwfx; HWND hedit=NULL; BOOL fCanPlayRecord; BOOL f;
// // clear the display // AppHourGlass(TRUE);
210
MEditPrintF(hedit, NULL);
// // // MEditPrintF(hedit, szDisplayTitle);
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Title"), (LPTSTR)m_paafd->szFileTitle); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Full Path"), (LPTSTR)m_paafd->szFilePath);
AppFormatBigNumber(ach, m_paafd->cbFileSize); MEditPrintF(hedit, TEXT("%25s: %s bytes"), (LPTSTR)TEXT("Total File Size"), (LPTSTR)ach);
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Last Change Date/Time"), (LPTSTR)ach);
dw = m_paafd->fdwFileAttributes; MEditPrintF(hedit, TEXT("%25s: %c %c%c%c%c %c%c%c%c (%.08lXh)"), (LPTSTR)TEXT("Attributes"), (dw & FILE_ATTRIBUTE_TEMPORARY) ? 't' : '-', (dw & FILE_ATTRIBUTE_NORMAL) ? 'n' : '-', (dw & 0x00000040) ? '?' : '-', (dw & FILE_ATTRIBUTE_ARCHIVE) ? 'a' : '-', (dw & FILE_ATTRIBUTE_DIRECTORY) ? 'd' : '-', (dw & 0x00000008) ? '?' : '-', (dw & FILE_ATTRIBUTE_SYSTEM) ? 's' : '-', (dw & FILE_ATTRIBUTE_HIDDEN) ? 'h' : '-', (dw & FILE_ATTRIBUTE_READONLY) ? 'r' : '-', dw);
pwfx = m_paafd->pwfx; if (NULL == pwfx) { fCanPlayRecord = FALSE;
// Comments by CR: Believe it or not, THIS IS Microsoft code!!! goto AA_Display_File_Properties_Exit; }
// // // // f = AcmAppGetFormatDescription(pwfx, szFormatTag, ach); MEditPrintF(hedit, TEXT("\r\n%25s: %s%s"), (LPTSTR)TEXT("Format"), f ? (LPTSTR)m_szNull : (LPTSTR)TEXT("*"), (LPTSTR)szFormatTag); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Attributes"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataBytes); MEditPrintF(hedit, TEXT("\r\n%25s: %s bytes"), (LPTSTR)TEXT("Data Size"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataBytes / pwfx->nAvgBytesPerSec); dw = m_paafd->dwDataBytes % pwfx->nAvgBytesPerSec; dw = (dw * 1000) / pwfx->nAvgBytesPerSec; MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (avg bytes)"), (LPTSTR)ach, dw);
AppFormatBigNumber(ach, m_paafd->dwDataSamples); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Total Samples"), (LPTSTR)ach);
AppFormatBigNumber(ach, m_paafd->dwDataSamples / pwfx->nSamplesPerSec); dw = m_paafd->dwDataSamples % pwfx->nSamplesPerSec; dw = (dw * 1000) / pwfx->nSamplesPerSec; MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (samples)"), (LPTSTR)ach, dw);
//
211
// // MEditPrintF(hedit, TEXT("\r\n%25s: %u"), (LPTSTR)TEXT("Format Tag"), pwfx->wFormatTag); MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Channels"), pwfx->nChannels);
AppFormatBigNumber(ach, pwfx->nSamplesPerSec); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Samples Per Second"), (LPTSTR)ach);
AppFormatBigNumber(ach, pwfx->nAvgBytesPerSec); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Avg Bytes Per Second"), (LPTSTR)ach);
AppFormatBigNumber(ach, pwfx->nBlockAlign); MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Block Alignment"), (LPTSTR)ach);
MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Bits Per Sample"), pwfx->wBitsPerSample);
if (WAVE_FORMAT_PCM != pwfx->wFormatTag) { AppFormatBigNumber(ach, pwfx->cbSize); MEditPrintF(hedit, TEXT("%25s: %s bytes\r\n"), (LPTSTR)TEXT("Extra Format Information"), (LPTSTR)ach);
AcmAppDumpExtraHeaderData(hedit, pwfx); }
// // note that we do NOT set the 'WAVE_ALLOWSYNC' bit on queries because // the player/recorder dialog uses MCIWAVE--which cannot work with // SYNC devices. // mmr = waveOutOpen(NULL, m_uWaveOutId,#if (WINVER < 0x0400) (LPWAVEFORMAT)pwfx,#else pwfx,#endif 0L, 0L, WAVE_FORMAT_QUERY);
fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
if (!fCanPlayRecord) { // // this situation can happen with the 'preferred' device settings // for the Sound Mapper. // mmr = waveInOpen(NULL, m_uWaveInId,#if (WINVER < 0x0400) (LPWAVEFORMAT)pwfx,#else pwfx,#endif 0L, 0L, WAVE_FORMAT_QUERY);
fCanPlayRecord = (MMSYSERR_NOERROR == mmr); }
AA_Display_File_Properties_Exit: return (fCanPlayRecord);} // AcmAppDisplayFileProperties()
//--------------------------------------------------------------------------;//// void AppHourGlass//
212
// Description:// This function changes the cursor to that of the hour glass or// back to the previous cursor.//// This function can be called recursively.//// Arguments:// BOOL fHourGlass: TRUE if we need the hour glass. FALSE if we need// the arrow back.//// Return (void):// On return, the cursor will be what was requested.////--------------------------------------------------------------------------;
void CSpeechPlayer:: AppHourGlass( BOOL fHourGlass){ static HCURSOR hcur; static UINT uWaiting = 0;
if (fHourGlass) { if (!uWaiting) { ShowCursor(TRUE); }
uWaiting++; } else { --uWaiting;
if (!uWaiting) { ShowCursor(FALSE); SetCursor(hcur); } }} // AppHourGlass()
//--------------------------------------------------------------------------;//// BOOL AppFormatBigNumber//// Description:////// Arguments:// LPTSTR pszNumber://// DWORD dw://// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppFormatBigNumber( LPTSTR pszNumber, DWORD dw){
// Comments by CR: Believe it or not, THIS IS Microsoft code (+ comments)!!! //
213
// this is ugly... // // if (dw >= 1000000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u,%03u"), (WORD)(dw / 1000000000L), (WORD)((dw % 1000000000L) / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000000L) { wsprintf(pszNumber, TEXT("%u,%03u,%03u"), (WORD)(dw / 1000000L), (WORD)((dw % 1000000L) / 1000), (WORD)(dw % 1000)); } else if (dw >= 1000) { wsprintf(pszNumber, TEXT("%u,%03u"), (WORD)(dw / 1000), (WORD)(dw % 1000)); } else { wsprintf(pszNumber, TEXT("%lu"), dw); }
return (TRUE);} // AppFormatBigNumber()
//--------------------------------------------------------------------------;//// BOOL AppFormatDosDateTime//// Description:////// Arguments:// LPTSTR pszDateTime://// UINT uDosDate://// UINT uDosTime://// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppFormatDosDateTime( LPTSTR pszDateTime, UINT uDosDate, UINT uDosTime){ static TCHAR szFormatDateTime[] = TEXT("%.02u/%.02u/%.02u %.02u:%.02u:%.02u");
UINT uDateMonth; UINT uDateDay; UINT uDateYear; UINT uTimeHour; UINT uTimeMinute; UINT uTimeSecond;
214
// // // uTimeHour = uDosTime >> 11; uTimeMinute = (uDosTime & 0x07E0) >> 5; uTimeSecond = (uDosTime & 0x001F) << 1;
uDateMonth = (uDosDate & 0x01E0) >> 5; uDateDay = (uDosDate & 0x001F); uDateYear = (uDosDate >> 9) + 80;
// // // // wsprintf(pszDateTime, szFormatDateTime, uDateMonth, uDateDay, uDateYear, uTimeHour, uTimeMinute, uTimeSecond);
return (TRUE);} // AppFormatDosDateTime()
//--------------------------------------------------------------------------;//// BOOL AcmAppGetFormatDescription//// Description:////// Arguments:// LPWAVEFORMATEX pwfx://// LPSTR pszFormatTag://// LPSTR pszFormat://// Return (BOOL)://////--------------------------------------------------------------------------;
TCHAR gszIntl[] = TEXT("Intl");TCHAR gszIntlList[] = TEXT("sList");TCHAR gszIntlDecimal[] = TEXT("sDecimal");TCHAR gchIntlList = ',';TCHAR gchIntlDecimal = '.';
BOOL CSpeechPlayer:: AcmAppGetFormatDescription( LPWAVEFORMATEX pwfx, LPTSTR pszFormatTag, LPTSTR pszFormat){ MMRESULT mmr; BOOL f;
f = TRUE;
// // get the name for the format tag of the specified format // if (NULL != pszFormatTag) {
215
ACMFORMATTAGDETAILS aftd;
// // initialize all unused members of the ACMFORMATTAGDETAILS // structure to zero // memset(&aftd, 0, sizeof(aftd));
// // fill in the required members of the ACMFORMATTAGDETAILS // structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query // aftd.cbStruct = sizeof(aftd); aftd.dwFormatTag = pwfx->wFormatTag;
// // ask the ACM to find the first available driver that // supports the specified format tag // mmr = acmFormatTagDetails(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG); if (MMSYSERR_NOERROR == mmr) { // // copy the format tag name into the caller's buffer // lstrcpy(pszFormatTag, aftd.szFormatTag); } else { PTSTR psz;
// // no ACM driver is available that supports the // specified format tag //
f = FALSE; psz = NULL;
// // the following stuff if proof that the world does NOT need // yet another ADPCM algorithm!! // switch (pwfx->wFormatTag) { case WAVE_FORMAT_UNKNOWN: psz = TEXT("** RESERVED INVALID TAG **"); break;
case WAVE_FORMAT_PCM: psz = TEXT("PCM"); break;
case WAVE_FORMAT_ADPCM: psz = TEXT("Microsoft ADPCM"); break;
case 0x0003: psz = TEXT("MV's *UNREGISTERED* ADPCM"); break;
case WAVE_FORMAT_IBM_CVSD: psz = TEXT("IBM CVSD"); break;
case WAVE_FORMAT_ALAW:
216
psz = TEXT("A-Law"); break;
case WAVE_FORMAT_MULAW: psz = TEXT("u-Law"); break;
case WAVE_FORMAT_OKI_ADPCM: psz = TEXT("OKI ADPCM"); break;
case WAVE_FORMAT_IMA_ADPCM: psz = TEXT("IMA/DVI ADPCM"); break;
case WAVE_FORMAT_DIGISTD: psz = TEXT("DIGI STD"); break;
case WAVE_FORMAT_DIGIFIX: psz = TEXT("DIGI FIX"); break;
case WAVE_FORMAT_YAMAHA_ADPCM: psz = TEXT("Yamaha ADPCM"); break;
case WAVE_FORMAT_SONARC: psz = TEXT("Sonarc"); break;
case WAVE_FORMAT_DSPGROUP_TRUESPEECH: psz = TEXT("DSP Group TrueSpeech"); break;
case WAVE_FORMAT_ECHOSC1: psz = TEXT("Echo SC1"); break;
case WAVE_FORMAT_AUDIOFILE_AF36: psz = TEXT("Audiofile AF36"); break;
case WAVE_FORMAT_CREATIVE_ADPCM: psz = TEXT("Creative Labs ADPCM"); break;
case WAVE_FORMAT_APTX: psz = TEXT("APTX"); break;
case WAVE_FORMAT_AUDIOFILE_AF10: psz = TEXT("Audiofile AF10"); break;
case WAVE_FORMAT_DOLBY_AC2: psz = TEXT("Dolby AC2"); break;
case WAVE_FORMAT_MEDIASPACE_ADPCM: psz = TEXT("Media Space ADPCM"); break;
case WAVE_FORMAT_SIERRA_ADPCM: psz = TEXT("Sierra ADPCM"); break;
case WAVE_FORMAT_G723_ADPCM:
217
psz = TEXT("CCITT G.723 ADPCM"); break;
case WAVE_FORMAT_GSM610: psz = TEXT("GSM 6.10"); break;
case WAVE_FORMAT_G721_ADPCM: psz = TEXT("CCITT G.721 ADPCM"); break;
case WAVE_FORMAT_DEVELOPMENT: psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **"); break;
default: wsprintf(pszFormatTag, TEXT("[%u] (unknown)"), pwfx->wFormatTag); break; }
if (NULL != psz) { lstrcpy(pszFormatTag, psz); } } }
// // get the description of the attributes for the specified // format // if (NULL != pszFormat) { ACMFORMATDETAILS afd;
// // initialize all unused members of the ACMFORMATDETAILS // structure to zero // memset(&afd, 0, sizeof(afd));
// // fill in the required members of the ACMFORMATDETAILS // structure for the ACM_FORMATDETAILSF_FORMAT query // afd.cbStruct = sizeof(afd); afd.dwFormatTag = pwfx->wFormatTag; afd.pwfx = pwfx;
// // the cbwfx member must be initialized to the total size // in bytes needed for the specified format. for a PCM // format, the cbSize member of the WAVEFORMATEX structure // is not valid. // if (WAVE_FORMAT_PCM == pwfx->wFormatTag) { afd.cbwfx = sizeof(PCMWAVEFORMAT); } else { afd.cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize; }
// // ask the ACM to find the first available driver that // supports the specified format //
218
mmr = acmFormatDetails(NULL, &afd, ACM_FORMATDETAILSF_FORMAT); if (MMSYSERR_NOERROR == mmr) { // // copy the format attributes description into the caller's // buffer // lstrcpy(pszFormat, afd.szFormat); } else { TCHAR ach[2]; TCHAR szChannels[24]; UINT cBits;
// // no ACM driver is available that supports the // specified format //
f = FALSE;
// // // ach[0] = gchIntlList; ach[1] = '\0';
gchIntlList = ach[0];
ach[0] = gchIntlDecimal; ach[1] = '\0';
gchIntlDecimal = ach[0];
// // compute the bit depth--this _should_ be the same as // wBitsPerSample, but isn't always... // cBits = (UINT)(pwfx->nAvgBytesPerSec * 8 / pwfx->nSamplesPerSec / pwfx->nChannels);
if ((1 == pwfx->nChannels) || (2 == pwfx->nChannels)) { if (1 == pwfx->nChannels) lstrcpy(szChannels, TEXT("Mono")); else lstrcpy(szChannels, TEXT("Stereo"));
wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %s"), pwfx->nSamplesPerSec / 1000, gchIntlDecimal, (UINT)(pwfx->nSamplesPerSec % 1000), gchIntlList, cBits, gchIntlList, (LPTSTR)szChannels); } else { wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %u Channels"), pwfx->nSamplesPerSec / 1000, gchIntlDecimal, (UINT)(pwfx->nSamplesPerSec % 1000), gchIntlList, cBits,
219
gchIntlList, pwfx->nChannels); } } }
// // // return (f);} // AcmAppGetFormatDescription()
//--------------------------------------------------------------------------;//// BOOL AcmAppDumpExtraHeaderData//// Description:////// Arguments:// HWND hedit://// LPWAVEFORMATEX pwfx://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppDumpExtraHeaderData( HWND hedit, LPWAVEFORMATEX pwfx){ static TCHAR szDisplayTitle[] = TEXT("Offset Data Bytes");
if ((WAVE_FORMAT_PCM == pwfx->wFormatTag) || (0 == pwfx->cbSize)) return (TRUE);
MEditPrintF(hedit, szDisplayTitle); MEditPrintF(hedit, TEXT("------ -----------------------------------------------"));
// Comments by CR: Believe it or not, THIS IS Microsoft code (+ comments) !!! // // !!! this is really horrible code !!! //{ #define ACMAPP_DUMP_BYTES_PER_LINE 16
UINT u; UINT v;
for (u = 0; u < pwfx->cbSize; u += ACMAPP_DUMP_BYTES_PER_LINE) { MEditPrintF(hedit, TEXT("~0x%.04X"), u);
for (v = 0; v < ACMAPP_DUMP_BYTES_PER_LINE; v++) { if ((u + v) >= pwfx->cbSize) break;
MEditPrintF(hedit, TEXT("~ %.02X"), ((LPBYTE)(pwfx + 1))[u + v]); }
MEditPrintF(hedit, m_szNull);
220
}
#undef ACMAPP_DUMP_BYTES_PER_LINE}
return (TRUE);} // AcmAppDumpExtraHeaderData()
//--------------------------------------------------------------------------;//// int MEditPrintF//// Description:// This function is used to print formatted text into a Multiline// Edit Control as if it were a standard console display. This is// a very easy way to display small amounts of text information// that can be scrolled and copied to the clip-board.//// Arguments:// HWND hedit: Handle to a Multiline Edit control.//// PTSTR pszFormat: Pointer to any valid format for wsprintf. If// this argument is NULL, then the Multiline Edit Control is cleared// of all text.////// Return (int):// Returns the number of characters written into the edit control.//// Notes:// The pszFormat string can contain combinations of escapes that// modify the default behaviour of this function. Escapes are single// character codes placed at the _beginning_ of the format string.//// Current escapes defined are://// ~ : Suppresses the default CR/LF added to the end of the// printed line. Since the most common use of this function// is to output a whole line of text with a CR/LF, that is// the default.//// ` : Suppresses logging to the debug terminal (regardless of// the global debug log options flag).//////--------------------------------------------------------------------------;
int CSpeechPlayer:: MEditPrintF( HWND hedit, PTSTR pszFormat, ...){ static TCHAR szCRLF[] = TEXT("\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_RC_CHARS]; int n; BOOL fCRLF; BOOL fDebugLog;
// // default the escapes // fCRLF = TRUE; fDebugLog = TRUE;
221
// // if the pszFormat argument is NULl. // if (NULL == pszFormat) { AcmAppDebugLog(NULL);
return (0); }
// // format and display the string in the window... first search for // escapes to modify default behaviour. // for (;;) { switch (*pszFormat) { case '~': fCRLF = FALSE; pszFormat++; continue;
case '`': fDebugLog = FALSE; pszFormat++; continue; }
break; }
va_start(va, pszFormat);#ifdef WIN32 n = wvsprintf(ach, pszFormat, va);#else n = wvsprintf(ach, pszFormat, (LPSTR)va);#endif va_end(va);
if (fDebugLog) { AcmAppDebugLog(ach); }
if (fCRLF) { if (fDebugLog) { AcmAppDebugLog(szCRLF); } }
return (n);} // MEditPrintF()
//--------------------------------------------------------------------------;//// void AcmAppDebugLog//// Description:// This function logs information to the debugger if the Debug Log// option is set. You can then run DBWin (or something similar)// to redirect the output whereever you want. Very useful for debugging// ACM drivers.//
222
// Arguments:// PTSTR pszFormat: Pointer to any valid format for wsprintf.//// Return (void):// None.////--------------------------------------------------------------------------;
void CSpeechPlayer:: AcmAppDebugLog( PTSTR pszFormat, ...){ static TCHAR szDebugLogSeparator[] =TEXT("=============================================================================\r\n");
va_list va; TCHAR ach[APP_MAX_STRING_ERROR_CHARS];
// // !!! UNICODE !!! // // if (0 != (APP_OPTIONSF_DEBUGLOG & m_fuAppOptions)) { if (NULL == pszFormat) { OutputDebugString(szDebugLogSeparator); return; }
// // format and display the string in a message box... // va_start(va, pszFormat);#ifdef WIN32 wvsprintf(ach, pszFormat, va);#else wvsprintf(ach, pszFormat, (LPSTR)va);#endif va_end(va);
OutputDebugString(ach); }} // AcmAppDebugLog()
//--------------------------------------------------------------------------;//// BOOL AcmAppFileNew//// Description://// Arguments:// HWND hwnd: Handle to main window.//// PACMAPPFILEDESC m_paafd: Pointer to file descriptor.//// Return (BOOL):////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppFileNew(){ TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS];
223
TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; MMRESULT mmr; LPWAVEFORMATEX pwfx; DWORD cbwfx; BOOL f; ACMFORMATCHOOSE afc; HMMIO hmmio; MMCKINFO ckRIFF; MMCKINFO ck; DWORD cSamples;
if (!m_fAcmAvailable) { return (FALSE); }
// // test for a modified file first... // // // get a filename // szFileTitle[0] = '\0'; szFilePath[0] = '\0';
strcpy(szFileTitle,m_szInitialFileTitle);//*CR.sprintf(szFilePath,"%s%s",m_szInitialDirSave,m_szInitialFileTitle);//*CR.
// // // // // // mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfx); if (MMSYSERR_NOERROR != mmr) { return (FALSE); }
//*CR. Used for Win 16 supportpwfx = NULL;//*CR.pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX [cbwfx]; //*CR.
if (NULL == pwfx) { return (FALSE); }
// // // // f = FALSE;
// // initialize the ACMFORMATCHOOSE members // memset(&afc, 0, sizeof(afc));
afc.cbStruct = sizeof(afc); afc.fdwStyle = ACMFORMATCHOOSE_STYLEF_SHOWHELP; afc.pwfx = pwfx;
224
afc.cbwfx = cbwfx; afc.pszTitle = TEXT("ACM App: New Format Choice");
afc.szFormatTag[0] = '\0'; afc.szFormat[0] = '\0'; afc.pszName = NULL; afc.cchName = 0;
afc.fdwEnum = 0; afc.pwfxEnum = NULL;
afc.hInstance = NULL; afc.pszTemplateName = NULL; afc.lCustData = 0L; afc.pfnHook = NULL;
// // //
// Comments by CR: This where the WAV file parameters (sample rate, etc) is setuppwfx->wFormatTag = PCM_FORMAT_TAG;pwfx->nChannels = PCM_CHANNELS;pwfx->nSamplesPerSec = PCM_SAMPLES_PER_SEC;pwfx->nAvgBytesPerSec = PCM_AVERAGE_BYTES_PER_SEC;pwfx->nBlockAlign = PCM_BLOCK_ALIGN;pwfx->wBitsPerSample = PCM_BITS_PER_SAMPLE;pwfx->cbSize = PCM_SIZE;
//
if (MMSYSERR_NOERROR != mmr) return (FALSE);
// // // hmmio = mmioOpen(szFilePath, NULL, MMIO_CREATE | MMIO_WRITE | MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
if (NULL == hmmio) return (FALSE);
// // create the RIFF chunk of form type 'WAVE' // ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); ckRIFF.cksize = 0L; mmioCreateChunk(hmmio, &ckRIFF, MMIO_CREATERIFF);
// // now create the destination fmt, fact, and data chunks _in that order_ // // hmmio is now descended into the 'RIFF' chunk--create the format chunk // and write the format header into it // cbwfx = SIZEOF_WAVEFORMATEX(pwfx);
ck.ckid = mmioFOURCC('f', 'm', 't', ' '); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0);
mmioWrite(hmmio, (HPSTR)pwfx, cbwfx); mmioAscend(hmmio, &ck, 0);
225
// // create the 'fact' chunk (not necessary for PCM--but is nice to have) // since we are not writing any data to this file (yet), we set the // samples contained in the file to 0.. // ck.ckid = mmioFOURCC('f', 'a', 'c', 't'); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0);
cSamples = 0L; mmioWrite(hmmio, (HPSTR)&cSamples, sizeof(DWORD)); mmioAscend(hmmio, &ck, 0);
// // create the data chunk with no data.. // ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); ck.cksize = 0L; mmioCreateChunk(hmmio, &ck, 0); mmioAscend(hmmio, &ck, 0);
mmioAscend(hmmio, &ckRIFF, 0);
MMRESULT mmResult = 0;//*CR.mmResult = mmioClose(hmmio, 0);
// // //
delete [] pwfx;//*CR.
lstrcpy(m_paafd->szFilePath, szFilePath); lstrcpy(m_paafd->szFileTitle, szFileTitle);
return (AcmAppFileOpen());//*CR.
// // success // return (TRUE);} // AcmAppFileNew()
//--------------------------------------------------------------------------;//// BOOL AcmAppFileOpen//// Description:// This function opens the specified file and get the important info// from it.//// NOTE! This function does NOT check for a modified file! It is// assumed that the calling function took care of everything before// calling this function.//// Arguments:// HWND hwnd: Handle to main window.//// PACMAPPFILEDESC m_paafd: Pointer to file descriptor.//// Return (BOOL):// The return value is TRUE if the function is successful. It is FALSE// if an error occurred. If an error does occur, then the contents// of the file descriptor will remain unchanged.////
226
//--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppFileOpen(){ WAVEIOCB wio; WIOERR werr;
HANDLE hf; DWORD cbFileSize; BOOL fReturn;
// // blow previous stuff... // if (NULL != m_paafd->pwfx) { m_paafd->pwfx = NULL; m_paafd->cbwfx = 0; }
m_paafd->fdwState = 0L; m_paafd->cbFileSize = 0L; m_paafd->uDosChangeDate = 0; m_paafd->uDosChangeTime = 0; m_paafd->fdwFileAttributes = 0L; m_paafd->dwDataBytes = 0L; m_paafd->dwDataSamples = 0L;
// // open the file for reading.. // hf = CreateFile(m_paafd->szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (INVALID_HANDLE_VALUE == hf) return (FALSE);
// // assume the worst // fReturn = FALSE;
// // determine the length in _bytes_ of the file // cbFileSize = GetFileSize((HANDLE)hf, NULL);
// // // // m_paafd->cbFileSize = cbFileSize;
BY_HANDLE_FILE_INFORMATION bhfi; WORD wDosChangeDate; WORD wDosChangeTime;
GetFileInformationByHandle(hf, &bhfi);
m_paafd->fdwFileAttributes = bhfi.dwFileAttributes;
FileTimeToDosDateTime(&bhfi.ftLastWriteTime, &wDosChangeDate, &wDosChangeTime);
m_paafd->uDosChangeDate = (UINT)wDosChangeDate; m_paafd->uDosChangeTime = (UINT)wDosChangeTime;
//
227
// now return the fully qualified path and title for the file // AppGetFileTitle(m_paafd->szFilePath, m_paafd->szFileTitle);
CloseHandle(hf);
// // // // werr = wioFileOpen(&wio, m_paafd->szFilePath, 0L); if (WIOERR_NOERROR == werr) { UINT cbwfx;
cbwfx = SIZEOF_WAVEFORMATEX(wio.pwfx);
m_paafd->pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX [cbwfx];//*CR. if (NULL != m_paafd->pwfx) {
memcpy(m_paafd->pwfx, wio.pwfx, cbwfx);//*CR.
m_paafd->cbwfx = cbwfx;
m_paafd->dwDataBytes = wio.dwDataBytes; m_paafd->dwDataSamples = wio.dwDataSamples;
fReturn = TRUE; }
wioFileClose(&wio, 0L); }
return (fReturn);} // AcmAppFileOpen()
//--------------------------------------------------------------------------;//// BOOL AppGetFileTitle//// Description:// This function extracts the file title from a file path and returns// it in the caller's specified buffer.//// Arguments:// PTSTR pszFilePath: Pointer to null terminated file path.//// PTSTR pszFileTitle: Pointer to buffer to receive the file title.//// Return (BOOL):// Always returns TRUE. But should return FALSE if this function// checked for bogus values, etc.//////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppGetFileTitle( PTSTR pszFilePath, PTSTR pszFileTitle){ #define IS_SLASH(c) ('/' == (c) || '\\' == (c))
PTSTR pch;
//
228
// scan to the end of the file path string.. // for (pch = pszFilePath; '\0' != *pch; pch++) ;
// // now scan back toward the beginning of the string until a slash (\), // colon, or start of the string is encountered. // while ((pch >= pszFilePath) && !IS_SLASH(*pch) && (':' != *pch)) { pch--; }
// // finally, copy the 'title' into the destination buffer.. skip ahead // one char since the above loop steps back one too many chars... // lstrcpy(pszFileTitle, ++pch);
return (TRUE);} // AppGetFileTitle()
//--------------------------------------------------------------------------;//// WIOERR wioFileOpen//// Description:////// Arguments:// LPWAVEIOCB pwio://// LPCTSTR pszFilePath://// DWORD fdwOpen://// Return (WIOERR)://////--------------------------------------------------------------------------;
WIOERR CSpeechPlayer:: wioFileOpen( LPWAVEIOCB pwio, LPCTSTR pszFilePath, DWORD fdwOpen){ WIOERR werr; HMMIO hmmio; MMCKINFO ckRIFF; MMCKINFO ck; DWORD dw;
// // validate a couple of things... // if (NULL == pwio) return (WIOERR_BADPARAM);
// // default our error return (assume the worst) //
memset(pwio, 0, sizeof(*pwio));//*CR. werr = WIOERR_FILEERROR;
pwio->dwFlags = fdwOpen;
229
// // first try to open the file, etc.. open the given file for reading // using buffered I/O // hmmio = mmioOpen((LPTSTR)pszFilePath, NULL, MMIO_READ | MMIO_ALLOCBUF); if (NULL == hmmio) goto wio_Open_Error;
pwio->hmmio = hmmio;
// // locate a 'WAVE' form type... // ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hmmio, &ckRIFF, NULL, MMIO_FINDRIFF)) goto wio_Open_Error;
// // we found a WAVE chunk--now go through and get all subchunks that // we know how to deal with... // pwio->dwDataSamples = (DWORD)-1L;
#if 0 if (lrt=riffInitINFO(&wio.pInfo)) { lr=lrt; goto wio_Open_Error; }#endif
// // // while (MMSYSERR_NOERROR == mmioDescend(hmmio, &ck, &ckRIFF, 0)) { // // quickly check for corrupt RIFF file--don't ascend past end! // if ((ck.dwDataOffset + ck.cksize) > (ckRIFF.dwDataOffset + ckRIFF.cksize)) {
// Comments by CR: Believe it or not, THIS IS Microsoft's code !!! werr = WIOERR_BADFILE; goto wio_Open_Error; }
switch (ck.ckid) { case mmioFOURCC('L', 'I', 'S', 'T'): if (ck.fccType == mmioFOURCC('I', 'N', 'F', 'O')) {#if 0 if(lrt=riffReadINFO(hmmio, &ck, wio.pInfo)) { lr=lrt; goto wio_Open_Error; }#endif } break;
case mmioFOURCC('D', 'I', 'S', 'P'):#if 0 riffReadDISP(hmmio, &ck, &(wio.pDisp));#endif break;
230
case mmioFOURCC('f', 'm', 't', ' '): // // !?! another format chunk !?! // if (NULL != pwio->pwfx) break;
// // get size of the format chunk, allocate and lock memory // for it. we always alloc a complete extended format header // (even for PCM headers that do not have the cbSize field // defined--we just set it to zero). // dw = ck.cksize; if (dw < sizeof(WAVEFORMATEX)) dw = sizeof(WAVEFORMATEX);
pwio->pwfx = (LPWAVEFORMATEX) new WAVEFORMATEX[dw]; if (NULL == pwio->pwfx) { werr = WIOERR_NOMEM; goto wio_Open_Error; }
// // read the format chunk // werr = WIOERR_FILEERROR; dw = ck.cksize; if (mmioRead(hmmio, (HPSTR)pwio->pwfx, dw) != (LONG)dw) goto wio_Open_Error; break;
case mmioFOURCC('d', 'a', 't', 'a'): // // !?! multiple data chunks !?! // if (0L != pwio->dwDataBytes) break;
// // just hang on to the total length in bytes of this data // chunk.. and the offset to the start of the data // pwio->dwDataBytes = ck.cksize; pwio->dwDataOffset = ck.dwDataOffset; break;
case mmioFOURCC('f', 'a', 'c', 't'): // // !?! multiple fact chunks !?! // if (-1L != pwio->dwDataSamples) break;
// // read the first dword in the fact chunk--it's the only // info we need (and is currently the only info defined for // the fact chunk...) // // if this fails, dwDataSamples will remain -1 so we will // deal with it later... // mmioRead(hmmio, (HPSTR)&pwio->dwDataSamples, sizeof(DWORD)); break;
231
}
// // step up to prepare for next chunk.. // mmioAscend(hmmio, &ck, 0); }
// // if no fmt chunk was found, then die! // if (NULL == pwio->pwfx) { werr = WIOERR_ERROR; goto wio_Open_Error; }
// // all wave files other than PCM are _REQUIRED_ to have a fact chunk // telling the number of samples that are contained in the file. it // is optional for PCM (and if not present, we compute it here). // // if the file is not PCM and the fact chunk is not found, then fail! // if (-1L == pwio->dwDataSamples) { if (WAVE_FORMAT_PCM == pwio->pwfx->wFormatTag) { pwio->dwDataSamples = pwio->dwDataBytes / pwio->pwfx->nBlockAlign; } else {
// Comments by CR: Believe it or not, THIS IS Microsoft's code (+ comments) !!! // // !!! HACK HACK HACK !!! // // although this should be considered an invalid wave file, we // will bring up a message box describing the error--hopefully // people will start realizing that something is missing??? // werr = WIOERR_BADFILE; goto wio_Open_Error;
// // !!! need to hack stuff in here !!! // pwio->dwDataSamples = 0L; } }
// // cool! no problems.. // return (WIOERR_NOERROR);
// // return error (after minor cleanup) //wio_Open_Error:
wioFileClose(pwio, 0L); return (werr);} // wioFileOpen()
//--------------------------------------------------------------------------;//// WIOERR wioFileClose
232
//// Description:////// Arguments:// LPWAVEIOCB pwio://// DWORD fdwClose://// Return (WIOERR):////--------------------------------------------------------------------------;
WIOERR CSpeechPlayer:: wioFileClose( LPWAVEIOCB pwio, DWORD fdwClose){ // // validate a couple of things... // if (NULL == pwio) return (WIOERR_BADPARAM);
// // get rid of stuff... // if (NULL != pwio->hmmio) { mmioClose(pwio->hmmio, 0); }
#if 0 if (pwio->pInfo) riffFreeINFO(&(lpwio->pInfo));
if (pwio->pDisp) riffFreeDISP(&(lpwio->pDisp));#endif
return (WIOERR_NOERROR);} // wioFileClose()
//--------------------------------------------------------------------------;//// BOOL AppFileNew//// Description:// This function is called to handle the IDM_FILE_NEW message. It is// responsible for clearing the working area for a new unnamed file.//// Arguments:// HWND hwnd: Handle to application window.//// PACMAPPFILEDESC m_paafd: Pointer to current file descriptor.//// Return (BOOL):// The return value is TRUE if the working area was cleared and is// ready for new stuff. The return value is FALSE if the user canceled// the operation.////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppFileNew( BOOL fCreate
233
){ BOOL f;
if (fCreate) { f = AcmAppFileNew();//*CR. if (!f) return (FALSE); } else { // // if there is currently a file path, then we have to do some real // work... // if ('\0' != m_paafd->szFilePath[0]) {
f = AcmAppFileNew();//*CR. if (!f) return (FALSE); }
// // blow away the old file path and title; set the window title // and return success // lstrcpy(m_paafd->szFilePath, m_szFileUntitled); lstrcpy(m_paafd->szFileTitle, m_szFileUntitled); }
AppTitle(m_paafd->szFileTitle);
return (TRUE);} // AppFileNew()
//--------------------------------------------------------------------------;//// BOOL AppFileOpen//// Description:// This function handles the IDM_FILE_OPEN message. It is responsible// for getting a new file name from the user and opening that file// if possible.//// Arguments:// HWND hwnd: Handle to application window.//// PACMAPPFILEDESC m_paafd: Pointer to current file descriptor.//// Return (BOOL):// The return value is TRUE if a new file was selected and opened.// It is FALSE if the user canceled the operation.////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AppFileOpen(){ TCHAR szFilePath[APP_MAX_FILE_PATH_CHARS]; TCHAR szFileTitle[APP_MAX_FILE_TITLE_CHARS]; BOOL f=FALSE;
strcpy(szFileTitle,m_szInitialFileTitle);//*CR.sprintf(szFilePath,"%s%s",m_szInitialDirSave,m_szInitialFileTitle);//*CR.
//!!! // read the new file... //
234
lstrcpy(m_paafd->szFilePath, szFilePath); lstrcpy(m_paafd->szFileTitle, szFileTitle); f = AcmAppFileOpen();//*CR. if ( f ) { // // set the window title text... // AppTitle(szFileTitle);//*CR. AcmAppDisplayFileProperties();//*CR. }
return (f);} // AppFileOpen()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordStatus//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordStatus(){ TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS]; TCHAR szMode[40]; TCHAR szPosition[40]; TCHAR szLength[40]; TCHAR szFormat[40]; MCIERROR mcierr = -1; UINT uStatus; BOOL fStartTimer; BOOL fPlay; BOOL fPause; BOOL fStop; BOOL fStart; BOOL fEnd; BOOL fRecord; BOOL fCommand; UINT uIdFocus; DWORD dwLength; DWORD dwPosition;
// // // if (AAPLAYRECORD_STATUS_NOT_OPEN != m_uPlayRecordStatus) {
mcierr = AcmPlayRecordSendCommand(TEXT("status mode"), szMode, SIZEOF(szMode), TRUE);//*CR. if (MMSYSERR_NOERROR != mcierr) { m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN; } }
// // assume all buttons disabled
235
// fStartTimer = FALSE; fPlay = FALSE; fPause = FALSE; fStop = FALSE; fStart = FALSE; fEnd = FALSE; fRecord = FALSE; fCommand = TRUE; uIdFocus = IDOK; dwPosition = 0L; dwLength = 0L; lstrcpy(szFormat, TEXT("???"));
// // // if (AAPLAYRECORD_STATUS_NOT_OPEN == m_uPlayRecordStatus) { lstrcpy(szMode, TEXT("not open")); } else if (0 == lstrcmpi(TEXT("not ready"), szMode)) { uStatus = AAPLAYRECORD_STATUS_NOT_READY;
fStartTimer = TRUE; } else if (0 == lstrcmpi(TEXT("paused"), szMode)) { uStatus = AAPLAYRECORD_STATUS_PAUSED;
fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("playing"), szMode)) { uStatus = AAPLAYRECORD_STATUS_PLAYING;
fStartTimer = TRUE; fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("stopped"), szMode)) { uStatus = AAPLAYRECORD_STATUS_STOPPED;
fPlay = TRUE; fStart = TRUE; fEnd = TRUE; fRecord = TRUE; } else if (0 == lstrcmpi(TEXT("recording"), szMode)) { uStatus = AAPLAYRECORD_STATUS_RECORDING;
fStartTimer = TRUE; fPause = TRUE; fStop = TRUE; } else if (0 == lstrcmpi(TEXT("seeking"), szMode)) { uStatus = AAPLAYRECORD_STATUS_SEEKING;
fStartTimer = TRUE; fStop = TRUE; }
236
// // // // // if (fStartTimer) { if (!m_fTimerGoing) {
SetTimer(NULL, 1, AAPLAYRECORD_TIMER_RESOLUTION, NULL);//*CR. m_fTimerGoing = TRUE; } } else if (m_fTimerGoing) {
KillTimer(NULL, 1);//*CR. m_fTimerGoing = FALSE; }
// // // // if (AAPLAYRECORD_STATUS_NOT_OPEN != m_uPlayRecordStatus) { // // //
mcierr = AcmPlayRecordSendCommand(TEXT("status position"), szPosition, SIZEOF(szPosition),TRUE);//*CR. if (MMSYSERR_NOERROR == mcierr) { dwPosition = _tcstoul(szPosition, NULL, 10); }
mcierr = AcmPlayRecordSendCommand(TEXT("status length"), szLength, SIZEOF(szLength), TRUE);//*CR. if (MMSYSERR_NOERROR == mcierr) { dwLength = _tcstoul(szLength, NULL, 10); }
mcierr = AcmPlayRecordSendCommand(TEXT("status time format"), szFormat, SIZEOF(szFormat),TRUE);//*CR. }
// // // // if (uStatus != m_uPlayRecordStatus) m_uPlayRecordStatus = uStatus;
// // // AppFormatBigNumber(szPosition, dwPosition); AppFormatBigNumber(szLength, dwLength);
wsprintf(ach, TEXT("%s: %14s (%s) %s"), (LPSTR)szMode, (LPSTR)szPosition, (LPSTR)szLength, (LPSTR)szFormat);
if ( mcierr )return (FALSE);
237
elsereturn (TRUE);
} // AcmAppPlayRecordStatus()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordPlay//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordPlay(){ MCIERROR mcierr = -1; TCHAR szPosition[40]; TCHAR szLength[40];
mcierr = AcmPlayRecordSendCommand(TEXT("status position"), szPosition, SIZEOF(szPosition), TRUE);//*CR. if (MMSYSERR_NOERROR != mcierr) { return (FALSE); }
mcierr = AcmPlayRecordSendCommand(TEXT("status length"), szLength, SIZEOF(szLength), TRUE);//*CR. if (MMSYSERR_NOERROR != mcierr) { return (FALSE); }
if (0 == lstrcmp(szPosition, szLength)) {
AcmPlayRecordSendCommand(TEXT("seek to start"), NULL, 0, TRUE);//*CR. }
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("play"), NULL, 0, TRUE);//*CR.
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordPlay()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordStop//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://
238
////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordStop(){ MCIERROR mcierr;
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("stop"), NULL, 0, TRUE);//*CR.
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordStop()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordRecord//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordRecord(){ MCIERROR mcierr;
// // //
mcierr = AcmPlayRecordSendCommand(TEXT("record insert"), NULL, 0, TRUE);//*CR. if (MMSYSERR_NOERROR == mcierr) { m_fDirty = TRUE; }
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordRecord()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordClose//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordClose(){ MCIERROR mcierr;
239
if (m_fDirty) {
mcierr = AcmPlayRecordSendCommand(TEXT("save"), NULL, 0, TRUE);//*CR. }
mcierr = AcmPlayRecordSendCommand(TEXT("close"), NULL, 0, TRUE);//*CR.
return (MMSYSERR_NOERROR == mcierr);} // AcmAppPlayRecordClose()
//--------------------------------------------------------------------------;//// MCIERROR AcmPlayRecordSendCommand//// Description:// The string is of the form "verb params" our device name is inserted// after the verb and send to the device.//// Arguments:// HWND hwnd://// PSTR pszCommand://// PSTR pszReturn://// UINT cbReturn://// BOOL fErrorBox://// Return (MCIERROR)://////--------------------------------------------------------------------------;
MCIERROR CSpeechPlayer:: AcmPlayRecordSendCommand( PTSTR pszCommand, PTSTR pszReturn, UINT cbReturn, BOOL fErrorBox){ MCIERROR mcierr; TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS * 2]; TCHAR *pch; PTSTR psz;
pch = pszCommand;
while (('\t' == *pch) || (' ' == *pch)) { pch++; }
if (0 == lstrlen(pch)) { return (MMSYSERR_NOERROR); }
pch = ach; psz = pszCommand; while (('\0' != *psz) && (' ' != *psz)) { *pch++ = *psz++; }
*pch++ = ' ';
240
lstrcpy(pch, m_szAlias); lstrcat(pch, psz);
mcierr = mciSendString(ach, pszReturn, cbReturn, NULL);//*CR. changed the hwnd to NULL if (MMSYSERR_NOERROR != mcierr) { if (fErrorBox) { int n;
n = wsprintf(ach, TEXT("Command: '%s'\n\nMCI Wave Error (%lu): "), (LPTSTR)pszCommand, mcierr);
mciGetErrorString(mcierr, &ach[n], SIZEOF(ach) - n); MessageBox(NULL, ach, TEXT("MCI Wave Error"), MB_ICONEXCLAMATION | MB_OK); } }
return (mcierr);} // AcmPlayRecordSendCommand()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordInitCommands//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordInitCommands(){ static PTSTR pszCommands[] = { TEXT("play"), TEXT("play to Y"), TEXT("play from X to Y"),
TEXT(""), TEXT("capability can eject"), TEXT("capability can play"), TEXT("capability can record"), TEXT("capability can save"), TEXT("capability compound device"), TEXT("capability device type"), TEXT("capability has audio"), TEXT("capability has video"), TEXT("capability inputs"), TEXT("capability outputs"), TEXT("capability uses files"),
TEXT(""), TEXT("cue input !"), TEXT("cue output !"),
TEXT(""), TEXT("delete to Y !"), TEXT("delete from X to Y !"),
241
TEXT(""), TEXT("info input"), TEXT("info file"), TEXT("info output"), TEXT("info product"),
TEXT(""), TEXT("pause"),
TEXT(""), TEXT("record insert !"), TEXT("record overwrite !"), TEXT("record to Y !"), TEXT("record from X to Y !"),
TEXT(""), TEXT("resume"),
TEXT(""), TEXT("save"), TEXT("save FILENAME"),
TEXT(""), TEXT("seek to Y"), TEXT("seek to start"), TEXT("seek to end"),
TEXT(""), TEXT("set alignment X"), TEXT("set any input"), TEXT("set any output"), TEXT("set audio all off"), TEXT("set audio all on"), TEXT("set audio left off"), TEXT("set audio left on"), TEXT("set audio right off"), TEXT("set audio right on"), TEXT("set bitspersample X"), TEXT("set bytespersec X"), TEXT("set channels X"), TEXT("set format tag X"), TEXT("set format tag pcm"), TEXT("set input X"), TEXT("set output X"), TEXT("set samplespersec X"), TEXT("set time format bytes"), TEXT("set time format milliseconds"), TEXT("set time format samples"),
TEXT(""), TEXT("status alignment"), TEXT("status bitspersample"), TEXT("status bytespersec"), TEXT("status channels"), TEXT("status current track"), TEXT("status format tag"), TEXT("status input"), TEXT("status length"), TEXT("status length track X"), TEXT("status level"), TEXT("status media present"), TEXT("status mode"), TEXT("status number of tracks"), TEXT("status output"), TEXT("status position"), TEXT("status position track X"), TEXT("status ready"), TEXT("status samplespersec"),
242
TEXT("status start position"), TEXT("status time format"),
TEXT(""), TEXT("stop"), NULL };
return (TRUE);} // AcmAppPlayRecordInitCommands()
//--------------------------------------------------------------------------;//// BOOL AcmAppPlayRecordOpen//// Description:////// Arguments:// HWND hwnd://// PACMAPPFILEDESC m_paafd://// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppPlayRecordOpen(){ TCHAR ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS]; MCIERROR mcierr = -1;
m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN;
m_fTimerGoing = FALSE; m_fFileOpen = FALSE;
m_fDirty = FALSE;
if (NULL == m_paafd->pwfx) return (FALSE);
wsprintf(ach, TEXT("open \"%s\" alias %s"), (LPSTR)m_paafd->szFilePath, (LPSTR)m_szAlias);
mcierr = mciSendString(ach, NULL, 0, NULL); if (MMSYSERR_NOERROR != mcierr) { mciGetErrorString(mcierr, ach, SIZEOF(ach)); return (FALSE); }
m_fFileOpen = TRUE; m_uPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_READY;
mcierr = AcmPlayRecordSendCommand(TEXT("set time format samples"), NULL, 0, TRUE); //*CR. removed hwnd param
if (WAVE_MAPPER != m_uWaveInId) { wsprintf(ach, TEXT("set input %u"), m_uWaveInId); mcierr = AcmPlayRecordSendCommand(ach, NULL, 0, TRUE);//*CR. }
if (WAVE_MAPPER != m_uWaveOutId) { wsprintf(ach, TEXT("set output %u"), m_uWaveOutId); mcierr = AcmPlayRecordSendCommand(ach, NULL, 0, TRUE);//*CR. }
243
if ( mcierr )return (FALSE);
elsereturn (TRUE);
} // AcmAppPlayRecordOpen()
//--------------------------------------------------------------------------;//// BOOL AcmAppInit//// Description:////// Arguments:////// Return (BOOL)://////--------------------------------------------------------------------------;
BOOL CSpeechPlayer:: AcmAppInit(){ DWORD dwVersion;
dwVersion = acmGetVersion(); if (0x0200 <= HIWORD(dwVersion)) m_fAcmAvailable = TRUE;//*CR. else m_fAcmAvailable = FALSE;
AppFileNew(FALSE);
return (m_fAcmAvailable);} // AcmAppInit()
244
//*****************************************************// stdafx.cpp : source file that includes just the standard includes// stdafx.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information//-----------------------------------------------------// Wireless Instant Voice Messaging Over the Internet// A Master of Science Thesis Presented to the Electtrical// and Computer Engineering Department of the University of// Florida, Gainesville, FL USA.//// by : Carlos A. Rivera-Cintron// Date: February 10, 2000//// This file was automatically generated by the// Microsoft Visual C++ 6.0 program, after the author created// the Playback.dll workspace.//-----------------------------------------------------#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY#include <statreg.h>#include <statreg.cpp>#endif
#include <atlimpl.cpp>
245
APPENDIX CEXPERIMENTS RESULTS
C.1 Ping Performance In Drive Experiment
Pinging 209.214.13.8 with 32 bytes of data:
Reply from 209.214.13.8: bytes=32 time=1547ms TTL=115Reply from 209.214.13.8: bytes=32 time=1398ms TTL=115Reply from 209.214.13.8: bytes=32 time=1100ms TTL=115Reply from 209.214.13.8: bytes=32 time=1610ms TTL=115Reply from 209.214.13.8: bytes=32 time=1585ms TTL=115Reply from 209.214.13.8: bytes=32 time=1990ms TTL=115Reply from 209.214.13.8: bytes=32 time=1745ms TTL=115Reply from 209.214.13.8: bytes=32 time=1490ms TTL=115Reply from 209.214.13.8: bytes=32 time=1700ms TTL=115Reply from 209.214.13.8: bytes=32 time=1700ms TTL=115Reply from 209.214.13.8: bytes=32 time=1420ms TTL=115Reply from 209.214.13.8: bytes=32 time=1385ms TTL=115Reply from 209.214.13.8: bytes=32 time=1590ms TTL=115Reply from 209.214.13.8: bytes=32 time=1805ms TTL=115Reply from 209.214.13.8: bytes=32 time=1615ms TTL=115Reply from 209.214.13.8: bytes=32 time=1495ms TTL=115Reply from 209.214.13.8: bytes=32 time=1500ms TTL=115Reply from 209.214.13.8: bytes=32 time=1305ms TTL=115Reply from 209.214.13.8: bytes=32 time=995ms TTL=115Reply from 209.214.13.8: bytes=32 time=1400ms TTL=115Reply from 209.214.13.8: bytes=32 time=1105ms TTL=115Reply from 209.214.13.8: bytes=32 time=1905ms TTL=115Reply from 209.214.13.8: bytes=32 time=1839ms TTL=115Reply from 209.214.13.8: bytes=32 time=2450ms TTL=115Request timed out.Reply from 209.214.13.8: bytes=32 time=1678ms TTL=115Reply from 209.214.13.8: bytes=32 time=1795ms TTL=115Reply from 209.214.13.8: bytes=32 time=1595ms TTL=115Reply from 209.214.13.8: bytes=32 time=1605ms TTL=115Reply from 209.214.13.8: bytes=32 time=1400ms TTL=115Reply from 209.214.13.8: bytes=32 time=1405ms TTL=115Reply from 209.214.13.8: bytes=32 time=1600ms TTL=115Reply from 209.214.13.8: bytes=32 time=1600ms TTL=115Reply from 209.214.13.8: bytes=32 time=1805ms TTL=115Reply from 209.214.13.8: bytes=32 time=1205ms TTL=115Reply from 209.214.13.8: bytes=32 time=1400ms TTL=115Reply from 209.214.13.8: bytes=32 time=1499ms TTL=115Reply from 209.214.13.8: bytes=32 time=1605ms TTL=115Reply from 209.214.13.8: bytes=32 time=1835ms TTL=115Reply from 209.214.13.8: bytes=32 time=1670ms TTL=115Reply from 209.214.13.8: bytes=32 time=1515ms TTL=115Reply from 209.214.13.8: bytes=32 time=1890ms TTL=115Reply from 209.214.13.8: bytes=32 time=1400ms TTL=115Reply from 209.214.13.8: bytes=32 time=1750ms TTL=115Reply from 209.214.13.8: bytes=32 time=1760ms TTL=115Reply from 209.214.13.8: bytes=32 time=1600ms TTL=115Request timed out.Reply from 209.214.13.8: bytes=32 time=1348ms TTL=115
246
Reply from 209.214.13.8: bytes=32 time=1694ms TTL=115Reply from 209.214.13.8: bytes=32 time=1600ms TTL=115
Ping statistics for 209.214.13.8: Packets: Sent = 50, Received = 48, Lost = 2 (4% loss),Approximate round trip times in milli-seconds: Minimum = 995ms, Maximum = 2450ms, Average = 1518ms
C.2 Boynton (client) Boynton (server), 50kB file transfer using 576 byte buffer
01:59:08.080959 CLIENT.1500 > SERVER.6300: S 21934672:21934672(0) win 8192 <mss 536,nop,nop,sackOK> (DF)01:59:09.321085 SERVER.6300 > CLIENT.1500: S 76928:76928(0) ack 21934673 win 8576 <mss 1460> (DF)01:59:09.330934 CLIENT.1500 > SERVER.6300: . ack 1 win 8576 (DF)01:59:09.335930 CLIENT.1500 > SERVER.6300: P 1:7(6) ack 1 win 8576 (DF)01:59:09.345936 CLIENT.1500 > SERVER.6300: . 7:543(536) ack 1 win 8576 (DF)01:59:09.350931 CLIENT.1500 > SERVER.6300: P 543:583(40) ack 1 win 8576 (DF)01:59:10.816012 SERVER.6300 > CLIENT.1500: . ack 7 win 8570 (DF)01:59:10.830925 CLIENT.1500 > SERVER.6300: . 583:1119(536) ack 1 win 8576 (DF)01:59:11.301036 SERVER.6300 > CLIENT.1500: . ack 583 win 8576 (DF)01:59:11.315920 CLIENT.1500 > SERVER.6300: P 1119:1655(536) ack 1 win 8576 (DF)01:59:11.325917 CLIENT.1500 > SERVER.6300: P 1655:2191(536) ack 1 win 8576 (DF)01:59:11.640935 CLIENT.1500 > SERVER.6300: P 2191:2727(536) ack 1 win 8576 (DF)01:59:12.705979 SERVER.6300 > CLIENT.1500: . ack 1119 win 8576 (DF)01:59:12.720918 CLIENT.1500 > SERVER.6300: P 2727:3263(536) ack 1 win 8576 (DF)01:59:12.730908 CLIENT.1500 > SERVER.6300: P 3263:3799(536) ack 1 win 8576 (DF)01:59:13.110969 SERVER.6300 > CLIENT.1500: . ack 1655 win 8576 (DF)01:59:13.125905 CLIENT.1500 > SERVER.6300: P 3799:4335(536) ack 1 win 8576 (DF)01:59:13.260907 CLIENT.1500 > SERVER.6300: P 4335:4871(536) ack 1 win 8576 (DF)01:59:13.611028 SERVER.6300 > CLIENT.1500: . ack 2191 win 8576 (DF)01:59:13.625904 CLIENT.1500 > SERVER.6300: P 4871:5407(536) ack 1 win 8576 (DF)01:59:13.700906 CLIENT.1500 > SERVER.6300: P 5407:5943(536) ack 1 win 8576 (DF)01:59:14.325963 SERVER.6300 > CLIENT.1500: . ack 2727 win 8576 (DF)01:59:14.340896 CLIENT.1500 > SERVER.6300: P 5943:6479(536) ack 1 win 8576 (DF)01:59:14.350891 CLIENT.1500 > SERVER.6300: P 6479:7015(536) ack 1 win 8576 (DF)01:59:14.905984 SERVER.6300 > CLIENT.1500: . ack 3263 win 8576 (DF)01:59:14.920899 CLIENT.1500 > SERVER.6300: P 7015:7551(536) ack 1 win 8576 (DF)01:59:14.930892 CLIENT.1500 > SERVER.6300: P 7551:8087(536) ack 1 win 8576 (DF)01:59:15.715960 SERVER.6300 > CLIENT.1500: . ack 3799 win 8576 (DF)01:59:15.730884 CLIENT.1500 > SERVER.6300: . 8087:8623(536) ack 1 win 8576 (DF)01:59:15.740880 CLIENT.1500 > SERVER.6300: P 8623:9159(536) ack 1 win 8576 (DF)01:59:16.115949 SERVER.6300 > CLIENT.1500: . ack 4335 win 8576 (DF)01:59:16.130889 CLIENT.1500 > SERVER.6300: P 9159:9695(536) ack 1 win 8576 (DF)01:59:16.225886 CLIENT.1500 > SERVER.6300: P 9695:10231(536) ack 1 win 8576 (DF)01:59:16.420987 SERVER.6300 > CLIENT.1500: . ack 4871 win 8576 (DF)01:59:16.765893 CLIENT.1500 > SERVER.6300: P 10231:10767(536) ack 1 win 8576 (DF)01:59:16.925951 SERVER.6300 > CLIENT.1500: . ack 5407 win 8576 (DF)01:59:16.930875 CLIENT.1500 > SERVER.6300: P 10767:11303(536) ack 1 win 8576 (DF)01:59:17.445882 CLIENT.1500 > SERVER.6300: P 11303:11839(536) ack 1 win 8576 (DF)01:59:17.526003 SERVER.6300 > CLIENT.1500: . ack 5943 win 8576 (DF)01:59:17.610874 CLIENT.1500 > SERVER.6300: P 11839:12375(536) ack 1 win 8576 (DF)01:59:17.820874 CLIENT.1500 > SERVER.6300: P 12375:12911(536) ack 1 win 8576 (DF)01:59:18.025865 CLIENT.1500 > SERVER.6300: P 12911:13447(536) ack 1 win 8576 (DF)01:59:18.225927 SERVER.6300 > CLIENT.1500: . ack 6479 win 8576 (DF)01:59:18.230955 SERVER.6300 > CLIENT.1500: . ack 7015 win 8576 (DF)01:59:18.240863 CLIENT.1500 > SERVER.6300: P 13447:13983(536) ack 1 win 8576 (DF)01:59:18.315860 CLIENT.1500 > SERVER.6300: P 13983:14407(424) ack 1 win 8576 (DF)01:59:18.565871 CLIENT.1500 > SERVER.6300: . 14407:14943(536) ack 1 win 8576 (DF)01:59:18.570854 CLIENT.1500 > SERVER.6300: P 14943:14983(40) ack 1 win 8576 (DF)01:59:18.630930 SERVER.6300 > CLIENT.1500: . ack 7551 win 8576 (DF)01:59:18.770896 CLIENT.1500 > SERVER.6300: . 14983:15519(536) ack 1 win 8576 (DF)01:59:18.771943 CLIENT.1500 > SERVER.6300: P 15519:15559(40) ack 1 win 8576 (DF)01:59:18.975862 CLIENT.1500 > SERVER.6300: . 15559:16095(536) ack 1 win 8576 (DF)01:59:19.030911 SERVER.6300 > CLIENT.1500: . ack 8087 win 8576 (DF)01:59:19.040851 CLIENT.1500 > SERVER.6300: P 16095:16135(40) ack 1 win 8576 (DF)
247
01:59:19.725929 SERVER.6300 > CLIENT.1500: . ack 8623 win 8576 (DF)01:59:19.740850 CLIENT.1500 > SERVER.6300: . 16135:16671(536) ack 1 win 8576 (DF)01:59:19.745843 CLIENT.1500 > SERVER.6300: P 16671:16711(40) ack 1 win 8576 (DF)01:59:20.130915 SERVER.6300 > CLIENT.1500: . ack 9159 win 8576 (DF)01:59:20.145930 CLIENT.1500 > SERVER.6300: . 16711:17247(536) ack 1 win 8576 (DF)01:59:20.150844 CLIENT.1500 > SERVER.6300: P 17247:17287(40) ack 1 win 8576 (DF)01:59:20.550962 SERVER.6300 > CLIENT.1500: . ack 9695 win 8576 (DF)01:59:20.565844 CLIENT.1500 > SERVER.6300: . 17287:17823(536) ack 1 win 8576 (DF)01:59:20.570838 CLIENT.1500 > SERVER.6300: P 17823:17863(40) ack 1 win 8576 (DF)01:59:20.930905 SERVER.6300 > CLIENT.1500: . ack 10231 win 8576 (DF)01:59:20.945859 CLIENT.1500 > SERVER.6300: . 17863:18399(536) ack 1 win 8576 (DF)01:59:20.950834 CLIENT.1500 > SERVER.6300: P 18399:18439(40) ack 1 win 8576 (DF)01:59:21.230903 SERVER.6300 > CLIENT.1500: . ack 10767 win 8576 (DF)01:59:21.245845 CLIENT.1500 > SERVER.6300: . 18439:18975(536) ack 1 win 8576 (DF)01:59:21.250833 CLIENT.1500 > SERVER.6300: P 18975:19015(40) ack 1 win 8576 (DF)01:59:21.730943 SERVER.6300 > CLIENT.1500: . ack 11303 win 8576 (DF)01:59:21.741847 CLIENT.1500 > SERVER.6300: . 19015:19551(536) ack 1 win 8576 (DF)01:59:21.750826 CLIENT.1500 > SERVER.6300: P 19551:19591(40) ack 1 win 8576 (DF)01:59:22.030894 SERVER.6300 > CLIENT.1500: . ack 11839 win 8576 (DF)01:59:22.045830 CLIENT.1500 > SERVER.6300: . 19591:20127(536) ack 1 win 8576 (DF)01:59:22.050825 CLIENT.1500 > SERVER.6300: P 20127:20167(40) ack 1 win 8576 (DF)01:59:22.435889 SERVER.6300 > CLIENT.1500: . ack 12375 win 8576 (DF)01:59:22.450828 CLIENT.1500 > SERVER.6300: . 20167:20703(536) ack 1 win 8576 (DF)01:59:22.455830 CLIENT.1500 > SERVER.6300: P 20703:20743(40) ack 1 win 8576 (DF)01:59:23.230929 SERVER.6300 > CLIENT.1500: . ack 12911 win 8576 (DF)01:59:23.245821 CLIENT.1500 > SERVER.6300: . 20743:21279(536) ack 1 win 8576 (DF)01:59:23.250815 CLIENT.1500 > SERVER.6300: P 21279:21319(40) ack 1 win 8576 (DF)01:59:23.535883 SERVER.6300 > CLIENT.1500: . ack 13447 win 8576 (DF)01:59:23.550819 CLIENT.1500 > SERVER.6300: . 21319:21855(536) ack 1 win 8576 (DF)01:59:23.555820 CLIENT.1500 > SERVER.6300: P 21855:21895(40) ack 1 win 8576 (DF)01:59:23.941378 SERVER.6300 > CLIENT.1500: . ack 13983 win 8576 (DF)01:59:23.960852 CLIENT.1500 > SERVER.6300: . 21895:22431(536) ack 1 win 8576 (DF)01:59:23.965833 CLIENT.1500 > SERVER.6300: P 22431:22471(40) ack 1 win 8576 (DF)01:59:24.340904 SERVER.6300 > CLIENT.1500: . ack 14407 win 8152 (DF)01:59:24.345856 SERVER.6300 > CLIENT.1500: . ack 14983 win 8576 (DF)01:59:24.360838 CLIENT.1500 > SERVER.6300: . 22471:23007(536) ack 1 win 8576 (DF)01:59:24.365806 CLIENT.1500 > SERVER.6300: P 23007:23047(40) ack 1 win 8576 (DF)01:59:25.035901 SERVER.6300 > CLIENT.1500: . ack 15559 win 8576 (DF)01:59:25.050809 CLIENT.1500 > SERVER.6300: . 23047:23583(536) ack 1 win 8576 (DF)01:59:25.055800 CLIENT.1500 > SERVER.6300: P 23583:23623(40) ack 1 win 8576 (DF)01:59:25.535972 SERVER.6300 > CLIENT.1500: . ack 16135 win 8576 (DF)01:59:25.550803 CLIENT.1500 > SERVER.6300: . 23623:24159(536) ack 1 win 8576 (DF)01:59:25.555795 CLIENT.1500 > SERVER.6300: P 24159:24199(40) ack 1 win 8576 (DF)01:59:26.235868 SERVER.6300 > CLIENT.1500: . ack 16711 win 8576 (DF)01:59:26.245857 SERVER.6300 > CLIENT.1500: . ack 17287 win 8576 (DF)01:59:26.250805 CLIENT.1500 > SERVER.6300: . 24199:24735(536) ack 1 win 8576 (DF)01:59:26.251841 CLIENT.1500 > SERVER.6300: P 24735:24775(40) ack 1 win 8576 (DF)01:59:26.410804 CLIENT.1500 > SERVER.6300: . 24775:25311(536) ack 1 win 8576 (DF)01:59:26.415794 CLIENT.1500 > SERVER.6300: P 25311:25351(40) ack 1 win 8576 (DF)01:59:27.040878 SERVER.6300 > CLIENT.1500: . ack 17863 win 8576 (DF)01:59:27.055868 CLIENT.1500 > SERVER.6300: . 25351:25887(536) ack 1 win 8576 (DF)01:59:27.060864 CLIENT.1500 > SERVER.6300: P 25887:25927(40) ack 1 win 8576 (DF)01:59:27.441241 SERVER.6300 > CLIENT.1500: . ack 18439 win 8576 (DF)01:59:27.455787 CLIENT.1500 > SERVER.6300: . 25927:26463(536) ack 1 win 8576 (DF)01:59:27.460788 CLIENT.1500 > SERVER.6300: P 26463:26503(40) ack 1 win 8576 (DF)01:59:27.745842 SERVER.6300 > CLIENT.1500: . ack 19015 win 8576 (DF)01:59:27.760782 CLIENT.1500 > SERVER.6300: . 26503:27039(536) ack 1 win 8576 (DF)01:59:27.765776 CLIENT.1500 > SERVER.6300: P 27039:27079(40) ack 1 win 8576 (DF)01:59:28.150883 SERVER.6300 > CLIENT.1500: . ack 19591 win 8576 (DF)01:59:28.165778 CLIENT.1500 > SERVER.6300: . 27079:27615(536) ack 1 win 8576 (DF)01:59:28.170774 CLIENT.1500 > SERVER.6300: P 27615:27655(40) ack 1 win 8576 (DF)01:59:28.540869 SERVER.6300 > CLIENT.1500: . ack 20167 win 8576 (DF)01:59:28.555778 CLIENT.1500 > SERVER.6300: . 27655:28191(536) ack 1 win 8576 (DF)01:59:28.560779 CLIENT.1500 > SERVER.6300: P 28191:28231(40) ack 1 win 8576 (DF)01:59:29.240857 SERVER.6300 > CLIENT.1500: . ack 20743 win 8576 (DF)01:59:29.255770 CLIENT.1500 > SERVER.6300: . 28231:28767(536) ack 1 win 8576 (DF)01:59:29.260765 CLIENT.1500 > SERVER.6300: P 28767:28807(40) ack 1 win 8576 (DF)01:59:29.650881 SERVER.6300 > CLIENT.1500: . ack 21319 win 8576 (DF)
248
01:59:29.661774 CLIENT.1500 > SERVER.6300: . 28807:29343(536) ack 1 win 8576 (DF)01:59:29.670864 CLIENT.1500 > SERVER.6300: P 29343:29383(40) ack 1 win 8576 (DF)01:59:30.140882 SERVER.6300 > CLIENT.1500: . ack 21895 win 8576 (DF)01:59:30.155769 CLIENT.1500 > SERVER.6300: . 29383:29919(536) ack 1 win 8576 (DF)01:59:30.157160 CLIENT.1500 > SERVER.6300: P 29919:29959(40) ack 1 win 8576 (DF)01:59:31.060834 SERVER.6300 > CLIENT.1500: . ack 22471 win 8576 (DF)01:59:31.075835 CLIENT.1500 > SERVER.6300: . 29959:30495(536) ack 1 win 8576 (DF)01:59:31.080830 CLIENT.1500 > SERVER.6300: P 30495:30535(40) ack 1 win 8576 (DF)01:59:31.450893 SERVER.6300 > CLIENT.1500: . ack 23047 win 8576 (DF)01:59:31.465789 CLIENT.1500 > SERVER.6300: . 30535:31071(536) ack 1 win 8576 (DF)01:59:31.470745 CLIENT.1500 > SERVER.6300: P 31071:31111(40) ack 1 win 8576 (DF)01:59:31.745813 SERVER.6300 > CLIENT.1500: . ack 23623 win 8576 (DF)01:59:31.760751 CLIENT.1500 > SERVER.6300: . 31111:31647(536) ack 1 win 8576 (DF)01:59:31.765773 CLIENT.1500 > SERVER.6300: P 31647:31687(40) ack 1 win 8576 (DF)01:59:32.545821 SERVER.6300 > CLIENT.1500: . ack 24199 win 8576 (DF)01:59:32.560743 CLIENT.1500 > SERVER.6300: . 31687:32223(536) ack 1 win 8576 (DF)01:59:32.565737 CLIENT.1500 > SERVER.6300: P 32223:32263(40) ack 1 win 8576 (DF)01:59:32.955795 SERVER.6300 > CLIENT.1500: . ack 24775 win 8576 (DF)01:59:32.970779 CLIENT.1500 > SERVER.6300: . 32263:32799(536) ack 1 win 8576 (DF)01:59:32.975732 CLIENT.1500 > SERVER.6300: P 32799:32839(40) ack 1 win 8576 (DF)01:59:33.355792 SERVER.6300 > CLIENT.1500: . ack 25351 win 8576 (DF)01:59:33.370735 CLIENT.1500 > SERVER.6300: . 32839:33375(536) ack 1 win 8576 (DF)01:59:33.375730 CLIENT.1500 > SERVER.6300: P 33375:33415(40) ack 1 win 8576 (DF)01:59:34.050811 SERVER.6300 > CLIENT.1500: . ack 25927 win 8576 (DF)01:59:34.065733 CLIENT.1500 > SERVER.6300: . 33415:33951(536) ack 1 win 8576 (DF)01:59:34.070754 CLIENT.1500 > SERVER.6300: P 33951:33991(40) ack 1 win 8576 (DF)01:59:34.560809 SERVER.6300 > CLIENT.1500: . ack 26463 win 8576 (DF)01:59:34.561060 SERVER.6300 > CLIENT.1500: . ack 26503 win 8536 (DF)01:59:34.575726 CLIENT.1500 > SERVER.6300: . 33991:34527(536) ack 1 win 8576 (DF)01:59:34.580719 CLIENT.1500 > SERVER.6300: P 34527:34567(40) ack 1 win 8576 (DF)01:59:34.955780 SERVER.6300 > CLIENT.1500: . ack 27079 win 8576 (DF)01:59:34.970721 CLIENT.1500 > SERVER.6300: . 34567:35103(536) ack 1 win 8576 (DF)01:59:34.975717 CLIENT.1500 > SERVER.6300: P 35103:35143(40) ack 1 win 8576 (DF)01:59:35.250815 SERVER.6300 > CLIENT.1500: . ack 27655 win 8576 (DF)01:59:35.265719 CLIENT.1500 > SERVER.6300: . 35143:35679(536) ack 1 win 8576 (DF)01:59:35.270722 CLIENT.1500 > SERVER.6300: P 35679:35719(40) ack 1 win 8576 (DF)01:59:35.655845 SERVER.6300 > CLIENT.1500: . ack 28231 win 8576 (DF)01:59:35.670718 CLIENT.1500 > SERVER.6300: . 35719:36255(536) ack 1 win 8576 (DF)01:59:35.675711 CLIENT.1500 > SERVER.6300: P 36255:36295(40) ack 1 win 8576 (DF)01:59:36.455769 SERVER.6300 > CLIENT.1500: . ack 28807 win 8576 (DF)01:59:36.470711 CLIENT.1500 > SERVER.6300: . 36295:36831(536) ack 1 win 8576 (DF)01:59:36.475704 CLIENT.1500 > SERVER.6300: P 36831:36871(40) ack 1 win 8576 (DF)01:59:36.825823 SERVER.6300 > CLIENT.1500: . ack 29383 win 8576 (DF)01:59:36.840707 CLIENT.1500 > SERVER.6300: . 36871:37407(536) ack 1 win 8576 (DF)01:59:36.845702 CLIENT.1500 > SERVER.6300: P 37407:37447(40) ack 1 win 8576 (DF)01:59:37.155758 SERVER.6300 > CLIENT.1500: . ack 29959 win 8576 (DF)01:59:37.170703 CLIENT.1500 > SERVER.6300: . 37447:37983(536) ack 1 win 8576 (DF)01:59:37.175698 CLIENT.1500 > SERVER.6300: P 37983:38023(40) ack 1 win 8576 (DF)01:59:37.555762 SERVER.6300 > CLIENT.1500: . ack 30535 win 8576 (DF)01:59:37.570719 CLIENT.1500 > SERVER.6300: . 38023:38559(536) ack 1 win 8576 (DF)01:59:37.575715 CLIENT.1500 > SERVER.6300: P 38559:38599(40) ack 1 win 8576 (DF)01:59:37.955763 SERVER.6300 > CLIENT.1500: . ack 31111 win 8576 (DF)01:59:37.970700 CLIENT.1500 > SERVER.6300: . 38599:39135(536) ack 1 win 8576 (DF)01:59:37.975771 CLIENT.1500 > SERVER.6300: P 39135:39175(40) ack 1 win 8576 (DF)01:59:38.655788 SERVER.6300 > CLIENT.1500: . ack 31687 win 8576 (DF)01:59:38.670692 CLIENT.1500 > SERVER.6300: . 39175:39711(536) ack 1 win 8576 (DF)01:59:38.675686 CLIENT.1500 > SERVER.6300: P 39711:39751(40) ack 1 win 8576 (DF)01:59:39.060755 SERVER.6300 > CLIENT.1500: . ack 32263 win 8576 (DF)01:59:39.075737 CLIENT.1500 > SERVER.6300: . 39751:40287(536) ack 1 win 8576 (DF)01:59:39.080681 CLIENT.1500 > SERVER.6300: P 40287:40327(40) ack 1 win 8576 (DF)01:59:39.360749 SERVER.6300 > CLIENT.1500: . ack 32839 win 8576 (DF)01:59:39.375774 CLIENT.1500 > SERVER.6300: . 40327:40863(536) ack 1 win 8576 (DF)01:59:39.380679 CLIENT.1500 > SERVER.6300: P 40863:40903(40) ack 1 win 8576 (DF)01:59:39.760758 SERVER.6300 > CLIENT.1500: . ack 33415 win 8576 (DF)01:59:39.775682 CLIENT.1500 > SERVER.6300: . 40903:41439(536) ack 1 win 8576 (DF)01:59:39.780719 CLIENT.1500 > SERVER.6300: P 41439:41479(40) ack 1 win 8576 (DF)01:59:40.170743 SERVER.6300 > CLIENT.1500: . ack 33991 win 8576 (DF)01:59:40.185678 CLIENT.1500 > SERVER.6300: . 41479:42015(536) ack 1 win 8576 (DF)
249
01:59:40.190673 CLIENT.1500 > SERVER.6300: P 42015:42055(40) ack 1 win 8576 (DF)01:59:40.460772 SERVER.6300 > CLIENT.1500: . ack 34567 win 8576 (DF)01:59:40.475738 CLIENT.1500 > SERVER.6300: . 42055:42591(536) ack 1 win 8576 (DF)01:59:40.480669 CLIENT.1500 > SERVER.6300: P 42591:42631(40) ack 1 win 8576 (DF)01:59:41.260734 SERVER.6300 > CLIENT.1500: . ack 35143 win 8576 (DF)01:59:41.275669 CLIENT.1500 > SERVER.6300: . 42631:43167(536) ack 1 win 8576 (DF)01:59:41.280664 CLIENT.1500 > SERVER.6300: P 43167:43207(40) ack 1 win 8576 (DF)01:59:41.650761 SERVER.6300 > CLIENT.1500: . ack 35719 win 8576 (DF)01:59:41.665668 CLIENT.1500 > SERVER.6300: . 43207:43743(536) ack 1 win 8576 (DF)01:59:41.670698 CLIENT.1500 > SERVER.6300: P 43743:43783(40) ack 1 win 8576 (DF)01:59:41.980756 SERVER.6300 > CLIENT.1500: . ack 36295 win 8576 (DF)01:59:41.995668 CLIENT.1500 > SERVER.6300: . 43783:44319(536) ack 1 win 8576 (DF)01:59:42.000657 CLIENT.1500 > SERVER.6300: P 44319:44359(40) ack 1 win 8576 (DF)01:59:42.430731 SERVER.6300 > CLIENT.1500: . ack 36871 win 8576 (DF)01:59:42.445661 CLIENT.1500 > SERVER.6300: . 44359:44895(536) ack 1 win 8576 (DF)01:59:42.450686 CLIENT.1500 > SERVER.6300: P 44895:44935(40) ack 1 win 8576 (DF)01:59:42.830765 SERVER.6300 > CLIENT.1500: . ack 37447 win 8576 (DF)01:59:42.845656 CLIENT.1500 > SERVER.6300: . 44935:45471(536) ack 1 win 8576 (DF)01:59:42.850651 CLIENT.1500 > SERVER.6300: P 45471:45511(40) ack 1 win 8576 (DF)01:59:43.475719 SERVER.6300 > CLIENT.1500: . ack 38023 win 8576 (DF)01:59:43.490653 CLIENT.1500 > SERVER.6300: . 45511:46047(536) ack 1 win 8576 (DF)01:59:43.495645 CLIENT.1500 > SERVER.6300: P 46047:46087(40) ack 1 win 8576 (DF)01:59:43.890713 SERVER.6300 > CLIENT.1500: . ack 38599 win 8576 (DF)01:59:43.905654 CLIENT.1500 > SERVER.6300: . 46087:46623(536) ack 1 win 8576 (DF)01:59:43.906674 CLIENT.1500 > SERVER.6300: P 46623:46663(40) ack 1 win 8576 (DF)01:59:44.220707 SERVER.6300 > CLIENT.1500: . ack 39175 win 8576 (DF)01:59:44.235682 CLIENT.1500 > SERVER.6300: . 46663:47199(536) ack 1 win 8576 (DF)01:59:44.240640 CLIENT.1500 > SERVER.6300: P 47199:47239(40) ack 1 win 8576 (DF)01:59:45.220705 SERVER.6300 > CLIENT.1500: . ack 39751 win 8576 (DF)01:59:45.230758 SERVER.6300 > CLIENT.1500: . ack 40327 win 8576 (DF)01:59:45.235639 CLIENT.1500 > SERVER.6300: . 47239:47775(536) ack 1 win 8576 (DF)01:59:45.240631 CLIENT.1500 > SERVER.6300: P 47775:47815(40) ack 1 win 8576 (DF)01:59:45.395640 CLIENT.1500 > SERVER.6300: . 47815:48351(536) ack 1 win 8576 (DF)01:59:45.400630 CLIENT.1500 > SERVER.6300: P 48351:48391(40) ack 1 win 8576 (DF)01:59:45.675704 SERVER.6300 > CLIENT.1500: . ack 40863 win 8576 (DF)01:59:45.680788 SERVER.6300 > CLIENT.1500: . ack 40903 win 8536 (DF)01:59:45.690633 CLIENT.1500 > SERVER.6300: . 48391:48927(536) ack 1 win 8576 (DF)01:59:45.695628 CLIENT.1500 > SERVER.6300: P 48927:48967(40) ack 1 win 8576 (DF)01:59:46.065694 SERVER.6300 > CLIENT.1500: . ack 41479 win 8576 (DF)01:59:46.080721 CLIENT.1500 > SERVER.6300: P 48967:49487(520) ack 1 win 8576 (DF)01:59:46.085623 CLIENT.1500 > SERVER.6300: F 49487:49487(0) ack 1 win 8576 (DF)01:59:46.465792 SERVER.6300 > CLIENT.1500: . ack 42055 win 8576 (DF)01:59:46.870695 SERVER.6300 > CLIENT.1500: . ack 42631 win 8576 (DF)01:59:47.265691 SERVER.6300 > CLIENT.1500: . ack 43207 win 8576 (DF)01:59:47.970680 SERVER.6300 > CLIENT.1500: . ack 43783 win 8576 (DF)01:59:48.370708 SERVER.6300 > CLIENT.1500: . ack 44359 win 8576 (DF)01:59:48.670695 SERVER.6300 > CLIENT.1500: . ack 44935 win 8576 (DF)01:59:49.070711 SERVER.6300 > CLIENT.1500: . ack 45511 win 8576 (DF)01:59:49.870685 SERVER.6300 > CLIENT.1500: . ack 46087 win 8576 (DF)01:59:50.275695 SERVER.6300 > CLIENT.1500: . ack 46663 win 8576 (DF)01:59:50.670732 SERVER.6300 > CLIENT.1500: . ack 47239 win 8576 (DF)01:59:51.075690 SERVER.6300 > CLIENT.1500: . ack 47815 win 8576 (DF)01:59:51.875690 SERVER.6300 > CLIENT.1500: . ack 48391 win 8576 (DF)01:59:52.375676 SERVER.6300 > CLIENT.1500: . ack 48967 win 8576 (DF)01:59:52.880674 SERVER.6300 > CLIENT.1500: . ack 49488 win 8056 (DF)01:59:53.395720 SERVER.6300 > CLIENT.1500: F 1:1(0) ack 49488 win 8056 (DF)01:59:53.405596 CLIENT.1500 > SERVER.6300: . ack 2 win 8576 (DF)
250
C.3 Boynton (client) Gainesville (server) 25kB file transfer, at 1 byte per chunk
22:45:51.449784 44:45:53:54:0:0 20:53:52:43:0:0 0800 62: 166.62.191.207.1190 > 216.78.85.19.6300: S 726745:726745(0) win8192 <mss 536,nop,nop,sackOK> (DF)
4500 0030 a304 4000 8006 c453 a63e bfcf d84e 5513 04a6 189c 000b 16d9 0000 0000 7002 2000 9f25 0000 0204 0218 0101 0402
22:45:52.658298 20:53:52:43:0:0 44:45:53:54:0:0 0800 58: 216.78.85.19.6300 > 166.62.191.207.1190: S 82321:82321(0) ack726746 win 8576 <mss 1460> (DF)
4500 002c fe05 4000 7406 7556 d84e 5513 a63e bfcf 189c 04a6 0001 4191 000b 16da 6012 2180 6d6d 0000 0204 05b4
22:45:52.664769 44:45:53:54:0:0 20:53:52:43:0:0 0800 54: 166.62.191.207.1190 > 216.78.85.19.6300: . ack 1 win 8576 (DF) 4500 0028 a404 4000 8006 c35b a63e bfcf d84e 5513 04a6 189c 000b 16da 0001 4192 5010 2180 852a 0000
[THIS IS THE PACKET WITH THE SIX BYTES SPECIFYING THE SIZE OF THE VOICE FILE]22:45:52.669814 44:45:53:54:0:0 20:53:52:43:0:0 0800 60: 166.62.191.207.1190 > 216.78.85.19.6300: P 1:7(6) ack 1 win 8576(DF)
4500 002e a504 4000 8006 c255 a63e bfcf d84e 5513 04a6 189c 000b 16da 0001 4192 5018 2180 dc88 0000 3030 3633 4230
[THIS IS THE PACKET THAT BEGINS THE TRANSFER OF THE 25K FILE]22:45:52.680175 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 7:543(536) ack 1 win8576 (DF)
4500 0240 a604 4000 8006 bf43 a63e bfcf d84e 5513 04a6 189c 000b 16e0 0001 4192 5018 2180 5024 0000 [ 5249 4646 a863 0000 [BEGINNING OF THE FILE DATA] 5741 5645 666d ... ]
22:45:53.647933 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 7 win 8570 (DF) 4500 0028 ff05 4000 7406 745a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 16e0 5010 217a 852a 0000
22:45:53.655111 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 543:1079(536) ack 1 win8576 (DF)
4500 0240 a904 4000 8006 bc43 a63e bfcf d84e 5513 04a6 189c 000b 18f8 0001 4192 5018 2180 c628 0000 7b7c 7c7c 7c7c 7d7d 7d7d 7d7e 7e7e
22:45:53.660096 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 1079:1615(536) ack 1win 8576 (DF)
4500 0240 aa04 4000 8006 bb43 a63e bfcf d84e 5513 04a6 189c 000b 1b10 0001 4192 5018 2180 7ed6 0000 8080 8080 7f7f 807f 7e7e 7f7f 8080
22:45:54.639234 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 543 win 8576 (DF) 4500 0028 0006 4000 7406 735a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 18f8 5010 2180 830c 0000
22:45:54.645443 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 1615:2151(536) ack 1win 8576 (DF)
4500 0240 ac04 4000 8006 b943 a63e bfcf d84e 5513 04a6 189c 000b 1d28 0001 4192 5018 2180 ee2a 0000 8282 8282 8282 8383 8382 8383 8383
22:45:54.651040 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 2151:2687(536) ack 1win 8576 (DF)
4500 0240 ad04 4000 8006 b843 a63e bfcf d84e 5513 04a6 189c 000b 1f40 0001 4192 5018 2180 e21c 0000 7f7e 7e7e 7e7d 7d7c
251
7c7c 7c7c 7c7c22:45:55.440260 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 1079 win 8576 (DF)
4500 0028 0206 4000 7406 715a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 1b10 5010 2180 80f4 0000
22:45:55.446970 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 2687:3223(536) ack 1win 8576 (DF)
4500 0240 af04 4000 8006 b643 a63e bfcf d84e 5513 04a6 189c 000b 2158 0001 4192 5018 2180 4a73 0000 8281 8182 8283 8382 8282 8282 8181
22:45:55.451969 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 3223:3759(536) ack 1win 8576 (DF)
4500 0240 b004 4000 8006 b543 a63e bfcf d84e 5513 04a6 189c 000b 2370 0001 4192 5018 2180 0511 0000 8180 8081 8080 8081 8181 8181 8181
22:45:56.145697 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 1615 win 8576 (DF) 4500 0028 0306 4000 7406 705a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 1d28 5010 2180 7edc 0000
22:45:56.151138 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 3759:4295(536) ack 1win 8576 (DF)
4500 0240 b104 4000 8006 b443 a63e bfcf d84e 5513 04a6 189c 000b 2588 0001 4192 5018 2180 fee1 0000 7f7f 807f 8080 8081 8181 8181 8080
22:45:56.157152 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 4295:4831(536) ack 1win 8576 (DF)
4500 0240 b204 4000 8006 b343 a63e bfcf d84e 5513 04a6 189c 000b 27a0 0001 4192 5018 2180 bda2 0000 8383 8382 8281 8181 8080 8081 8180
22:45:56.637350 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 2151 win 8576 (DF) 4500 0028 0406 4000 7406 6f5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 1f40 5010 2180 7cc4 0000
22:45:56.643371 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 4831:5367(536) ack 1win 8576 (DF)
4500 0240 b304 4000 8006 b243 a63e bfcf d84e 5513 04a6 189c 000b 29b8 0001 4192 5018 2180 5a0d 0000 8183 827d 7a76 7576 7778 797d 838b
22:45:56.654170 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 5367:5903(536) ack 1win 8576 (DF)
4500 0240 b404 4000 8006 b143 a63e bfcf d84e 5513 04a6 189c 000b 2bd0 0001 4192 5018 2180 28d3 0000 8585 8585 8686 8685 8584 8586 8686
22:45:57.452255 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 2687 win 8576 (DF) 4500 0028 0606 4000 7406 6d5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 2158 5010 2180 7aac 0000
22:45:57.458120 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 5903:6439(536) ack 1win 8576 (DF)
4500 0240 b504 4000 8006 b043 a63e bfcf d84e 5513 04a6 189c 000b 2de8 0001 4192 5018 2180 4dbd 0000 7372 706e 6c6d 7174 7979 7a7b 7976
22:45:57.469189 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 6439:6975(536) ack 1win 8576 (DF)
4500 0240 b604 4000 8006 af43 a63e bfcf d84e 5513 04a6 189c 000b 3000 0001 4192 5018 2180 e9b5 0000 7a72 7480 7e74 8586
252
868c 8c8e 8f8f22:45:57.947220 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 3223 win 8576 (DF)
4500 0028 0706 4000 7406 6c5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 2370 5010 2180 7894 0000
22:45:57.953195 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 6975:7511(536) ack 1win 8576 (DF)
4500 0240 b704 4000 8006 ae43 a63e bfcf d84e 5513 04a6 189c 000b 3218 0001 4192 5018 2180 5dc8 0000 9295 9395 918e 8e90 8d89 8c92 918d
22:45:57.963172 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 7511:8047(536) ack 1win 8576 (DF)
4500 0240 b804 4000 8006 ad43 a63e bfcf d84e 5513 04a6 189c 000b 3430 0001 4192 5018 2180 1581 0000 8b8a 8a87 8382 7e7b 7b7a 7474 7171
22:45:58.446301 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 3759 win 8576 (DF) 4500 0028 0806 4000 7406 6b5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 2588 5010 2180 767c 0000
22:45:58.452468 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 8047:8583(536) ack 1win 8576 (DF)
4500 0240 b904 4000 8006 ac43 a63e bfcf d84e 5513 04a6 189c 000b 3648 0001 4192 5018 2180 f036 0000 8180 7f85 7d82 8086 7982 7b7f 807c
22:45:58.464164 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 8583:9119(536) ack 1win 8576 (DF)
4500 0240 ba04 4000 8006 ab43 a63e bfcf d84e 5513 04a6 189c 000b 3860 0001 4192 5018 2180 79a4 0000 7b7d 7978 7d7d 7174 7672 6c75 7172
22:45:59.147230 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 4295 win 8576 (DF) 4500 0028 0a06 4000 7406 695a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 27a0 5010 2180 7464 0000
22:45:59.153411 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 9119:9655(536) ack 1win 8576 (DF)
4500 0240 bb04 4000 8006 aa43 a63e bfcf d84e 5513 04a6 189c 000b 3a78 0001 4192 5018 2180 cf28 0000 6d6c 6a67 666b 726b 757d 7881 8a8a
22:45:59.162309 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 9655:10191(536) ack 1win 8576 (DF)
4500 0240 bc04 4000 8006 a943 a63e bfcf d84e 5513 04a6 189c 000b 3c90 0001 4192 5018 2180 ee27 0000 7077 7a7c 807f 7873 7685 6f6d 8183
22:45:59.642172 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 4831 win 8576 (DF) 4500 0028 0b06 4000 7406 685a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 29b8 5010 2180 724c 0000
22:45:59.648297 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 10191:10727(536) ack 1win 8576 (DF)
4500 0240 be04 4000 8006 a743 a63e bfcf d84e 5513 04a6 189c 000b 3ea8 0001 4192 5018 2180 4b3e 0000 9999 8f8b 8687 7d77 7579 8184 7e81
22:45:59.660162 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 10727:11263(536) ack 1win 8576 (DF)
4500 0240 bf04 4000 8006 a643 a63e bfcf d84e 5513 04a6 189c 000b 40c0 0001 4192 5018 2180 f3ba 0000 7f7e 7f7e 7f7f 7f7f
253
7f7f 8080 808022:45:59.943262 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 5367 win 8576 (DF)
4500 0028 0c06 4000 7406 675a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 2bd0 5010 2180 7034 0000
22:45:59.949295 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 11263:11799(536) ack 1win 8576 (DF)
4500 0240 c004 4000 8006 a543 a63e bfcf d84e 5513 04a6 189c 000b 42d8 0001 4192 5018 2180 c672 0000 7d7e 8081 8180 8185 8483 8586 8484
22:45:59.959977 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 11799:12335(536) ack 1win 8576 (DF)
4500 0240 c104 4000 8006 a443 a63e bfcf d84e 5513 04a6 189c 000b 44f0 0001 4192 5018 2180 7965 0000 6f68 6665 6263 6364 6879 7b6e 8b8e
22:46:00.343229 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 5903 win 8576 (DF) 4500 0028 0d06 4000 7406 665a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 2de8 5010 2180 6e1c 0000
22:46:00.350033 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 12335:12871(536) ack 1win 8576 (DF)
4500 0240 c204 4000 8006 a343 a63e bfcf d84e 5513 04a6 189c 000b 4708 0001 4192 5018 2180 10a4 0000 6765 655c 5e61 6877 8782 7a88 867e
22:46:00.360136 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 12871:13407(536) ack 1win 8576 (DF)
4500 0240 c304 4000 8006 a243 a63e bfcf d84e 5513 04a6 189c 000b 4920 0001 4192 5018 2180 f5f0 0000 8186 8583 7d80 737a 7a74 6c75 7578
22:46:01.053244 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 6439 win 8576 (DF) 4500 0028 0e06 4000 7406 655a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3000 5010 2180 6c04 0000
22:46:01.059925 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 13407:13943(536) ack 1win 8576 (DF)
4500 0240 c604 4000 8006 9f43 a63e bfcf d84e 5513 04a6 189c 000b 4b38 0001 4192 5018 2180 49c2 0000 7d7c 756c 6259 5a58 5d69 7c87 8883
[SMALLER PAKCET SENT]22:46:01.064798 44:45:53:54:0:0 20:53:52:43:0:0 0800 207: 166.62.191.207.1190 > 216.78.85.19.6300: P 13943:14096(153) ack 1win 8576 (DF)
4500 00c1 c704 4000 8006 9fc2 a63e bfcf d84e 5513 04a6 189c 000b 4d50 0001 4192 5018 2180 bdd9 0000 7f80 7e81 8280 8280 857d 847f 8684
22:46:01.448277 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 6975 win 8576 (DF) 4500 0028 0f06 4000 7406 645a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3218 5010 2180 69ec 0000
22:46:01.454996 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 14096:14632(536) ack 1win 8576 (DF)
4500 0240 c904 4000 8006 9c43 a63e bfcf d84e 5513 04a6 189c 000b 4de9 0001 4192 5018 2180 45a9 0000 7e83 7e84 827d 827e 8281 8283 8283
22:46:01.475133 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 14632:15168(536) ack 1win 8576 (DF)
4500 0240 cb04 4000 8006 9a43 a63e bfcf d84e 5513 04a6 189c 000b 5001 0001 4192
254
5018 2180 cd61 0000 8383 8282 8582 8082 8482 8182 8382
22:46:01.853235 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 7511 win 8576 (DF) 4500 0028 1006 4000 7406 635a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3430 5010 2180 67d4 0000
22:46:01.874217 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 15168:15704(536) ack 1win 8576 (DF)
4500 0240 cc04 4000 8006 9943 a63e bfcf d84e 5513 04a6 189c 000b 5219 0001 4192 5018 2180 98eb 0000 7c7a 767a 797e 7e7a 7b79 7375 7878
22:46:02.248225 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 8047 win 8576 (DF) 4500 0028 1106 4000 7406 625a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3648 5010 2180 65bc 0000
22:46:02.270020 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 15704:16240(536) ack 1win 8576 (DF)
4500 0240 cd04 4000 8006 9843 a63e bfcf d84e 5513 04a6 189c 000b 5431 0001 4192 5018 2180 3216 0000 8f8f 908f 8f8a 8782 807d 7b77 7776
22:46:02.648132 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 8583 win 8576 (DF) 4500 0028 1206 4000 7406 615a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3860 5010 2180 63a4 0000
22:46:02.670022 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 16240:16776(536) ack 1win 8576 (DF)
4500 0240 d304 4000 8006 9243 a63e bfcf d84e 5513 04a6 189c 000b 5649 0001 4192 5018 2180 38c7 0000 6e6f 7070 6f70 7071 7277 7a78 7f80
22:46:03.653216 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 9119 win 8576 (DF) 4500 0028 1306 4000 7406 605a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3a78 5010 2180 618c 0000
22:46:03.658094 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 9655 win 8576 (DF) 4500 0028 1406 4000 7406 5f5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3c90 5010 2180 5f74 0000
[SMALLER PAKCET SENT]22:46:03.664709 44:45:53:54:0:0 20:53:52:43:0:0 0800 95: 166.62.191.207.1190 > 216.78.85.19.6300: P 16776:16817(41) ack 1win 8576 (DF)
4500 0051 d804 4000 8006 8f32 a63e bfcf d84e 5513 04a6 189c 000b 5861 0001 4192 5018 2180 a331 0000 7578 767b 7d83 878d 8f97 9799 9695
22:46:03.678192 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 16817:17353(536) ack 1win 8576 (DF)
4500 0240 d904 4000 8006 8c43 a63e bfcf d84e 5513 04a6 189c 000b 588a 0001 4192 5018 2180 8bb8 0000 6b72 7679 8186 888b 908e 9191 8f8d
22:46:04.468182 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 10191 win 8576 (DF) 4500 0028 1506 4000 7406 5e5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 3ea8 5010 2180 5d5c 0000
[SMALLER PAKCET SENT]22:46:04.473984 44:45:53:54:0:0 20:53:52:43:0:0 0800 549: 166.62.191.207.1190 > 216.78.85.19.6300: P 17353:17848(495) ack 1win 8576 (DF)
4500 0217 da04 4000 8006 8b6c a63e bfcf d84e 5513 04a6 189c 000b 5aa2 0001 4192 5018 2180 9c7f 0000 8d8b 8b8d 8e8e 8d8c 8c8c 8b88 827e
255
22:46:04.490034 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 17848:18384(536) ack 1win 8576 (DF)
4500 0240 db04 4000 8006 8a43 a63e bfcf d84e 5513 04a6 189c 000b 5c91 0001 4192 5018 2180 5065 0000 7975 767a 7b7b 7e82 8186 868a 8c8c
22:46:04.848158 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 10727 win 8576 (DF) 4500 0028 1706 4000 7406 5c5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 40c0 5010 2180 5b44 0000
22:46:04.870017 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 18384:18920(536) ack 1win 8576 (DF)
4500 0240 dc04 4000 8006 8943 a63e bfcf d84e 5513 04a6 189c 000b 5ea9 0001 4192 5018 2180 f4f2 0000 8282 8282 8382 8280 7f7f 7e7b 7978
22:46:05.248189 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 11263 win 8576 (DF) 4500 0028 1806 4000 7406 5b5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 42d8 5010 2180 592c 0000
22:46:05.269736 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 18920:19456(536) ack 1win 8576 (DF)
4500 0240 dd04 4000 8006 8843 a63e bfcf d84e 5513 04a6 189c 000b 60c1 0001 4192 5018 2180 1443 0000 8483 8281 8180 7d7b 7872 6d6a 6663
22:46:06.273509 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 12335 win 8576 (DF) 4500 0028 1b06 4000 7406 585a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 4708 5010 2180 54fc 0000
22:46:06.295009 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 19456:19992(536) ack 1win 8576 (DF)
4500 0240 de04 4000 8006 8743 a63e bfcf d84e 5513 04a6 189c 000b 62d9 0001 4192 5018 2180 7c8d 0000 8284 8386 898f 9396 9696 908e 8b89
22:46:06.309990 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 19992:20528(536) ack 1win 8576 (DF)
4500 0240 df04 4000 8006 8643 a63e bfcf d84e 5513 04a6 189c 000b 64f1 0001 4192 5018 2180 6a33 0000 6b6c 6a6b 6c6f 7575 767c 7f7d 8689
22:46:07.054129 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 12871 win 8576 (DF) 4500 0028 1c06 4000 7406 575a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 4920 5010 2180 52e4 0000
22:46:07.059078 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 13407 win 8576 (DF) 4500 0028 1d06 4000 7406 565a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 4b38 5010 2180 50cc 0000
[SMALLER PAKCET SENT]22:46:07.065675 44:45:53:54:0:0 20:53:52:43:0:0 0800 102: 166.62.191.207.1190 > 216.78.85.19.6300: P 20528:20576(48) ack 1win 8576 (DF)
4500 0058 e004 4000 8006 872b a63e bfcf d84e 5513 04a6 189c 000b 6709 0001 4192 5018 2180 0ace 0000 8179 7e76 7675 7076 766d 7878 7476
22:46:07.081057 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 20576:21112(536) ack 1win 8576 (DF)
4500 0240 e104 4000 8006 8443 a63e bfcf d84e 5513 04a6 189c 000b 6739 0001 4192 5018 2180 b0ea 0000 7073 6f72 7573 7275 7471 7272 6f72
22:46:07.954164 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 13943 win 8576 (DF)
256
4500 0028 1f06 4000 7406 545a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 4d50 5010 2180 4eb4 0000
[SMALLER PAKCET SENT]22:46:07.959311 44:45:53:54:0:0 20:53:52:43:0:0 0800 542: 166.62.191.207.1190 > 216.78.85.19.6300: P 21112:21600(488) ack 1win 8576 (DF)
4500 0210 e204 4000 8006 8373 a63e bfcf d84e 5513 04a6 189c 000b 6951 0001 4192 5018 2180 27c6 0000 8b88 8985 8683 8081 817c 7c80 7e7a
22:46:07.968837 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 14096 win 8423 (DF) 4500 0028 2006 4000 7406 535a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 4de9 5010 20e7 4eb4 0000
[SMALLER PAKCET SENT]22:46:07.975971 44:45:53:54:0:0 20:53:52:43:0:0 0800 406: 166.62.191.207.1190 > 216.78.85.19.6300: P 21600:21952(352) ack 1win 8576 (DF)
4500 0188 e304 4000 8006 82fb a63e bfcf d84e 5513 04a6 189c 000b 6b39 0001 4192 5018 2180 1538 0000 8080 8080 7f7f 8080 8080 8080 8180
22:46:08.749222 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 14632 win 8576 (DF) 4500 0028 2106 4000 7406 525a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5001 5010 2180 4c03 0000
[SMALLER PAKCET SENT]22:46:08.754860 44:45:53:54:0:0 20:53:52:43:0:0 0800 391: 166.62.191.207.1190 > 216.78.85.19.6300: P 21952:22289(337) ack 1win 8576 (DF)
4500 0179 e404 4000 8006 820a a63e bfcf d84e 5513 04a6 189c 000b 6c99 0001 4192 5018 2180 44a1 0000 7f81 8282 8281 8180 807f 7e7e 7e7f
22:46:08.764095 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 15168 win 8576 (DF) 4500 0028 2206 4000 7406 515a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5219 5010 2180 49eb 0000
[SMALLER PAKCET SENT]22:46:08.770907 44:45:53:54:0:0 20:53:52:43:0:0 0800 438: 166.62.191.207.1190 > 216.78.85.19.6300: P 22289:22673(384) ack 1win 8576 (DF)
4500 01a8 e504 4000 8006 80db a63e bfcf d84e 5513 04a6 189c 000b 6dea 0001 4192 5018 2180 bc1b 0000 807b 7a7a 7471 7175 7c7e 8083 8889
22:46:08.786139 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 22673:23209(536) ack 1win 8576 (DF)
4500 0240 e604 4000 8006 7f43 a63e bfcf d84e 5513 04a6 189c 000b 6f6a 0001 4192 5018 2180 8acf 0000 8586 8685 8483 8384 8586 8686 8787
22:46:09.754216 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 15704 win 8576 (DF) 4500 0028 2306 4000 7406 505a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5431 5010 2180 47d3 0000
[SMALLER PAKCET SENT]22:46:09.759726 44:45:53:54:0:0 20:53:52:43:0:0 0800 206: 166.62.191.207.1190 > 216.78.85.19.6300: P 23209:23361(152) ack 1win 8576 (DF)
4500 00c0 e704 4000 8006 7fc3 a63e bfcf d84e 5513 04a6 189c 000b 7182 0001 4192 5018 2180 6217 0000 7d7c 7d7c 7d7e 7e7e 7e7e 7e7f 7f7f
22:46:09.769072 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 16240 win 8576 (DF) 4500 0028 2406 4000 7406 4f5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5649
257
5010 2180 45bb 0000
[SMALLER PAKCET SENT]22:46:09.775962 44:45:53:54:0:0 20:53:52:43:0:0 0800 478: 166.62.191.207.1190 > 216.78.85.19.6300: P 23361:23785(424) ack 1win 8576 (DF)
4500 01d0 e804 4000 8006 7db3 a63e bfcf d84e 5513 04a6 189c 000b 721a 0001 4192 5018 2180 264d 0000 8080 8080 8081 8282 8283 8282 8182
22:46:09.790805 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 23785:24321(536) ack 1win 8576 (DF)
4500 0240 e904 4000 8006 7c43 a63e bfcf d84e 5513 04a6 189c 000b 73c2 0001 4192 5018 2180 3d3c 0000 8283 7f7f 827e 8081 807f 8180 8381
22:46:10.364126 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 16817 win 8576 (DF) 4500 0028 2506 4000 7406 4e5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 588a 5010 2180 437a 0000
[SMALLER PAKCET SENT]22:46:10.369691 44:45:53:54:0:0 20:53:52:43:0:0 0800 166: 166.62.191.207.1190 > 216.78.85.19.6300: P 24321:24433(112) ack 1win 8576 (DF)
4500 0098 ea04 4000 8006 7ceb a63e bfcf d84e 5513 04a6 189c 000b 75da 0001 4192 5018 2180 9121 0000 7f81 807f 8180 7f7f 7f7f 807f 7f80
22:46:10.385002 44:45:53:54:0:0 20:53:52:43:0:0 0800 590: 166.62.191.207.1190 > 216.78.85.19.6300: P 24433:24969(536) ack 1win 8576 (DF)
4500 0240 eb04 4000 8006 7a43 a63e bfcf d84e 5513 04a6 189c 000b 764a 0001 4192 5018 2180 ba39 0000 7e7e 7e7e 7f7e 7f80 7f7f 7f7e 7f7e
22:46:11.464124 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 17353 win 8576 (DF) 4500 0028 2606 4000 7406 4d5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5aa2 5010 2180 4162 0000
[SMALLER PAKCET SENT]22:46:11.470640 44:45:53:54:0:0 20:53:52:43:0:0 0800 95: 166.62.191.207.1190 > 216.78.85.19.6300: P 24969:25010(41) ack 1win 8576 (DF)
4500 0051 ec04 4000 8006 7b32 a63e bfcf d84e 5513 04a6 189c 000b 7862 0001 4192 5018 2180 c390 0000 7d7f 7e7c 7d7e 7c7d 7e7e 7e7e 7e7e
[SMALLER PAKCET SENT]22:46:11.485266 44:45:53:54:0:0 20:53:52:43:0:0 0800 571: 166.62.191.207.1190 > 216.78.85.19.6300: FP 25010:25527(517) ack1 win 8576 (DF)
4500 022d ed04 4000 8006 7856 a63e bfcf d84e 5513 04a6 189c 000b 788b 0001 4192 5019 2180 d113 0000 7f7f 7f7f 8080 8080 7f80 7f80 8080
22:46:11.964141 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 17848 win 8081 (DF) 4500 0028 2706 4000 7406 4c5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5c91 5010 1f91 4162 0000
22:46:12.474156 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 18384 win 8576 (DF) 4500 0028 2806 4000 7406 4b5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 5ea9 5010 2180 3d5b 0000
22:46:13.159111 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 18920 win 8576 (DF) 4500 0028 2906 4000 7406 4a5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 60c1 5010 2180 3b43 0000
22:46:13.779096 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 19456 win 8576 (DF) 4500 0028 2b06 4000 7406 485a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 62d9 5010 2180 392b 0000
258
22:46:14.069034 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 19992 win 8576 (DF) 4500 0028 2c06 4000 7406 475a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 64f1 5010 2180 3713 0000
22:46:14.469355 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 20576 win 8576 (DF) 4500 0028 2d06 4000 7406 465a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6739 5010 2180 34cb 0000
22:46:15.270094 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 21112 win 8576 (DF) 4500 0028 2f06 4000 7406 445a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6951 5010 2180 32b3 0000
22:46:15.670148 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 21600 win 8088 (DF) 4500 0028 3006 4000 7406 435a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6b39 5010 1f98 32b3 0000
22:46:16.165118 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 21952 win 8576 (DF) 4500 0028 3106 4000 7406 425a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6c99 5010 2180 2f6b 0000
22:46:16.179867 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 22289 win 8239 (DF) 4500 0028 3206 4000 7406 415a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6dea 5010 202f 2f6b 0000
22:46:16.680025 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 22673 win 8576 (DF) 4500 0028 3406 4000 7406 3f5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 6f6a 5010 2180 2c9a 0000
22:46:17.380258 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 23361 win 8576 (DF) 4500 0028 3506 4000 7406 3e5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 721a 5010 2180 29ea 0000
22:46:17.875027 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 23785 win 8152 (DF) 4500 0028 3606 4000 7406 3d5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 73c2 5010 1fd8 29ea 0000
22:46:18.275198 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 24433 win 8576 (DF) 4500 0028 3706 4000 7406 3c5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 764a 5010 2180 25ba 0000
22:46:19.470114 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 25010 win 8576 (DF) 4500 0028 3806 4000 7406 3b5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 788b 5010 2180 2379 0000
22:46:19.490016 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: . ack 25528 win 8059 (DF) 4500 0028 3906 4000 7406 3a5a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 7a91 5010 1f7b 2378 0000
22:46:19.504737 20:53:52:43:0:0 44:45:53:54:0:0 0800 54: 216.78.85.19.6300 > 166.62.191.207.1190: F 1:1(0) ack 25528 win8059 (DF)
4500 0028 3a06 4000 7406 395a d84e 5513 a63e bfcf 189c 04a6 0001 4192 000b 7a91 5011 1f7b 2377 0000
22:46:19.511548 44:45:53:54:0:0 20:53:52:43:0:0 0800 54: 166.62.191.207.1190 > 216.78.85.19.6300: . ack 2 win 8576 (DF) 4500 0028 f204 4000 8006 755b a63e bfcf d84e 5513 04a6 189c 000b 7a91 0001 4193 5010 2180 2172 0000
259
REFERENCES
[1] Hon, A.S., An Introduction To Paging - What It Is And How It Works,http://www.mot.com/MIMS/MSPG/Special/explain_paging/ptoc.html , MotorolaElectronics Pte Ltd., 1996.
[2] Motorola, Motorola KeyNote Voice Memory™ Pager Specs Sheet,http://www.mot.com/MIMS/MSPG/Products/Voice/keynotevm/specs.html , 1997.
[3] Motorola, Motorola FLEX™ Decoding,http://www.mot.com/MIMS/MSPG/Products/OEM/FLEXDecoding, 2000.
[4] Motorola, PageWriter™ 2000 Service Manual, 1997.
[5] Couch, Leon W., Digital and Analog Communications Systems, 3rd Edition,Macmillan, New York, 1990.
[6] Sanchez, Carlos, Multimedia Services over Wireless Cellular Networks, Master’sThesis to the University of Florida, 2000.
[7] Bertsekas, Dimitri and Robert Gallager, Data Networks, 2nd Edition, Prentice Hall,Upper Saddle River, NJ, 1992.
[8] Microsoft, Microsoft TechNet, http://technet.microsoft.com/cdonline/content/, 1999.
[9] Larkin, Joseph C., Packet Telephony - Implementing a Testbed, Master’s Thesis to theUniversity of Florida, 1996.
[10] Goncalves, Marcus, Voice Over IP Networks, McGraw-Hill, New York, 1999.
[11] Cattermole, KW, “Pulse Code Modulation: Invented for Microwaves, UsedEverywhere,” 100 Years of Radio, IEE, University of Essex, United Kingdom, 1995.
[12] Roy, Tirtha, Voice Over IP - Implementing a Packet Telehony Gateway Testbed,Master’s Thesis to the University of Florida, 1998.
[13] Kuruppillai, Rajan and Mahi Dontamsetti and Fil J. Consentino, Wireless PCS,McGraw-Hill, New York, 1996.
260
[14] Charoenruengkit, Werayuth, The Speech Coding Based on the GELP Algorithm,Master’s Thesis to the University of Florida, 1999.
[15] Childers, DG and C-F Wong, “Measuring and Modeling Vocal Source-TractInteraction,” IEEE Transactions on Biomedical Engineering, Volume 41, Issue 7, July1994.
[16] McNealis, Martin, IP Crossroads ,http://www.cisco.com/warp/public/784/packet/july98/9.html , Cisco Systems, 1999.
[17] Latchman, Haniph A., Computer Communication Networks and the Internet,McGraw-Hill, New York, 1997.
[18] Deering, S. and R. Hinden, Internet Protocol Version 6 (IPv6), ftp://ftp.isi.edu/in-notes/rfc2460.txt, 1998.
[19] Eyre, J. and J. Bier, “DSPs court the consumer”, IEEE Spectrum, March 1999.
[20] Greenstreet, Debbie and Bill Witowsky, “Quality of Service in Voice-Over PacketProducts,” Multimedia Systems Design Magazine, November 1998.
[21] Microsoft, “The Component Object Model,” Microsoft Visual C++ 6.0 DevelopersNetwork Library (MSDN), 1999.
[22] Richard, Dr. Grimes and Alex Stockton and Julian Templeman and George V.Reilly, Beginning ATL COM, Wrox Press, Birmingham, UK, 1998.
[23] Rector, Brent and Chris Sells and Jim Springfield, ATL Internals, Addison-Wesley,Reading, Massachusetts, 1999.
[24] Rumbaugh, James and Michael Blaha and William Premerlani and Frederick Eddyand William Lorensen, Object Oriented Modeling and Design, Prentice Hall, UpperSaddle River, New Jersey, 1994.
[25] Perkins, C., IP Mobility Support, IETF RFC 2002, October 1996.
[26] Solomon, James, Mobile IP-The Internet Unplugged, Prentice Hall, Upper SaddleRiver, New Jersey, 1998.
[27] Simpson, W., The Point-to-Point Protocol (PPP), IETF RFC 1661, July 1994.
[28] Loyd, B. and W. Simpson, PPP Authentication Protocols, IETF RFC 1334, October1992.
261
[29] Simpson, W., PPP Challenge Handshake Authentication Protocol (CHAP), IETFRFC 1994, August 1996.
[30] McGregor, G., The PPP Internet Protocol Control Protocol (IPCP), IETF RFC1332, May 1992.
[31] Cobb, S., PPP Internet Protocol Control Protocol Extensions for Name ServerAddresses, IETF RFC 1877, December 1995.
[32] Degionanni, Loris and Piero Viano and Fulvio Risso, WinDump: TcpDump forWindows, http://netgroup-serv.polito.it/windump/, Politecnicio di Torino, Italy, 2000.
[33] Postel, John, Transmission Control Protocol, IETF RFC 0793, September 1981.
262
BIOGRAPHICAL SKETCH
Carlos A. Rivera-Cintron was born in 1969 in San Juan, Puerto Rico. In 1993, he
received a Bachelor of Science degree in electrical engineering, with high honors, from
the University of Puerto Rico at Mayaguez. Since 1993, Carlos has been working at the
Motorola, Boynton Beach Florida location, where he has been involved in many areas of
development for wireless, mobile data communication devices.
Top Related