Important notice: This post is about integrating the legacy Nabto 4/Micro (uNabto) platform which is no longer supported for new designs. Instead, it is highly recommended to look at the modern Nabto 5/Edge platform. CC3200 is not yet supported by Nabto 5/Edge – but you can follow the general integration guide for integrating Nabto 5/Edge to new platforms, including a step-by-step test-harness to simplify the integration. Also, take a look at the embedded platforms currently supported by Nabto 5/Edge.
Texas Instrument’s CC3200 is a single-chip microcontroller unit with built-in Wi-Fi connectivity, created for the Internet of Things. It can run the FreeRTOS operating system and provides a hardware encryption engine. Sounds interesting? It did to us! So we created a demo that is capable of streaming two-way audio between the CC3200 and an Android App using our uNabto framework. Why do you need Nabto for this? Because it solves all the router and firewall hassle for you: all you need to connect to the device is a unique Device ID!
What you need
Just hook up the two boards as described in the Audio BoosterPack User Guide provided by TI.
How the Nabto platform works
How does the Nabto platform work exactly? The drawing below gives a brief overview. Your CC3200 represents the Device running the uNabto server. As soon as it connects to the internet it identifies itself at the Nabto Basestation, using its unique ID. If a Client (i.e. the Android App in this demo) wants to connect to the CC3200, a connect request with the ID is sent to the Basestation, and a direct connection to the device is established.
Get more information on the Nabto Cloud Console and the Client/Device SDKs at console.cloud.nabto.com.
The uNabto Platform Adapter:
The uNabto Platform Adapter is a small component that abstracts the Native Platforms network and time functionality. The Platform Adapter is part of the uNabto server.
The uNabto server is divided into two layers:
- The uNabto framework (uNabto SDK)
- The uNabto Platform Adapter abstraction layer between the framework and the Native Platform
To run the uNabto server on the CC3200, we only need to implement the uNabto Platform Adapter (for details see the TEN023 Nabto device SDK guide). The CC3200 adapter is divided into the following files:
- unabto_config.h: Basic uNabto configuration
- unabto_platform_types.h: Define all necessary uNabto types
- unabto_platform.h: Platform specific ad-hoc functions
- unabto_adapter_network.c: Init, close, read and write functionality for network data
- unabto_adapter_time.c: Time functions
- unabto_adapter_dns.c: DNS resolving
- unabto_adapter_random.c: Random generator
- unabto_adapter_crypto.c: CC3200 hardware encryption
If you are interested in how the platform adapter is implemented in detail, check the adapter files on GitHub.
The Device Application
Info: The following describes the audio demo application (‘audio’ branch). A more generic and straightforward example of using streaming to echo data is maintained in the ‘master’ branch of our CC3200 GitHub repository.
The uNabto server is running in its own task implemented in unabto_task.c. After waiting for the network connection being established in another task, the uNabto server is initialized with basic settings as well as the unique Device ID and pre-shared encryption key from console.cloud.nabto.com. Then, the server continuously handles incoming network events and checks for available recorded audio to send to the client.
void UNabto(void* pvParameters) { // device id and key from console.cloud.nabto.com const char* nabtoId = "<DEVICE ID>"; const char* presharedKey = "<KEY>"; // Initialize uNabto nabto_main_setup* nms = unabto_init_context(); nms->ipAddress = g_uiIpAddress; nms->id = nabtoId; nms->secureAttach = 1; nms->secureData = 1; nms->cryptoSuite = CRYPT_W_AES_CBC_HMAC_SHA256; const char* p; unsigned char* up; for (p = presharedKey, up = nms->presharedKey; *p; p += 2, ++up) { *up = hctoi(p[0]) * 16 + hctoi(p[1]); // hex string to byte array } while ((!IS_CONNECTED(g_ulStatus)) || (!IS_IP_ACQUIRED(g_ulStatus))) { osi_Sleep(500); } srand(xTaskGetTickCount()); stream_audio_init(); unabto_init(); while (true) { wait_event(); stream_audio_write(); } }
The actual audio streaming code is in stream_audio.c. The unabto_stream_event() function handles all incoming streaming events. Once a Nabto stream connection is established, the device is waiting for a stream command. In this case, there is only the command “audio”. If an unknown command is received, the device returns “-” and closes the stream. If “audio” is received from the client an acknowledgment is returned (“+”) and the actual audio streaming is started. Incoming audio data from the client is processed in lines 125-137:
if (my_audio_stream.state == STREAM_STATE_STREAMING) { const uint8_t* buf; unabto_stream_hint hint; size_t readLength = unabto_stream_read(stream, &buf, &hint); if (readLength > 0) { adpcm_decode(pPlayBuffer, buf, readLength); if (!unabto_stream_ack(stream, buf, readLength, &hint)) { my_audio_stream.state = STREAM_STATE_CLOSING; } } else { if (hint != UNABTO_STREAM_HINT_OK) { my_audio_stream.state = STREAM_STATE_CLOSING; } } }
The data is read from the stream, decoded, and written to the circular play buffer. Processed data has to be acknowledged with unabto_stream_ack(). For the audio encoding ADPCM is used (for implementation details see adpcm_audio.c). It compresses the two 16-bit stereo samples to one single byte. At 16000 samples per second, this results in a transfer bitrate of 16 kbit/s which is no problem for the CC3200, even for encrypted remote connections. If you want to have a more advanced codec like for example Speex, just replace the encoding and decoding functions.
As mentioned before, the uNabto task continuously checks for available recorded audio by calling the stream_audio_write() function. If new encoded audio is available and a stream is established, the data is sent.
void stream_audio_write() { if (my_audio_stream.state != STREAM_STATE_STREAMING) { return; } size_t encodedLen = adpcm_encode(pRecordBuffer, encodedBuf, sizeof(encodedBuf)); if (encodedLen == 0) { return; } else { UNABTO_ASSERT(encodedLen == sizeof(encodedBuf)); } unabto_stream_hint hint; size_t writeLength = unabto_stream_write(my_audio_stream.stream, encodedBuf, sizeof(encodedBuf), &hint); if (writeLength <= 0 && hint != UNABTO_STREAM_HINT_OK) { my_audio_stream.state = STREAM_STATE_CLOSING; } UpdateReadPtr(pRecordBuffer, writeLength * ENCODING_RATIO); }
Using the CC3200 Code
You can get the whole CC3200 code including the described platform adapter and the audio streaming device application from the audio branch of our public CC3200 GitHub repository. Simply follow the instructions in the README to set everything up.
The Android Client
The Android audio streaming client is also published on GitHub. It uses our android client SDK available on JCenter (for source code see GitHub repository). It is included in the build.gradle with one single line:
compile ‘com.nabto.android:nabto-api:1.0.1’
}
The main App logic is implemented in MainActiviy.java. Once the unique Device ID is entered in the UI and the OPEN AUDIO STREAM button is pressed, a thread is started to establish the stream connection and send the “audio” command. Then, a recording + sending and a receiving + playing thread are started until the connection breaks or the stream is closed by the user.
To run the App on your Android device, follow the README instructions in the repository. If you enter the Device ID, you should be able to establish a stream connection and hear the microphone (and line-in) input of the opposite device.
Good job and bunch of thanks for this valuable post.
I will try “CC3200 Two-Way Audio with Android”.
But It happened “CONNECT_TO_HOST_FAILED” in Android App.
1. I inputed nabtoId & presharedKey in “cc3200 unabto_task.c”.
(Device ID/License Key created in “appmyproduct site”)
2. I installed Android App
3. I inputed editTextDeviceId in MainActiviy.java (Device ID created in “appmyproduct site”) => (same with nabtoId)
4. I runed Android App and pressed “OPEN AUDIO STREAM” button
==> “CONNECT_TO_HOST_FAILED” in Android App.
nabtoApi.openSession(“guest”, “”); in Android App
Is it “guest” or “login email and password in “appmyproduct site”?
Thank you
Hi there!
The last question is easy – for this demo, it should just be “guest” and empty password as you have seen (see our other blog posts and general documentation on how to later securely pair client and device).
Can you connect to the device using another client, for instance the Nabto CLI (available as “Modernized CLI” from https://github.com/nabto/nabto-cli)? It has a stream test option that you can use to see if it is just possible to open a stream, of course you cannot use it for anything useful, but it should at least not yield an error. Use it as follows:
$ nabto-cli --stream-read -d 1.axis.nabto.net -n guest
nabtoStreamOpen() succeeded, stream = 0x7f9338c11b40
Otherwise, any logs and console output from either peer (your Android app and the target device) would be useful and also your device id so we can track from our side. If you don’t like posting this here, just send to [email protected].
Thanks,
Ulrik
Hi.
Please update the latest console login page in the github link.
https://github.com/nabto/unabto-cc3200/tree/audio
Also, the SDK of CC3200 is upgraded to 1.4.0, so I am not sure if it work for it, will try and check.
One request, you could provide a binary that has CLI which takes the Device ID and Pre shared key as input, stores it in the S-Flash, then reboots to run the application.
This will fasten the proof of concept for developers who would want to evaluate Nabto capability and help them to migrate and start developement on the Nabto platform.
Regards
Vijay
http://www.365designs.in
Blog articles like this is mostly done for a proof-of-concept validation and is meant for generating ideas. We only keep a small set of standard integrations up-to-date or when customers under a support contract requests this; there are simply too many different toolchains and integrations to keep up with this for our small team. We are considering to make an updated blog post to add video support for the CC32xx, this will include an update to latest SDK. But right now our tech team is too busy.