Sie sind auf Seite 1von 89

Bluetooth Walkie-Talkie

IKT502 - Informatikkseminar Autumn 2005 HGSKOLEN I AGDER


Agder University College

Faculty of Engineering and Science

Author(s): Aleksander Albretsen Morten Krkvik Version: 1.0 Status: FINAL

Supervisor(s): Frank Reichert

Pages: 89 (including this page) Modified date: 2005-12-06

Keywords: bluetooth, j2me, mmapi, jabwt, peer-to-peer

Abstract: Bluetooth in mobile phones are typically used for connecting Bluetooth headsets and establishing connections to the Internet on behalf of a computer or a PDA. In this project, we want to extend the usage of Bluetooth by examine the possibilities of using your Bluetooth enabled mobile phone as a walkie-talkie, allowing users to exchange instant messages between their terminals. The goal of this project is to specify the necessary system components, selected protocols, proposed terminal implementation strategy and developing a functional prototype of the Bluetooth walkie-talkie. Our proposed solution is an application running on the mobile phone, based on J2ME, utilizing the JABWT (JSR-82) and MMAPI (JSR-135) libraries and previous work by Ben Hui on peer-topeer communication between Bluetooth- and J2ME enabled terminals. We experienced that, after testing the key features of MMAPI on different terminals supporting the MMAPI library (by product specifications), the MMAPI implementation was incomplete on certain terminals, which disabled some of the features of our proposed solution. We also learned that audio recording had to be completed before it could be streamed to another terminal, and that not all mobile phones support JABWT.

License: This work is licensed under the Creative Commons Attribution-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Version Control
Version 1 0.1 0.2 0.3 1.0 Status 2 DRAFT REVIEW REVIEW FINAL Date 3 2005.12.02 2005.12.04 2005.12.05 2005.12.06 Change 4 First draft Document sent for review Added text to chapter 7 and 8 Final version Author 5 AA and MK AA and MK AA and MK AA and MK

Version indicates the version number starting at 0.1 for the first draft and 1.0 for the first version uploaded for review. Version numbers are maintained by the project group. 2 Status is DRAFT, REVIEW or FINAL
3 4 5

Date is given in ISO format: yyyy-mm-dd Change describes the changes carried out since the previous version Author your name(s)

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Table of Contents
1 Executive summary ............................................................................................................ 4 2 Introduction ........................................................................................................................ 5 3 Background ........................................................................................................................ 6 3.1 J2ME ........................................................................................................................... 6 3.2 Bluetooth ..................................................................................................................... 6 3.3 Mobile Media ............................................................................................................... 7 4 Problem description............................................................................................................ 8 5 Requirements specification for Bluetooth Walkie-Talkie .................................................... 9 6 Design of Bluetooth Walkie-Talkie.................................................................................... 10 7 Implementation ................................................................................................................. 13 8 Evaluation and testing ...................................................................................................... 15 9 Discussion ........................................................................................................................ 17 9.1 Project outcomes....................................................................................................... 17 9.2 Evaluation of the overall results................................................................................. 17 10 Conclusion ..................................................................................................................... 18 Appendix ............................................................................................................................... 19 A1 Glossary & abbreviations ............................................................................................... 19 A2 References..................................................................................................................... 20 A3 UML model..................................................................................................................... 21 A4 NetLayer diff................................................................................................................... 26 A5 Source code listing......................................................................................................... 34

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

1 Executive summary
Bluetooth technology has become the de facto standard for short-range communication between mobile phones, and several low-end mobile phones are today Bluetooth enabled. However, the usage of this technology has been, more or less, limited to establishing connections to headsets and PDA devices, typically used by the advanced user. The aim of this project is to extend the basic usage of this technology by developing an application allowing novice users to easily exchange instant messages between their mobile terminals. The following subproblems were studied during this project: Required system components Protocol selection Implementation strategy The actual implementation

The proposed solution is an application, running on each terminal, based on J2ME MIDP 2.0/CLDC 1.0, using JABWT (JSR-82) and MMAPI (JSR-135) libraries. By utilizing components of Ben Hui's BlueChat application, the terminals are able to create an ad-hoc Bluetooth network and possesses the ability to broadcast messages. The proposed solution has the ability to broadcast audio streams and pictures, as well as text messages, to all parties of the Bluetooth network. During the live testing of the proposed solution, some problems encountered. On specific terminals, such as the SonyEricsson K750i, audio recording, being a part of the MMAPI library, is not supported. After investigating this issue, we learned that very few phones actually support this feature. Although the number of Bluetooth enabled mobile phones is increasing, it is not given that all J2ME implementations support JABWT (JSR-82). As a result of this, not all Bluetooth enabled phones can utilize the Bluetooth stack using J2ME. For instance, one of our terminals used for testing, the 3G-enabled SonyEricsson Z800, does not support JABWT. Despite the problems with some of our terminals, we were able the test audio streaming and picture broadcast, as well as sending text messages, using the emulator provided by Sun's Wireless Toolkit. During the live tests, we were only able to test picture- and text message broadcast. Since we were unable to perform a live test of audio messaging, we do not have any solid test results showing whether this feature is suitable for Bluetooth. However, broadcasting pictures taken with the built-in camera and text messages was quite acceptable.

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

2 Introduction

Bluetooth[9] is a well-known technology, however few mobile phone applications exploits the possibilities of using it for other purposes than establishing connections to headsets and computers. Mobile phones are getting more powerful in means of CPU and memory, making it possible for developers to make use of advanced multimedia functions. In this project, we examine the possibilities of using a Bluetooth enabled mobile phone as a walkie-talkie, allowing users to exchange instant messages to each other. As most mobile phones support J2ME[10], we found Java to be the natural language for this task. Along with libraries such as the Mobile Media API (MMAPI) [7] and Java API for Bluetooth Wireless Technology (JABWT) [6,9], J2ME offers many exciting possibilities. Many people find programming with Bluetooth and J2ME a difficult task. This is one of the reasons why Ben Hui wrote an article called Go wild wirelessly with Bluetooth and Java [8]. This article looks at how developers can easily build Bluetooth applications by covering important design- and implementations elements of a typical Bluetooth application. In this project, we have based the low level networking part of our proposed solution on this article, allowing us to focus on a higher level of networking, in addition to MMAPI and completing the prototype. The background section of this report takes you through the basic elements of J2ME, Bluetoothand multimedia functions. Problems to be solved during the project are defined in the project description section, followed by a detailed requirement specification of our proposed solution, BTWT. Based on preliminary literature review, the proposed solution design is sketched out in chapter 6 followed by details regarding implementation. Chapter 8 describes the testing and evaluation of BTWT, both simulation and live tests with real mobile phones. The report is concluded with a discussion of our findings and a conclusion about mobile multimedia applications using the Bluetooth technology. A glossary and abbreviations for this report can be found in appendix A1.

See also http://sep.stanford.edu/sep/prof/Intro.html


5

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

3 Background
In this project, we have used J2ME (Java for mobile devices) with the Bluetooth API and the Mobile Media API. This chapter will explain the basics in the difference between J2ME and J2SE, the Bluetooth API and the Mobile Media API.

3.1 J2ME
The first part of J2ME Game Programming [10] describes what J2ME is. When SUN wanted to run Java on low-cost and low-power devices such as mobile phones, they soon realize that fitting J2SE in such a device would be impossible, hence J2ME. To make J2ME flexible and not limited by the low-end devices of the hardware-range, the J2ME designers divided J2ME into configurations and profiles. Meaning that they have peeled off all the functionality, and each group of devices has their own configuration and profile describing what functionality those devices supports. This makes J2ME quite different from J2SE, because J2SE comes with a huge common library. All J2ME configurations, profiles and APIs are described in something called a JSR [1] (Java Specification Request). A J2ME configuration defines the capabilities of a group of devices with similar hardware, limiting Java to suite these devices capabilities. The configuration defined for mobile phones is called CLDC which is described in JSR-30 [2]. There is also a CLDC 1.1 release described in JSR-139 [3]. CLDC has some important differences from J2SE (see [2,10] for more details): no floating-point math, no Object.finalize method, no java.lang.Error exception class hierarchy, no support for weak references, no reflection, no support for advance thread control, the JNI is not implemented, and finally no support for user-defined class loaders. CLDC 1.1 supports floatingpoint, limited form of weak-refferances and many other nice features, see [3,10] for more details. In addition to a profile, a configuration is needed to complete the J2ME environment for a collection of devices. The most popular, and the only useful, profile is the MIDP profile which targets MIDs (Micro Information Devices) and is implemented inn all mobile phones that supports J2ME. A java application written for a MID is called a MIDlet. MIDP comes in different version due to the development of mobile phones. The first and the initial MIDP is the MIDP 1.0 [4]. As the functionality of mobile phones has increased the MIDP hans been developed to MIDP 2.0 [5]. The difference in MIDP 1.0 and MIDP 2.0 inculdes support for; real tcp/ip sockets, midi and wave support, better UI, PNG image transparency, and much more. The CLDC configuration and the MIDP profile are so popular and commonly used that one might say that when people talk about J2ME applications they are actually talking about MIDlets, which is based on the CLDS configuration and the MIDP profile. To support different types of hardware, and to extend the functionality of CLDC and MIDP there are developed a set of APIs. It is up to the different mobile manufacturer to decide which version of CLDC and MIDP and which APIs the want the mobile phone to support.

3.2 Bluetooth
Bluetooth [9] is as an open standard for low-cost, low-power, short-range radio network with the goal of replacing the cable used to connect devices such as mobile phones, headsets and portable computers to each other. The Bluetooth specification defines a complete system from the radio up to the application layer, including the software stack. On the other hand the Bluetooth specification does not describe a common software API for use by software developers. This is where the JABWT (Java API Bluetooth Wireless Technology) [6,9] also called JSR-82 come to hand. JABWT specifies a common API for Bluetooth application programming with J2ME.
6 v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

The Bluetooth specification consists of, among others, a Bluetooth stack and Bluetooth profiles. It is important to take notice of that not the entire Bluetooth stack and all the Bluetooth profiles are implemented in JABWT. For instance, the audio profile is not implemented. For information regarding JABWT and the implemented Bluetooth features, see [9]. The article Go Wild Wirelessly with Bluetooth and Java [8], written by Ben Hui, explains how to create a basic Bluetooth application using J2ME through an example called BlueChat. BlueChat is a peer-to-peer chat application which uses Bluetooth as the network backend using JABWT. The BlueChat application is divided in to two parts, one user interface component and a network layer. The BlueChat network layer is an abstraction of JABWT and is capable of discovering new nearby peers, establishing connection to these peers and sending text messages between them. If no other nearby peer has been found, the network layer establishes a new network which future nearby peers can discover and connect to. Please read [8] for more information about BlueChat.

3.3 Mobile Media


The Mobile Media API (MMAPI), described in JSR-135 [7], provides a common api for multimedia application development under J2ME. The MMAPI support features such as: Audio and video playback from local and external files, local buffers and streams. Audio and video recording to local file or buffer, but not to live stream Access to the mobile phone vibrator.

Even though a J2ME device supports MMAPI it does not have to support every feature available trough the api. It is therefore possible to query the device to find out which features it supports. For example, a SonyEricsson K750i does not support audio recording, but it supports picture recording.

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

4 Problem description
The aim of this project is to develop a walkie-talkie application that uses Bluetooth to transfer the data. Since we want to enable as many terminals as possible to run this application, the natural choice of language is J2ME. Combining these technologies raise some problems which needs to be handled. We will now identify and explain those problems. First, we have to find out what J2ME is and how to program a J2ME MIDlet. We have already figured out the basics during the literature study, but we still have to figure out how to set up a developer environment for J2ME. Then, it is over to Bluetooth and Bluetooth programming, which is the main problem of the project. We have learned that there is an API for Bluetooth programming in J2ME called JABWT, and we assume that we can extend the network layer from BlueChat to send audio messages. Therefore, we have to figure out how the network layer in BlueChat uses the JABWT to create a Bluetooth peer-to-peer network, and if it is possible to extend the network layer to send audio messages. Audio messages over Bluetooth also raises a question regarding the use of bandwidth; how long time will it take to send a audio message over Bluetooth, and what happens when a peer sends the messages to several other peers? Since we want to send audio messages, we have to find out how to record-, send- and play audio messages. We have already found out that we can not stream the audio message directly while recording, so we need to record to a temporary buffer on the sender side until the user is finished recording, and then send the audio to the other peers, which will play the received audio message. This raises an important question; how long can we record a message until the device runs out of memory?

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

5 Requirements specification for Bluetooth Walkie-Talkie


The following text shows a list of the requirements for our Bluetooth Walkie-Talkie MIDlet. All requirements have the highest priority, as they are vital for the MIDlet to function. R01 Audio messages are to be recorded to a buffer at the sender peer. Since MMAPI does not support live streaming while recording, we have to record to a temporarily buffer before sending the audio stream. R02 The user must have the ability to accept or discharge the recorded audio message. If the user made a mistake during the recording, there must be an option for cancelling the sending of the message. R03 Send buffered audio message when the recording user accepts it. The buffered audio message should be sent when the user accepts the recording. R04 A sender peer has to be able to send a message simultaneously to all parties of the chat room. To enable the message to arrive at all the other peers as simultaneously as possible the sending peer has to send the recorded message asynchronously. R05 A peer has to be able to discover a chat room. A peer has to be able to discover a chat room created by another peer. R06 A peer has to be able to connect to a discovered chat room. A peer has to be able to connect to another peers chat room. R07 A peer must have the ability to act as a server To make it possible for new peers to join the chat room, all existing peers must act as servers and be able to connect a new peer to the network. R08 A peer has to be able to handle gracefully disconnection from another peer. When a peer disconnects for what ever reason this should be handled gracefully by peers. R09 A user has to enter a nickname before he or she can join a chat room. Every user in a chat room has to have a nickname that identifies them to the other peers. R10 A peer must be able to create a new network. If the peer is unable to find an existing chat room it has to be able to create a new one. R11 A peer must be able to receive an audio message. When a recording peer is sending its recorded message, the receiving peer must have the ability to receive an audio message. R12 A peer must be able to play back a received message. When peer has received a new audio message, it must have the ability to play it for the user.

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

6 Design of Bluetooth Walkie-Talkie


We decided to base the Bluetooth Walkie-Talkie on key components from Ben Hui's BlueChat application and the MMAPI library. Using the components from BlueChat gives us a higher level of abstraction in Bluetooth programming for J2ME. The component from BlueChat, NetLayer, provides the functionality to establish a Bluetooth adhoc peer-to-peer network, and an interface for sending text messages to all connected peers. This component will need some modifications to support audio transmissions. To enable multimedia functionality, MMAPI is needed. MMAPI provide the functionality for recording and playback of audio. As shown in figure 1, our MIDlet called BTWT, will be developed against MIDP 2.0, MMAPI and NetLayer. MIDP 2.0 supports wave and midi files, and this is the reason for selecting MIDP2.0 over MIDP 1.0. Because of our design decisions, the terminal must support MIDP 2.0, MMAPI- and JABWT libraries. The modified NetLayer from Ben Hui's BlueChat will be bundled with the BTWT MIDlet.

Figure 1 - Bluetooth Walkie-Talkie system components

10

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

An overview of our proposed solution, as shown in figure 2, will consist of a main MIDlet class, the NetLayer, a graphical user interface, and an Audio- recorder and player.

Figure 2 - Bluetooth Walkie-Talkie Overview

Our choice of programming environment is the Eclipse IDE [11] bundled with EclipseME [12]. EclipseME is an Eclipse plugin to help develop J2ME MIDlets. EclipseME does the dirty work of connecting Wireless Toolkits to the Eclipse platform, allowing us to focus on the J2ME programming. We will also be using Subversion (SVN) [14] for version control. Eclipse and Subversion was chosen based on previous experiences in version control and Java development. The primary Wireless Toolkit (WTK) of choice was Sun's WTK [13], because it runs under both Linux and Windows. We will also use the SonyEricsson and the Nokia Series 80 WTK for testing our MIDlet under different environments. For live testing of the MIDlet a SonyEricsson K750i will be used. Figure 3 shows Eclipse bundled with EclipseME emulating a MIDlet using Suns WTK.

v1.0

11

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Figure 3 - Eclipse IDE bundled with EclipseME and Sun WTK

12

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

7 Implementation
We started the implementation phase by modelling our BTWT MIDlet in UML. This model has been updated as we discovered necessary changes along the implementation phase. The complete UML model for our MIDlet is shown in appendix A3. Based on the model, we first wrote a MIDlet that was able to send text messages using the Network Layer from BlueChat. In other words integrating the Network Layer in to our MIDlet. During this phase, we also wrote the code for our GUI, and had in mind all the time that we had to prepare the MIDlet for audio messages. In figure 4 there are two mobile phones running the BTWT MIDlet with the ability to send text messages. Frame 1 shows Peer 1 creating a chat room, and Peer2 joining. This is all done by the Network Layer. Frame 2-3 shows Peer1 sending the message Hello. This is a test message. Frame 4 shows that Peer2 receives this message. (Highlighted button is indicating that the user is pushing it to continue).
(1) Peer1: (2) Peer1: (3 ) Peer1: (4) Peer2:

Figure 4 - BTWT: Peer1 sending a text message to Peer2

After having a working version that supported text messages, we started to implement audio messages in to our MIDlet. First, we implemented the audio recorder function. During this phase we discovered a vital problem for our project. Almost no phones support audio recording trough the MMAPI, and worst of all was that our test phone K750i does not support audio recording. The only way we were able to test audio recording was emulating our MIDlet using Suns J2ME emulator and Nokias S80 device emulator. After having a functional audio recording solution, we modified the Network Layer to support audio messages. This modification included adding support for sending audio data as a stream of binary data, and adding support to receive this stream of binary data and placing it in a buffer for playback. We also had to implement an audio player that is able to play the received stream. Since we use SVN for version control, we are able to document the changes we have done to the Network Layer. A complete comparison between the original Network Layer and our source is listed in appendix A4.

v1.0

13

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

After having discovered that we were unable to demonstrate our solution, we were disappointed. Then we thought of the possibility to record a picture, using the phones camera, and send it to the other peers. We wrote some test codes to evaluate the possibility to record, send and view a picture with our test phone K750i. This test was successfully, and we decided to implement a picture recorder and picture viewer function to our MIDlet, see figure 5 below.

Figure 5 - Bluetooth Walkie-Talkie overview with support for picture messages

Figure 6 shows Peer1 recording and sending a picture to Peer2. As in figure 4 the first frame shows the creation of the chat room. In frame 2 Peer1 chooses to create a new picture message, and in frame 3 the user is seeing a live picture from his camera which he or she can capture and send. Frame 4 shows Peer2 showing a received picture from Peer1. (Highlighted button is indicating that the user is pushing it to continue)
(1) Peer1: (2) Peer1: (3 ) Peer1: (4) Peer2:

Figur 6 - BTWT: Peer1 sending a picture message to Peer2

A complete listing of the BTWT MIDlet source code can be found in appendix A5.

14

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

8 Evaluation and testing


After implementation of each requirement, it was tested in the emulators and on a live mobile phone. All tests were performed using the Sun Wireless Toolkit emulator, Nokia S80 emulator, SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone. The following text describes the test and its outcome according to each requirement. R01 Audio messages are to be recorded to a buffer at the sender peer. On the emulators, we were not able to actually record any audio using a microphone connected to the computer, which means all recorded audio was silent. In our test we recorded 5 seconds of silent audio to the buffer. The Nokia S80 emulator ended up with a buffer of size 818KB. Sun's WTK emulator buffer resulted in a relatively small buffer size, 37KB. The SonyEricsson W800/K750i emulator throwed an exception when attempting to record any audio. This is because this specific model does not support audio recording. The same results was achieved when testing this on the SonyEricsson K750i mobile phone. R02 The user must have the ability to accept or discharge the recorded audio message. The Sun's WTK emulator and Nokia S80 emulator worked as expected on this test. The emulators was able to press the 'Back' button and return to 'idle' state. The SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone was not able to record, but was immediately given the option of pressing 'Back' to return to 'idle' state. R03 Send buffered audio message when the recording user accepts it. The Sun's WTK emulator and Nokia S80 emulator worked as expected on this test. The SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone was never given this option. On the Nokia S80 emulator, sending 5 seconds of audio (818KB) took approx. 27 seconds to one peer (avg. 30KB/s), approx. 58 seconds to two peers (avg. 28KB/s) and approx 93 seconds to three peers (avg. 26KB/s). On the Sun WTK emulator, sending 5 seconds of audio (37KB) took 2ms to one peer (avg. 18500KB/s), 6ms to two peers (avg. 12333KB/s) and 4ms to three peers (avg. 27750KB/s). We were not able to perform this test on the SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone as audio recording is not supported. R04 A sender peer has to be able to send a message simultaneously to all parties of the chat room. All emulators and the SonyEricsson K750i mobile phone were able to send message to all parties of the chat room as expected, as the Network Layer is designed to send all messages in an asynchronous matter. R05 A peer has to be able to discover a chat room. All emulators and the SonyEricsson K750i mobile phone were able to discover created chat rooms.

v1.0

15

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

R06 A peer has to be able to connect to a discovered chat room. All emulators and the SonyEricsson K750i mobile phone were able to connect to the discovered chat room. R07 A peer must have the ability to act as a server All emulators and the SonyEricsson K750i mobile phone were opening ports for incoming connections. R08 A peer has to be able to handle gracefully disconnection from another peer. All emulators and the SonyEricsson K750i mobile phone were able handle both normal and abnormal disconnection in a graceful matter. R09 A user has to enter a nickname before he or she can join a chat room. All emulators and the SonyEricsson K750i mobile phone are forced to enter a nickname before connecting to the Bluetooth network. An error message is given if no nickname is set. R10 A peer must be able to create a new network. All emulators and the SonyEricsson K750i mobile phone were able to create a new Bluetooth network. R11 A peer must be able to receive an audio message. The Sun WTK emulator and the Nokia S80 emulator were able to receive audio messages. This test was not performed on the SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone, as this specific model does not support audio recording. R12 A peer must be able to play back a received message. The Sun WTK emulator were assumed to be able to play back the received message, as this did not throw any exceptions. We were not able to confirm this as the received audio message was silent. The Nokia S80 emulator were not able to decode the audio stream, due to a thrown unsupported audio exception. This test was not performed on the SonyEricsson W800/K750i emulator and the SonyEricsson K750i mobile phone, as this specific model does not support audio recording.

16

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

9 Discussion
In this section, we will discuss our findings and results during the project.

9.1 Project outcomes


In this project, we initially set 12 high priority requirements for our proposed solution. We found most of the requirements to be successfully implemented. The previous work done by Ben Hui on BlueChat covered several of the requirements, and proved to be quite useful in this project. Because of the variation in the test results on audio transfer, we are unable to determine whether Bluetooth is suitable for transferring audio between two mobile phones or not. Bluetooth is capable of transferring data at a rate of 728kbps [15]. It should therefore be theoretically possible to transfer encoded audio with an acceptable response between two Bluetooth devices. Due to the inability to perform a live test of audio recording, we are also unable to determine a maximum buffer size for recorded audio. As a curiosity we implemented support for picture messaging, which turned out to be quite acceptable. We believe that this feature has increased the value of this project.

9.2 Evaluation of the overall results


The most serious problems we encountered were not being able to do any audio recording on our mobile phones. In addition, there is also a question of how credible the audio recording performed on the emulators was, as we were not able to hear any sound. Since there are almost no mobile phones currently supporting audio recording, one might say that the overall goal of creating a walkie-talkie for mobile phones was never met. Despite this, we still believe that this project contributes with the gained experience.

v1.0

17

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

10 Conclusion
The Network layer in BlueChat served as nice base for our application, and we believe these components are useful for any type of Bluetooth peer-to-peer applications for J2ME. Although we were unable to perform a live test of audio messaging, Bluetooth should be capable of transferring audio messages due to the transfer rate at 728kbps. Our biggest concern regarding audio recording is the limited memory available on the mobile phone, which will limit the audio message duration. The results show that MMAPI is suitable for audio recording and audio playback as long as the necessary features are implemented. Because of the way J2ME is designed with its configurations and profiles, there is no absolute assurance that an application written for one device will run on another J2ME enabled device. We find this frustrating and that it distances J2ME from what we think of as the Java philosophy write once, run everywhere. Despite the issues we encountered during this project regarding J2ME and its libraries, we believe this project has contributed to increased knowledge of how to extend the basic usage of Bluetooth technology.

18

v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Appendix A1 Glossary & abbreviations


BTWT NetLayer J2ME JSR CLDC MIDP MID JABWT MMAPI Acronym for Bluetooth Walkie-Talkie The Bluetooth network layer in Ben Huis BlueChat [8] Java for mobile devices [10] Java Specification Request [1] A J2ME configuration for mobile devices [2,3,10] A J2ME profile for MIDs [4,5,10] Mobile Information Device [10] Java APIs for Bluetooth Wireless Technology (JSR-82) [6] Mobile Media API (JSR-135) [7]

Bluetooth Wire replacement radio technology [9] SVN PDA Acronym for Subversion [14] Personal Digital Assistant

v1.0

19

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

A2 References
[1] JSRs: Java Specification Requests. URL: http://jcp.org/en/jsr/overview/ [2] JSR-30: J2ME Connected, Limited Device Configuration URL: http://www.jcp.org/en/jsr/detail?id=30 [3] JSR-139: Connected Limited Device Configuration 1.1 URL: http://www.jcp.org/en/jsr/detail?id=139 [4] JSR-37: Mobile Information Device Profile for the J2ME Platform URL: http://www.jcp.org/en/jsr/detail?id=37 [5] JSR-118: Mobile Information Device Profile 2.0 URL: http://www.jcp.org/en/jsr/detail?id=118 [6] JSR-82: Java APIs for Bluetooth URL: http://www.jcp.org/en/jsr/detail?id=82 [7] JSR-135: Mobile Media API URL: http://www.jcp.org/en/jsr/detail?id=135 [8] Ben Hui, Go Wild Wirelessly with Bluetooth and Java. In Java Developers Journal, Vol: 9 Iss: 2 (Feb. 5, 2004) URL: http://java.sys-con.com/read/43551.htm [9] C Bala Kumar, Paul J. Kline and Timothy J. Thompson. Bluetooth Application Programming with the Java APIs. Amsterdam; Boston: Morgan Kaufmann Publishers, 2004. ISBN: 1-55860-934-2 [10] Martin J. Wells. J2ME Game Programming. Boston, MA: Premier Press, 2004 ISBN: 1-59200-118-1 [11] Eclipse IDE URL: http://www.eclipse.org/ [12] Eclipse ME URL: http://www.eclipseme.org/ [13] SUN Wireless Toolkit URL: http://java.sun.com/products/sjwtoolkit/ [14] Subversion URL: http://subversion.tigris.org/ [15] Ericsson Bluetooth FAQ URL: http://www.ericsson.com/mobilityworld/sub/open/technologies/bluetooth/faq.html#q2
20 v1.0

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Appendix 3

UML model

v1.0

21

BlueTooth Walkie-Talkie

22
AudioRecorder (from org::ikt502::btwt) ~ recorder - recordAudioUI - recordGui (from org::ikt502::btwt::gui) RecordAudioUI PictureRecorder (from org::ikt502::btwt) - recorder - recordGui (from org::ikt502::btwt::gui) - recordPictureUI RecordPictureUI - btwt BTWT ~ gui (from org::ikt502::btwt::gui) ~ parent AudioPlayer ~ gui - debugUI - parent DebugUI (from org::ikt502::btwt::gui) (from org::ikt502::btwt) - btwt (from org::ikt502::btwt) BtwtGUI - enterNickUI - btwt - parent ~ parent EnterNickUI (from org::ikt502::btwt::gui) << interface >> BTListener ImageViewerUI - gui (from org::ikt502::btwt::gui) (from org::ikt502::btwt::network) ~ callback ~ parent - enterTextUI EnterTextUI (from org::ikt502::btwt::gui) - gui ~ parent - parent - chatUI ChatUI (from org::ikt502::btwt::gui) EndPoint (from org::ikt502::btwt::network) MessageHandler (from org::ikt502::btwt::gui) SelectChatTypeUI (from org::ikt502::btwt::gui) + endpt + endpt - selectChatTypeUI ~ sender Sender ~ reader Reader (from org::ikt502::btwt::network)

~ callback

~ btnet

NetLayer

(from org::ikt502::btwt::network)

~ btnet

ChatPacket

(from org::ikt502::btwt::network)

Util

(from org::ikt502::btwt::network)

(from org::ikt502::btwt::network)

v1.0
Created with Poseidon for UML Community Edition. Not for Commercial Use.

Package Overview: org.ikt502.btwt

v1.0
network - btwt gui AudioRecorder -startTime:long -contentType:String -buffer:ByteArrayOutputStream -isRecording:boolean= false -thread:Thread << create >>+AudioRecorder(btwt:BTWT,recordGui:RecordAudioUI):AudioRecorder +run():void +startRecording():void +stopRecording():void +sendRecordedMessage():void -startRecord():void -stopRecord():void -log(s:String):void AudioPlayer ~stream:InputStream ~contentType:String ~from:String ~start:long << create >>+AudioPlayer(gui:BtwtGUI,stream:InputStream,contentType:String,from:String):AudioPlayer +start():void +run():void -playStream():void +playerUpdate(arg0:Player,arg1:String,arg2:Object):void -log(s:String):void

BTWT

<< create >>+BTWT():BTWT +startApp():void +pauseApp():void +destroyApp(unconditional:boolean):void +getDisplay():Display +quitApp():void +joinNetwork(nick:String):void +sendTextMessage(s:String):void +sendAudio(stream:ByteArrayOutputStream,contentType:String):void +sendPicture(picture:byte[]):void -playAudioMessage(stream:InputStream,contentType:String,from:String):void -showPicture(picture:byte[],from:String):void +handleAction(event:String,param1:Object,param2:Object):void -log(s:String):void

- btwt

PictureRecorder

-picture:byte[] ~canShowPicture:boolean= false -thread:Thread

<< create >>+PictureRecorder(btwt:BTWT,recordGui:RecordPictureUI):PictureRecorder +start():void +run():void -runRecorder():void +takeSnapshot():void -generateSnapshot():void +getCameraAsItem():Item +getPicture():byte[] +sendPicture():void +discardPlayer():void -log(s:String):void

23
Created with Poseidon for UML Community Edition. Not for Commercial Use.

Package Overview: org.ikt502.btwt.gui

24
MessageHandler +setGUI(gui:BtwtGUI):void +addMessage(s:String):void +addDebugMessage(s:String):void SelectChatTypeUI - selectChatTypeUI +TEXT_MESSAGE:int= 0 +AUDIO_MESSAGE:int= 1 +PICTURE_MESSAGE:int= 2 << create >>+SelectChatTypeUI(parent:BtwtGUI):SelectChatTypeUI +show():void - gui BtwtGUI - gui ~ parent ~ parent - enterTextUI << create >>+EnterTextUI(parent:BtwtGUI):EnterTextUI +show():void EnterTextUI - parent - recordPictureUI RecordAudioUI << create >>+BtwtGUI(btwt:BTWT):BtwtGUI +addMessage(s:String):void +addDebugMessage(s:String):void +commandAction(command:Command,displayable:Displayable):void ~ parent +getDisplay():Display +showChatWindow():void -handleEnterNick(cmd:Command):void -handleChat(command:Command):void -handleSelectChatType(command:Command):void -handleEnterText(command:Command):void -handleRecordAudio(command:Command):void -handleRecordPicture(command:Command):void +getBTWT():BTWT ~ parent -handleDebug(command:Command):void +log(s:String):void - recordAudioUI - parent - parent +START:int= 0 +RECORDING:int= 1 +READY_TO_SEND:int= 2 +SENDT:int= 4 +FAILED:int= 5 << create >>+RecordAudioUI(parent:BtwtGUI):RecordAudioUI +getRecorder():AudioRecorder +getParent():BtwtGUI +setState(cmd:int):void +show():void - debugUI ChatUI -msgs:Vector= new Vector() -midx:int= 0 -w:int -h:int -fh:int -x0:int= 0 -y0:int= 0 << create >>+ChatUI(parent:BtwtGUI):ChatUI +addMessage(s:String):void +clearMessages():void +show():void +keyPressed(key:int):void #paint(g:Graphics):void DebugUI -msgs:Vector= new Vector() -midx:int= 0 -w:int -h:int -fh:int -x0:int= 0 -y0:int= 0 << create >>+DebugUI(parent:BtwtGUI):DebugUI +addMessage(s:String):void +clearMessages():void +show():void +keyPressed(key:int):void #paint(g:Graphics):void - chatUI

ImageViewerUI

-picture:byte[] -from:String

<< create >>+ImageViewerUI(picture:byte[],from:String,gui:BtwtGUI):ImageViewerUI +show():void +commandAction(arg0:Command,arg1:Displayable):void

EnterNickUI

<< create >>+EnterNickUI(parent:BtwtGUI):EnterNickUI +isValidNick():boolean +getNick():String +show():void

- enterNickUI

RecordPictureUI

+START:int= 0 +CAMERA_READY:int= 1 +VERIFY:int= 2 +SENDT:int= 3 +FAILED:int= 4 -state:int= 3

<< create >>+RecordPictureUI(parent:BtwtGUI):RecordPictureUI +getState():int +setState(cmd:int):void +show():void +getRecorder():PictureRecorder +getParent():BtwtGUI

v1.0
Created with Poseidon for UML Community Edition. Not for Commercial Use.

v1.0
EndPoint (from org ::ikt502 ::btwt ::network ) ~remoteUrl :String ~transId :int= -1 ~ callback +remoteName :String ~msgs :Vector = new Vector() << create >> +EndPoint (btnet :NetLayer ,rdev :RemoteDevice ,c:StreamConnection ):EndPoint +putString (signal :int,s:String ):void +putStream (signal :int,stream :ByteArrayOutputStream ,contentType :String ):void +putPicture (signal :int,picture :byte[] ):void +getString ():ChatPacket +peekString ():boolean -log (s:String ):void + endpt ~ sender Sender (from org::ikt502::btwt::network) -done:boolean= false << create >>+Sender():Sender +stop():void +run():void -log(s:String):void + endpt +localName :String ~ reader -done:boolean= false << create >>+Reader():Reader +stop():void +run():void -log(s:String):void (from org::ikt502::btwt::network) Reader ChatPacket (from org::ikt502::btwt::network) Util (from org::ikt502::btwt::network) +signal:int +sender:String +msg:String +contentType:String +streamOut:ByteArrayOutputStream +picture:byte[] +streamIn:InputStream << create >>+ChatPacket(signal:int,msg:String):ChatPacket << create >>+ChatPacket(signal:int,sender:String,msg:String):ChatPacket << create >>+ChatPacket(signal:int,stream:ByteArrayOutputStream,contentType:String):ChatPacket << create >>+ChatPacket(signal:int,sender:String,stream:InputStream,contentType:String):ChatPacket << create >>+ChatPacket(signal:int,picture:byte[]):ChatPacket << create >>+ChatPacket(signal:int,sender:String,picture:byte[]):ChatPacket << create >>+ChatPacket():ChatPacket << create >>-Util():Util -log(s:String):void +printRemoteDevice(dev:RemoteDevice,devClass:DeviceClass):void +printLocalDevice(dev:LocalDevice):void +printServiceRecord(r:ServiceRecord):void +printDataElement(e:DataElement,id:int,indent:String):void +idToName(id:int):String +uuidToName(u:UUID):String +majorToName(d:int):String +minorToName(d:int,m:int):String +majorServiceToName(d:int):String[] +isContainsUUID(r:ServiceRecord,uuid:UUID):boolean -isContainsUUID(e:DataElement,uuid:UUID):boolean

Package Overview: org.ikt502.btwt.network

<< interface >>

BTListener

(from org::ikt502::btwt::network)

+EVENT_JOIN:String= "join" +EVENT_LEAVE:String= "leave" +EVENT_RECEIVED:String= "received" +EVENT_SENT:String= "sent"

+handleAction(action:String,param1:Object,param2:Object):void

~ callback

NetLayer

(from org::ikt502::btwt::network)

+SIGNAL_HANDSHAKE:int= 0 +SIGNAL_MESSAGE:int= 1 +SIGNAL_TERMINATE:int= 3 +SIGNAL_HANDSHAKE_ACK:int= 4 +SIGNAL_TERMINATE_ACK:int= 5 +SIGNAL_AUDIO_MESSAGE:int= 6 +SIGNAL_PICTURE_MESSAGE:int= 7 -SERVICE_TELEPHONY:int= 0x400000 ~done:boolean= false ~localName:String= "" ~endPoints:Vector= new Vector() ~pendingEndPoints:Vector= new Vector() ~serviceRecordToEndPoint:Hashtable= new Hashtable() ~lock:Object= new Object() ~timer:Timer= new Timer()

~ btnet

<< create >>+NetLayer():NetLayer +init(name:String,callback:BTListener):void +disconnect():void +query():void +findEndPointByRemoteDevice(rdev:RemoteDevice):EndPoint +findEndPointByTransId(id:int):EndPoint +sendString(s:String):void +sendAudio(stream:ByteArrayOutputStream,contentType:String):void +sendPicture(picture:byte[]):void +cleanupRemoteEndPoint(endpt:EndPoint):void +run():void +log(s:String):void

25

Created with Poseidon for UML Community Edition. Not for Commercial Use.

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Appendix 4

NetLayer patch

(Changes in NetLayer)

26

v1.0

Index: EndPoint.java =================================================================== --- EndPoint.java (revision 10) +++ EndPoint.java (revision 121) @@ -44,9 +44,9 @@ Reader reader; // local user nick name String localName; public String localName; // remote user nick name String remoteName; public String remoteName;

+ +

// BTListener implementation for callback NetLayer event BTListener callback; @@ -101,9 +101,33 @@ } } + + + + + + + + + + + + + + + + + + + + + + + + + public synchronized void putStream( int signal, ByteArrayOutputStream stream, String contentType ) { log("invoke putStream "+signal+" MULTIMEDIA"); // put the message on the queue, pending to be sent by Sender thread msgs.addElement( new ChatPacket( signal, stream, contentType ) ); synchronized( sender ) { // tell sender that there is a message pending to be sent sender.notify(); } } public synchronized void putPicture( int signal, byte[] picture ) { log("invoke putPicture "+signal); // put the message on the queue, pending to be sent by Sender thread msgs.addElement( new ChatPacket( signal, picture ) ); synchronized( sender ) { // tell sender that there is a message pending to be sent sender.notify(); } log("putPicture finished..."); }

public synchronized ChatPacket getString() { -// log("invoke getString()"); if ( msgs.size() > 0 ) { // if there are message pending, return it and remove it from the vector Index: Sender.java =================================================================== --- Sender.java (revision 10) +++ Sender.java (revision 121) @@ -21,14 +21,25 @@ * @version 1.0 */ import java.io.*; +import java.util.Date; +import org.ikt502.btwt.gui.MessageHandler; + public class Sender implements Runnable { - // end point that this sender sends data to + /** + * end point that this sender sends data to + */ public EndPoint endpt; + + + /** * */ private boolean done = false;

+ + +

/** * */ public Sender() { } @@ -41,6 +52,9 @@ done = true; } + + + /** * */ public void run() { try @@ -63,11 +77,48 @@ if ( s != null )

v1.0

27

{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } if ( s != null && s.signal == NetLayer.SIGNAL_TERMINATE ) @@ -86,16 +137,19 @@ log(e.getClass().getName()+" "+e.getMessage()); } log("sender thread exit for "+endpt.remoteName); } + + + /** + * + * @param s + */ private static void log( String s) { System.out.println("Sender: "+s); // "S" means Sender class if ( ChatMain.isDebug ) ChatMain.instance.gui_log( "S", s ); MessageHandler.addDebugMessage( "S: " + s ); } } \ No newline at end of file Index: Reader.java =================================================================== --- Reader.java (revision 10) +++ Reader.java (revision 121) @@ -22,6 +22,8 @@ */ import java.io.*; +import org.ikt502.btwt.gui.MessageHandler; + public class Reader implements Runnable { // end point that this reader reads data from @@ -64,8 +66,52 @@ // read in a string message. emit RECEIVED event to BTListener implementation endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); + } else if ( signal == NetLayer.SIGNAL_HANDSHAKE ) } // if there is a message to send, send it now log("sending signal "+s.signal+" string "+s.msg+" to "+endpt.remoteName); dataout.writeInt(s.signal); dataout.writeUTF(s.msg ); dataout.flush(); //Time the transmision... long start = new Date().getTime(); //Audio Message... if ( s.signal == NetLayer.SIGNAL_AUDIO_MESSAGE ) { // if there is a message to send, send it log("sending signal "+s.signal+" audio to //Send Audio Message dataout.writeInt(s.signal); dataout.writeInt(s.streamOut.size()); dataout.writeUTF(s.contentType); dataout.write(s.streamOut.toByteArray()); dataout.flush(); }

now "+endpt.remoteName); //Anounce Audio Message... //...its length... //...and its content type... //Then its content...

//Picture Message... else if ( s.signal == NetLayer.SIGNAL_PICTURE_MESSAGE ) { // if there is a message to send, send it now log("sending signal "+s.signal+" picture to "+endpt.remoteName); //Send Audio Message dataout.writeInt(s.signal); //Anounce Picture Message... dataout.writeInt(s.picture.length); //...its length... dataout.write(s.picture); //Then its content... dataout.flush(); } //Other Messages... else { // if there is a message to send, send it now log("sending signal "+s.signal+" string "+s.msg+" to "+endpt.remoteName); dataout.writeInt(s.signal); dataout.writeUTF(s.msg ); dataout.flush(); } //Calc time used... long time = new Date().getTime() - start; log("Transmision time for signal "+s.signal+" was " + time + "ms..." );

28

v1.0

+ +

+ + + + int size = datain.readInt(); + String contentType = datain.readUTF(); + + byte[] buffer = new byte[size]; + for (int i = 0; i < size; i++) + { + buffer[i] = datain.readByte(); + } + + ChatPacket packet = new ChatPacket( NetLayer.SIGNAL_AUDIO_MESSAGE, endpt.remoteName, new ByteArrayInputStream(bu ffer), contentType); + + log("read in AUDIO MESSAGE from "+endpt.remoteName+". AdvSize/RecSize: "+size+"/"+buffer.length); + + // read in a string message. emit RECEIVED event to BTListener implementation + endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); + + } + + else if ( signal == NetLayer.SIGNAL_PICTURE_MESSAGE ) + { + int size = datain.readInt(); + + byte[] buffer = new byte[size]; + for (int i = 0; i < size; i++) + { + buffer[i] = datain.readByte(); + } + + ChatPacket packet = new ChatPacket( NetLayer.SIGNAL_PICTURE_MESSAGE, endpt.remoteName, buffer); + + log("read in VIDEO MESSAGE from "+endpt.remoteName); + + // read in a string message. emit RECEIVED event to BTListener implementation + endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); + + } + + else if ( signal == NetLayer.SIGNAL_HANDSHAKE ) + { String s = datain.readUTF(); log("read in HANDSHAKE name "+s+" from "+endpt.remoteName); // update the remote user nick name @@ -77,7 +123,9 @@ endpt.callback.handleAction( BTListener.EVENT_JOIN, endpt, null ); + + + } else if ( signal == NetLayer.SIGNAL_TERMINATE ) } else if ( signal == NetLayer.SIGNAL_TERMINATE ) { log("read in TERMINATE from "+endpt.remoteName);

if ( signal == NetLayer.SIGNAL_AUDIO_MESSAGE ) { //Anounce inncomming messaeg... MessageHandler.addMessage("Receiving audio message from "+endpt.remoteName+", please wait...");

@@ -93,7 +141,9 @@ // stop this reader, no need to read any more signal stop(); + + + } else if ( signal == NetLayer.SIGNAL_HANDSHAKE_ACK ) }

else if ( signal == NetLayer.SIGNAL_HANDSHAKE_ACK ) { // the string data is the remote user nick name String s = datain.readUTF(); @@ -101,14 +151,18 @@ // update remote user nick name endpt.remoteName = s; + + + } else if ( signal == NetLayer.SIGNAL_TERMINATE_ACK ) } else if ( signal == NetLayer.SIGNAL_TERMINATE_ACK ) { System.out.println("read in TERMINATE_ACK from "+endpt.remoteName); // doesnt do anything, just wake up from readInt() so that the thread can stop

+ + +

} else }

else { log("Unkonwn signal, probably connection closed"); } @@ -129,11 +183,8 @@ System.out.println("Reader: "+s);

v1.0

29

+ }

// "R" means Reader class if ( ChatMain.isDebug ) ChatMain.instance.gui_log( "R", s ); MessageHandler.addDebugMessage( "R: " + s );

} \ No newline at end of file Index: NetLayer.java =================================================================== --- NetLayer.java (revision 10) +++ NetLayer.java (revision 121) @@ -8,6 +8,8 @@ import javax.bluetooth.DeviceClass; import javax.bluetooth.ServiceRecord; +import org.ikt502.btwt.gui.MessageHandler; + /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). @@ -39,7 +41,9 @@ public final static int SIGNAL_TERMINATE = 3; public final static int SIGNAL_HANDSHAKE_ACK = 4; public final static int SIGNAL_TERMINATE_ACK = 5; + public final static int SIGNAL_AUDIO_MESSAGE = 6; + public final static int SIGNAL_PICTURE_MESSAGE = 7; + // BlueChat specific service UUID // note: this UUID must be a string of 32 char // do not use the 0x???? constructor because it wont @@ -91,7 +95,7 @@ } public void init(String name, BTListener callback) { { log( "invoke init()" ); try { this.localName = name; @@ -214,6 +218,37 @@ } + /** * * @param stream */ public void sendAudio (ByteArrayOutputStream stream, String contentType) { log("invoke sendAudio..."); for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); // put the string on EndPoint, so sender will send the message endpt.putStream( NetLayer.SIGNAL_AUDIO_MESSAGE, stream, contentType ); } } /** * * @param stream */ public void sendPicture ( byte[] picture ) { log("invoke sendPicture..."); for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); // put the string on EndPoint, so sender will send the message endpt.putPicture( NetLayer.SIGNAL_PICTURE_MESSAGE, picture ); } }

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

/** * Clean up the resource for a EndPoint, remove it from the active list. * This is triggered by a remote EndPoint leaving the network * @param endpt @@ -277,7 +312,7 @@ log("local service waiting for client connection"); // this message is to inform user that the server is up and ready ChatMain.instance.gui_log( "", "Ready to accept connection. Wait..." ); MessageHandler.addMessage("Ready to accept connection. Wait...");

// // start accepting client connection. @@ -591,7 +626,7 @@ pendingEndPoints.removeAllElements(); // this message is to inform user that chatting can start

30

v1.0

+ }

ChatMain.instance.gui_log( "", "You can start chatting now" ); MessageHandler.addMessage( "You can start chatting now..." );

Index: ChatPacket.java =================================================================== --- ChatPacket.java (revision 10) +++ ChatPacket.java (revision 121) @@ -1,5 +1,8 @@ package org.ikt502.btwt.network; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). @@ -21,29 +24,128 @@ * @author Ben Hui * @version 1.0 */ public class ChatPacket { - // signal, must be one of NetLayer.SIGNAL_XXX + /** + * signal, must be one of NetLayer.SIGNAL_XXX + */ public int signal; - // indicate the nick name of the sender + + /** + * indicate the nick name of the sender + */ public String sender; - // the message content + + /** + * Storage for a text message + */ public String msg; + + /** + * Content-Type of audio stream + */ + public String contentType; + + /** + * Storage for an outgoing audio stream + */ + public ByteArrayOutputStream streamOut; + + /** + * Storage for a picture + */ + public byte[] picture; + + /** + * Storage for an incoming audio stream + */ + public InputStream streamIn; + + /** + * Create a new outgoing ChatPacket with TextMessage + * + * @param signal Signal Type + * @param msg Text message + */ public ChatPacket(int signal, String msg) { this.signal = signal; this.msg = msg; + this.signal = signal; + this.msg = msg; } + + + + + + + /** * Create a new incoming ChatPacket with TextMessage * * @param signal Signal Type * @param sender Whom it is from * @param msg Text message */ public ChatPacket(int signal, String sender, String msg) { this.signal = signal; this.sender = sender; this.msg = msg; this.signal = signal; this.sender = sender; this.msg = msg; }

+ + +

v1.0

31

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

/** * Create a new outgoing ChatPacket with AudioMessage * * @param signal Signal Type * @param stream Audio stream in audio message * @param contentType Content-Type of the audio stream */ public ChatPacket(int signal, ByteArrayOutputStream stream, String contentType) { this.signal = signal; this.streamOut = stream; this.contentType = contentType; } /** * Create a new incoming ChatPacket with AudioMessage * * @param signal Signal Type * @param sender Whom it is from * @param stream Audio stream in audio message * @param contentType Content-Type of the audio stream */ public ChatPacket(int signal, String sender, InputStream stream, String contentType) { this.signal = signal; this.sender = sender; this.streamIn = stream; this.contentType = contentType; } /** * Create a new outgoing ChatPacket with PictureMessage * * @param signal Signal Type * @param picture Picture in picture message */ public ChatPacket(int signal, byte[] picture) { this.signal = signal; this.picture = picture; } /** * Create a new incoming ChatPacket with PictureMessage * * @param signal Signal Type * @param sender Whom it is from * @param picture Picture in picture message */ public ChatPacket(int signal, String sender, byte[] picture) { this.sender = sender; this.signal = signal; this.picture = picture; }

/** * Create new emty ChatPacket */ public ChatPacket() { } Index: Util.java =================================================================== --- Util.java (revision 10) +++ Util.java (revision 121) @@ -5,6 +5,9 @@ import java.util.Enumeration; import java.io.IOException; import java.util.Vector; + +import org.ikt502.btwt.gui.MessageHandler; + /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). @@ -34,11 +37,7 @@ private static void log( String s ) { System.out.println( s ); // "U" means Util class if ( ChatMain.isDebug ) ChatMain.instance.gui_log( "U", s ); + MessageHandler.addDebugMessage( "U: " + s ); } public static void printRemoteDevice( RemoteDevice dev, DeviceClass devClass ) @@ -112,11 +111,11 @@ int type = e.getDataType(); if ( type == DataElement.DATALT || type == DataElement.DATSEQ ) { Enumeration enum = (Enumeration)e.getValue(); + Enumeration enumeration = (Enumeration)e.getValue();

32

v1.0

log(indent+"DataElement["+idToName(id)+"] "+type+" (# of element: "+e.getSize()+")"); while ( enum.hasMoreElements() ) while ( enumeration.hasMoreElements() ) { DataElement e2 = (DataElement)enum.nextElement(); + DataElement e2 = (DataElement)enumeration.nextElement(); printDataElement( e2, id, indent+" " ); } } else if ( type == DataElement.U_INT_1 || type == DataElement.U_INT_2 || type == DataElement.U_INT_4 || @@ -568,10 +567,10 @@ + } else if ( type == DataElement.DATALT || type == DataElement.DATSEQ ) { Enumeration enum = (Enumeration)e.getValue(); Enumeration enumeration = (Enumeration)e.getValue(); while (enum.hasMoreElements()) { DataElement e2 = (DataElement) enum.nextElement(); while (enumeration.hasMoreElements()) { DataElement e2 = (DataElement) enumeration.nextElement(); if ( isContainsUUID( e2, uuid ) ) // recursive return true; }

+ + +

v1.0

33

Aleksander Albretsen, Morten Krkvik

Bluetooth Walkie-Talkie

Appendix 5

Source code listing

34

v1.0

./org/ikt502/btwt/gui/RecordPictureUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.gui; import javax.microedition.lcdui.*; import org.ikt502.btwt.PictureRecorder; /** * RecorderPictureUI controlls the picture recorder * * @authors Aleksander Albretsen and Morten Krkvik */ public class RecordPictureUI extends Form { /** * Possible "States" for this Form... */ public static final int START = 0; public static final int CAMERA_READY = 1; public static final int VERIFY = 2; public static final int SENDT = 3; public static final int FAILED = 4; /** * Command to be shown at the first button... * Only one of these commands are used at the same time... */ private Command capture; private Command send; private Command ok; /** * The PictureRecorder */ private PictureRecorder recorder; /** * ref. to GUI controller */ private BtwtGUI parent; /** * Current state */ private int state = 3; /** * Construct new RecordPictureUI * * @param parent Ref. to GUI controller. */ public RecordPictureUI(BtwtGUI parent) { //Create Form... super("Bluetooth Walkie-Talkie"); //Only one of capture = new send = new ok = new these are used at the same time... Command("Capture", Command.OK, 1); Command("Send", Command.OK, 1); Command("OK", Command.OK, 1);

//Always show "Back" command... addCommand(new Command("Back", //Set command listener setCommandListener( parent );

Command.BACK, 2));

//Create recorder recorder = new PictureRecorder(parent.getBTWT(), this); //Add ref. to parent GUI this.parent = parent; } /** * Get the current state * * @return Integer code for the current state */ public int getState() { return state; } /** * Fetch the recorder object * * @return the Picture Recorder */ public PictureRecorder getRecorder() { return recorder; }

v1.0

35

./org/ikt502/btwt/gui/RecordPictureUI.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: ); 147: //Fix command list 148: removeCommand(ok); 149: removeCommand(capture); 150: addCommand(send); 151: break; 152: 153: case SENDT: 154: //Show text 155: append( new StringItem("Picture Message", "\n\nYour picture is now transmitting to the other peers... Press OK to continue.") ); 156: //Fix command list 157: removeCommand(capture); 158: removeCommand(send); 159: addCommand(ok); 160: break; 161: 162: case FAILED: 163: //Show text 164: append( new StringItem("Picture Message", "\n\nAn error occured... Press OK to co ntinue.") ); 165: //Fix command list 166: removeCommand(capture); 167: removeCommand(send); 168: addCommand(ok); 169: break; 170: } 171: } 172: 173: /** 174: * Make this UI the visible UI 175: */ 176: public void show() 177: { 178: parent.log("PictureRecorder::show()"); 179: 180: //Show... 181: parent.getDisplay().setCurrent(this); 182: setState(START); 183: /** * Fetch the UI Controller object * * @return the UI Controller */ public BtwtGUI getParent() { return this.parent; } /** * Set the current state * * (0) START : Camera is "warming" up. * (1) CAMERA_READY : The camera is ready for use * (2) VERIFY : Picture recorded, verify it * (3) SENDT : Picture message sendt * (4) FAILED : Used to inform the user that an error has occured. * * @param cmd Integer code for the current state */ public void setState(int cmd) { parent.log("RecordPictureUI::setState("+cmd+")"); //Clear Screen... deleteAll(); //Save state... state = cmd; switch (cmd) { case START: //Show pre. text... append( new StringItem("", "Waiting for camera to start...") ); //Fix command list removeCommand(ok); removeCommand(send); break; case CAMERA_READY: //Show camera image append( recorder.getCameraAsItem() ); //Fix command list removeCommand(ok); removeCommand(send); addCommand(capture); break; case VERIFY: //Show text append( Image.createImage( recorder.getPicture(), 0, recorder.getPicture().length)

36

v1.0

./org/ikt502/btwt/gui/RecordPictureUI.java
184: 185: 186: 187: } //Start Camera... recorder.start(); }

v1.0

37

./org/ikt502/btwt/gui/EnterNickUI.java
1: package org.ikt502.btwt.gui; 2: 3: import javax.microedition.lcdui.*; 4: 5: /** 6: * User interface used to ask the user to enter a nick name 7: * 8: * @authors Aleksander Albretsen and Morten Krkvik 9: */ 10: public class EnterNickUI extends Form 11: { 12: /** 13: * ref. to GUI controller 14: */ 15: private BtwtGUI parent; 16: 17: /** 18: * TextFiled used to ask for nick name 19: */ 20: private TextField nickName; 21: 22: /** 23: * Construct new EnterNickUI 24: * 25: * @param parent Ref. to GUI controller. 26: */ 27: public EnterNickUI(BtwtGUI parent) 28: { 29: //Create Form... 30: super("BT Walkie-Talkie"); 31: 32: addCommand(new Command("Continue", Command.OK, 1)); 33: 34: append( new StringItem("", "Welcome to Bluetooth Walkie-Talkie. Please enter your nickname and press Conti nue to start your Walkie-Talkie.\n" ) ); 35: append( nickName = new TextField("Nickname:", "", 10, TextField.ANY ) ); 36: 37: setCommandListener( parent ); 38: 39: //Add ref. to parent GUI 40: this.parent = parent; 41: } 42: 43: /** 44: * Validate nickname. Give warning if nickname is not given. 45: */ 46: public boolean isValidNick() 47: { 48: if (nickName.getString().length() > 0) 49: { 50: return true; 51: } 52: else 53: { 54: //Show warning ! 55: Alert alert = new Alert( "No Nickname...", "You have to enter a nickname befoure you can start your walkie-talkie!", null, AlertType.WARNING ); 56: alert.setTimeout( Alert.FOREVER ); 57: parent.getDisplay().setCurrent( alert, this ); 58: return false; 59: } 60: } 61: 62: /** 63: * Get the nick name the user entered 64: * 65: * @retutn entered nick name 66: */ 67: public String getNick() 68: { 69: return nickName.getString(); 70: } 71: 72: 73: /** 74: * Make this UI the visible UI 75: */ 76: public void show() 77: { 78: parent.getDisplay().setCurrent(this); 79: } 80: }

38

v1.0

./org/ikt502/btwt/gui/ChatUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.gui; import java.util.Vector; import javax.microedition.lcdui.*; /** * User interface that shows all activity. * * @authors Aleksander Albretsen and Morten Krkvik */ public class ChatUI extends Canvas { /** * list of available message to display */ private Vector msgs = new Vector(); /** * current message idx */ private int midx = 0; /** * graphic width */ private int w; /** * graphic height */ private int h; /** * font height */ private int fh; /** * font to write message on screen */ private Font f; /** * text scroll pos at x-axis */ private int x0 = 0; /** * text scroll pos at y-axis */ private int y0 = 0; /** * ref. to GUI controller */ private BtwtGUI parent; /** * Construct new ChatUI * * @param parent Ref. to GUI controller. */ public ChatUI(BtwtGUI parent) { //Add COMMANDS addCommand(new Command("New Message", Command.ITEM, 1)); addCommand(new Command("Show Debug", Command.ITEM, 2)); addCommand(new Command("Phone Info", Command.ITEM, 3)); addCommand(new Command("About", Command.ITEM, 4)); addCommand(new Command("Exit", Command.EXIT, 5)); //Set CommandListener setCommandListener( parent ); //Add default lines at top... clearMessages(); //Add ref. to parent GUI this.parent = parent; } /** * Add new message to the screen * * @param s String to add */ public void addMessage(String s) { msgs.addElement(s); this.repaint(); } /**

v1.0

39

./org/ikt502/btwt/gui/ChatUI.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: } * Clear the screen */ public void clearMessages() { msgs.removeAllElements(); msgs.addElement("Bluetooth Walkie-Talkie"); } /** * Make this UI the visible UI */ public void show() { parent.getDisplay().setCurrent(this); } /** * Handle keyPressed event * * @param key */ public void keyPressed( int key ) { if ( getGameAction( key ) == Canvas.RIGHT ) { x0+=50; } else if ( getGameAction( key ) == Canvas.LEFT ) { x0-=50; } else if ( getGameAction( key ) == Canvas.UP ) { // note: change this from 50 to 100 if you want to scroll faster y0-=50; } else if ( getGameAction( key ) == Canvas.DOWN ) { // note: change this from 50 to 100 if you want to scroll faster y0+=50; } repaint(); } /** * Override the paint method from Canvas and draw message list * * @param g Graphics object */ protected void paint(Graphics g) { if ( f == null ) { // cache the font and width,height value // when it is used the first time f = Font.getFont( Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL ); w = this.getWidth(); h = this.getHeight(); fh = f.getHeight(); } int y = fh; // 1st line y value // message will be rendered in black color, on top of white backgound g.setColor( 255, 255, 255 ); g.fillRect( 0, 0, w, h ); g.setColor( 0, 0, 0 ); g.setFont( f ); g.translate(-x0, -y0); // render the messages on screen for ( int i= midx; i< msgs.size(); i++ ) { String s = (String)msgs.elementAt(i); g.drawString( s, 0, y, Graphics.BASELINE | Graphics.LEFT ); y += fh; } }

40

v1.0

./org/ikt502/btwt/gui/DebugUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.gui; import java.util.Vector; import javax.microedition.lcdui.*; /** * Userinterface that shows debug messages * * @authors Aleksander Albretsen and Morten Krkvik */ public class DebugUI extends Canvas { /** * list of available message to display */ private Vector msgs = new Vector(); /** * current message idx */ private int midx = 0; /** * graphic width */ private int w; /** * graphic height */ private int h; /** * font height */ private int fh; /** * font to write message on screen */ private Font f; /** * text scroll pos at x-axis */ private int x0 = 0; /** * text scroll pos at y-axis */ private int y0 = 0; /** * ref. to GUI controller */ private BtwtGUI parent; /** * Construct new DebuUI * * @param parent Ref. to GUI controller. */ public DebugUI(BtwtGUI parent) { //Add COMMANDS addCommand(new Command("Back", Command.OK, 1)); //Set CommandListener setCommandListener( parent ); //Add default lines at top... clearMessages(); //Add ref. to parent GUI this.parent = parent; } /** * Add new debug message to the screen * * @param s String to add */ public void addMessage(String s) { msgs.addElement(s); } /** * Clear the screen */ public void clearMessages() { msgs.removeAllElements();

v1.0

41

./org/ikt502/btwt/gui/DebugUI.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: } msgs.addElement("DEBUG MESSAGES:"); } /** * Make this UI the visible UI */ public void show() { parent.getDisplay().setCurrent(this); } /** * Handle keyPressed event * * @param key */ public void keyPressed( int key ) { if ( getGameAction( key ) == Canvas.RIGHT ) { x0+=50; } else if ( getGameAction( key ) == Canvas.LEFT ) { x0-=50; } else if ( getGameAction( key ) == Canvas.UP ) { // note: change this from 50 to 100 if you want to scroll faster y0-=50; } else if ( getGameAction( key ) == Canvas.DOWN ) { // note: change this from 50 to 100 if you want to scroll faster y0+=50; } repaint(); } /** * Override the paint method from Canvas and draw message list * * @param g Graphics object */ protected void paint(Graphics g) { if ( f == null ) { // cache the font and width,height value // when it is used the first time f = Font.getFont( Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL ); w = this.getWidth(); h = this.getHeight(); fh = f.getHeight(); } int y = fh; // 1st line y value // message will be rendered in black color, on top of white backgound g.setColor( 255, 255, 255 ); g.fillRect( 0, 0, w, h ); g.setColor( 0, 0, 0 ); g.setFont( f ); g.translate(-x0, -y0); // render the messages on screen for ( int i= midx; i< msgs.size(); i++ ) { String s = (String)msgs.elementAt(i); g.drawString( s, 0, y, Graphics.BASELINE | Graphics.LEFT ); y += fh; } }

42

v1.0

./org/ikt502/btwt/gui/BtwtGUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: /* * mainGUI.java * * Created on 21. oktober 2005, 12:26 */ package org.ikt502.btwt.gui; import javax.bluetooth.LocalDevice; import javax.microedition.lcdui.*; import org.ikt502.btwt.*; /** * Bluetooth Walkie-Talkie GUI Controller class * * @authors Aleksander Albretsen and Morten Krakvik */ public class BtwtGUI implements CommandListener { /** * Parent BTWT object */ private BTWT btwt; /** * User */ private private private private private private private

interface objects EnterNickUI ChatUI DebugUI SelectChatTypeUI EnterTextUI RecordAudioUI RecordPictureUI enterNickUI; chatUI; debugUI; selectChatTypeUI; enterTextUI; recordAudioUI; recordPictureUI;

/** * Variables used to suppress repeating commands */ private Command prevCommand; private Displayable prevDisplayable; /** * Construct a new GUI Controller * * @param btwt Ref. to BTWT main object. */ public BtwtGUI(BTWT btwt) { //Store ref. to parent this.btwt = btwt; //Create all GUI enterNickUI chatUI debugUI selectChatTypeUI enterTextUI recordAudioUI recordPictureUI objects... = new EnterNickUI(this); = new ChatUI(this); = new DebugUI(this); = new SelectChatTypeUI(this); = new EnterTextUI(this); = new RecordAudioUI(this); = new RecordPictureUI(this);

//Init command. prevCommand = new Command("Dummy", Command.ITEM, 0); //Load first GUI menu... enterNickUI.show(); //Add this GUI to the MessageHandler MessageHandler.setGUI(this); } /** * Show message on chat user interface */ public void addMessage(String s) { chatUI.addMessage(s); } /** * Show message on debug interface */ public void addDebugMessage(String s) { debugUI.addMessage(s); } /** * Called by the system to indicate that a command has been invoked on a particular displayable. * * @param command the Command that ws invoked * @param displayable the Displayable on which the command was invoked

v1.0

43

./org/ikt502/btwt/gui/BtwtGUI.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: **/ public synchronized void commandAction(Command command, Displayable displayable) { //Do not allow repeat commands... if (prevCommand.getLabel().equals(command.getLabel()) && prevDisplayable == displayable) return; prevCommand = command; prevDisplayable = displayable; if( displayable == enterNickUI ) { handleEnterNick( command ); } else if( displayable == chatUI ) { handleChat( command ); } else if( displayable == selectChatTypeUI ) { handleSelectChatType( command ); } else if( displayable == enterTextUI ) { handleEnterText( command ); } else if( displayable == recordAudioUI ) { handleRecordAudio( command ); } else if( displayable == recordPictureUI ) { handleRecordPicture( command ); } else if( displayable == debugUI ) { handleDebug( command ); } } /** * Return the MIDlets display */ public Display getDisplay() { return btwt.getDisplay(); } /** * Show the chat window. */ public void showChatWindow() { chatUI.show(); } /** * Handle commands form the enter nick screen * * @param command Command from CommandListener */ private void handleEnterNick( Command command ) { if (command.getLabel().equals("Continue")) { // Validate nickname if (enterNickUI.isValidNick()) { // Join bluetooth network (NetLayer) btwt.joinNetwork(enterNickUI.getNick()); // Show chat user interface chatUI.show(); } } } /** * Handle commands form the chat screen * * @param command Command from CommandListener */ private void handleChat( Command command ) { // user pressed new message if (command.getLabel().equals("New Message")) { selectChatTypeUI.show(); } // user pressed bluetooth info else if (command.getLabel().equals("Phone Info")) { Alert alert = new Alert( "Phone information", "Phone memory: " + Runtime.getRuntime().totalMemory() + "\n\n" +

44

v1.0

./org/ikt502/btwt/gui/BtwtGUI.java
187: "api.version: " + LocalDevice.getProperty("bluetooth.api.version") + "\n\n" + 188: "connected.devices.max: " + LocalDevice.getProperty("bluetooth.connected.devices.ma x") + "\n\n" + 189: "supports.audio.capture: " + System.getProperty("supports.audio.capture") + "\n\n" + 190: "supports.video.capture: " + System.getProperty("supports.video.capture") + "\n\n" + 191: "supports.recording: " + System.getProperty("supports.recording") + "\n\n" + 192: "video.snapshot.encodings: " + System.getProperty("video.snapshot.encodings") + "\ n\n" + 193: "video.encodings: " + System.getProperty("video.encodings") + "\n\n" + 194: "audio.encodings: " + System.getProperty("audio.encodings") 195: , null, AlertType.INFO ); 196: alert.setTimeout( Alert.FOREVER ); 197: getDisplay().setCurrent( alert, chatUI ); 198: } 199: // user pressed about 200: else if (command.getLabel().equals("About")) 201: { 202: Alert alert = new Alert( "About", "Bluetooth Walkie-Talkie, demo application. Created by Aleksander Albretsen and Morten Krkvik for Agder Mobility Lab.\n\nCodes are based on: \nBlueChat 1.0. By Ben Hui (c) 2004. Visit www .benhui.net for more mobile dev resources.", null, AlertType.INFO ); 203: alert.setTimeout( Alert.FOREVER ); 204: getDisplay().setCurrent( alert, chatUI ); 205: } 206: // user pressed show debug 207: else if (command.getLabel().equals("Show Debug")) 208: { 209: debugUI.show(); 210: } 211: // user pressed exit 212: else if (command.getLabel().equals("Exit")) 213: { 214: btwt.quitApp(); 215: } 216: } 217: 218: /** 219: * Handle commands form the select chat type screen 220: * 221: * @param command Command from CommandListener 222: */ 223: private void handleSelectChatType( Command command ) 224: { 225: // user pressed back 226: if (command.getLabel().equals("Back")) 227: { 228: chatUI.show(); 229: } 230: else 231: { 232: //Text 233: if (selectChatTypeUI.isSelected(SelectChatTypeUI.TEXT_MESSAGE)) 234: { 235: enterTextUI.show(); 236: } 237: 238: //Audio 239: else if (selectChatTypeUI.isSelected(SelectChatTypeUI.AUDIO_MESSAGE)) 240: { 241: recordAudioUI.show(); 242: } 243: 244: //Picture 245: else if (selectChatTypeUI.isSelected(SelectChatTypeUI.PICTURE_MESSAGE)) 246: { 247: recordPictureUI.show(); 248: } 249: } 250: } 251: 252: /** 253: * Handle commands form the enter text screen 254: * 255: * @param command Command from CommandListener 256: */ 257: private void handleEnterText( Command command ) 258: { 259: // user pressed back 260: if (command.getLabel().equals("Back")) 261: { 262: chatUI.show(); 263: } 264: 265: // user pressed send 266: else if (command.getLabel().equals("Send")) 267: { 268: btwt.sendTextMessage(enterTextUI.getString()); 269: chatUI.show(); 270: } 271: } 272: 273: /**

v1.0

45

./org/ikt502/btwt/gui/BtwtGUI.java
274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: * Handle commands form the record audio screen * * @param command Command from CommandListener */ private void handleRecordAudio( Command command ) { // user pressed back if (command.getLabel().equals("Back")) { //Go back to chat window... chatUI.show(); } else if( command.getLabel().equals( "Start" ) ) { // Start recording... recordAudioUI.getRecorder().startRecording(); } else if( command.getLabel().equals( "Stop" ) ) { // Start recording and send when done... recordAudioUI.getRecorder().stopRecording(); } else if( command.getLabel().equals( "Send" ) ) { // Start recording and send when done... recordAudioUI.getRecorder().sendRecordedMessage(); } else if( command.getLabel().equals( "OK" ) ) { //Go back to chat window... chatUI.show(); } } /** * Handle commands form the record picture screen * * @param command Command from CommandListener */ private void handleRecordPicture( Command command ) { // user pressed back if (command.getLabel().equals("Back")) { //Show Chat window... chatUI.show(); } // user pressed capture else if (command.getLabel().equals("Capture")) { //Stop Camera... recordPictureUI.getRecorder().takeSnapshot(); } // user pressed send else if (command.getLabel().equals("Send")) { //Stop Camera... recordPictureUI.getRecorder().sendPicture(); } // user pressed OK else if (command.getLabel().equals("OK")) { //Show Chat window... chatUI.show(); } } /** * Handle commands form the debug screen * * @param command Command from CommandListener */ private void handleDebug( Command command ) { // user pressed back if (command.getLabel().equals("Back")) { chatUI.show(); } } /** * Get ref. to BTWT main object * * @return BTWT main object */ public BTWT getBTWT() { return btwt; }

46

v1.0

./org/ikt502/btwt/gui/BtwtGUI.java
367: 368: 369: 370: 371: 372: 373: 374: 375: 376: } /** * Log string, for debug purposes */ public void log(String s) { addDebugMessage("UI: " + s); System.out.println("UI: " + s); }

v1.0

47

./org/ikt502/btwt/gui/ImageViewerUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: package org.ikt502.btwt.gui; import import import import import import javax.microedition.lcdui.Command; javax.microedition.lcdui.CommandListener; javax.microedition.lcdui.Displayable; javax.microedition.lcdui.Form; javax.microedition.lcdui.Image; javax.microedition.lcdui.StringItem;

/** * Form with the ability to show an image * * @authors Aleksander Albretsen and Morten Krkvik */ public class ImageViewerUI extends Form implements CommandListener { /** * Storage for the image */ private byte[] picture; /** * Whom the picture is from */ private String from; /** * ref. to GUI controller */ private BtwtGUI gui; /** * Construct a new ImageViewerUI * * @param picture The picture * @param from Nick name to whom the picture is from * @param parent Ref. to GUI controller. */ public ImageViewerUI(byte[] picture, String from, BtwtGUI gui) { //Call usper super("Bluetooth Walkie-Talkie"); //Store... this.picture = picture; this.from = from; this.gui = gui; //Add OK button addCommand(new Command("Close", Command.EXIT, 1)); //Set CommandListener setCommandListener(this); } /** * Make this UI the visible UI */ public void show() { this.append( new StringItem("Picture from " + from + "", "")); this.append( Image.createImage( picture, 0, picture.length) ); gui.getDisplay().setCurrent(this); } /** * Return to the Chat UI when the user presses a key */ public void commandAction(Command arg0, Displayable arg1) { gui.showChatWindow(); } }

48

v1.0

./org/ikt502/btwt/gui/SelectChatTypeUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: package org.ikt502.btwt.gui; import javax.microedition.lcdui.*; /** * Through this dialog the user can select what type of message to send * * @authors Aleksander Albretsen and Morten Krkvik */ public class SelectChatTypeUI extends List { /** * */ public static int TEXT_MESSAGE = 0; public static int AUDIO_MESSAGE = 1; public static int PICTURE_MESSAGE = 2; /** * */ private BtwtGUI parent; /** * Construct new SelectChatTypeUI * * @param parent Ref. to GUI controller. */ public SelectChatTypeUI(BtwtGUI parent) { //Super super("Select message type:", Choice.IMPLICIT, new java.lang.String[] { "Text Message", "Audio Message", "Picture Message" }, new javax.microedition.lcdui.Image[] { null, null, null }); setCommandListener(parent); setSelectedFlags(new boolean[] { false, false, false }); //Add COMMANDS addCommand(new Command("Select", Command.OK, 1)); addCommand(new Command("Back", Command.BACK, 2)); //Set CommandListener setCommandListener( parent ); //Add ref. to parent GUI this.parent = parent; } /** * Make this UI the visible UI */ public void show() { parent.getDisplay().setCurrent(this); } }

v1.0

49

./org/ikt502/btwt/gui/RecordAudioUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.gui; import javax.microedition.lcdui.*; import org.ikt502.btwt.*; /** * RecorderAudioUI controlls the audio recorder * * @authors Aleksander Albretsen and Morten Krkvik */ public class RecordAudioUI extends Form { /** * Possible "States" for this Form... */ public static final int START = 0; public static final int RECORDING = 1; public static final int READY_TO_SEND = 2; public static final int SENDT = 4; public static final int FAILED = 5; /** * Command to be shown at the first button... * Only one of these commands are used at the same time... */ private Command start; private Command stop; private Command send; private Command ok; /** * ref. to GUI controller */ private BtwtGUI parent; /** * The AudioRecorder */ private AudioRecorder recorder; /** * Construct new RecordAudioUI * * @param parent Ref. to GUI controller. */ public RecordAudioUI(BtwtGUI parent) { //Create Form... super("Bluetooth Walkie-Talkie"); //Only one of these are used start = new Command("Start", stop = new Command("Stop", send = new Command("Send", ok = new Command("OK", at the same Command.OK, Command.OK, Command.OK, Command.OK, time... 1); 1); 1); 1);

//Always show "Back" command... addCommand(new Command("Back", //Add command listener... setCommandListener( parent );

Command.BACK, 2));

//Create recorder recorder = new AudioRecorder(parent.getBTWT(), this); //Add ref. to parent GUI this.parent = parent; } /** * Fetch the recorder object * * @return the Audio Recorder */ public AudioRecorder getRecorder() { return recorder; } /** * Fetch the UI Controller object * * @return the UI Controller */ public BtwtGUI getParent() { return this.parent; } /** * Set the current state * * (0) START

: Ready to start recording.

50

v1.0

./org/ikt502/btwt/gui/RecordAudioUI.java
94: * (1) RECORDING : AudioRecorder is recording. 95: * (2) READY_TO_SEND : Recording finished, ready to send the recorded audio message. 96: * (3) SENDT : Audio message sendt. 97: * (4) FAILED : Used to inform the user that an error has occured. 98: * 99: * @param cmd Integer code for the state 100: */ 101: public void setState(int cmd) 102: { 103: //Clear Screen... 104: this.deleteAll(); 105: 106: switch (cmd) 107: { 108: case START: 109: //Show text 110: append( new StringItem("Record Audio Message", "\n\nPress Start to start recordin g.") ); 111: //Fix command list 112: removeCommand(stop); 113: removeCommand(ok); 114: removeCommand(send); 115: addCommand(start); 116: break; 117: 118: case RECORDING: 119: //Show text 120: append( new StringItem("Record Audio Message", "\n\nRecording...\nPress Stop when you are finnished to stop recording.") ); 121: //Fix command list 122: removeCommand(start); 123: removeCommand(ok); 124: removeCommand(send); 125: addCommand(stop); 126: break; 127: 128: case READY_TO_SEND: 129: //Show text 130: append( new StringItem("Record Audio Message", "\n\nDone...\nPress Send to send t he recorded message.") ); 131: //Fix command list 132: removeCommand(stop); 133: removeCommand(start); 134: removeCommand(ok); 135: addCommand(send); 136: break; 137: 138: case SENDT: 139: //Show text 140: append( new StringItem("Record Audio Message", "\n\nYour message is now transmittin g to the other peers... Press OK to continue.") ); 141: //Fix command list 142: removeCommand(stop); 143: removeCommand(start); 144: removeCommand(send); 145: addCommand(ok); 146: break; 147: 148: case FAILED: 149: //Show text 150: append( new StringItem("Record Audio Message", "\n\nAn error occured while recordin g... Press OK to continue.") ); 151: //Fix command list 152: removeCommand(stop); 153: removeCommand(start); 154: removeCommand(send); 155: addCommand(ok); 156: break; 157: } 158: } 159: 160: /** 161: * Make this UI the visible UI 162: */ 163: public void show() 164: { 165: setState(START); 166: parent.getDisplay().setCurrent(this); 167: } 168: }

v1.0

51

./org/ikt502/btwt/gui/MessageHandler.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: package org.ikt502.btwt.gui; /** * Since Ben Hui uses a lot of static methods, * we have implemented this class as a layer between * our code and his to show messages in our GUI. * * @authors Aleksander Albretsen and Morten Krkvik */ public class MessageHandler { /** * Ref. to the UI controller */ private static BtwtGUI gui; /** * Set ref. to the UI controller * * @param gui The GUI controller. */ public static void setGUI(BtwtGUI gui) { MessageHandler.gui = gui; } /** * Add message to the ChatUI * * @param s String to add */ public static void addMessage(String s) { if (gui != null) { gui.addMessage(s); } } /** * Add message to the DebugUI * * @param s String to add */ public static void addDebugMessage(String s) { if (gui != null) { gui.addDebugMessage(s); } } }

52

v1.0

./org/ikt502/btwt/gui/EnterTextUI.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: package org.ikt502.btwt.gui; import javax.microedition.lcdui.*; /** * TextBox used to enter a new text message * * @authors Aleksander Albretsen and Morten Krkvik */ public class EnterTextUI extends TextBox { /** * ref. to GUI controller */ private BtwtGUI parent; /** * Construct new EnterTextUI * * @param parent Ref. to GUI controller. */ public EnterTextUI(BtwtGUI parent) { //Create Form... super("Enter Message", "", 200, TextField.ANY); addCommand(new Command("Send", Command.OK, 1)); addCommand(new Command("Back", Command.BACK, 2)); setCommandListener( parent ); //Add ref. to parent GUI this.parent = parent; } /** * Make this UI the visible UI */ public void show() { parent.getDisplay().setCurrent(this); } }

v1.0

53

./org/ikt502/btwt/BTWT.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: /* * BTWT.java * * Created on 21. oktober 2005, 13:35 */ package org.ikt502.btwt; import java.io.ByteArrayOutputStream; import java.io.InputStream; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import org.ikt502.btwt.gui.*; import org.ikt502.btwt.network.*; /** * Bluetooth Walkie-Talkie MIDlet * * @authors Aleksander Albretsen and Morten Krakvik */ public class BTWT extends MIDlet implements BTListener { /** * Ref. to the MIDlets display */ Display display; /** * Ref. to the GUI controller */ BtwtGUI gui; /** * Ref. to the Network Layer */ NetLayer btnet; /** * Create a new BlueTooth walkie-talkie. */ public BTWT() { super(); display = Display.getDisplay(this); } /** * MIDlet is starting... * @see MIDlet */ public void startApp() throws MIDletStateChangeException { //Create and show GUI gui = new BtwtGUI(this); } /** * MIDlet paused * @see MIDlet */ public void pauseApp() { } /** * MIDlet is closing * @see MIDlet */ public void destroyApp(boolean unconditional) throws MIDletStateChangeException { } /** * Return the MIDlets display */ public Display getDisplay() { return display; } /** * Close MIDlet */ public void quitApp() { //Disconnect... btnet.disconnect(); //Close Midlet try {

54

v1.0

./org/ikt502/btwt/BTWT.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: this.destroyApp(true); this.notifyDestroyed(); } catch(Exception e) { e.printStackTrace(); } } /** * Tel Network Layer to join avalible Chat Room * * @param nick String containing the users nickname. */ public void joinNetwork(String nick) { // user enters virtual chat room. // create and initialize Bluetooth network layer btnet = new NetLayer(); log("Set local nick name to: "+nick); // initialize the network layer. This will start the local BlueChat server btnet.init( nick, this ); // search for existing BlueChat nodes btnet.query(); } /** * Tell NetworkLayer to send a tekst message * * @param s String containing message */ public void sendTextMessage(String s) { btnet.sendString(s); } /** * Tell NetworkLayer to send a audio message * * @param stream Stream containing audio message */ public void sendAudio(ByteArrayOutputStream stream, String contentType) { btnet.sendAudio(stream, contentType); } /** * Tell NetworkLayer to send a picture message * * @param picture byte array containing picture */ public void sendPicture(byte[] picture) { log("BTWT::sendPicture()"); btnet.sendPicture(picture); } /** * Create a AudioPlayer and play the received message */ private synchronized void playAudioMessage(InputStream stream, String contentType, String from) { AudioPlayer player = new AudioPlayer(gui, stream, contentType, from); player.start(); } /** * Create a ImageViewer and view the received picture */ private synchronized void showPicture(byte[] picture, String from) { ImageViewerUI viewer = new ImageViewerUI(picture, from, gui); viewer.show(); } /** * Actions from Network Layer... */ public void handleAction(String event, Object param1, Object param2) { log("invoke handleAction. action="+event); if ( event.equals( BTListener.EVENT_JOIN ) ) { // a new user has join the chat room EndPoint endpt = (EndPoint) param1; gui.addMessage ( endpt.remoteName + " joins the chat room" ); } else if ( event.equals( BTListener.EVENT_SENT ) ) { // nothing to do

v1.0

55

./org/ikt502/btwt/BTWT.java
187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: } } else if ( event.equals( BTListener.EVENT_RECEIVED ) ) { // a new message has received from a remote user EndPoint endpt = (EndPoint) param1; ChatPacket msg = (ChatPacket) param2; //Type of message ? if (msg.signal == NetLayer.SIGNAL_MESSAGE) { gui.addMessage(endpt.remoteName + ": " + msg.msg); } else if (msg.signal == NetLayer.SIGNAL_AUDIO_MESSAGE) { playAudioMessage(msg.streamIn, msg.contentType, endpt.remoteName); } else if (msg.signal == NetLayer.SIGNAL_PICTURE_MESSAGE) { showPicture(msg.picture, endpt.remoteName); } } else if ( event.equals( BTListener.EVENT_LEAVE ) ) { // a user has leave the chat room EndPoint endpt = (EndPoint) param1; gui.addMessage ( endpt.remoteName + " leaves the chat room" ); } } /** * Log string, for debug purposes */ private void log(String s) { gui.addDebugMessage(s); System.out.println("BTWT: " + s); }

56

v1.0

./org/ikt502/btwt/network/ChatPacket.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.network; import java.io.ByteArrayOutputStream; import java.io.InputStream; /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * A holder object for BlueChat network packet data. * <p>Description: ChatPacket can represent severl type of message, which is defined * by NetLayer.SIGNAL_XXX enumeration. The common type is SIGNAL_MESSAGE, which * hold an user entered message to sent across the virtual chat room.</p> * <p>Copyright: Copyright (c) 2003</p> * @author Ben Hui * @version 1.0 */ public class ChatPacket { /** * signal, must be one of NetLayer.SIGNAL_XXX */ public int signal; /** * indicate the nick name of the sender */ public String sender; /** * Storage for a text message */ public String msg; /** * Content-Type of audio stream */ public String contentType; /** * Storage for an outgoing audio stream */ public ByteArrayOutputStream streamOut; /** * Storage for a picture */ public byte[] picture; /** * Storage for an incoming audio stream */ public InputStream streamIn; /** * Create a new outgoing ChatPacket with TextMessage * * @param signal Signal Type * @param msg Text message */ public ChatPacket(int signal, String msg) { this.signal = signal; this.msg = msg; } /** * Create a new incoming ChatPacket with TextMessage * * @param signal Signal Type * @param sender Whom it is from * @param msg Text message */ public ChatPacket(int signal, String sender, String msg) { this.signal = signal; this.sender = sender; this.msg = msg; } /** * Create a new outgoing ChatPacket with AudioMessage * * @param signal Signal Type

v1.0

57

./org/ikt502/btwt/network/ChatPacket.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: } * @param stream Audio stream in audio message * @param contentType Content-Type of the audio stream */ public ChatPacket(int signal, ByteArrayOutputStream stream, String contentType) { this.signal = signal; this.streamOut = stream; this.contentType = contentType; } /** * Create a new incoming ChatPacket with AudioMessage * * @param signal Signal Type * @param sender Whom it is from * @param stream Audio stream in audio message * @param contentType Content-Type of the audio stream */ public ChatPacket(int signal, String sender, InputStream stream, String contentType) { this.signal = signal; this.sender = sender; this.streamIn = stream; this.contentType = contentType; } /** * Create a new outgoing ChatPacket with PictureMessage * * @param signal Signal Type * @param picture Picture in picture message */ public ChatPacket(int signal, byte[] picture) { this.signal = signal; this.picture = picture; } /** * Create a new incoming ChatPacket with PictureMessage * * @param signal Signal Type * @param sender Whom it is from * @param picture Picture in picture message */ public ChatPacket(int signal, String sender, byte[] picture) { this.sender = sender; this.signal = signal; this.picture = picture; } /** * Create new emty ChatPacket */ public ChatPacket() { }

58

v1.0

./org/ikt502/btwt/network/Util.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.network; import javax.bluetooth.*; import java.util.Enumeration; import java.io.IOException; import java.util.Vector; import org.ikt502.btwt.gui.MessageHandler; /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * <p>Title: A utility class to dump JABWT object contents</p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2002</p> * @author Ben Hui * @version 1.0 */ public class Util { private Util() { } private static void log( String s ) { System.out.println( s ); MessageHandler.addDebugMessage( "U: " + s ); } public static void printRemoteDevice( RemoteDevice dev, DeviceClass devClass ) { try { log("Print Remote Device "+dev.getBluetoothAddress()); log("Name: "+dev.getFriendlyName( true ) ); log("Auth: "+dev.isAuthenticated()+" Encrypted: "+dev.isEncrypted()+" Trusted: "+dev.isTrustedDevice() ); if ( devClass != null ) { log("MajorDevice:" + majorToName(devClass.getMajorDeviceClass())); log("MinorDevice:" + minorToName(devClass.getMajorDeviceClass(), devClass.getMinorDeviceClass())); log("ServiceClass:"); String[] str = Util.majorServiceToName(devClass.getServiceClasses()); for (int i = 0; i < str.length; i++) { log(" " + str[i]); } } } catch (IOException e) { } } public static void printLocalDevice( LocalDevice dev ) { log("Print Local Device "+dev.getBluetoothAddress()); log("Name: "+dev.getFriendlyName()); DeviceClass devClass = dev.getDeviceClass(); if ( devClass != null ) { log("MajorDevice:" + majorToName(devClass.getMajorDeviceClass())); log("MinorDevice:" + minorToName(devClass.getMajorDeviceClass(), devClass.getMinorDeviceClass())); log("ServiceClass:"); String[] str = Util.majorServiceToName(devClass.getServiceClasses()); for (int i = 0; i < str.length; i++) { log(" " + str[i]); } } } /* public static void printDeviceClass( DeviceClass d ) { log("Print Device Class "+d.toString()); }

v1.0

59

./org/ikt502/btwt/network/Util.java
94: */ 95: public static void printServiceRecord( ServiceRecord r ) 96: { 97: int[] ids = r.getAttributeIDs(); 98: log("Print Service Record (# of element: "+ids.length+")"); 99: log("Print Service Record URL "+r.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false ) ); 100: 101: 102: for ( int i=0; i < ids.length; i++ ) 103: { 104: DataElement el = r.getAttributeValue( ids[i] ); 105: printDataElement( el, ids[i], "" ); 106: } 107: } 108: 109: public static void printDataElement( DataElement e, int id, String indent ) 110: { 111: int type = e.getDataType(); 112: if ( type == DataElement.DATALT || type == DataElement.DATSEQ ) 113: { 114: Enumeration enumeration = (Enumeration)e.getValue(); 115: log(indent+"DataElement["+idToName(id)+"] "+type+" (# of element: "+e.getSize()+")"); 116: while ( enumeration.hasMoreElements() ) 117: { 118: DataElement e2 = (DataElement)enumeration.nextElement(); 119: printDataElement( e2, id, indent+" " ); 120: } 121: } else if ( type == DataElement.U_INT_1 || type == DataElement.U_INT_2 || type == DataElement.U_INT_4 || 122: type == DataElement.INT_1 || type == DataElement.INT_2 || type == DataElement.INT_4 || type == Da taElement.INT_8 ) 123: { 124: long v = e.getLong(); 125: log(indent+"DataElement["+idToName(id)+"] "+v); 126: } else if ( type == DataElement.UUID ) 127: { 128: UUID uuid = (UUID) e.getValue(); 129: log(indent+"DataElement["+idToName(id)+"] "+ uuidToName(uuid) ); 130: } else if ( type == DataElement.U_INT_8 || type == DataElement.U_INT_16 || type == DataElement.INT_16 ) 131: { 132: byte[] v = (byte[]) e.getValue(); 133: String s = ""; 134: for ( int i=0; i< v.length; i++ ) 135: { 136: s+= Integer.toHexString( (int) v[i] ); 137: } 138: log(indent+"DataElement["+idToName(id)+"] "+s ); 139: 140: } else if ( type == DataElement.STRING || type == DataElement.URL ) 141: { 142: String v = (String) e.getValue(); 143: log(indent+"DataElement["+idToName(id)+"] "+v ); 144: 145: } else if ( type == DataElement.BOOL ) 146: { 147: boolean v = e.getBoolean(); 148: log(indent+"DataElement["+idToName(id)+"] "+ String.valueOf( v)); 149: 150: } else if ( type == DataElement.NULL ) 151: { 152: log(indent+"DataElement["+idToName(id)+"] NULL"); 153: 154: } 155: 156: } 157: 158: // convert Attribute ID to human friendly name 159: public static String idToName( int id ) 160: { 161: if ( id == 0x0000 ) 162: { 163: return "ServiceRecordHandle"; 164: } else if ( id == 0x0001 ) 165: { 166: return "ServiceClassIDList"; 167: 168: } else if ( id == 0x0002 ) 169: { 170: return "ServiceRecordState"; 171: } else if ( id == 0x0003 ) 172: { 173: return "ServiceID"; 174: } else if ( id == 0x0004 ) 175: { 176: return "ProtocolDescriptorList"; 177: } else if ( id == 0x0005 ) 178: { 179: return "BrowseGroupList"; 180: } else if ( id == 0x0006 ) 181: { 182: return "LanguageBasedAttributeIDList"; 183: } else if ( id == 0x0007 ) 184: { 185: return "ServiceInfoTimeToLive";

60

v1.0

./org/ikt502/btwt/network/Util.java
186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: } else if ( id == 0x0008 ) { return "ServiceAvailability"; } else if ( id == 0x0009 ) { return "BluetoothProfileDescriptorList"; } else if ( id == 0x000A ) { return "DocumentationURL"; } else if ( id == 0x000B ) { return "ClientExecutableURL"; } else if ( id == 0x000C ) { return "IconURL"; } else if ( id == 0x000D ) { return "AdditionalProtocol"; } else if ( id == 0x0100 ) { return "ServiceName"; } else if ( id == 0x0101 ) { return "ServiceDescription"; } else if ( id == 0x0102 ) { return "ProviderName"; } else if ( id == 0x0200 ) { /** @todo why the spec say it is GroupID, IpSubnet and VersionNumberList as well? */ return "GroupID"; } else if ( id == 0x0201 ) { return "ServiceDatabaseState"; } else if ( id == 0x0300 ) { return "ServiceVersion"; } else if ( id == 0x0301 ) { return "ExternalNetwork"; } else if ( id == 0x0302 ) { // @todo or FaxClass1Support in case of Fax Profile return "RemoteAudioVolumeControl"; } else if ( id == 0x0303 ) { // @todo or FaxClass2Support in case of Fax Profile return "SupportedFormatList"; } else if ( id == 0x0304 ) { return "FaxClass2Support"; } else if ( id == 0x0305 ) { return "AudioFeedbackSupport"; } else if ( id == 0x0306 ) { return "NetworkAddress"; } else if ( id == 0x0307 ) { return "WAPGateway"; } else if ( id == 0x0308 ) { return "HomePageURL"; } else if ( id == 0x0309 ) { return "WAPStackType"; } else if ( id == 0x030A ) { return "SecurityDescription"; } else if ( id == 0x030B ) { return "NetAccessType"; } else if ( id == 0x030C ) { return "MaxNetAccessrate"; } else if ( id == 0x030D ) { return "IPv4Subnet"; } else if ( id == 0x030E ) { return "IPv6Subnet"; } else if ( id == 0x0310 ) { return "SupportedCapabalities"; } else if ( id == 0x0311 ) { return "SupportedFeatures"; } else if ( id == 0x0312 ) { return "SupportedFunctions"; } else if ( id == 0x0313 ) {

v1.0

61

./org/ikt502/btwt/network/Util.java
279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: return "TotalImagingDataCapacity"; } else { return "UnknownAttribute("+id+")"; } } public static String uuidToName( UUID u ) { if ( u.equals( new UUID( 0x0001 ) )) return "SDP"; else if ( u.equals( new UUID( 0x0003 ) )) return "RFCOMM"; else if ( u.equals( new UUID( 0x0008 ) )) return "OBEX"; else if ( u.equals( new UUID( 0x000C ) )) return "HTTP"; else if ( u.equals( new UUID( 0x0100 ) )) return "L2CAP"; else if ( u.equals( new UUID( 0x000F ) )) return "BNEP"; else if ( u.equals( new UUID( 0x1000 ) )) return "ServiceDiscoveryServerServiceClassID"; else if ( u.equals( new UUID( 0x1001 ) )) return "BrowseGroupDescriptorCerviceClassID"; else if ( u.equals( new UUID( 0x1002 ) )) return "PublicBrowseGroup"; else if ( u.equals( new UUID( 0x1101 ) )) return "SerialPort"; else if ( u.equals( new UUID( 0x1102 ) )) return "LANAccessUsingPPP"; else if ( u.equals( new UUID( 0x1103 ) )) return "DialupNetworking"; else if ( u.equals( new UUID( 0x1104 ) )) return "IrMCSync"; else if ( u.equals( new UUID( 0x1105 ) )) return "OBEX ObjectPushProfile"; else if ( u.equals( new UUID( 0x1106 ) )) return "OBEX FileTrasnferProfile"; else if ( u.equals( new UUID( 0x1107 ) )) return "IrMCSyncCommand"; else if ( u.equals( new UUID( 0x1108 ) )) return "Headset"; else if ( u.equals( new UUID( 0x1109 ) )) return "CordlessTelephony"; else if ( u.equals( new UUID( 0x110A ) )) return "AudioSource"; else if ( u.equals( new UUID( 0x1111 ) )) return "Fax"; else if ( u.equals( new UUID( 0x1112 ) )) return "HeadsetAudioGateway"; else if ( u.equals( new UUID( 0x1115 ) )) return "PersonalAreaNetworkingUser"; else if ( u.equals( new UUID( 0x1116 ) )) return "NetworkAccessPoint"; else if ( u.equals( new UUID( 0x1117 ) )) return "GroupNetwork"; else if ( u.equals( new UUID( 0x111E ) )) return "Handsfree"; else if ( u.equals( new UUID( 0x111F ) )) return "HandsfreeAudioGateway"; else if ( u.equals( new UUID( 0x1201 ) )) return "GenericNetworking"; else if ( u.equals( new UUID( 0x1202 ) )) return "GenericFileTransfer"; else if ( u.equals( new UUID( 0x1203 ) )) return "GenericAudio"; else if ( u.equals( new UUID( 0x1204 ) )) return "GenericTelephony"; else return u.toString(); } public static String majorToName( int d ) { if ( d == 0x0000 ) return "Miscellaneous"; else if ( d == 0x0100) return "Computer"; else if ( d == 0x0200 ) return "Phone"; else if ( d == 0x0300 ) return "LANAccessPoint"; else if ( d == 0x0400 ) return "AudioVideo"; else if ( d == 0x0500 ) return "Peripheral"; else if ( d == 0x0600 ) return "Imaging"; else if ( d == 0x1F00 ) return "Uncategorized"; else return "UnknownMajorDevice("+d+")";

62

v1.0

./org/ikt502/btwt/network/Util.java
372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: } /** * * @param d major device class * @param m minor device class * @return */ public static String minorToName( int d, int m ) { if ( d == 0x0000 ) return "Miscellaneous"; else if ( d == 0x0100 && m == 0x00 ) return "Uncategorized"; else if ( d == 0x0100 && m == 0x04 ) return "Workstation"; else if ( d == 0x0100 && m == 0x08 ) return "Server"; else if ( d == 0x0100 && m == 0x0C ) return "Laptop"; else if ( d == 0x0100 && m == 0x10 ) return "HandheldPcPda"; else if ( d == 0x0100 && m == 0x14 ) return "PalmPcPda"; else if ( d == 0x0100 && m == 0x18 ) return "Wearable"; else if ( d == 0x0200 && m == 0x00 ) return "Uncategorized"; else if ( d == 0x0200 && m == 0x04 ) return "Cellular"; else if ( d == 0x0200 && m == 0x08 ) return "Cordless"; else if ( d == 0x0200 && m == 0x0C ) return "SmartPhone"; else if ( d == 0x0200 && m == 0x10 ) return "Modem"; else if ( d == 0x0200 && m == 0x14 ) return "ISDN"; else if ( d == 0x0300 && m == 0x00 ) return "FullyAvailable"; else if ( d == 0x0300 && m == 0x20 ) return "1to17%Utilized"; else if ( d == 0x0300 && m == 0x40 ) return "17to33%Utilized"; else if ( d == 0x0300 && m == 0x60 ) return "33to50%Utilized"; else if ( d == 0x0300 && m == 0x80 ) return "50to67%Utilized"; else if ( d == 0x0300 && m == 0xA0 ) return "67to83%Utilized"; else if ( d == 0x0300 && m == 0xC0 ) return "83to100%Utilized"; else if ( d == 0x0300 && m == 0xE0 ) return "NoServiceAvailable"; else if ( d == 0x0400 && m == 0x00 ) return "Uncategorized"; else if ( d == 0x0400 && m == 0x04 ) return "Headset"; else if ( d == 0x0400 && m == 0x08 ) return "HandsFree"; else if ( d == 0x0400 && m == 0x0C ) return "(Reserved)"; else if ( d == 0x0400 && m == 0x10 ) return "Microphone"; else if ( d == 0x0400 && m == 0x14 ) return "Loudspeaker"; else if ( d == 0x0400 && m == 0x18 ) return "Headphones"; else if ( d == 0x0400 && m == 0x1C ) return "PortableAudio"; else if ( d == 0x0400 && m == 0x20 ) return "CarAudio"; else if ( d == 0x0400 && m == 0x24 ) return "SetTopBox"; else if ( d == 0x0400 && m == 0x28 ) return "HiFiAudioDevice"; else if ( d == 0x0400 && m == 0x2C ) return "VCR"; else if ( d == 0x0400 && m == 0x30 ) return "VideoCamera"; else if ( d == 0x0400 && m == 0x34 ) return "Camcorder"; else if ( d == 0x0400 && m == 0x38 ) return "VideoMonitor"; else if ( d == 0x0400 && m == 0x3C ) return "VideoDisplayAndLoudspeaker"; else if ( d == 0x0400 && m == 0x40 ) return "VideoConferencing"; else if ( d == 0x0400 && m == 0x44 ) return "(Reserved)"; else if ( d == 0x0400 && m == 0x48 ) return "GamingToy"; else if ( d == 0x0500 && m == 0x00)

v1.0

63

./org/ikt502/btwt/network/Util.java
465: return "Uncategoried"; 466: else if ( d == 0x0500 && m == 0x04) 467: return "Joystick"; 468: else if ( d == 0x0500 && m == 0x08) 469: return "Gamepad"; 470: else if ( d == 0x0500 && m == 0x0C) 471: return "RemoteControl"; 472: else if ( d == 0x0500 && m == 0x10) 473: return "SensingDevice"; 474: else if ( d == 0x0500 && m == 0x14) 475: return "DigitizerTablet"; 476: else if ( d == 0x0500 && m == 0x18) 477: return "CardReader"; 478: else if ( d == 0x0500 && m == 0x40) 479: return "Keyboard"; 480: else if ( d == 0x0500 && m == 0x80) 481: return "PointingDevice"; 482: else if ( d == 0x0500 && m == 0xC0) 483: return "KeyboardPointingDevice"; 484: else if ( d == 0x0600 && m == 0x10) 485: return "Display"; 486: else if ( d == 0x0600 && m == 0x20) 487: return "Camera"; 488: else if ( d == 0x0600 && m == 0x40) 489: return "Scanner"; 490: else if ( d == 0x0600 && m == 0x80) 491: return "Printer"; 492: else if ( d == 0x1F00 ) 493: return "Uncategorized("+m+")"; 494: else 495: return "UnknownMinorDevice("+m+")"; 496: 497: } 498: 499: public static String[] majorServiceToName( int d ) 500: { 501: Vector v = new Vector(); 502: 503: if ( (d & 0x2000) > 0 ) 504: v.addElement( "LimitedDiscoverableMode" ); 505: if ( (d & 0x10000) > 0 ) 506: v.addElement( "Positioning" ); 507: if ( (d & 0x20000) > 0 ) 508: v.addElement( "Networking" ); 509: if ( (d & 0x40000) > 0 ) 510: v.addElement( "Rendering" ); 511: if ( (d & 0x80000) > 0 ) 512: v.addElement( "Capturing" ); 513: if ( (d & 0x100000) > 0 ) 514: v.addElement( "ObjectTransfer" ); 515: if ( (d & 0x200000) > 0 ) 516: v.addElement( "Audio" ); 517: if ( (d & 0x400000) > 0 ) 518: v.addElement( "Telephony" ); 519: if ( (d & 0x800000) > 0 ) 520: v.addElement( "Information" ); 521: 522: String[] str = new String[ v.size() ]; 523: v.copyInto( str ); 524: return str; 525: 526: } 527: /* This function requires javax.obex which is not availabe 528: on Nokia Series60 Concept SDK beta 0.3 529: public static void printObexHeaderSet( HeaderSet h ) 530: { 531: try { 532: log("Print OBEX Header"); 533: int[] ids = h.getHeaderList(); 534: for (int i = 0; i < ids.length; i++) { 535: log("ID[" + ids[i] + "]: " + h.getHeader(ids[i])); 536: } 537: } 538: catch (Exception ex) { 539: ex.printStackTrace(); 540: } 541: 542: } 543: */ 544: 545: public static boolean isContainsUUID( ServiceRecord r, UUID uuid ) 546: { 547: int[] ids = r.getAttributeIDs(); 548: 549: for ( int i=0; i < ids.length; i++ ) 550: { 551: DataElement e = r.getAttributeValue( ids[i] ); 552: if ( isContainsUUID( e, uuid ) ) 553: return true; 554: } 555: return false; 556: 557: }

64

v1.0

./org/ikt502/btwt/network/Util.java
558: 559: private static boolean isContainsUUID( DataElement e, UUID uuid ) 560: { 561: int type = e.getDataType(); 562: 563: if ( type == DataElement.UUID ) 564: { 565: if ( e.getValue().equals( uuid ) ) 566: return true; 567: 568: } else if ( type == DataElement.DATALT || type == DataElement.DATSEQ ) 569: { 570: Enumeration enumeration = (Enumeration)e.getValue(); 571: 572: while (enumeration.hasMoreElements()) { 573: DataElement e2 = (DataElement) enumeration.nextElement(); 574: if ( isContainsUUID( e2, uuid ) ) // recursive 575: return true; 576: } 577: } 578: return false; 579: 580: } 581: }

v1.0

65

./org/ikt502/btwt/network/Reader.java
1: package org.ikt502.btwt.network; 2: 3: /** 4: * BlueChat example application. 5: * Originally published in Java Developers Journal (volume 9 issue 2). 6: * Updated by Ben Hui on www.benhui.net. 7: * Copyright: (c) 2003-2004 8: * Author: Ben Hui 9: * 10: * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, 11: * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. 12: * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, 13: * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, 14: * PROFESSIONAL TRAINNING MATERIAL. 15: * 16: * Reader thread that read in signal and data from a bluetooth connection. 17: * <p>Description: Reader is a Runnable implementation that read in signal and data (String) 18: * from connected DataInputStream. Each EndPoint has it own reader thread.</p> 19: * <p>Copyright: Copyright (c) 2003</p> 20: * @author Ben Hui 21: * @version 1.0 22: */ 23: import java.io.*; 24: 25: import org.ikt502.btwt.gui.MessageHandler; 26: 27: public class Reader implements Runnable 28: { 29: // end point that this reader reads data from 30: public EndPoint endpt; 31: 32: private boolean done = false; 33: 34: public Reader() { 35: } 36: 37: /** 38: * set done flag to true, which will exit the while loop 39: */ 40: public void stop() 41: { 42: done = true; 43: } 44: 45: public void run() 46: { 47: try 48: { 49: DataInputStream datain = endpt.con.openDataInputStream(); 50: 51: while ( !done ) 52: { 53: log("waiting for next signal from "+endpt.remoteName); 54: // read in the next signal (an integer) 55: // this will block until there is data to read 56: int signal = datain.readInt(); 57: 58: if ( signal == NetLayer.SIGNAL_MESSAGE ) 59: { 60: String s = datain.readUTF(); 61: 62: ChatPacket packet = new ChatPacket( NetLayer.SIGNAL_MESSAGE, endpt.remoteName, s ); 63: 64: log("read in MESSAGE string "+s+" from "+endpt.remoteName); 65: 66: // read in a string message. emit RECEIVED event to BTListener implementation 67: endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); 68: 69: } 70: 71: if ( signal == NetLayer.SIGNAL_AUDIO_MESSAGE ) 72: { 73: //Anounce inncomming messaeg... 74: MessageHandler.addMessage("Receiving audio message from "+endpt.remoteName+", please wait..."); 75: 76: int size = datain.readInt(); 77: String contentType = datain.readUTF(); 78: 79: byte[] buffer = new byte[size]; 80: for (int i = 0; i < size; i++) 81: { 82: buffer[i] = datain.readByte(); 83: } 84: 85: ChatPacket packet = new ChatPacket( NetLayer.SIGNAL_AUDIO_MESSAGE, endpt.remoteName, new ByteArrayInputSt ream(buffer), contentType); 86: 87: log("read in AUDIO MESSAGE from "+endpt.remoteName+". AdvSize/RecSize: "+size+"/"+buffer.length); 88: 89: // read in a string message. emit RECEIVED event to BTListener implementation 90: endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); 91: 92: }

66

v1.0

./org/ikt502/btwt/network/Reader.java
93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: else if ( signal == NetLayer.SIGNAL_PICTURE_MESSAGE ) { int size = datain.readInt(); byte[] buffer = new byte[size]; for (int i = 0; i < size; i++) { buffer[i] = datain.readByte(); } ChatPacket packet = new ChatPacket( NetLayer.SIGNAL_PICTURE_MESSAGE, endpt.remoteName, buffer); log("read in VIDEO MESSAGE from "+endpt.remoteName); // read in a string message. emit RECEIVED event to BTListener implementation endpt.callback.handleAction( BTListener.EVENT_RECEIVED, endpt, packet ); } else if ( signal == NetLayer.SIGNAL_HANDSHAKE ) { String s = datain.readUTF(); log("read in HANDSHAKE name "+s+" from "+endpt.remoteName); // update the remote user nick name endpt.remoteName = s; // echo acknowledgment and local user friendly name back to remote device endpt.putString( NetLayer.SIGNAL_HANDSHAKE_ACK, endpt.localName );

endpt.callback.handleAction( BTListener.EVENT_JOIN, endpt, null ); } else if ( signal == NetLayer.SIGNAL_TERMINATE ) { log("read in TERMINATE from "+endpt.remoteName); // echo acknowledgment and local friendly name back to remote device endpt.putString( NetLayer.SIGNAL_TERMINATE_ACK, "end" ); // emit LEAVE event to BTListener implementation endpt.callback.handleAction( BTListener.EVENT_LEAVE, endpt, null ); // clean up end point resources and associated connections endpt.btnet.cleanupRemoteEndPoint( endpt ); // stop this reader, no need to read any more signal stop(); } else if ( signal == NetLayer.SIGNAL_HANDSHAKE_ACK ) { // the string data is the remote user nick name String s = datain.readUTF(); log("read in HANDSHAKE_ACK name "+s+" from "+endpt.remoteName); // update remote user nick name endpt.remoteName = s; } else if ( signal == NetLayer.SIGNAL_TERMINATE_ACK ) { System.out.println("read in TERMINATE_ACK from "+endpt.remoteName); // doesnt do anything, just wake up from readInt() so that the thread can stop

} else { log("Unkonwn signal, probably connection closed"); } } // while !done datain.close(); } catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } log("reader thread exit for "+endpt.remoteName); } private static void log( String s) { System.out.println("Reader: "+s); // "R" means Reader class

v1.0

67

./org/ikt502/btwt/network/Reader.java
186: 187: 188: } 189: 190: } MessageHandler.addDebugMessage( "R: " + s );

68

v1.0

./org/ikt502/btwt/network/EndPoint.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.network; import import import import javax.bluetooth.*; javax.microedition.io.*; java.io.*; java.util.*;

/** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * * A EndPoint object represent all the connection attribute of an active BlueChat node. * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * @author Ben Hui * @version 1.0 */ public class EndPoint { // remote device object RemoteDevice remoteDev; // remote device class DeviceClass remoteClass; // remote service URL String remoteUrl; // connection to remote service StreamConnection con; // bluetooth discovery transId, obtainsed from searchServices int transId = -1; // -1 must be used for default. cannot use 0 // sender thread Sender sender; // reader thread Reader reader; // local user nick name public String localName; // remote user nick name public String remoteName; // BTListener implementation for callback NetLayer event BTListener callback; // reference to NetLayer NetLayer btnet; // vector of ChatPacket pending to be sent to remote service. // when message is sent, it is removed from the vector. Vector msgs = new Vector(); public EndPoint( NetLayer btnet, RemoteDevice rdev, StreamConnection c ) { this.btnet = btnet; remoteDev = rdev; try { // NOTE in 6600, this parameter must be false because // according to some observation from other developer // setting this to true mean the Bluetooth system need to make // another connection to remote device, however, there is no available // free connection, so it will give you exception remoteName = rdev.getFriendlyName(false); // this is a temp name } catch (IOException ex) { remoteName = "Unknown"; // ignore } localName = btnet.localName; callback = btnet.callback; con = c; sender = new Sender(); sender.endpt = this; reader = new Reader(); reader.endpt = this;

} public synchronized void putString( int signal, String s ) {

v1.0

69

./org/ikt502/btwt/network/EndPoint.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: } log("invoke putString "+signal+" // put the message on the queue, msgs.addElement( new ChatPacket( synchronized( sender ) { // tell sender that there is a sender.notify(); } } public synchronized void putStream( int signal, ByteArrayOutputStream stream, String contentType ) { log("invoke putStream "+signal+" MULTIMEDIA"); // put the message on the queue, pending to be sent by Sender thread msgs.addElement( new ChatPacket( signal, stream, contentType ) ); synchronized( sender ) { // tell sender that there is a message pending to be sent sender.notify(); } } public synchronized void putPicture( int signal, byte[] picture ) { log("invoke putPicture "+signal); // put the message on the queue, pending to be sent by Sender thread msgs.addElement( new ChatPacket( signal, picture ) ); synchronized( sender ) { // tell sender that there is a message pending to be sent sender.notify(); } log("putPicture finished..."); } public synchronized ChatPacket getString() { if ( msgs.size() > 0 ) { // if there are message pending, return it and remove it from the vector ChatPacket s = (ChatPacket) msgs.firstElement(); msgs.removeElementAt(0); return s; } else { // if there is no message pending. return null return null; } } public synchronized boolean peekString() { return ( msgs.size() > 0 ); } private static void log( String s ) { System.out.println("EndPoint: "+s); } "+s); pending to be sent by Sender thread signal, s ) );

message pending to be sent

70

v1.0

./org/ikt502/btwt/network/BTListener.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: package org.ikt502.btwt.network; /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * Interface for BlueChat NetLayer callback. * <p>Description: Implementation of this interface will handle BlueChat network event.</p> * <p>Copyright: Copyright (c) 2003</p> * @author Ben Hui * @version 1.0 */ public interface BTListener { public final static String EVENT_JOIN = "join"; public final static String EVENT_LEAVE = "leave"; public final static String EVENT_RECEIVED = "received"; public final static String EVENT_SENT = "sent";

/** * BlueChat network activity action handler. * @param action must be one of NetLayer.ACT_XXX field * @param param1 usually the EntPoint object that correspond to the action * @param param2 varies by action value */ public void handleAction( String action, Object param1, Object param2 ); }

v1.0

71

./org/ikt502/btwt/network/Sender.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.network; /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * Sender thread that send out signal and data to a bluetooth connection. * <p>Description: Sender is a Runnable implementation that send signal and data (String) * to connected DataInputStream. Each EndPoint has it own sender thread.</p> * <p>Copyright: Copyright (c) 2003</p> * @author Ben Hui * @version 1.0 */ import java.io.*; import java.util.Date; import org.ikt502.btwt.gui.MessageHandler; public class Sender implements Runnable { /** * end point that this sender sends data to */ public EndPoint endpt; /** * */ private boolean done = false; /** * */ public Sender() { } /** * set done flag to true, which will exit the while loop */ public void stop() { done = true; } /** * */ public void run() { try { DataOutputStream dataout = endpt.con.openDataOutputStream(); while( !done ) { // check to see if there are any message to send. // if not, then wait for 5 second if ( ! endpt.peekString() ) { synchronized (this) { this.wait(5000); } } // wake up and get next string ChatPacket s = endpt.getString(); if ( s != null ) { //Time the transmision... long start = new Date().getTime(); //Audio Message... if ( s.signal == NetLayer.SIGNAL_AUDIO_MESSAGE ) { // if there is a message to send, send it log("sending signal "+s.signal+" audio to //Send Audio Message dataout.writeInt(s.signal); dataout.writeInt(s.streamOut.size()); dataout.writeUTF(s.contentType); dataout.write(s.streamOut.toByteArray()); dataout.flush();

now "+endpt.remoteName); //Anounce Audio Message... //...its length... //...and its content type... //Then its content...

72

v1.0

./org/ikt502/btwt/network/Sender.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: } } //Picture Message... else if ( s.signal == NetLayer.SIGNAL_PICTURE_MESSAGE ) { // if there is a message to send, send it now log("sending signal "+s.signal+" picture to "+endpt.remoteName); //Send Audio Message dataout.writeInt(s.signal); //Anounce Picture Message... dataout.writeInt(s.picture.length); //...its length... dataout.write(s.picture); //Then its content... dataout.flush(); } //Other Messages... else { // if there is a message to send, send it now log("sending signal "+s.signal+" string "+s.msg+" to "+endpt.remoteName); dataout.writeInt(s.signal); dataout.writeUTF(s.msg ); dataout.flush(); } //Calc time used... long time = new Date().getTime() - start; log("Transmision time for signal "+s.signal+" was " + time + "ms..." ); } if ( s != null && s.signal == NetLayer.SIGNAL_TERMINATE ) { // if the message is a TERMINATE signal, then break the run loop as well stop(); } } // while !done // close the output stream dataout.close(); } catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } log("sender thread exit for "+endpt.remoteName); }

/** * * @param s */ private static void log( String s) { System.out.println("Sender: "+s); // "S" means Sender class MessageHandler.addDebugMessage( "S: " + s ); }

v1.0

73

./org/ikt502/btwt/network/NetLayer.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt.network; import import import import import import import javax.microedition.io.*; javax.bluetooth.*; java.io.*; java.util.*; javax.bluetooth.RemoteDevice; javax.bluetooth.DeviceClass; javax.bluetooth.ServiceRecord;

import org.ikt502.btwt.gui.MessageHandler; /** * BlueChat example application. * Originally published in Java Developers Journal (volume 9 issue 2). * Updated by Ben Hui on www.benhui.net. * Copyright: (c) 2003-2004 * Author: Ben Hui * * YOU ARE ALLOWED TO USE THIS CODE FOR EDUCATIONAL, PERSONAL TRAINNING, * REFERENCE PURPOSE. YOU MAY DISTRIBUTE THIS CODE AS-IS OR MODIFIED FORM. * HOWEVER, YOU CANNOT USE THIS CODE FOR COMMERCIAL PURPOSE. THIS INCLUDE, * BUT NOT LIMITED TO, PRODUCING COMMERCIAL SOFTWARE, CONSULTANT SERVICE, * PROFESSIONAL TRAINNING MATERIAL. * * This is the main class for handling bluetooth connectivity and * device/service discovery process. This class does many things, including * - search for bluetooth devices (query()) * - create a local BlueChat server and register it with bluetooth (run()) * - search for remote BlueChat services using searchServices() * - handle incoming connection request from remote BlueChat * - establish connection to remote BlueChat * * @author Ben Hui * @version 1.0 */ public class NetLayer implements Runnable { public final static int SIGNAL_HANDSHAKE = 0; public final static int SIGNAL_MESSAGE = 1; public final static int SIGNAL_TERMINATE = 3; public final static int SIGNAL_HANDSHAKE_ACK = 4; public final static int SIGNAL_TERMINATE_ACK = 5; public final static int SIGNAL_AUDIO_MESSAGE = 6; public final static int SIGNAL_PICTURE_MESSAGE = 7; // BlueChat specific service UUID // note: this UUID must be a string of 32 char // do not use the 0x???? constructor because it wont // work. not sure if it is a N6600 bug or not private final static UUID uuid = new UUID("102030405060708090A0B0C0D0E0F010", false); // // major service class as SERVICE_TELEPHONY private final static int SERVICE_TELEPHONY = 0x400000; // reference to local bluetooth device singleton LocalDevice localDevice = null; // reference to local discovery agent singleton DiscoveryAgent agent = null; // local BlueChat service server object StreamConnectionNotifier server; // reference to BListener implementation. for BlueChat event callback BTListener callback = null; boolean done = false; String localName = ""; // list of active EndPoints. all messages will be sent to all // active EndPoints Vector endPoints = new Vector(); // list of pending EndPoints. this is used to keep track of // discovered devices waiting for service discovery. When all the near-by // BlueChat service has been discovered, this list will be cleared until the // next inquiry Vector pendingEndPoints = new Vector();

// map ServiceRecord to EndPoint // see DoServiceDiscovery and serviceSearchCompleted Hashtable serviceRecordToEndPoint = new Hashtable(); // synchronization lock // see DoServiceDiscovery and serviceSearchCompleted Object lock = new Object(); // timer to schedule task to do service discovery // see inquiryCompleted Timer timer = new Timer(); public NetLayer()

74

v1.0

./org/ikt502/btwt/network/NetLayer.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: { } public void init(String name, BTListener callback) { log( "invoke init()" ); try { this.localName = name; this.callback = callback; // // initialize the JABWT stack localDevice = LocalDevice.getLocalDevice(); // obtain reference to singleton localDevice.setDiscoverable(DiscoveryAgent.GIAC); // set Discover mode to GIAC agent = localDevice.getDiscoveryAgent(); // obtain reference to singleton // print local device information Util.printLocalDevice( localDevice );

// start bluetooth server socket // see run() for implementation of local BlueChat service Thread thread = new Thread( this ); thread.start();

} catch (BluetoothStateException e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } catch (IOException e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } } public void disconnect() { log("invoke disconnect()"); // stop server socket, not longer accept client connection done = true; try { // this close will interrupt server.acceptAndOpen() // wake it up to exit server.close(); } catch (IOException ex) { } // stop each EndPoint reader and sender threads // and send TERMINATE signal to other connected // BlueChat peers for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); endpt.putString( NetLayer.SIGNAL_TERMINATE, "end" ); endpt.sender.stop(); endpt.reader.stop(); } } public void query() { try { log("invoke query()"); // although JSR-82 provides the ability to lookup // cached and preknown devices, we intentionally by-pass // them and go to discovery mode directly. // this allow us to retrieve the latest active BlueChat parties agent.startInquiry(DiscoveryAgent.GIAC, new Listener()); } catch (BluetoothStateException e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } }

public EndPoint findEndPointByRemoteDevice( RemoteDevice rdev ) { for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); if ( endpt.remoteDev.equals( rdev ) ) { return endpt;

v1.0

75

./org/ikt502/btwt/network/NetLayer.java
187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: } } return null; // not found, return null } public EndPoint findEndPointByTransId( int id ) { for ( int i=0; i < pendingEndPoints.size(); i++ ) { EndPoint endpt = (EndPoint) pendingEndPoints.elementAt( i ); if ( endpt.transId == id ) { return endpt; } } return null; // not found, return null } /** * Send a string message to all active EndPoints * @param s */ public void sendString( String s ) { log("invoke sendString string="+s); for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); // put the string on EndPoint, so sender will send the message endpt.putString( NetLayer.SIGNAL_MESSAGE, s ); } } /** * * @param stream */ public void sendAudio (ByteArrayOutputStream stream, String contentType) { log("invoke sendAudio..."); for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); // put the string on EndPoint, so sender will send the message endpt.putStream( NetLayer.SIGNAL_AUDIO_MESSAGE, stream, contentType ); } } /** * * @param stream */ public void sendPicture ( byte[] picture ) { log("invoke sendPicture..."); for ( int i=0; i < endPoints.size(); i++ ) { EndPoint endpt = (EndPoint) endPoints.elementAt( i ); // put the string on EndPoint, so sender will send the message endpt.putPicture( NetLayer.SIGNAL_PICTURE_MESSAGE, picture ); } } /** * Clean up the resource for a EndPoint, remove it from the active list. * This is triggered by a remote EndPoint leaving the network * @param endpt */ public void cleanupRemoteEndPoint( EndPoint endpt ) { log("invoke cleanupRemoteEndPoint()"); // set done flag to true to exit the run loop endpt.reader.stop(); endpt.sender.stop(); // remove this end point from the active end point list endPoints.removeElement( endpt ); } /** * Implement local BlueChat service. */ public void run() { // connection to remote device StreamConnection c = null; try { // Create a server connection object, using a // Serial Port Profile URL syntax and our specific UUID // and set the service name to BlueChatApp

76

v1.0

./org/ikt502/btwt/network/NetLayer.java
280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: server = (StreamConnectionNotifier)Connector.open( "btspp://localhost:" + uuid.toString() +";name=BlueChatApp"); // Retrieve the service record template ServiceRecord rec = localDevice.getRecord( server ); // set ServiceRecrod ServiceAvailability (0x0008) attribute to indicate our service is available // 0xFF indicate fully available status // This operation is optional rec.setAttributeValue( 0x0008, new DataElement( DataElement.U_INT_1, 0xFF ) ); // Print the service record, which already contains // some default values Util.printServiceRecord( rec ); // Set the Major Service Classes flag in Bluetooth stack. // We choose Object Transfer Service rec.setDeviceServiceClasses( SERVICE_TELEPHONY );

} catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } while( !done) { try { /////////////////////////////// log("local service waiting for client connection"); // this message is to inform user that the server is up and ready MessageHandler.addMessage("Ready to accept connection. Wait..."); // // start accepting client connection. // This method will block until a client // connected c = server.acceptAndOpen(); log("local service accept a new client connection");

// // retrieve the remote device object RemoteDevice rdev = RemoteDevice.getRemoteDevice( c ); // // check to see if the EndPoint already exist EndPoint endpt = findEndPointByRemoteDevice( rdev ); if ( endpt != null ) { // this is a safe guard to assure that this client // has not been connected before log("client connection end point already exist.. ignore this connection"); } else { // - create a new EndPoint object // - initialize the member variables // - start the data reader and sender threads. endpt = new EndPoint( this, rdev, c); Thread t1 = new Thread( endpt.sender ); t1.start(); Thread t2 = new Thread( endpt.reader ); t2.start(); // add this EndPoint to the active list endPoints.addElement( endpt ); log("a new active EndPoint is established. name=" + endpt.remoteName); }

} catch (IOException e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); // // // // if if any exception happen, we assume this connection is failed and close it. closing the connection will cause the reader and sender thread to exit (because they will got exception as well). (c != null) try { c.close(); } catch (IOException e2) { // ignore

v1.0

77

./org/ikt502/btwt/network/NetLayer.java
373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: } } finally { // nothing to do here } } // while !done } // end run() public static void log(String s) { System.out.println("NetLayer: "+s); }

/** * Internal discovery listener class for handling device & service discovery events. * @author Ben Hui * @version 1.0 */ class Listener implements DiscoveryListener { /** * A device is discovered. * Create a EndPoint for the device discovered and put it on the pending list. * A service search will happen when all the qualifying devices are discovered. * * @param remoteDevice * @param deviceClass */ public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) { try { log("invoke deviceDiscovered name=" + remoteDevice.getFriendlyName(false)); } catch (IOException ex) { } // only device of SERVICE_OBJECT_TRANSFER will be considered as candidate device // because in our BlueChat service, we explicitly set the service class to // SERVICE_OBJECT_TRANSFER. see the run() method if ( (deviceClass.getServiceClasses() & SERVICE_OBJECT_TRANSFER) != 0 ) { try { // create a inactive EndPoint and put it on the pending list EndPoint endpt = new EndPoint(NetLayer.this, remoteDevice, null); pendingEndPoints.addElement( endpt ); } catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } } else { log("found device that is not Object Transfer Service, ignore this device..."); } } /** * device discovery completed. * After device inquery completed, we start to search for BlueChat services. * We loop through all the pending EndPoints and request agent.searchServices * on each of the remote device. * @param transId */ public void inquiryCompleted(int transId) { log( "invoke inqueryCompleted" ); // wait 100ms and start doing service discovery // the choice of 100ms is really just a guess timer.schedule( new DoServiceDiscovery(), 100 ); } /** * a service is discovered from a remote device. * when a BlueChat service is discovered, we establish a connection to * this service. This signal joining the existing virtual chat room. * @param transId * @param svcRec */ public void servicesDiscovered(int transId, ServiceRecord[] svcRec) { log( "invoke servicesDiscovered:"+transId+","+svcRec.length); try { for ( int i=0; i< svcRec.length; i++ ) {

// //

// // // //

78

v1.0

./org/ikt502/btwt/network/NetLayer.java
466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: Util.printServiceRecord( svcRec[i] );

EndPoint endpt = findEndPointByTransId( transId ); serviceRecordToEndPoint.put( svcRec[i], endpt ); } } catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()); log(e.getMessage()); } } /** * service discovery is completed. * @param int0 * @param int1 */ public void serviceSearchCompleted(int transID, int respCode) { log("invoke serviceSearchCompleted: "+transID); // print response code if ( respCode == SERVICE_SEARCH_COMPLETED ) log("SERVICE_SEARCH_COMPLETED"); else if ( respCode == SERVICE_SEARCH_TERMINATED ) log("SERVICE_SEARCH_TERMINATED"); else if ( respCode == SERVICE_SEARCH_ERROR ) log("SERVICE_SEARCH_ERROR"); else if ( respCode == SERVICE_SEARCH_NO_RECORDS ) log("SERVICE_SEARCH_NO_RECORDS"); else if ( respCode == SERVICE_SEARCH_DEVICE_NOT_REACHABLE ) log("SERVICE_SEARCH_DEVICE_NOT_REACHABLE");

for ( Enumeration records = serviceRecordToEndPoint.keys(); records.hasMoreElements(); ) { try {

ServiceRecord rec = (ServiceRecord) records.nextElement(); // We make an assumption that the first service is BlueChat. In fact, only one // service record will be found on each device. // Note: we know the found service is BlueChat service because we search on specific UUID, // this UUID is unique to us. String url = rec.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false ); log("BlueChat service url="+url); StreamConnection con = (StreamConnection)Connector.open( url ); // retrieve the pending EndPoint and initialize the necessary member variables // to activate the EndPoint. this includes // - initialize connection // - start sender and reader thread EndPoint endpt = (EndPoint) serviceRecordToEndPoint.get( rec ); if ( endpt != null ) { endpt.con = con;

Thread t1 = new Thread( endpt.sender ); t1.start(); Thread t2 = new Thread( endpt.reader ); t2.start(); endPoints.addElement( endpt ); log("a new active EndPoint is established. name=" + endpt.remoteName); // once a EndPoint established, the BlueChat client is responsible to initiate the // handshake protocol. endpt.putString( NetLayer.SIGNAL_HANDSHAKE, localName );

} else { log("cannot find pending EndPoint when a service is discovered. ignore this service..."); } } catch (Exception e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } } // for // finished process current batch of service record

v1.0

79

./org/ikt502/btwt/network/NetLayer.java
559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: } // clear it and service discovery on next device serviceRecordToEndPoint.clear(); synchronized( lock ) { // unlock to proceed to service search on next device // see DoServiceDiscovery.run() lock.notifyAll(); } } } // inner class Listener class DoServiceDiscovery extends TimerTask { public void run() { // // for each EndPoint, we search for BlueChat service for (int i = 0; i < pendingEndPoints.size(); i++) { EndPoint endpt = (EndPoint) pendingEndPoints.elementAt(i); try { log("search service on device " + endpt.remoteName); // // searchServices return a transaction id, which we will used to // identify which remote device the service is found in our callback // listener (class Listener) // // note: in theory, only one runtine instance of Listener is needed // to handle all discovery callback. however, there is a bug in rococo // simualtor that cause callback fails with one instance of used // so we make a new Listener for every searchServices() endpt.transId = agent.searchServices(null // null to indicate retrieve default attributes , new UUID[] { uuid } // BlueChat service UUID SerialPort , endpt.remoteDev, new Listener()); // wait until the above service discovery is completed // because N6600 cannot handle more than one service discovery // request at the same time // see serviceSearchCompleted() synchronized( lock ) { try { lock.wait(); } catch (InterruptedException ex) { } } } catch (BluetoothStateException e) { e.printStackTrace(); log(e.getClass().getName()+" "+e.getMessage()); } } // for // no more service to discovery. so any pending EndPoints // will be ignored and removed pendingEndPoints.removeAllElements(); // this message is to inform user that chatting can start MessageHandler.addMessage( "You can start chatting now..." ); } }

80

v1.0

./org/ikt502/btwt/PictureRecorder.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt; import java.io.*; import import import import import javax.microedition.lcdui.Item; javax.microedition.media.Manager; javax.microedition.media.MediaException; javax.microedition.media.Player; javax.microedition.media.control.VideoControl;

import org.ikt502.btwt.gui.RecordPictureUI; /** * Picture Recorder records pictures * * @authors Aleksander Albretsen and Morten Krakvik */ public class PictureRecorder implements Runnable { /** * */ private BTWT btwt; /** * */ private RecordPictureUI recordGui; /** * */ private byte[] picture; /** * */ private Item cameraAsItem; /** * */ boolean canShowPicture = false; /** * */ private Player p; private VideoControl vc; private Thread thread; /** * * @param btwt * @param recordGui */ public PictureRecorder(BTWT btwt, RecordPictureUI recordGui) { //Save vars... this.btwt = btwt; this.recordGui = recordGui; } /** * */ public void start() { thread = new Thread( this ); thread.start(); } /** * */ public void run() { log("PictureRecorder::run()"); runRecorder(); } /** * */ private void runRecorder() { try { //Create and realize player... p = Manager.createPlayer("capture://video"); p.realize(); //Grab the video control and set it to the current display.

v1.0

81

./org/ikt502/btwt/PictureRecorder.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: vc = (VideoControl) p.getControl("VideoControl"); if (vc == null) { log("Unsupported: Cant get VideoControl"); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } else { //Fetch cameraAsItem... cameraAsItem = (Item) vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, null); //Start Camera... p.prefetch(); p.start(); //Change state recordGui.setState(RecordPictureUI.CAMERA_READY); } } catch(IOException ioe) { log("Exception: " + ioe.getMessage()); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } catch(MediaException me) { log("Exception: " + me.getMessage()); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } catch(SecurityException se) { log("Exception: " + se.getMessage()); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } } /** * */ public void takeSnapshot() { new CaptureThread(this).start(); } /** * */ private void generateSnapshot() { log("PictureRecorder::generateSnapshot()"); try { if (vc != null) { //Generat snapshot (picture).. picture = vc.getSnapshot(null); //Stop the video recorder... discardPlayer(); //Wait for player to REALY stop !! Thread.sleep(1500); //Show Picture recordGui.setState(RecordPictureUI.VERIFY); } else { log("VideoControl = NULL !"); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } } catch (MediaException me) { recordGui.setState(RecordPictureUI.FAILED); log("Exception: " + me.getMessage()); } catch (InterruptedException ie) { log("They wont let me sleep, exception message: " + ie.getMessage()); } } /** * */ public Item getCameraAsItem() { return cameraAsItem; }

82

v1.0

./org/ikt502/btwt/PictureRecorder.java
187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: /** * */ public byte[] getPicture() { return picture; } /** * */ public void sendPicture() { log("PictureRecorder::sendPicture()"); if ( (picture != null) && (picture.length > 0) ) { //Send Audio message... btwt.sendPicture(picture); //Change state recordGui.setState(RecordPictureUI.SENDT); } else { log("No picture found !"); discardPlayer(); recordGui.setState(RecordPictureUI.FAILED); } } /** * Called in case of exception to make sure invalid players are closed */ public void discardPlayer() { log("PictureRecorder::discardPlayer()"); if (p != null) { log("Closing player..."); p.close(); } } /** * */ private void log(String s) { recordGui.getParent().addDebugMessage("Pic: " + s); System.out.println("Picture: " + s); } /** * */ private class CaptureThread implements Runnable { /** * */ PictureRecorder rec; /** * */ private Thread thread; /** * * @param rec */ public CaptureThread(PictureRecorder rec) { this.rec = rec; } /** * */ public void start() { thread = new Thread( this ); thread.start(); } /** * */ public void run() { log("CaptureThread::run()"); rec.generateSnapshot(); log("CaptureThread terminated...");

v1.0

83

./org/ikt502/btwt/PictureRecorder.java
280: 281: 282: } 283: } }

84

v1.0

./org/ikt502/btwt/AudioPlayer.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt; import java.io.IOException; import java.io.InputStream; import java.util.Date; import import import import javax.microedition.media.Manager; javax.microedition.media.MediaException; javax.microedition.media.Player; javax.microedition.media.PlayerListener;

import org.ikt502.btwt.gui.*; /** * AudioPlayer plays audio messages received from another peer. * * @authors Aleksander Albretsen and Morten Krakvik */ public class AudioPlayer implements Runnable, PlayerListener { /** * Reference to the GUI controller. */ private BtwtGUI gui; /** * Audio message from peer. */ private InputStream stream; /** * Content type of audio message */ private String contentType; /** * The nicname to the peer the message is received from. */ private String from; /** * Variable used to stor time stamps, enabling us to record time. */ private long start; /** * Create new AudioPlayer * * @param gui Reference to the GuiController (object of type BtwtGUI) * @param stream Audio message from peer */ public AudioPlayer(BtwtGUI gui, InputStream stream, String contentType, String from) { this.gui = gui; this.stream = stream; this.from = from; this.contentType = contentType; } /** * Start the AudioPlayer */ public void start() { Thread thread = new Thread( this ); thread.start(); } /** * Invoked by thread.start(); */ public void run() { start = new Date().getTime(); log("AudioPlayer thread start..." ); gui.addMessage("...playing audio message from " + from + "..." ); this.playStream(); log("Thread end after " + (new Date().getTime() - start) + "ms..." ); } /** * Create a player and play audio message from peer. */ private void playStream() { //log content type log("Content-type for received media: " + contentType); try { Player p = Manager.createPlayer(stream, contentType); p.addPlayerListener(this); p.realize(); p.start();

v1.0

85

./org/ikt502/btwt/AudioPlayer.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: } } catch (MediaException pe) { log("Error: " + pe.getMessage()); } catch (IOException ioe) { log("Error: " + ioe.getMessage()); } } /** * @see PlayerListener */ public void playerUpdate(Player arg0, String arg1, Object arg2) { //Log events... log("Update: " + arg0.toString() + " - " + arg1 + " - " + arg2.toString()); //Time play-time... if (arg1.equals("endOfMedia")) { log("Player stoped after " + (new Date().getTime() - start) + "ms..." ); } } /** * Log string, for debug purposes */ private void log(String s) { System.out.println("Player: " + s); gui.addDebugMessage("Pl: " + s); }

86

v1.0

./org/ikt502/btwt/AudioRecorder.java
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: package org.ikt502.btwt; import import import import import import import javax.microedition.media.Manager; javax.microedition.media.Player; javax.microedition.media.control.*; javax.microedition.media.MediaException; java.io.IOException; java.io.ByteArrayOutputStream; java.util.Date;

import org.ikt502.btwt.gui.*; /** * Audio Recorder records audio messages * * @authors Aleksander Albretsen and Morten Krakvik */ public class AudioRecorder implements Runnable { /** * Reference to the RecordAudioUI */ private RecordAudioUI recordGui; /** * Reference to the GUI controller. */ private BTWT btwt; /** * The Player and its surrounding objects. */ private Player p; private long startTime; private String contentType; private RecordControl rc; private ByteArrayOutputStream buffer; private boolean isRecording = false; private Thread thread; /** * Create new AudioRecorder * * @param btwt BTWT main object. * @param recordGui ref. to the RecordAudioUI */ public AudioRecorder( BTWT btwt, RecordAudioUI recordGui) { this.btwt = btwt; this.recordGui = recordGui; } /** * Invoked by thread.start(); */ public void run() { startRecord(); } /** * Start recording audio to buffer */ public void startRecording() { thread = new Thread( this ); thread.start(); } /** * Stop the recording */ public void stopRecording() { this.stopRecord(); } /** * Send recorded message to all other peers. */ public void sendRecordedMessage() { log("AudioRecorder::sendRecordedMessage()"); if ( (buffer != null) && (buffer.size() > 0) ) { //Send Audio message... btwt.sendAudio(buffer, contentType); //Change state recordGui.setState(RecordAudioUI.SENDT); } }

v1.0

87

./org/ikt502/btwt/AudioRecorder.java
94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: /** * Start Recording */ private void startRecord() { log("AudioRecorder::startRecording()"); try { //Create buffer... buffer = new ByteArrayOutputStream(); //Create en realize player.... p = Manager.createPlayer( "capture://audio" ); p.realize(); //Create Record Controller rc = (RecordControl) p.getControl( "RecordControl" ); rc.setRecordStream( buffer ); //Get content-type... contentType = p.getContentType(); log("Selected content type: " + contentType); //Start recording p.start(); rc.startRecord(); //Time recording... startTime = new Date().getTime(); //Set state to recording.... recordGui.setState(RecordAudioUI.RECORDING); isRecording = true; //Record for maximum time of 5 sec. Thread.sleep( 5000 - (new Date().getTime() - startTime) ); stopRecord(); } catch( IOException ioe ) { recordGui.setState(RecordAudioUI.FAILED); log(ioe.getMessage()); ioe.printStackTrace(); } catch( MediaException me ) { recordGui.setState(RecordAudioUI.FAILED); log(me.getMessage()); me.printStackTrace(); } catch( InterruptedException ie ) { recordGui.setState(RecordAudioUI.FAILED); log(ie.getMessage()); ie.printStackTrace(); } } /** * Stop Recording */ private synchronized void stopRecord() { if( !isRecording ) return; log("AudioRecorder::stopRecording()"); try { //Time it... log("Recording ended after " + (new Date().getTime() - startTime) + "ms..." ); //Stop recording p.stop(); rc.stopRecord(); //Commit to buffer rc.commit(); buffer.flush(); log("Buffer Size on record: "+buffer.size()); //Done recording ! p.close(); recordGui.setState(RecordAudioUI.READY_TO_SEND); isRecording = false; } catch( IOException ioe ) { recordGui.setState(RecordAudioUI.FAILED);

88

v1.0

./org/ikt502/btwt/AudioRecorder.java
187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: } log(ioe.getMessage()); ioe.printStackTrace(); } catch( MediaException me ) { recordGui.setState(RecordAudioUI.FAILED); log(me.getMessage()); me.printStackTrace(); } } /** * Log string, for debug purposes */ private void log(String s) { recordGui.getParent().addDebugMessage("Rec: " + s); System.out.println("Recorder: " + s); }

v1.0

89

Das könnte Ihnen auch gefallen